summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2019-11-02 11:07:23 +0800
committerJohn Hodge <tpg@ucc.asn.au>2019-11-02 11:07:23 +0800
commit1d02810c3cf908bfba7c15ae50eb5314603b9d85 (patch)
tree79dd5e4ef4c3ff79db0912ba546f08e61a7a8c10
parent7111acba04d72fe4084b1a1f3209ff83efe8614d (diff)
parent8b53b38f40625ab0510f541d69db3f83332a830a (diff)
downloadmrust-1d02810c3cf908bfba7c15ae50eb5314603b9d85.tar.gz
Merge branch 'nightly-1.29' - #95 Working support for rustc 1.29
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml4
-rw-r--r--Makefile160
-rw-r--r--Notes/BugStories.txt48
-rw-r--r--Notes/CodegenCEmbeddedTags.diff168
-rw-r--r--Notes/MIR-Optimisations.md67
-rw-r--r--Notes/MIR-PackedLValue.txt65
-rw-r--r--Notes/NOTES.txt177
-rw-r--r--Notes/SMiri-GenericFfi.md46
-rw-r--r--Notes/TopLevelTypecheck.md17
-rw-r--r--Notes/Typeck.txt12
-rw-r--r--Notes/todo.txt55
-rw-r--r--README.md6
-rwxr-xr-xTestRustcBootstrap.sh49
-rwxr-xr-xbuild-1.19.0.sh9
-rw-r--r--disabled_tests_run-pass.txt17
-rw-r--r--minicargo.mk108
-rw-r--r--run_rustc/Makefile160
-rw-r--r--rust-nightly-date2
-rw-r--r--rust-version2
-rw-r--r--rustc-1.19.0-src.patch (renamed from rust_src.patch)0
-rw-r--r--rustc-1.29.0-src.patch85
-rw-r--r--samples/test/enums.rs15
-rw-r--r--samples/test/funny_hash.rs39
-rw-r--r--samples/test/thread_drop.rs17
-rw-r--r--samples/test/vec_retain.rs6
-rw-r--r--script-overrides/stable-1.29.0-linux/build_compiler_builtins.txt1
-rw-r--r--script-overrides/stable-1.29.0-linux/build_libc.txt2
-rw-r--r--script-overrides/stable-1.29.0-linux/build_rustc_asan.txt0
-rw-r--r--script-overrides/stable-1.29.0-linux/build_rustc_lsan.txt0
-rw-r--r--script-overrides/stable-1.29.0-linux/build_rustc_msan.txt0
-rw-r--r--script-overrides/stable-1.29.0-linux/build_rustc_tsan.txt0
-rw-r--r--script-overrides/stable-1.29.0-linux/build_std.txt5
-rw-r--r--script-overrides/stable-1.29.0-linux/build_unwind.txt1
-rw-r--r--script-overrides/stable-1.29.0-windows/build_compiler_builtins.txt1
-rw-r--r--script-overrides/stable-1.29.0-windows/build_libc.txt2
-rw-r--r--script-overrides/stable-1.29.0-windows/build_rustc_asan.txt0
-rw-r--r--script-overrides/stable-1.29.0-windows/build_rustc_lsan.txt0
-rw-r--r--script-overrides/stable-1.29.0-windows/build_rustc_msan.txt0
-rw-r--r--script-overrides/stable-1.29.0-windows/build_rustc_tsan.txt0
-rw-r--r--script-overrides/stable-1.29.0-windows/build_std.txt5
-rw-r--r--script-overrides/stable-1.29.0-windows/build_unwind.txt1
-rw-r--r--scripts/log_get_last_function.py31
-rw-r--r--src/ast/ast.cpp102
-rw-r--r--src/ast/ast.hpp113
-rw-r--r--src/ast/attrs.hpp12
-rw-r--r--src/ast/crate.cpp146
-rw-r--r--src/ast/crate.hpp20
-rw-r--r--src/ast/dump.cpp49
-rw-r--r--src/ast/expr.cpp12
-rw-r--r--src/ast/expr.hpp39
-rw-r--r--src/ast/expr_ptr.hpp1
-rw-r--r--src/ast/generics.hpp6
-rw-r--r--src/ast/item.hpp15
-rw-r--r--src/ast/macro.hpp10
-rw-r--r--src/ast/path.cpp164
-rw-r--r--src/ast/path.hpp168
-rw-r--r--src/ast/pattern.cpp2
-rw-r--r--src/ast/pattern.hpp4
-rw-r--r--src/ast/types.cpp9
-rw-r--r--src/ast/types.hpp13
-rw-r--r--src/common.hpp21
-rw-r--r--src/coretypes.hpp2
-rw-r--r--src/debug.cpp8
-rw-r--r--src/expand/asm.cpp6
-rw-r--r--src/expand/assert.cpp88
-rw-r--r--src/expand/cfg.cpp14
-rw-r--r--src/expand/concat.cpp4
-rw-r--r--src/expand/crate_tags.cpp22
-rw-r--r--src/expand/derive.cpp776
-rw-r--r--src/expand/env.cpp20
-rw-r--r--src/expand/file_line.cpp26
-rw-r--r--src/expand/format_args.cpp203
-rw-r--r--src/expand/include.cpp19
-rw-r--r--src/expand/lang_item.cpp94
-rw-r--r--src/expand/macro_rules.cpp28
-rw-r--r--src/expand/mod.cpp287
-rw-r--r--src/expand/proc_macro.cpp91
-rw-r--r--src/expand/proc_macro.hpp8
-rw-r--r--src/expand/rustc_diagnostics.cpp14
-rw-r--r--src/expand/std_prelude.cpp8
-rw-r--r--src/expand/stringify.cpp6
-rw-r--r--src/expand/test.cpp15
-rw-r--r--src/expand/test_harness.cpp19
-rw-r--r--src/hir/crate_post_load.cpp2
-rw-r--r--src/hir/deserialise.cpp376
-rw-r--r--src/hir/dump.cpp79
-rw-r--r--src/hir/expr.cpp9
-rw-r--r--src/hir/expr.hpp38
-rw-r--r--src/hir/expr_ptr.cpp16
-rw-r--r--src/hir/expr_ptr.hpp1
-rw-r--r--src/hir/expr_state.hpp6
-rw-r--r--src/hir/from_ast.cpp503
-rw-r--r--src/hir/from_ast.hpp2
-rw-r--r--src/hir/from_ast_expr.cpp72
-rw-r--r--src/hir/generic_params.cpp2
-rw-r--r--src/hir/generic_params.hpp16
-rw-r--r--src/hir/hir.cpp1107
-rw-r--r--src/hir/hir.hpp205
-rw-r--r--src/hir/hir_ops.cpp1148
-rw-r--r--src/hir/item_path.hpp20
-rw-r--r--src/hir/main_bindings.hpp2
-rw-r--r--src/hir/path.cpp6
-rw-r--r--src/hir/path.hpp26
-rw-r--r--src/hir/pattern.cpp72
-rw-r--r--src/hir/pattern.hpp21
-rw-r--r--src/hir/serialise.cpp202
-rw-r--r--src/hir/serialise_lowlevel.cpp62
-rw-r--r--src/hir/serialise_lowlevel.hpp31
-rw-r--r--src/hir/type.cpp121
-rw-r--r--src/hir/type.hpp52
-rw-r--r--src/hir/visitor.cpp54
-rw-r--r--src/hir/visitor.hpp3
-rw-r--r--src/hir_conv/bind.cpp230
-rw-r--r--src/hir_conv/constant_evaluation.cpp505
-rw-r--r--src/hir_conv/constant_evaluation.hpp33
-rw-r--r--src/hir_conv/expand_type.cpp19
-rw-r--r--src/hir_conv/main_bindings.hpp6
-rw-r--r--src/hir_conv/markings.cpp15
-rw-r--r--src/hir_conv/resolve_ufcs.cpp35
-rw-r--r--src/hir_conv/resolve_ufcs_outer.cpp384
-rw-r--r--src/hir_expand/annotate_value_usage.cpp59
-rw-r--r--src/hir_expand/closures.cpp397
-rw-r--r--src/hir_expand/reborrow.cpp4
-rw-r--r--src/hir_expand/ufcs_everything.cpp8
-rw-r--r--src/hir_expand/vtable.cpp30
-rw-r--r--src/hir_typeck/common.cpp25
-rw-r--r--src/hir_typeck/common.hpp22
-rw-r--r--src/hir_typeck/expr_check.cpp220
-rw-r--r--src/hir_typeck/expr_cs.cpp4034
-rw-r--r--src/hir_typeck/expr_visit.cpp92
-rw-r--r--src/hir_typeck/expr_visit.hpp20
-rw-r--r--src/hir_typeck/helpers.cpp1001
-rw-r--r--src/hir_typeck/helpers.hpp27
-rw-r--r--src/hir_typeck/impl_ref.cpp61
-rw-r--r--src/hir_typeck/impl_ref.hpp17
-rw-r--r--src/hir_typeck/outer.cpp121
-rw-r--r--src/hir_typeck/static.cpp567
-rw-r--r--src/hir_typeck/static.hpp60
-rw-r--r--src/ident.cpp5
-rw-r--r--src/include/debug.hpp13
-rw-r--r--src/include/ident.hpp28
-rw-r--r--src/include/main_bindings.hpp1
-rw-r--r--src/include/rc_string.hpp116
-rw-r--r--src/include/span.hpp1
-rw-r--r--src/include/synext_decorator.hpp3
-rw-r--r--src/include/synext_macro.hpp6
-rw-r--r--src/include/tagged_union.hpp12
-rw-r--r--src/include/target_version.hpp19
-rw-r--r--src/macro_rules/eval.cpp892
-rw-r--r--src/macro_rules/macro_rules.hpp54
-rw-r--r--src/macro_rules/mod.cpp51
-rw-r--r--src/macro_rules/parse.cpp509
-rw-r--r--src/macro_rules/pattern_checks.hpp1
-rw-r--r--src/main.cpp144
-rw-r--r--src/mir/check.cpp198
-rw-r--r--src/mir/check_full.cpp230
-rw-r--r--src/mir/cleanup.cpp176
-rw-r--r--src/mir/dump.cpp45
-rw-r--r--src/mir/from_hir.cpp400
-rw-r--r--src/mir/from_hir.hpp22
-rw-r--r--src/mir/from_hir_match.cpp354
-rw-r--r--src/mir/helpers.cpp145
-rw-r--r--src/mir/helpers.hpp11
-rw-r--r--src/mir/mir.cpp208
-rw-r--r--src/mir/mir.hpp452
-rw-r--r--src/mir/mir_builder.cpp636
-rw-r--r--src/mir/mir_ptr.hpp9
-rw-r--r--src/mir/optimise.cpp1686
-rw-r--r--src/parse/common.hpp5
-rw-r--r--src/parse/eTokenType.enum.h3
-rw-r--r--src/parse/expr.cpp91
-rw-r--r--src/parse/interpolated_fragment.cpp11
-rw-r--r--src/parse/interpolated_fragment.hpp3
-rw-r--r--src/parse/lex.cpp23
-rw-r--r--src/parse/parseerror.cpp22
-rw-r--r--src/parse/paths.cpp42
-rw-r--r--src/parse/pattern.cpp75
-rw-r--r--src/parse/root.cpp920
-rw-r--r--src/parse/token.cpp56
-rw-r--r--src/parse/token.hpp7
-rw-r--r--src/parse/tokenstream.cpp4
-rw-r--r--src/parse/tokenstream.hpp2
-rw-r--r--src/parse/types.cpp83
-rw-r--r--src/rc_string.cpp113
-rw-r--r--src/resolve/absolute.cpp425
-rw-r--r--src/resolve/index.cpp333
-rw-r--r--src/resolve/use.cpp686
-rw-r--r--src/slice.hpp35
-rw-r--r--src/span.cpp6
-rw-r--r--src/trans/allocator.cpp19
-rw-r--r--src/trans/allocator.hpp10
-rw-r--r--src/trans/auto_impls.cpp248
-rw-r--r--src/trans/codegen.cpp15
-rw-r--r--src/trans/codegen.hpp2
-rw-r--r--src/trans/codegen_c.cpp1055
-rw-r--r--src/trans/codegen_mmir.cpp422
-rw-r--r--src/trans/enumerate.cpp953
-rw-r--r--src/trans/main_bindings.hpp4
-rw-r--r--src/trans/mangling.cpp17
-rw-r--r--src/trans/mangling_v2.cpp292
-rw-r--r--src/trans/monomorphise.cpp80
-rw-r--r--src/trans/target.cpp192
-rw-r--r--src/trans/target.hpp13
-rw-r--r--src/trans/trans_list.cpp17
-rw-r--r--src/trans/trans_list.hpp17
-rw-r--r--src/version.cpp8
-rwxr-xr-xtest_smiri.sh7
-rw-r--r--tools/common/debug.cpp4
-rw-r--r--tools/common/target_detect.h8
-rw-r--r--tools/common/toml.cpp3
-rw-r--r--tools/common/toml.h2
-rw-r--r--tools/dump_hirfile/Makefile56
-rw-r--r--tools/dump_hirfile/main.cpp327
-rw-r--r--tools/minicargo/Makefile2
-rw-r--r--tools/minicargo/build.cpp291
-rw-r--r--tools/minicargo/build.h10
-rw-r--r--tools/minicargo/cfg.cpp269
-rw-r--r--tools/minicargo/cfg.hpp9
-rw-r--r--tools/minicargo/main.cpp29
-rw-r--r--tools/minicargo/manifest.cpp340
-rw-r--r--tools/minicargo/manifest.h34
-rw-r--r--tools/minicargo/repository.cpp3
-rw-r--r--tools/minicargo/stringlist.h16
-rw-r--r--tools/standalone_miri/Makefile7
-rw-r--r--tools/standalone_miri/debug.cpp16
-rw-r--r--tools/standalone_miri/debug.hpp19
-rw-r--r--tools/standalone_miri/ffi.cpp141
-rw-r--r--tools/standalone_miri/hir_sim.cpp120
-rw-r--r--tools/standalone_miri/hir_sim.hpp120
-rw-r--r--tools/standalone_miri/lex.cpp4
-rw-r--r--tools/standalone_miri/linux.api50
-rw-r--r--tools/standalone_miri/main.cpp19
-rw-r--r--tools/standalone_miri/mir.cpp100
-rw-r--r--tools/standalone_miri/miri.cpp1547
-rw-r--r--tools/standalone_miri/miri.hpp19
-rw-r--r--tools/standalone_miri/module_tree.cpp110
-rw-r--r--tools/standalone_miri/module_tree.hpp34
-rw-r--r--tools/standalone_miri/u128.hpp170
-rw-r--r--tools/standalone_miri/value.cpp594
-rw-r--r--tools/standalone_miri/value.hpp299
-rw-r--r--tools/standalone_miri/win32.api24
-rw-r--r--tools/testrunner/main.cpp143
-rw-r--r--vsproject/build_cargo_minicargo.cmd11
-rw-r--r--vsproject/build_rustc_minicargo.cmd11
-rw-r--r--vsproject/build_std.cmd20
-rw-r--r--vsproject/minicargo/minicargo.vcxproj9
-rw-r--r--vsproject/minicargo/minicargo.vcxproj.filters3
-rw-r--r--vsproject/mrustc.vcxproj6
-rw-r--r--vsproject/mrustc.vcxproj.filters18
-rw-r--r--vsproject/run_hello.cmd13
-rw-r--r--vsproject/standalone_miri/standalone_miri.vcxproj11
-rw-r--r--vsproject/standalone_miri/standalone_miri.vcxproj.filters3
253 files changed, 23677 insertions, 10404 deletions
diff --git a/.gitignore b/.gitignore
index e6040167..85e154ff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,7 @@
/vsproject/*/*.opendb
/vsproject/*/*.user
/vsproject/output
+/vsproject/output-*
/vsproject/output_mmir
/vsproject/*.obj
/vsproject/*.pdb
diff --git a/.travis.yml b/.travis.yml
index 04d7ea11..d2df23dc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,7 +8,7 @@ matrix:
- os: linux
before_install:
- export CC=gcc-6
- - export CC-x86_64-linux-gnu=gcc-6
+# - export CC-x86_64-linux-gnu=gcc-6
- export CXX=g++-6
addons:
apt:
@@ -31,7 +31,7 @@ install:
script:
- set -e
- - make -f minicargo.mk output/libtest.hir # libstd
+ - make -f minicargo.mk output/libtest.rlib # libstd
- make test # hello_world
# Tests
- set +e
diff --git a/Makefile b/Makefile
index 2ef88f9e..1fbd7934 100644
--- a/Makefile
+++ b/Makefile
@@ -15,9 +15,13 @@ ifeq ($(OS),Windows_NT)
endif
EXESUF ?=
CXX ?= g++
-V ?= @
-
-TARGET_CC ?= clang
+V ?= !
+GPROF ?=
+ifeq ($(V),!)
+ V := @
+else
+ V :=
+endif
TAIL_COUNT ?= 10
@@ -50,7 +54,7 @@ CXXFLAGS += -Wno-unknown-warning-option
RUST_FLAGS := --cfg debug_assertions
RUST_FLAGS += -g
RUST_FLAGS += -O
-RUST_FLAGS += -L output/
+RUST_FLAGS += -L output$(OUTDIR_SUF)/
RUST_FLAGS += $(RUST_FLAGS_EXTRA)
SHELL = bash
@@ -68,6 +72,13 @@ endif
OBJDIR = .obj/
+ifneq ($(GPROF),)
+ OBJDIR := .obj-gprof/
+ CXXFLAGS += -pg -no-pie
+ LINKFLAGS += -pg -no-pie
+ EXESUF := -gprof$(EXESUF)
+endif
+
BIN := bin/mrustc$(EXESUF)
OBJ := main.o version.o
@@ -89,16 +100,17 @@ OBJ += expand/env.o
OBJ += expand/test.o
OBJ += expand/rustc_diagnostics.o
OBJ += expand/proc_macro.o
+OBJ += expand/assert.o
OBJ += expand/test_harness.o
OBJ += macro_rules/mod.o macro_rules/eval.o macro_rules/parse.o
OBJ += resolve/use.o resolve/index.o resolve/absolute.o
OBJ += hir/from_ast.o hir/from_ast_expr.o
OBJ += hir/dump.o
-OBJ += hir/hir.o hir/generic_params.o
+OBJ += hir/hir.o hir/hir_ops.o hir/generic_params.o
OBJ += hir/crate_ptr.o hir/expr_ptr.o
OBJ += hir/type.o hir/path.o hir/expr.o hir/pattern.o
OBJ += hir/visitor.o hir/crate_post_load.o
-OBJ += hir_conv/expand_type.o hir_conv/constant_evaluation.o hir_conv/resolve_ufcs.o hir_conv/bind.o hir_conv/markings.o
+OBJ += hir_conv/expand_type.o hir_conv/constant_evaluation.o hir_conv/resolve_ufcs.o hir_conv/resolve_ufcs_outer.o hir_conv/bind.o hir_conv/markings.o
OBJ += hir_typeck/outer.o hir_typeck/common.o hir_typeck/helpers.o hir_typeck/static.o hir_typeck/impl_ref.o
OBJ += hir_typeck/expr_visit.o
OBJ += hir_typeck/expr_cs.o
@@ -112,8 +124,8 @@ OBJ += mir/from_hir.o mir/from_hir_match.o mir/mir_builder.o
OBJ += mir/check.o mir/cleanup.o mir/optimise.o
OBJ += mir/check_full.o
OBJ += hir/serialise.o hir/deserialise.o hir/serialise_lowlevel.o
-OBJ += trans/trans_list.o trans/mangling.o
-OBJ += trans/enumerate.o trans/monomorphise.o trans/codegen.o
+OBJ += trans/trans_list.o trans/mangling_v2.o
+OBJ += trans/enumerate.o trans/auto_impls.o trans/monomorphise.o trans/codegen.o
OBJ += trans/codegen_c.o trans/codegen_c_structured.o trans/codegen_mmir.o
OBJ += trans/target.o trans/allocator.o
@@ -137,25 +149,26 @@ RUSTC_SRC_DES := rust-nightly-date
RUSTCSRC := rustc-nightly-src/
else ifeq ($(RUSTC_SRC_TY),stable)
RUSTC_SRC_DES := rust-version
-RUSTCSRC := rustc-$(shell cat $(RUSTC_SRC_DES))-src/
+RUSTC_VERSION ?= $(shell cat $(RUSTC_SRC_DES))
+RUSTCSRC := rustc-$(RUSTC_VERSION)-src/
else
$(error Unknown rustc channel)
endif
RUSTC_SRC_DL := $(RUSTCSRC)/dl-version
-MAKE_MINICARGO = $(MAKE) -f minicargo.mk RUSTC_VERSION=$(shell cat $(RUSTC_SRC_DES)) RUSTC_CHANNEL=$(RUSTC_SRC_TY)
+MAKE_MINICARGO = $(MAKE) -f minicargo.mk RUSTC_VERSION=$(RUSTC_VERSION) RUSTC_CHANNEL=$(RUSTC_SRC_TY) OUTDIR_SUF=$(OUTDIR_SUF)
-output/libstd.hir: $(BIN)
+output$(OUTDIR_SUF)/libstd.rlib: $(RUSTC_SRC_DL) $(BIN)
$(MAKE_MINICARGO) $@
-output/libtest.hir output/libpanic_unwind.hir output/libproc_macro.hir: output/libstd.hir
+output$(OUTDIR_SUF)/libtest.rlib output$(OUTDIR_SUF)/libpanic_unwind.rlib output$(OUTDIR_SUF)/libproc_macro.rlib: output$(OUTDIR_SUF)/libstd.rlib
$(MAKE_MINICARGO) $@
-output/rustc output/cargo: output/libtest.hir
+output$(OUTDIR_SUF)/rustc output$(OUTDIR_SUF)/cargo: output$(OUTDIR_SUF)/libtest.rlib
$(MAKE_MINICARGO) $@
-TEST_DEPS := output/libstd.hir output/libtest.hir output/libpanic_unwind.hir output/librust_test_helpers.a
+TEST_DEPS := output$(OUTDIR_SUF)/libstd.rlib output$(OUTDIR_SUF)/libtest.rlib output$(OUTDIR_SUF)/libpanic_unwind.rlib
-fcn_extcrate = $(patsubst %,output/lib%.hir,$(1))
+fcn_extcrate = $(patsubst %,output$(OUTDIR_SUF)/lib%.rlib,$(1))
fn_getdeps = \
$(shell cat $1 \
@@ -166,6 +179,10 @@ fn_getdeps = \
.PHONY: RUSTCSRC
RUSTCSRC: $(RUSTC_SRC_DL)
+#
+# rustc (with std/cargo) source download
+#
+# NIGHTLY:
ifeq ($(RUSTC_SRC_TY),nightly)
rustc-nightly-src.tar.gz: $(RUSTC_SRC_DES)
@export DL_RUST_DATE=$$(cat rust-nightly-date); \
@@ -174,25 +191,25 @@ rustc-nightly-src.tar.gz: $(RUSTC_SRC_DES)
rm -f rustc-nightly-src.tar.gz; \
curl -sS https://static.rust-lang.org/dist/$${DL_RUST_DATE}/rustc-nightly-src.tar.gz -o rustc-nightly-src.tar.gz
-# TODO: Handle non-nightly download
-$(RUSTC_SRC_DL): rust-nightly-date rustc-nightly-src.tar.gz rust_src.patch
+$(RUSTC_SRC_DL): rust-nightly-date rustc-nightly-src.tar.gz rustc-nightly-src.patch
@export DL_RUST_DATE=$$(cat rust-nightly-date); \
export DISK_RUST_DATE=$$([ -f $(RUSTC_SRC_DL) ] && cat $(RUSTC_SRC_DL)); \
if [ "$$DL_RUST_DATE" != "$$DISK_RUST_DATE" ]; then \
rm -rf rustc-nightly-src; \
tar -xf rustc-nightly-src.tar.gz; \
- cd $(RUSTSRC) && patch -p0 < ../rust_src.patch; \
+ cd $(RUSTSRC) && patch -p0 < ../rustc-nightly-src.patch; \
fi
cat rust-nightly-date > $(RUSTC_SRC_DL)
else
-RUSTC_SRC_TARBALL := rustc-$(shell cat $(RUSTC_SRC_DES))-src.tar.gz
+# NAMED (Stable or beta)
+RUSTC_SRC_TARBALL := rustc-$(RUSTC_VERSION)-src.tar.gz
$(RUSTC_SRC_TARBALL): $(RUSTC_SRC_DES)
@echo [CURL] $@
@rm -f $@
@curl -sS https://static.rust-lang.org/dist/$@ -o $@
-$(RUSTC_SRC_DL): $(RUSTC_SRC_TARBALL) rust_src.patch
+$(RUSTC_SRC_DL): $(RUSTC_SRC_TARBALL) rustc-$(RUSTC_VERSION)-src.patch
tar -xf $(RUSTC_SRC_TARBALL)
- cd $(RUSTCSRC) && patch -p0 < ../rust_src.patch;
+ cd $(RUSTCSRC) && patch -p0 < ../rustc-$(RUSTC_VERSION)-src.patch;
cat $(RUSTC_SRC_DES) > $(RUSTC_SRC_DL)
endif
@@ -201,8 +218,8 @@ endif
.PHONY: local_tests
local_tests:
@$(MAKE) -C tools/testrunner
- @mkdir -p output/local_tests
- ./tools/bin/testrunner -o output/local_tests samples/test
+ @mkdir -p output$(OUTDIR_SUF)/local_tests
+ ./tools/bin/testrunner -o output$(OUTDIR_SUF)/local_tests -L output samples/test
#
# RUSTC TESTS
@@ -215,14 +232,20 @@ rust_tests: RUST_TESTS_run-pass
.PHONY: RUST_TESTS RUST_TESTS_run-pass
RUST_TESTS: RUST_TESTS_run-pass
-RUST_TESTS_run-pass: output/librust_test_helpers.a
+RUST_TESTS_run-pass: output$(OUTDIR_SUF)/test/librust_test_helpers.a
@$(MAKE) -C tools/testrunner
- @mkdir -p output/rust_tests/run-pass
- ./tools/bin/testrunner -o output/rust_tests/run-pass $(RUST_TESTS_DIR)run-pass --exceptions disabled_tests_run-pass.txt
-output/librust_test_helpers.a: output/rust_test_helpers.o
+ @mkdir -p output$(OUTDIR_SUF)/rust_tests/run-pass
+ make -f minicargo.mk output$(OUTDIR_SUF)/test/libtest.so
+ ./tools/bin/testrunner -L output$(OUTDIR_SUF)/test -o output$(OUTDIR_SUF)/rust_tests/run-pass $(RUST_TESTS_DIR)run-pass --exceptions disabled_tests_run-pass.txt
+output$(OUTDIR_SUF)/test/librust_test_helpers.a: output$(OUTDIR_SUF)/test/rust_test_helpers.o
@mkdir -p $(dir $@)
ar cur $@ $<
-output/rust_test_helpers.o: $(RUSTCSRC)src/rt/rust_test_helpers.c
+ifeq ($(RUSTC_VERSION),1.19.0)
+RUST_TEST_HELPERS_C := $(RUSTCSRC)src/rt/rust_test_helpers.c
+else
+RUST_TEST_HELPERS_C := $(RUSTCSRC)src/test/auxiliary/rust_test_helpers.c
+endif
+output$(OUTDIR_SUF)/test/rust_test_helpers.o: $(RUST_TEST_HELPERS_C)
@mkdir -p $(dir $@)
$(CC) -c $< -o $@
@@ -230,87 +253,26 @@ output/rust_test_helpers.o: $(RUSTCSRC)src/rt/rust_test_helpers.c
# libstd tests
#
.PHONY: rust_tests-libs
+rust_tests-libs: $(TEST_DEPS)
+ make -f minicargo.mk $@
-LIB_TESTS := collections #std
-#LIB_TESTS += rustc_data_structures
-rust_tests-libs: $(patsubst %,output/lib%-test_out.txt, $(LIB_TESTS))
-
-RUNTIME_ARGS_output/libcollections-test := --test-threads 1
-#RUNTIME_ARGS_output/libcore-test := --test-threads 1
-RUNTIME_ARGS_output/libstd-test := --test-threads 1
-RUNTIME_ARGS_output/libstd-test += --skip ::collections::hash::map::test_map::test_index_nonexistent
-RUNTIME_ARGS_output/libstd-test += --skip ::collections::hash::map::test_map::test_drops
-RUNTIME_ARGS_output/libstd-test += --skip ::collections::hash::map::test_map::test_placement_drop
-RUNTIME_ARGS_output/libstd-test += --skip ::collections::hash::map::test_map::test_placement_panic
-RUNTIME_ARGS_output/libstd-test += --skip ::io::stdio::tests::panic_doesnt_poison # Unbounded execution
-
-output/libcore-test: $(RUSTCSRC)src/libcore/tests/lib.rs $(TEST_DEPS)
- @echo "--- [MRUSTC] --test -o $@"
- @mkdir -p output/
- @rm -f $@
- $(DBG) $(ENV_$@) $(BIN) --test $< -o $@ $(RUST_FLAGS) $(ARGS_$@) $(PIPECMD)
-# # HACK: Work around gdb returning success even if the program crashed
- @test -e $@
-output/lib%-test: $(RUSTCSRC)src/lib%/lib.rs $(TEST_DEPS)
- @echo "--- [MRUSTC] --test -o $@"
- @mkdir -p output/
- @rm -f $@
- $(DBG) $(ENV_$@) $(BIN) --test $< -o $@ $(RUST_FLAGS) $(ARGS_$@) $(PIPECMD)
-# # HACK: Work around gdb returning success even if the program crashed
- @test -e $@
-output/lib%-test: $(RUSTCSRC)src/lib%/src/lib.rs $(TEST_DEPS)
- @echo "--- [MRUSTC] $@"
- @mkdir -p output/
- @rm -f $@
- $(DBG) $(ENV_$@) $(BIN) --test $< -o $@ $(RUST_FLAGS) $(ARGS_$@) $(PIPECMD)
-# # HACK: Work around gdb returning success even if the program crashed
- @test -e $@
-output/%_out.txt: output/%
- @echo "--- [$<]"
- $V./$< $(RUNTIME_ARGS_$<) > $@ || (tail -n 1 $@; mv $@ $@_fail; false)
+
+.PHONY: test
+#
+# TEST: Rust standard library and the "hello, world" run-pass test
+#
+test: output$(OUTDIR_SUF)/rust/test_run-pass_hello_out.txt
# "hello, world" test - Invoked by the `make test` target
-output/rust/test_run-pass_hello: $(RUST_TESTS_DIR)run-pass/hello.rs $(TEST_DEPS)
+output$(OUTDIR_SUF)/rust/test_run-pass_hello: $(RUST_TESTS_DIR)run-pass/hello.rs $(TEST_DEPS)
@mkdir -p $(dir $@)
@echo "--- [MRUSTC] -o $@"
$(DBG) $(BIN) $< -o $@ $(RUST_FLAGS) $(PIPECMD)
-output/rust/test_run-pass_hello_out.txt: output/rust/test_run-pass_hello
+output$(OUTDIR_SUF)/rust/test_run-pass_hello_out.txt: output$(OUTDIR_SUF)/rust/test_run-pass_hello
@echo "--- [$<]"
@./$< | tee $@
-
-.PHONY: test test_rustos
-#
-# TEST: Rust standard library and the "hello, world" run-pass test
-#
-test: output/libstd.hir output/rust/test_run-pass_hello_out.txt $(BIN) TEST_targetsaveback
-
-.PHONY: TEST_targetsaveback
-TEST_targetsaveback:
- $(BIN) --target ./samples/target_stress_test.toml --dump-target-spec TMP-dump-target_stress_test.toml
- $(BIN) --target ./TMP-dump-target_stress_test.toml --dump-target-spec TMP-dump-target_stress_test-2.toml
- diff ./samples/target_stress_test.toml TMP-dump-target_stress_test.toml
- diff TMP-dump-target_stress_test.toml TMP-dump-target_stress_test-2.toml
-
-#
-# TEST: Attempt to compile rust_os (Tifflin) from ../rust_os
-#
-test_rustos: $(addprefix output/rust_os/,libkernel.hir)
-
-RUSTOS_ENV := RUST_VERSION="mrustc 0.1"
-RUSTOS_ENV += TK_GITSPEC="unknown"
-RUSTOS_ENV += TK_VERSION="0.1"
-RUSTOS_ENV += TK_BUILD="mrustc:0"
-
-output/rust_os/libkernel.hir: ../rust_os/Kernel/Core/main.rs output/libcore.hir output/libstack_dst.hir $(BIN)
- @mkdir -p $(dir $@)
- export $(RUSTOS_ENV) ; $(DBG) $(BIN) $(RUST_FLAGS) $< -o $@ --cfg arch=amd64 $(PIPECMD)
-output/libstack_dst.hir: ../rust_os/externals/crates.io/stack_dst/src/lib.rs $(BIN)
- @mkdir -p $(dir $@)
- $(DBG) $(BIN) $(RUST_FLAGS) $< -o $@ --cfg feature=no_std $(PIPECMD)
-
-
# -------------------------------
# Compile rules for mrustc itself
# -------------------------------
diff --git a/Notes/BugStories.txt b/Notes/BugStories.txt
new file mode 100644
index 00000000..b7437fb6
--- /dev/null
+++ b/Notes/BugStories.txt
@@ -0,0 +1,48 @@
+2019-07-13: Sizeof mismatch
+===========================
+
+librustc takes ~20mins to recompile, and that's just one crate out of ~80 in rustc
+- rustc failing on a consistency check
+- Turn on debug logging, add more to find where things become inconsistent
+- add assertion that a hashmap insert worked
+- started crashing earlier (but same place)
+- Print the map, item is there
+- Start dumping hashes, they don't match
+- Check equality of pre-hash values, they match
+- Check input to hasher, don't see anything too odd
+- Add more debug to make it easier to see the instance hashig
+- Notice the difference, a pointer difference?
+- Match the hash inputs to fields, find an odd pair with the `ty::Slice` type
+- Start chasing it's Hash impl down, it's supposed to just hash the pointer
+ - Actual impl hashes two words, not just one
+ - The source code checks sizeof to pick between one/two word hashing
+ - But post-optimisation it's always picking two
+ - Turn off that optimisation and rebuild librustc, no change?
+- Check libcore's metadata, it has the bug already (in the generic version?)
+- Enable optimisation debug and rebuild libcore
+- Oh look, `sizeof<*const T>` where `T: ?Sized` is returning 16 instead of returning "I don't know yet"
+
+
+2019-07-20: Leaking MPSC handles
+================================
+
+- rustc just stopping after codegen
+- gdb backtrace shows only one thread, waiting on a MPSC receiver
+- add debugging for MPSC Shared handles for that specific type, LOOTS of them being made (testing on a 14 core machine)
+- Turn down codegen units to 1, now a total of 6 handles (much easier)
+- Check all allocation paths, looks like all of them should call the destructor on the returned handle...
+ - One path hands a handle to a thread, let's chase that down
+ - Nope... that destuctor does get called... hmm...
+- Break down (after two weekends) and hack in handle indexes to mpsc::Shared
+ (on clone, allocate a unique ID and store that in the handle).
+- Re-run, printing the handle indexes - Notice that one code path (two
+ handles) leaks its handles
+- Re-check, the destructor is called... but I can't break on it?
+- Chase down the call chain, reach a Box drop impl (wait... that exists, I
+ thought the compiler made a custom one)
+ - It does absolutely nothing. No free, no destructor... oops
+- Turns out that 1.29 added a no-op Drop impl for Box (1.19 didn't have one), which
+ caused mrustc's magic Drop impl to not be created.
+
+<!-- vim: ft=markdown
+-->
diff --git a/Notes/CodegenCEmbeddedTags.diff b/Notes/CodegenCEmbeddedTags.diff
new file mode 100644
index 00000000..62fea1cb
--- /dev/null
+++ b/Notes/CodegenCEmbeddedTags.diff
@@ -0,0 +1,168 @@
+diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
+index 9af87d47..bcf296db 100644
+--- a/src/trans/codegen_c.cpp
++++ b/src/trans/codegen_c.cpp
+@@ -1385,12 +1385,22 @@ namespace {
+
+ void emit_enum_path(const TypeRepr* repr, const TypeRepr::FieldPath& path)
+ {
+- if( TU_TEST1(repr->variants, Values, .field.index == path.index) )
++ if( TU_TEST1(repr->variants, Values, .field.index == path.index) || path.index == ~0u )
+ {
+- m_of << ".TAG";
++ // TODO: The tag can be within the union
++ if( repr->fields.size() >= 2 )
++ {
++ m_of << ".DATA.var_tag.TAG";
++ }
++ else
++ {
++ m_of << ".TAG";
++ }
++ return ;
+ }
+ else
+ {
++ // TODO: Support for non-zero offsets?
+ m_of << ".DATA.var_" << path.index;
+ }
+ const auto* ty = &repr->fields[path.index].ty;
+@@ -1458,55 +1468,44 @@ namespace {
+ assert(1 + union_fields.size() + 1 >= repr->fields.size());
+ // Make the union!
+ // NOTE: The way the structure generation works is that enum variants are always first, so the field index = the variant index
+- // TODO:
+- if( !this->type_is_bad_zst(repr->fields[0].ty) || ::std::any_of(union_fields.begin(), union_fields.end(), [this,repr](auto x){ return !this->type_is_bad_zst(repr->fields[x].ty); }) )
++ m_of << "\tunion {\n";
++ bool is_tagged = (1 + union_fields.size() < repr->fields.size());
++ // > First field
++ for(size_t idx = 0; idx < repr->fields.size()-(is_tagged ? 1 : 0); idx ++)
+ {
+- m_of << "\tunion {\n";
+- // > First field
+- {
+- m_of << "\t\t";
+- const auto& ty = repr->fields[0].ty;
+- if( this->type_is_bad_zst(ty) ) {
+- m_of << "// ZST: " << ty << "\n";
+- }
+- else {
+- emit_ctype( ty, FMT_CB(ss, ss << "var_0") );
+- m_of << ";\n";
+- //sized_fields ++;
+- }
++ m_of << "\t\tstruct {";
++ const auto& ty = repr->fields[idx].ty;
++ if( this->type_is_bad_zst(ty) ) {
++ m_of << "/* ZST: " << ty << "*/";
+ }
+- // > All others
+- for(auto idx : union_fields)
++ else {
++ emit_ctype( ty, FMT_CB(os, os << "d") );
++ m_of << ";";
++ //sized_fields ++;
++ }
++ if( is_tagged )
+ {
+- m_of << "\t\t";
+-
+- const auto& ty = repr->fields[idx].ty;
+- if( this->type_is_bad_zst(ty) ) {
+- m_of << "// ZST: " << ty << "\n";
+- }
+- else {
+- emit_ctype( ty, FMT_CB(ss, ss << "var_" << idx) );
+- m_of << ";\n";
+- //sized_fields ++;
++ auto padbytes = repr->fields.back().offset - Target_GetSizeOf(ty);
++ if( padbytes > 0 )
++ {
++ m_of << "char pad[" << padbytes << "];";
+ }
++ emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "TAG")); m_of << ";";
+ }
+- m_of << "\t} DATA;\n";
++ m_of << "} var_" << idx << "\n";
+ }
+-
+- if( repr->fields.size() == 1 + union_fields.size() )
++ // NOTE: The tag can be placed within variants (overlapping with padding bytes)
++ if( !is_tagged )
+ {
+ // No tag, the tag is in one of the fields.
+ DEBUG("Untagged, nonzero or other");
+ }
+ else
+ {
+- //assert(repr->fields.back().offset != repr->fields.front().offset);
+ DEBUG("Tag present at offset " << repr->fields.back().offset << " - " << repr->fields.back().ty);
+-
+- m_of << "\t";
+- emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "TAG"));
+- m_of << ";\n";
++ m_of << "\t\tstruct { char pad[" << repr->fields.back().offset << "]; "; emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "TAG")); m_of << "; } var_tag;\n";
+ }
++ m_of << "\t} DATA;\n";
+ }
+ else if( repr->fields.size() == 1 )
+ {
+@@ -1591,7 +1590,7 @@ namespace {
+ {
+ auto var_lv =::MIR::LValue::new_Downcast(mv$(self), 0);
+
+- m_of << "\tswitch(rv->TAG) {\n";
++ m_of << "\tswitch((*rv)";emit_enum_path(repr, {~0u}); m_of << ") {\n";
+ for(unsigned int var_idx = 0; var_idx < e->values.size(); var_idx ++)
+ {
+ m_of << "\tcase " << e->values[var_idx] << ":\n";
+@@ -1652,7 +1651,7 @@ namespace {
+ {
+ case TypeRepr::VariantMode::TAGDEAD: throw "";
+ TU_ARM(repr->variants, Values, ve) {
+- m_of << " .TAG = "; emit_enum_variant_val(repr, var_idx); m_of << ",";
++ m_of << " .DATA = { .var_tag = { .TAG = "; emit_enum_variant_val(repr, var_idx); m_of << " }},";
+ } break;
+ TU_ARM(repr->variants, NonZero, ve) {
+ } break;
+@@ -1949,7 +1948,7 @@ namespace {
+ emit_literal(ity, *e.val, params);
+ m_of << " }, ";
+ }
+- m_of << ".TAG = "; emit_enum_variant_val(repr, e.idx);
++ emit_enum_path(repr, {~0u}); m_of << " = "; emit_enum_variant_val(repr, e.idx);
+ m_of << "}";
+ }
+ ),
+@@ -3292,11 +3291,11 @@ namespace {
+ }
+ else if( enm_p->is_value() )
+ {
+- emit_lvalue(e.dst); m_of << ".TAG = "; emit_enum_variant_val(repr, ve.index);
++ emit_lvalue(e.dst); emit_enum_path(repr, {~0u}); m_of << " = "; emit_enum_variant_val(repr, ve.index);
+ }
+ else
+ {
+- emit_lvalue(e.dst); m_of << ".TAG = "; emit_enum_variant_val(repr, ve.index);
++ emit_lvalue(e.dst); emit_enum_path(repr, {~0u}); m_of << " = "; emit_enum_variant_val(repr, ve.index);
+
+ ::HIR::TypeRef tmp;
+ const auto& vty = mir_res.get_param_type(tmp, ve.val);
+@@ -3542,7 +3541,7 @@ namespace {
+ if (ve.type.m_data.is_Primitive() && ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Enum())
+ {
+ emit_lvalue(ve.val);
+- m_of << ".TAG";
++ m_of << ".TAG"; // TODO: Fix for tag locations? (may not be needed for value-only enums)
+ special = true;
+ }
+ if (!special)
+@@ -3605,7 +3604,7 @@ namespace {
+ case ::HIR::CoreType::Str:
+ MIR_BUG(mir_res, "Unsized tag?!");
+ }
+- m_of << indent << "switch("; emit_lvalue(val); m_of << ".TAG) {\n";
++ m_of << indent << "switch("; emit_lvalue(val); emit_enum_path(repr, {~0u}); m_of << ") {\n";
+ for(size_t j = 0; j < n_arms; j ++)
+ {
+ // TODO: Get type of this field and check if it's signed.
diff --git a/Notes/MIR-Optimisations.md b/Notes/MIR-Optimisations.md
index 57f29c88..df7d8239 100644
--- a/Notes/MIR-Optimisations.md
+++ b/Notes/MIR-Optimisations.md
@@ -18,6 +18,19 @@ If a recorded local is used via field access, record the field and location
At the end of the block, remove original tuple assignment and propagate the values to destinations.
+Simple De-Temporary
+===================
+
+Purpose: Remove single-use temporaries
+`_1 = ...; _2 = _1` -> `_2 = ...`
+
+Algorithm
+---------
+
+- Locate locals that are only every read/written once
+- If the use is an assignment AND the destination isn't invalidated between the first assign and second
+ - Replace the original assignment with the second destination
+
De-Temporary (version 1)
========================
@@ -186,3 +199,57 @@ CFG Simplification
==================
Purpose: Remove gotos to blocks that only have a single use
+
+Borrow Elimination
+==================
+Purpose: Remove borrows generated by method calls that have been inlined
+
+Overview
+--------
+- Find locals that are only assigned once, and only ever used via a deref
+ operation.
+ - Allow drops to use the destination by value
+- If the assignment was a Borrow RValue, continue
+- Iterate forward, replacing usage of the value with the original source while:
+ - The source isn't invalidated
+ - The number of replacements is less than the number of known usage sites
+- If the original borrow itself contained a deref of a local, update that
+ local's usage count.
+- If all usage sites were updated, erase the original borrow
+
+
+Borrow Elimination 2
+====================
+Purpose: Remove borrows of borrows that are never used again
+
+Overview
+--------
+- Find assign-once/use-once locals (ignoring drop)
+- If the source is a borrow of a deref of a local/argument, continue
+- If the source inner value is of the same type as the local, continue
+ - I.e. we're not re-borrowing a `&mut` as `&`
+- If the variable's type is not `&` (i.e. it's &mut or &uniq)
+ - Check the usage count for the source value, and only continue is this is
+ the only usage site of the source
+ - Ideally: This would only check forwards, but that's hard
+- If the variable's type is `&`, check the path between assignment and usage
+ for invalidation.
+- If no invalidation found, replace usage with inner of assignment and erase
+ assignment.
+
+
+Slice Transmute
+===============
+Purpose: Detect places where slices are createdby transmuting from a (usize,usize) and replace with
+dedicated MIR statement.
+
+Overview
+--------
+- Find transmute calls with a destination type of `&[T]`
+- Check the input type:
+ - `(usize,usize)` : good
+ - `struct Foo { usize, usize }` : good
+- Check if the input was a use/write once local
+- Locate assignment of input
+ - Check if it was a struct/tuple literal
+- Remove assignment, replace transmute with at `MAKEDST` op
diff --git a/Notes/MIR-PackedLValue.txt b/Notes/MIR-PackedLValue.txt
new file mode 100644
index 00000000..ce889aee
--- /dev/null
+++ b/Notes/MIR-PackedLValue.txt
@@ -0,0 +1,65 @@
+Problem statement:
+- MIR LValues are very common, and suffer from excessive indirection when
+ dereferences and field accesses are present
+- Many MIR analysis passes care most about the inner values
+- Pointer chasing ruins cache locality
+
+Solution: Replace the tagged union tree with a flatteded structure
+
+Quirk: Indexing takes two LValues to produce one BUT one of those is of a
+lesser class, so doesn't need to be treated the same.
+
+
+
+Structure proposal:
+----
+A LValue is made up of:
+- A root value (referencing a local, argument, static, or the return value)
+- And a list of wrappers (dereference, field, downcast, index)
+
+Root values are encoded as a packed pointer/value and tag, with the tag stored in the low 2 bits of the pointer
+- This allows a 32-bit pointer to a word to be stored, using the alignment bits as tag
+- Arguments and locals are encoded with the argument/local index in the "data" bits
+- Return value is encoded as argument `-1` (all 1 bits in data)
+- Statics are encoded as a pointer to a `::HIR::Path`
+ - This adds a new pointer access and allocation vs the existing LValue structure
+ - HIR::Path already has a bunch of pointers in it, may not hurt that much (and may help by keeping the normal size
+ of the LValue down)
+
+Wrappers are stored as a vector of words, packed in a similar way to root values
+- Dereference is stored just as an entry (could pack multiple derefs into one, but that would make handling more
+ difficult)
+- Field/Downcast is stored with the field/variant index in the "data" bits
+- Indexing is stored as a pointer to a LValue
+ - ALTERNATIVE: Could require that indexing always uses a local, and just store the local index
+ - This would vastly reduce complexity in handling the Index wrapper, BUT would add a new statement in some cases
+ - A quick scan of the MMIR output of libstd crates, shows that the vast majority of indexing cases are with a local
+ directly.
+ - Doing so would simplify monomorph/clone/serialise (no need to clone the wrapper list, just copy it).
+ - Would also improve comparison times
+
+
+
+Usecase comparisons
+------
+(Using 32-bit architecture)
+
+NOTES:
+- Existing `LValue` structure is 3 words long (1 tag, plus 2 pointers for largest variant)
+ - WRONG. It's actually far larger due to the ::HIR::Path embedded in it (estimate at least 8 pointers, very likely
+ more). That should be fixed given the number of LValue-s that exist
+ - Fixed now, had a slight improvement in compile times (and memory usage?)
+- New structure is 4 words long (root value, plus len/cap/ptr for vector)
+
+- Field access via `&self`
+ - Old: Field(Deref(Argument(0)), 0)
+ - 12 + 12 + 12 = 36 bytes w/ 2 pointers
+ - New: LValue( Argument(0), { Deref, Field(0) } )
+ - 16 + 8 = 24 bytes w/ 1 pointer
+
+- Array stored in `&self` (common in librand)
+ - `(*arg0).2[var16].0`
+ - Old: Field( Index(Field(Deref(Argument(0)), 2), Local(16)), 0 )
+ - 12 * 5 + 12 = 72 bytes 2/ 5 pointers
+ - New: LValue( Argument(0), { Deref, Field(2), Index(16), Field(0) } )
+ - 16 + 16 = 32 bytes w/ 1 pointer
diff --git a/Notes/NOTES.txt b/Notes/NOTES.txt
new file mode 100644
index 00000000..40c81152
--- /dev/null
+++ b/Notes/NOTES.txt
@@ -0,0 +1,177 @@
+
+Interesting topics:
+- Evolution of the codebase (from initial AST-C conversion, through to current MIR based codegen)
+- Typecheck pain. Complications from inferrence combined with coercions
+- Shortcuts taken: no borrowck, no privacy (suprisingly works), no coherence
+- MIR match generation
+- Design choices and deviation: MIR structure, proc macros
+- `macro_rules!`, aborted attempts
+- C backend pain (compiler bugs, standards quirks, workarounds)
+- Future Evolution: Borrowcheck, archetectual changes (for consteval, expand/resolve interaction)
+
+
+Introduction
+============
+- What is it
+- Origin and original intention
+ - Always been the intention to convert rust into C
+ - Meant to break the bootstrap chain
+ - But also for fun
+ - Started as just a parser and AST, with the intention of just converting the AST straight into C
+- Frozen version
+ - Frozen to target rustc 1.19, because that was the stable version at the time
+ - The built rustc can then go and build 1.20 and bootstrap continues down the line.
+- Rewrites
+ - No SW engineering project gets things right first time, almost everything has been through at least one re-factor
+- Architecture
+ - Parsing, expansion, and name resolution
+ - HIR generated from name-resolved AST (simpler, no more relative paths)
+ - Consteval, typechecking, closure expansion
+ - MIR generated from the fully type-annotated HIR (high-level, rust-specialised assembly)
+ - MIR validated, optimised, validated again, monomorphised, optimised again
+ - MIR passed to the codegen backend (C generator usually)
+ - Module tree and MIR serialised and saved (for libraries)
+- Side-projects
+ - `minicargo` - Clone of cargo, but specialised for building rustc/cargo
+ - `standalone_miri` - Just-for-fun miri clone, with some very rough FFI support
+
+
+Evolution
+=========
+- Started as effectively just a parser back in 2014
+- Original intent was to convert the AST directly into C code
+- First attempt at typecheck was in AST, but AST has constructs that only apply before expand/resolve
+- HIR added to simplify post-expand passes (remove syntatic sugar, relative paths, ...)
+- HIR Typecheck originally worked directly with the syntax tree, worked up to a point
+- HIR Typecheck v2 switched to enumerating rules/inferrence variables from the source tree, and then resolved those until stability.
+ - Typecheck is still a pain the rear, enough to make another article.
+- HIR went direct to MIR (this was after rustc gained a MIR)
+ - This isn't exactly nesessesary, as it should be possible to convert HIR to C.
+ - But, at this stage, mrustc was so close to a fully-fledged compiler, might as well go the full way
+- `macro_rules!` - Rewritten a few times, but that's its own article
+- MIR optimisation added not long after codegen, in an attempt reduce time spent in the C compiler (it worked, but optimisation is expensive)
+
+
+Typecheck Pain
+==============
+- Rust has type inferrence interacting with coercions and trait resolution
+- Rustc's type resolution (... as far as I know) works directly on the AST (well, HIR/HAIR)
+- Mrustc did that to begin with, but it makes reasoning inferrence interactions hard
+- Re-wrote type resolution to build up equality, coercion, and complex rules and iterates over them to do type equalities
+ - The complex rules handle things like method calls, operators, casts, patterns with `..` in them, ...
+
+Inferrence on its own is relatively easy, fixed coercion sets (and associated coercion points) are a little harder, but once trait bounds are introduced the system becomes extremely compleex.
+
+
+Shortcuts
+========
+- Borrow checking (by-design) doesn't impact codegen in any way
+- Privacy technically impacts name lookups (with autoderef), but isn't used in rustc/cargo
+- Coherence just exists to aid the reader/compiler, mrustc just searches every known impl (becuase it's simpler)
+
+MIR Match Generation
+====================
+Pattern matching is a complex part of rust, especially if you're interested in generating efficient code.
+
+The simplest model just handles match statements as chained `if let` statements (check each pattern, and fall on to the next one if it doesn't match).
+This is actually how `match` logically works (you can see this when using `if` guards on match arms, or by having a `_` pattern before other patterns), and in the degerate case chained attern checks are the only correct conversion.
+
+For efficiency though, you'd want to convert match into effectively a C switch statment (a jump table, binary search, or just an easy-to-predict chain of comparisons).
+
+Mrustc does this by first turning match arms into a list of pattern rules (simplified patterns that handle destructuring and value ranges), then checking if it's possible to re-order and combine the patterns into an efficient form. If possible, then the arms are sorted and parsed into a decision tree in MIR (using binary searches, switch-like constructs, and simple equalitiy checks). If not possible (mostly if there's if-guarded arms), then the rules are turned into chained pattern checks and left with the hope that the backend can optimise them better.
+
+All said and done, MIR generation for match statements clocks in to be larger than the rest of MIR generation (by a significant margin), and that's not accounting for the sections it shares with the rest (scope handling is another aspect that is complicated by match statements and how they extend value lifetimes).
+
+
+Design Choices
+==============
+
+MIR
+---
+- Prefer a smaller generated MIR over conceptual simplicity
+- Doesn't follow SSA, instead re-using and de-duplicating variables wherever possible
+
+Procedual Macros
+----------------
+- Had a chance to do proc macros the "right" way
+- Entirely IPC-based, with each macro invocation spawning a fresh process
+- IPC is via basic serialisation over stdin/stdout
+
+C as the primary backend
+------------------------
+- A pain in the rear to avoid compiler bugs (and undefined behavior) BUT
+- C is everywhere, while LLVM (and to a lesser extent gcc) have a constained target range
+- Even with LLVM-supported targets, building/linking LLVM is a non-trivial task.
+ - mrustc's primary goal is to allow building rustc with minimal third-party code (just a working C++ compiler, which nearly always includes a working C compiler)
+
+
+`macro_rules!` attemts
+----------------------
+
+At first, macro handling went the full C++ way - for each arm the parser would attempt to parse the arm, and catch the syntax error exception and move on to the next arm. This wasn't exactly efficient, or easy to debug, but it did ensure that the macro evaluation parser and the main parser were the same. The dowside here was that, because the lexer has to create tokens to hand out to the parser, and it's not known when parsing if another arm might still be tried, expensive copies need to be made of every single captured variable (even if they only ever get used once).
+
+The second attempt went the complete oposite way, attempting to parse the entire set of macro patterns into a decision tree. Turns out that rust macros are very like rust match statemets, they logically work by trying each arm in sequence and pick the first one that works. This turns out to make a simple decision tree impossible (sometimes macros will have ambigious captures, e.g. one arm capturing a :ident and another :expr - both could match).
+
+The third and final model uses a vastly simplified version of the main parser, that just checks if an input token stream is valid for the specified syntax fragment. Combined with a "lexer" that doesn't hand out ownership of the captured items, this new model is both correct and efficient (only doing expensive copies when captures are used multiple times). The only downside is that now there's two parsers involved with macro expansion (and it's easy for them to get out of sync).
+
+C Pains
+=======
+
+- Zero-sized structures
+ - Stritly-speaking not allowed in C, required a lot of work to remove
+- gcc/msvc featureset mismatches
+ - The C backend has hard-coded asm to intrinsic mappings for MSVC
+- Alignment quirks
+ - Turns out that `uint64_t` has an alignment of 4 on x86 gcc
+- Compiler bugs!
+ - Older versions of gcc treating zero-sized structures as UB (and mis-optimising because of it)
+ - x86 FPU overflow, still an outstanding issue
+- Slooooow
+ - Despite optimisation in mrustc, translating MIR directly to C is slow, and the C optimisation/codegen phase isn't fast either.
+
+
+Rustc Bootstrap
+==============
+
+Proc macros
+-----------
+1.29.0's bootstrap program uses proc macro derive, so ends up dynamically
+linking with rustc. This leads to an ABI disagreement if rustc was built with
+mrustc.
+
+Solution: Build rustc manually using itself, by patching minicargo to support
+running with rustc.
+OR: Build rustc using a manual cargo invocation.
+- If this uses proc macros... bootstrap is "broken" at 1.29
+
+
+Future Evolution
+================
+
+Upgrade target version
+----------------------
+
+Mrust targets rustc 1.19 currently, which is over a year old at this point. Upgrading however isn't a simple task, as new compiler features have been added (notable MIR-based consteval, which requires doing MIR generation for some items before typecheck is possible on others).
+
+Borrow Check
+------------
+
+More than one MIR generation issue has lead to bugs that could have been caught by a borrowcheck implementation, Compared to other parts of the compiler (looking at you match generation), a borrow checker itself wouldn't be too hard. What is hard about adding a borrow checkers is region inferrence (propagating lifetime annotations around the type checking phase)
+
+
+On-demand codegen
+-----------------
+
+As part of upgrading the target version, and just removing old and redundant code, it'd be nice to support full MIR constant evaluation (currently the consteval phase has two evaluatorss - one handling local HIR, the other handling MIR from external sources). Generating MIR (and doing typeheck of required items) during the constant evaluation phase would completely remove the HIR evaluator, and all of the type guessing performed to allow HIR constant evaluation (which routinely falls over when exposed to new code).
+
+Parser Re-write
+---------------
+
+The mrustc parser is ancient, with some functions dating back to the start of the project in 2014. On its own, this isn't a problem, but the parsing model itself makes both debugging nd extending the parser challenging. The current model works with a push-pull lexer (which hands out tokens, and allows the caller to push the token back if not needed). More recent code (e.g. the MIRI parser) use a peek/consume model, where the lexer "owns" the tokens until the token is actually consumed - much simpler to debug (via logging when tokens are consumed) and is a closer match to how the lexer gets used in practice.
+
+
+
+
+<!-- vim: ft=markdown
+-->
+
diff --git a/Notes/SMiri-GenericFfi.md b/Notes/SMiri-GenericFfi.md
new file mode 100644
index 00000000..d43b44ad
--- /dev/null
+++ b/Notes/SMiri-GenericFfi.md
@@ -0,0 +1,46 @@
+Problem description:
+====================
+
+There's a collection of hard-coded FFI hooks in `miri.cpp` to handle both API
+rules (e.g. that the `write` syscall takes a count and a buffer of at least
+that valid size) and wrapping non-trivial or dangerous calls (e.g. the pthread
+ones).
+
+
+It would be more useful to have a runtime description/encoding of these APIs
+that runs safety checks and handles the magic.
+
+
+Requirements
+============
+
+- Validity checks (pointer validity, tags)
+ - These checks should provide useful error messages
+- Returned allocation tagging (valid size, opaque tags)
+ - Some returned allocations can be complex
+- Completely re-definining operations
+ - E.g. replacing pthread APIs with checked versions
+
+
+
+Design Ideas
+============
+
+Raw MIR?
+-------
+- Downside: How would it differ from actual MIR?
+
+
+Basic-alike instruction sequence
+--------------------------------
+- All lines start with a keyword
+ - `ASSIGN`
+ - `LET`
+ - `CALL`
+
+
+Simplified rust-ish language
+----------------------------
+- Basic type inference (uni-directional)
+- Full AST
+
diff --git a/Notes/TopLevelTypecheck.md b/Notes/TopLevelTypecheck.md
new file mode 100644
index 00000000..de7b945c
--- /dev/null
+++ b/Notes/TopLevelTypecheck.md
@@ -0,0 +1,17 @@
+Problem: Top-level typecheck is fragile, doesn't handle bounds referencing
+each other.
+
+
+Can generate a similar rule structure to the expression handling?
+
+
+Or, create a new typecheck helper that can handle partially-checked bounds
+
+
+
+Requirements:
+- UFCS resoluton in bounds and impl headers
+ - Does this need to search other impls?
+ - A quick check with the playpen implies that non-generics require fully-qualified paths.
+ - But Generics don't.
+
diff --git a/Notes/Typeck.txt b/Notes/Typeck.txt
index 06b392c0..3ff88c5b 100644
--- a/Notes/Typeck.txt
+++ b/Notes/Typeck.txt
@@ -27,5 +27,17 @@ Needs to be able to point to functions in:
Maybe can use separate types for each usecase?
+
+
+# Hard Questions
+
+## libgit2 inferrence quirk
+Query on rust type inferrence rules (as designed/intended, not as implemented)
+
+Can the presence of a trait impl influence type inferrence for the Self type?
+
+- `*mut _ : Convert<*mut T>`, if there's only one type that implements that
+ trait, is it valid to infer `_` based on that impl?
+
<!-- vim: ft=markdown
-->
diff --git a/Notes/todo.txt b/Notes/todo.txt
index 7041c8b9..5b244a34 100644
--- a/Notes/todo.txt
+++ b/Notes/todo.txt
@@ -6,24 +6,62 @@ TODO:
- Remove variables that are just assigned from arguments
- Clean up AST
- Almost done, just a few little niggles left
-- Split arg patterns and arg types up for cleaner serialisation
- - Could be a good idea to do as part of changing HIR::TraitImpl to only contain the impl data
- - May not be too useful due to argument monomorphisation.
- Optimise typecheck.
+ - Mostly done with trait resolve cleanup
## Big change TODOs
- Support MIR-only RLibs
+ - Defer C codegen until final binary generation?
+- Dylib support (requires trans API restructure)
+ - Will improve disk usage for tests (can dynamically link libstd)
- Fix Span annotations
+ - Spans are missing on HIR items, sub-par reporting in typecheck and later
+ - Spans can be off by a line or two
- Refactor parse to use a consume model lexer
- Optimise optimise (and typecheck)
+ - Partially down with trait resolution optimisation. Needs further profiling
- Complete structed C codegen
+ - Upside: It'll look cool
+ - Unknown: Will it be faster?
+- RTL/register-based SSA interrim backend
+ - Convert MIR into a form that can be handed over to LLVM or Cranelift (or GIMPLE)
+ - Use alloca-s for non-pointer/integer/borrowed locals
## Smaller changes
-- Only generate destructors if needed (removes C warnings)
+- Make type ascritpion its own node type
+ - AST and HIR
+ - Then remove per-node type annotations from AST
- Cache specialisation tree
-- Dependency files from mrustc
- - Partally done, not complete
+ - TODO: Profile to determine if this is a slow point.
+- Delete HIR after MIR generation
+ - Problem: HIR is sometimes touched again after MIR gen
+ - May just be able to do the delete in the main MIR gen phase
+- Split types and patterns in HIR function arguments
+ - Upsides:
+ - Less data in the serialsed .hir file
+ - Note: Patterns aren't actually stored in metadata
+ - Simpler logic post MIR generation
+ - Reduced use of .first/.second
+ - Memory usage reduction for external functions
+ - Downsides:
+ - Lots of code touched
+ - Extra complexity in typecheck and MIR lowering?
+- Sort trait impls in a similar way to type impls
+ - ```c++
+ template<T> struct ImplGroup {
+ std::map<SimplePath, T> named;
+ std::vector<T> primitives;
+ std::vector<T> generic;
+ }
+ std::map<SimplePath, ImplGroup<TraitImpl>> trait_impls;
+ ``` <!-- `-->
+ - Problem: Trait lookup on ivars?
+ - TODO: Profile a large crate again to see what the overhead of searching
+ trait impls is.
+ - Should help with widely implemented traits (e.g. Debug)
+ - Downside: Another SimplePath per impl cluster, plus the vector size - Not
+ too big but something to be aware of (7 pointers overhead plus indirection).
## Optimisations
@@ -32,4 +70,9 @@ TODO:
- Dead assignment removal (Delete `<val> = Use(<val>)`
- Tuple destructure removal
- Spot `#1 = (...,)`, `#2 = (#1).n` where #1 is Write-once, borrow-none
+- Remove useless borrows (remove write-once &T lvalues if they're never used by
+ value - only used via deref)
+
+<!-- vim: ft=markdown
+-->
diff --git a/README.md b/README.md
index d17ef42b..3f2691b3 100644
--- a/README.md
+++ b/README.md
@@ -18,9 +18,11 @@ Progress
- (incomplete) x86 windows
- (incomplete) x86-64 windows
- Builds working copies of `rustc` and `cargo` from a release source tarball
-- `rustc` bootstrap tested and validated
+ - Supports both rustc 1.19.0 and 1.29.0
+- `rustc` bootstrap tested and validated (1.19.0 validated once, 1.29.0 is repeatable)
- See the script `TestRustcBootstrap.sh` for how this was done.
+
Getting Started
===============
@@ -120,5 +122,5 @@ Medium-term
-Note: All progress is against the source of rustc 1.19.0
+Note: All progress is against the source of rustc 1.19.0 AND rustc 1.29.0
diff --git a/TestRustcBootstrap.sh b/TestRustcBootstrap.sh
index db195038..3a1ecb1b 100755
--- a/TestRustcBootstrap.sh
+++ b/TestRustcBootstrap.sh
@@ -1,28 +1,42 @@
-#!/bin/sh
+#!/bin/bash
# Builds rustc with the mrustc stage0 and downloaded stage0
set -e
-PREFIX=${PWD}/run_rustc/prefix/
WORKDIR=${WORKDIR:-rustc_bootstrap}/
+RUSTC_VERSION=${*-1.29.0}
+RUN_RUSTC_SUF=""
+if [[ "$RUSTC_VERSION" == "1.29.0" ]]; then
+ RUSTC_VERSION_NEXT=1.30.0
+elif [[ "$RUSTC_VERSION" == "1.19.0" ]]; then
+ RUSTC_VERSION_NEXT=1.20.0
+ RUN_RUSTC_SUF=-1.19.0
+else
+ echo "Unknown rustc version"
+fi
+
MAKEFLAGS=-j8
export MAKEFLAGS
echo "=== Building stage0 rustc (with libstd)"
-make -C run_rustc
+make -C run_rustc RUSTC_VERSION=${RUSTC_VERSION}
+
+PREFIX=${PWD}/run_rustc/output${RUN_RUSTC_SUF}/prefix/
-if [ ! -e rustc-1.20.0-src.tar.gz ]; then
- wget https://static.rust-lang.org/dist/rustc-1.20.0-src.tar.gz
+if [ ! -e rustc-${RUSTC_VERSION_NEXT}-src.tar.gz ]; then
+ wget https://static.rust-lang.org/dist/rustc-${RUSTC_VERSION_NEXT}-src.tar.gz
fi
+echo "--- Working in directory ${WORKDIR}"
+echo "=== Cleaning up"
+rm -rf ${WORKDIR}build
#
# Build rustc using entirely mrustc-built tools
#
-echo "--- Working in directory ${WORKDIR}"
echo "=== Building rustc bootstrap mrustc stage0"
mkdir -p ${WORKDIR}mrustc/
-tar -xf rustc-1.20.0-src.tar.gz -C ${WORKDIR}mrustc/
-cat - > ${WORKDIR}mrustc/rustc-1.20.0-src/config.toml <<EOF
+tar -xf rustc-${RUSTC_VERSION_NEXT}-src.tar.gz -C ${WORKDIR}mrustc/
+cat - > ${WORKDIR}mrustc/rustc-${RUSTC_VERSION_NEXT}-src/config.toml <<EOF
[build]
cargo = "${PREFIX}bin/cargo"
rustc = "${PREFIX}bin/rustc"
@@ -31,10 +45,15 @@ vendor = true
EOF
echo "--- Running x.py, see ${WORKDIR}mrustc.log for progress"
(cd ${WORKDIR} && mv mrustc build)
-(cd ${WORKDIR}build/rustc-1.20.0-src/ && ./x.py build --stage 3) > ${WORKDIR}mrustc.log 2>&1
-(cd ${WORKDIR} && mv build mrustc)
+cleanup_mrustc() {
+ (cd ${WORKDIR} && mv build mrustc)
+}
+trap cleanup_mrustc EXIT
+(cd ${WORKDIR}build/rustc-${RUSTC_VERSION_NEXT}-src/ && LD_LIBRARY_PATH=${PREFIX}lib/rustlib/x86_64-unknown-linux-gnu/lib ./x.py build --stage 3) > ${WORKDIR}mrustc.log 2>&1
+cleanup_mrustc
+trap - EXIT
rm -rf ${WORKDIR}mrustc-output
-cp -r ${WORKDIR}mrustc/rustc-1.20.0-src/build/x86_64-unknown-linux-gnu/stage2 ${WORKDIR}mrustc-output
+cp -r ${WORKDIR}mrustc/rustc-${RUSTC_VERSION_NEXT}-src/build/x86_64-unknown-linux-gnu/stage2 ${WORKDIR}mrustc-output
tar -czf ${WORKDIR}mrustc.tar.gz -C ${WORKDIR} mrustc-output
#
@@ -42,16 +61,16 @@ tar -czf ${WORKDIR}mrustc.tar.gz -C ${WORKDIR} mrustc-output
#
echo "=== Building rustc bootstrap downloaded stage0"
mkdir -p ${WORKDIR}official/
-tar -xf rustc-1.20.0-src.tar.gz -C ${WORKDIR}official/
-cat - > ${WORKDIR}official/rustc-1.20.0-src/config.toml <<EOF
+tar -xf rustc-${RUSTC_VERSION_NEXT}-src.tar.gz -C ${WORKDIR}official/
+cat - > ${WORKDIR}official/rustc-${RUSTC_VERSION_NEXT}-src/config.toml <<EOF
[build]
full-bootstrap = true
vendor = true
EOF
echo "--- Running x.py, see ${WORKDIR}official.log for progress"
(cd ${WORKDIR} && mv official build)
-(cd ${WORKDIR}build/rustc-1.20.0-src/ && ./x.py build --stage 3) > ${WORKDIR}official.log 2>&1
+(cd ${WORKDIR}build/rustc-${RUSTC_VERSION_NEXT}-src/ && ./x.py build --stage 3) > ${WORKDIR}official.log 2>&1
(cd ${WORKDIR} && mv build official)
rm -rf ${WORKDIR}official-output
-cp -r ${WORKDIR}official/rustc-1.20.0-src/build/x86_64-unknown-linux-gnu/stage2 ${WORKDIR}official-output
+cp -r ${WORKDIR}official/rustc-${RUSTC_VERSION_NEXT}-src/build/x86_64-unknown-linux-gnu/stage2 ${WORKDIR}official-output
tar -czf ${WORKDIR}official.tar.gz -C ${WORKDIR} official-output
diff --git a/build-1.19.0.sh b/build-1.19.0.sh
new file mode 100755
index 00000000..79f5cd97
--- /dev/null
+++ b/build-1.19.0.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+set -e
+make
+RUSTC_VERSION=1.19.0 MRUSTC_TARGET_VER=1.19 OUTDIR_SUF=-1.19.0 make RUSTCSRC
+RUSTC_VERSION=1.19.0 MRUSTC_TARGET_VER=1.19 OUTDIR_SUF=-1.19.0 make test
+RUSTC_VERSION=1.19.0 MRUSTC_TARGET_VER=1.19 OUTDIR_SUF=-1.19.0 time make -f minicargo.mk LIBS
+RUSTC_VERSION=1.19.0 MRUSTC_TARGET_VER=1.19 OUTDIR_SUF=-1.19.0 time make -f minicargo.mk output-1.19.0/stdtest/rustc_data_structures-test_out.txt
+RUSTC_VERSION=1.19.0 MRUSTC_TARGET_VER=1.19 OUTDIR_SUF=-1.19.0 time make -f minicargo.mk output-1.19.0/rustc
+RUSTC_VERSION=1.19.0 MRUSTC_TARGET_VER=1.19 OUTDIR_SUF=-1.19.0 time make -f minicargo.mk output-1.19.0/cargo
diff --git a/disabled_tests_run-pass.txt b/disabled_tests_run-pass.txt
index 25b0b838..49a7f787 100644
--- a/disabled_tests_run-pass.txt
+++ b/disabled_tests_run-pass.txt
@@ -20,6 +20,8 @@ sepcomp-fns-backwards # ^
sepcomp-statics # ^
sepcomp-unwind # ^
sepcomp-lib-lto # -C lto
+lto-many-codegen-units # ^
+lto-still-runs-thread-dtor # ^
mir_overflow_off # -Z force-overflow-checks=off
no-landing-pads # -Z no-landing-pads
num-wrapping # -C debug-assertions
@@ -28,6 +30,8 @@ slice-of-zero-size-elements # ^
optimization-fuel-0 # -Z fuel=foo=0
optimization-fuel-1 # ^
warn-ctypes-inhibit # -D improper-ctypes
+z-crate-attr # -Z crate-attr
+thin-lto-global-allocator # -Z thinlto
# Requires unwinding panics
unwind-resource
@@ -65,6 +69,7 @@ test-should-fail-good-message
unit-like-struct-drop-run
unwind-unique
vector-sort-panic-safe
+test-allow-fail-attr
# LEX
lex-bare-cr-nondoc-comment # Don't treat \r as a new line
@@ -241,6 +246,8 @@ wrapping-int-api # Implicit integer truncation with `<large_literal> as u64`
fat-ptr-cast # Array unsize missed
issue-20797 # Trait unsize runthrough
issue-26905 # Manual CoerceUnsized not working?
+# - Unsupported features
+unsized-tuple-impls # Unsized tuples, no CoerceUnsized impl
# MIR GEN:
issue-18352 # append_from_lit - Match literal Borrow
@@ -343,6 +350,13 @@ abi-sysv64-arg-passing # ERROR: Empty struct arguments to FFI aren't actually e
extern-pass-empty # ^
thread-local-extern-static # TODO: #[no_mangle] on statatic definition
+# SIMD (minimal support in mrustc, all SIMD ops abort)
+simd-intrinsic-float-math
+simd-intrinsic-float-minmax
+simd-intrinsic-generic-gather
+simd-intrinsic-generic-reduction
+simd-intrinsic-generic-select
+
# HIR MISC
xcrate-associated-type-defaults # type_is_specialisable - Handle missing type in impl(0x17e3018) ::"xcrate_associated_type_defaults"::Foo<u32,> for () {}, name = Out
default-associated-types # ^
@@ -358,6 +372,7 @@ linkage1 # "extern_weak" linkage
reexport-test-harness-main # NOT A BUG: Tests an implementation detail of the test harness
test-runner-hides-start # BUG: Test harness doesn't hide #[start]
tls-dtors-are-run-in-a-static-binary # Thread-local destructors aren't being run.
+issue-42747 # 27 deep enum chain, VERY long time in gcc
# TEST RUNNER
exec-env # Runtime environment variable
@@ -371,6 +386,7 @@ backtrace-debuginfo-aux
issue-24313 # Not sure if this is unwinding or TLS problems...
box-of-array-of-drop-1
box-of-array-of-drop-2
+builtin-clone-unwind
catch-unwind-bang
cleanup-rvalue-temp-during-incomplete-alloc
drop-trait-enum
@@ -382,6 +398,7 @@ issue-26655
issue-29485
issue-29948
issue-30018-panic
+issue-42148
issue-8460 # .. except it fails because there's no overflow checks
multi-panic
nested-vec-3
diff --git a/minicargo.mk b/minicargo.mk
index 49d24ff3..8381ed96 100644
--- a/minicargo.mk
+++ b/minicargo.mk
@@ -5,7 +5,7 @@
OUTDIR_SUF ?=
MMIR ?=
RUSTC_CHANNEL ?= stable
-RUSTC_VERSION ?= 1.19.0
+RUSTC_VERSION ?= $(shell cat rust-version)
ifeq ($(OS),Windows_NT)
else ifeq ($(shell uname -s || echo not),Darwin)
OVERRIDE_SUFFIX ?= -macos
@@ -16,7 +16,7 @@ PARLEVEL ?= 1
MINICARGO_FLAGS ?=
ifneq ($(MMIR),)
- OUTDIR_SUF := -mmir
+ OUTDIR_SUF := $(OUTDIR_SUF)-mmir
MINICARGO_FLAGS += -Z emit-mmir
endif
ifneq ($(PARLEVEL),1)
@@ -27,6 +27,10 @@ OUTDIR := output$(OUTDIR_SUF)/
MRUSTC := bin/mrustc
MINICARGO := tools/bin/minicargo
+RUSTC_OUT_BIN := rustc
+ifeq ($(RUSTC_VERSION),1.29.0)
+ RUSTC_OUT_BIN := rustc_binary
+endif
ifeq ($(RUSTC_CHANNEL),nightly)
RUSTCSRC := rustc-nightly-src/
else
@@ -39,7 +43,7 @@ LLVM_TARGETS ?= X86;ARM;AArch64#;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVP
OVERRIDE_DIR := script-overrides/$(RUSTC_CHANNEL)-$(RUSTC_VERSION)$(OVERRIDE_SUFFIX)/
.PHONY: bin/mrustc tools/bin/minicargo
-.PHONY: $(OUTDIR)libstd.hir $(OUTDIR)libtest.hir $(OUTDIR)libpanic_unwind.hir $(OUTDIR)libproc_macro.hir
+.PHONY: $(OUTDIR)libstd.rlib $(OUTDIR)libtest.rlib $(OUTDIR)libpanic_unwind.rlib $(OUTDIR)libproc_macro.rlib
.PHONY: $(OUTDIR)rustc $(OUTDIR)cargo
.PHONY: all LIBS
@@ -47,35 +51,42 @@ OVERRIDE_DIR := script-overrides/$(RUSTC_CHANNEL)-$(RUSTC_VERSION)$(OVERRIDE_SUF
all: $(OUTDIR)rustc
-LIBS: $(OUTDIR)libstd.hir $(OUTDIR)libtest.hir $(OUTDIR)libpanic_unwind.hir $(OUTDIR)libproc_macro.hir
+LIBS: $(OUTDIR)libstd.rlib $(OUTDIR)libtest.rlib $(OUTDIR)libpanic_unwind.rlib $(OUTDIR)libproc_macro.rlib
$(MRUSTC):
$(MAKE) -f Makefile all
- @test -e $@
+ test -e $@
$(MINICARGO):
$(MAKE) -C tools/minicargo/
- @test -e $@
+ test -e $@
# Standard library crates
# - libstd, libpanic_unwind, libtest and libgetopts
# - libproc_macro (mrustc)
-$(OUTDIR)libstd.hir: $(MRUSTC) $(MINICARGO)
+$(OUTDIR)libstd.rlib: $(MRUSTC) $(MINICARGO)
$(MINICARGO) $(RUSTCSRC)src/libstd --script-overrides $(OVERRIDE_DIR) --output-dir $(OUTDIR) $(MINICARGO_FLAGS)
- @test -e $@
-$(OUTDIR)libpanic_unwind.hir: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.hir
+ test -e $@
+$(OUTDIR)libpanic_unwind.rlib: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.rlib
$(MINICARGO) $(RUSTCSRC)src/libpanic_unwind --script-overrides $(OVERRIDE_DIR) --output-dir $(OUTDIR) $(MINICARGO_FLAGS)
- @test -e $@
-$(OUTDIR)libtest.hir: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.hir $(OUTDIR)libpanic_unwind.hir
+ test -e $@
+$(OUTDIR)libtest.rlib: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.rlib $(OUTDIR)libpanic_unwind.rlib
$(MINICARGO) $(RUSTCSRC)src/libtest --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(OUTDIR) $(MINICARGO_FLAGS)
- @test -e $@
-$(OUTDIR)libgetopts.hir: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.hir
+ test -e $@
+$(OUTDIR)libgetopts.rlib: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.rlib
$(MINICARGO) $(RUSTCSRC)src/libgetopts --script-overrides $(OVERRIDE_DIR) --output-dir $(OUTDIR) $(MINICARGO_FLAGS)
- @test -e $@
+ test -e $@
# MRustC custom version of libproc_macro
-$(OUTDIR)libproc_macro.hir: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.hir
+$(OUTDIR)libproc_macro.rlib: $(MRUSTC) $(MINICARGO) $(OUTDIR)libstd.rlib
$(MINICARGO) lib/libproc_macro --output-dir $(OUTDIR) $(MINICARGO_FLAGS)
- @test -e $@
+ test -e $@
+
+$(OUTDIR)test/libtest.so: $(MRUSTC) $(MINICARGO)
+ mkdir -p $(dir $@)
+ MINICARGO_DYLIB=1 $(MINICARGO) $(RUSTCSRC)src/libstd --script-overrides $(OVERRIDE_DIR) --output-dir $(dir $@) $(MINICARGO_FLAGS)
+ MINICARGO_DYLIB=1 $(MINICARGO) $(RUSTCSRC)src/libpanic_unwind --script-overrides $(OVERRIDE_DIR) --output-dir $(dir $@) $(MINICARGO_FLAGS)
+ MINICARGO_DYLIB=1 $(MINICARGO) $(RUSTCSRC)src/libtest --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) $(MINICARGO_FLAGS)
+ test -e $@
RUSTC_ENV_VARS := CFG_COMPILER_HOST_TRIPLE=$(RUSTC_TARGET)
RUSTC_ENV_VARS += LLVM_CONFIG=$(abspath $(LLVM_CONFIG))
@@ -84,11 +95,13 @@ RUSTC_ENV_VARS += CFG_RELEASE_CHANNEL=$(RUSTC_CHANNEL)
RUSTC_ENV_VARS += CFG_VERSION=$(RUSTC_VERSION)-$(RUSTC_CHANNEL)-mrustc
RUSTC_ENV_VARS += CFG_PREFIX=mrustc
RUSTC_ENV_VARS += CFG_LIBDIR_RELATIVE=lib
+RUSTC_ENV_VARS += LD_LIBRARY_PATH=$(abspath output)
$(OUTDIR)rustc: $(MRUSTC) $(MINICARGO) LIBS $(LLVM_CONFIG)
mkdir -p $(OUTDIR)rustc-build
$(RUSTC_ENV_VARS) $(MINICARGO) $(RUSTCSRC)src/rustc --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(OUTDIR)rustc-build -L $(OUTDIR) $(MINICARGO_FLAGS)
- cp $(OUTDIR)rustc-build/rustc $(OUTDIR)
+# $(RUSTC_ENV_VARS) $(MINICARGO) $(RUSTCSRC)src/librustc_codegen_llvm --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(OUTDIR)rustc-build -L $(OUTDIR) $(MINICARGO_FLAGS)
+ cp $(OUTDIR)rustc-build/$(RUSTC_OUT_BIN) $@
$(OUTDIR)cargo: $(MRUSTC) LIBS
mkdir -p $(OUTDIR)cargo-build
$(MINICARGO) $(RUSTCSRC)src/tools/cargo --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(OUTDIR)cargo-build -L $(OUTDIR) $(MINICARGO_FLAGS)
@@ -114,17 +127,62 @@ $(RUSTCSRC)build/Makefile: $(RUSTCSRC)src/llvm/CMakeLists.txt
#
# Developement-only targets
#
-$(OUTDIR)rustc-build/librustc_trans.hir: $(MRUSTC) LIBS $(LLVM_CONFIG)
- $(MINICARGO) $(RUSTCSRC)src/librustc_trans --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) $(MINICARGO_FLAGS)
-$(OUTDIR)rustc-build/librustdoc.hir: $(MRUSTC) LIBS
+$(OUTDIR)liballoc.rlib: $(MRUSTC) $(MINICARGO)
+ $(MINICARGO) $(RUSTCSRC)src/liballoc --script-overrides $(OVERRIDE_DIR) --output-dir $(OUTDIR) $(MINICARGO_FLAGS)
+$(OUTDIR)rustc-build/librustdoc.rlib: $(MRUSTC) LIBS
$(MINICARGO) $(RUSTCSRC)src/librustdoc --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) $(MINICARGO_FLAGS)
-#$(OUTDIR)cargo-build/libserde-1_0_6.hir: $(MRUSTC) LIBS
+#$(OUTDIR)cargo-build/libserde-1_0_6.rlib: $(MRUSTC) LIBS
# $(MINICARGO) $(RUSTCSRC)src/vendor/serde --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) $(MINICARGO_FLAGS)
-$(OUTDIR)cargo-build/libgit2-0_6_6.hir: $(MRUSTC) LIBS
+$(OUTDIR)cargo-build/libgit2-0_6_6.rlib: $(MRUSTC) LIBS
$(MINICARGO) $(RUSTCSRC)src/vendor/git2 --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) --features ssh,https,curl,openssl-sys,openssl-probe $(MINICARGO_FLAGS)
-$(OUTDIR)cargo-build/libserde_json-1_0_2.hir: $(MRUSTC) LIBS
+$(OUTDIR)cargo-build/libserde_json-1_0_2.rlib: $(MRUSTC) LIBS
$(MINICARGO) $(RUSTCSRC)src/vendor/serde_json --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) $(MINICARGO_FLAGS)
-$(OUTDIR)cargo-build/libcurl-0_4_6.hir: $(MRUSTC) LIBS
+$(OUTDIR)cargo-build/libcurl-0_4_6.rlib: $(MRUSTC) LIBS
$(MINICARGO) $(RUSTCSRC)src/vendor/curl --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) $(MINICARGO_FLAGS)
-$(OUTDIR)cargo-build/libterm-0_4_5.hir: $(MRUSTC) LIBS
+$(OUTDIR)cargo-build/libterm-0_4_5.rlib: $(MRUSTC) LIBS
$(MINICARGO) $(RUSTCSRC)src/vendor/term --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) $(MINICARGO_FLAGS)
+$(OUTDIR)cargo-build/libfailure-0_1_2.rlib: $(MRUSTC) LIBS
+ $(MINICARGO) $(RUSTCSRC)src/vendor/failure --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR) --features std,derive,backtrace,failure_derive $(MINICARGO_FLAGS)
+
+#
+# Testing
+#
+.PHONY: rust_tests-libs
+
+LIB_TESTS := alloc std
+LIB_TESTS += rustc_data_structures
+rust_tests-libs: $(patsubst %,$(OUTDIR)stdtest/%-test_out.txt, $(LIB_TESTS)) $(OUTDIR)stdtest/collectionstests_out.txt
+.PRECIOUS: $(OUTDIR)stdtest/alloc-test
+.PRECIOUS: $(OUTDIR)stdtest/std-test
+.PRECIOUS: $(OUTDIR)stdtest/rustc_data_structures-test
+
+RUNTIME_ARGS_$(OUTDIR)stdtest/alloc-test := --test-threads 1
+RUNTIME_ARGS_$(OUTdIR)stdtest/std-test := --test-threads 1
+# VVV Requires panic destructors (unwinding panics)
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::io::stdio::tests::panic_doesnt_poison
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sync::mutex::tests::test_arc_condvar_poison
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sync::mutex::tests::test_mutex_arc_poison
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sync::once::tests::poison_bad
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sync::once::tests::wait_for_force_to_finish
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sync::rwlock::tests::test_rw_arc_no_poison_rw
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sync::rwlock::tests::test_rw_arc_poison_wr
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sync::rwlock::tests::test_rw_arc_poison_ww
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sys_common::remutex::tests::poison_works
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::thread::local::tests::dtors_in_dtors_in_dtors
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::thread::local::tests::smoke_dtor
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sync::mutex::tests::test_get_mut_poison
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sync::mutex::tests::test_into_inner_poison
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sync::mutex::tests::test_mutex_arc_access_in_unwind
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sync::rwlock::tests::test_get_mut_poison
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sync::rwlock::tests::test_into_inner_poison
+RUNTIME_ARGS_$(OUTDIR)stdtest/std-test += --skip ::sync::rwlock::tests::test_rw_arc_access_in_unwind
+RUNTIME_ARGS_$(OUTDIR)stdtest/rustc_data_structures-test := --test-threads 1
+
+$(OUTDIR)stdtest/%-test: $(RUSTCSRC)src/lib%/lib.rs LIBS
+ $(MINICARGO) --test $(RUSTCSRC)src/lib$* --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(dir $@) -L $(OUTDIR)
+$(OUTDIR)stdtest/collectionstests: $(OUTDIR)stdtest/alloc-test
+ test -e $@
+$(OUTDIR)collectionstest_out.txt: $(OUTDIR)%
+$(OUTDIR)%_out.txt: $(OUTDIR)%
+ @echo "--- [$<]"
+ $V./$< $(RUNTIME_ARGS_$<) > $@ 2>&1 || (tail -n 1 $@; mv $@ $@_fail; false)
diff --git a/run_rustc/Makefile b/run_rustc/Makefile
index e38e8181..8cd16ae8 100644
--- a/run_rustc/Makefile
+++ b/run_rustc/Makefile
@@ -1,60 +1,144 @@
# Makefile that builds libstd using the mrustc-built rustc
-RUSTC := ../output/rustc
-RUST_SRC := ../rustc-1.19.0-src/src/
+RUSTC_VERSION_DEF = $(shell cat ../rust-version)
+RUSTC_VERSION ?= $(RUSTC_VERSION_DEF)
+RUST_SRC ?= ../rustc-$(RUSTC_VERSION)-src/src/
+ifeq ($(RUSTC_VERSION),$(RUSTC_VERSION_DEF))
+OUTDIR_SUF ?=
+else
+OUTDIR_SUF ?= -$(RUSTC_VERSION)
+endif
-PREFIX := prefix/
+RUSTC_TARGET := x86_64-unknown-linux-gnu
+
+OUTDIR := output$(OUTDIR_SUF)/
+PREFIX := $(OUTDIR)prefix/
BINDIR := $(PREFIX)bin/
-LIBDIR := $(PREFIX)lib/rustlib/x86_64-unknown-linux-gnu/lib/
+LIBDIR := $(PREFIX)lib/rustlib/$(RUSTC_TARGET)/lib/
+CARGO_HOME := $(PREFIX)cargo_home/
+PREFIX_S := $(OUTDIR)prefix-s/
+LIBDIR_S := $(PREFIX_S)lib/rustlib/$(RUSTC_TARGET)/lib/
+BINDIR_S := $(PREFIX_S)bin/
+
+LLVM_CONFIG := $(RUST_SRC)../build/bin/llvm-config
+LLVM_TARGETS ?= X86;ARM;AArch64#;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX
+
+RUSTC_ENV_VARS := CFG_COMPILER_HOST_TRIPLE=$(RUSTC_TARGET)
+RUSTC_ENV_VARS += LLVM_CONFIG=$(abspath $(LLVM_CONFIG))
+RUSTC_ENV_VARS += CFG_RELEASE=
+RUSTC_ENV_VARS += CFG_RELEASE_CHANNEL=$(RUSTC_CHANNEL)
+RUSTC_ENV_VARS += CFG_VERSION=$(RUSTC_VERSION)-stable-mrustc
+RUSTC_ENV_VARS += CFG_PREFIX=mrustc
+RUSTC_ENV_VARS += CFG_LIBDIR_RELATIVE=lib
+RUSTC_ENV_VARS += LD_LIBRARY_PATH=$(abspath output)
+
+CARGO_ENV := CFG_COMPILER_HOST_TRIPLE=$(RUSTC_TARGET)
+CARGO_ENV += RUSTC_BOOTSTRAP=1
+CARGO_ENV += CARGO_HOME=$(CARGO_HOME)
+CARGO_ENV += RUSTFLAGS="-Z force-unstable-if-unmarked"
V ?= @
-all: $(BINDIR)rustc $(BINDIR)cargo $(LIBDIR)libstd.rlib $(BINDIR)hello_world
+all: $(BINDIR)rustc $(LIBDIR)libstd.rlib $(BINDIR)hello_world
+all: $(BINDIR)cargo
-RUSTFLAGS_liblibc := --cfg stdbuild
-RUSTFLAGS_libstd := -l dl -l rt -l pthread
-RUSTFLAGS_libunwind := -l gcc_s
+RUSTFLAGS_core :=
+RUSTFLAGS_libc := --cfg stdbuild
+RUSTFLAGS_std := -l dl -l rt -l pthread
+RUSTFLAGS_unwind := -l gcc_s
+RUSTFLAGS_alloc :=
+RUSTFLAGS_alloc_system :=
+RUSTFLAGS_compiler_builtins := --cfg feature=\"compiler-builtins\"
-$(RUSTC):
- make -C ../ output/rustc -j 3
-../output/cargo:
- make -C ../ output/cargo -j 3
+../output$(OUTDIR_SUF)/rustc:
+ make -C ../ output$(OUTDIR_SUF)/rustc -j 3
+../output$(OUTDIR_SUF)/cargo:
+ make -C ../ output$(OUTDIR_SUF)/cargo -j 3
-$(BINDIR)rustc: $(RUSTC)
+$(BINDIR)rustc_m: ../output$(OUTDIR_SUF)/rustc
@mkdir -p $(dir $@)
$Vcp $< $@
-$(BINDIR)cargo: ../output/cargo
+$(BINDIR_S)rustc: ../output$(OUTDIR_SUF)/rustc
@mkdir -p $(dir $@)
$Vcp $< $@
+$(BINDIR)cargo: ../output$(OUTDIR_SUF)/cargo
+ @mkdir -p $(dir $@)
+ $Vcp $< $@
+
+$(CARGO_HOME)config: Makefile
+ @mkdir -p $(dir $@)
+ @echo "[create] $@"
+ $Vecho "[source.crates-io]" > $@
+ $Vecho "replace-with = \"vendored-sources\"" >> $@
+ $Vecho "[source.vendored-sources]" >> $@
+ $Vecho "directory = \"$(abspath $(RUST_SRC)vendor)\"" >> $@
+
+# Actual libstd build (using cargo, and using manually-build libstd as deps)
+$(LIBDIR)libstd.rlib: $(BINDIR_S)rustc $(BINDIR)cargo $(LIBDIR_S)libstd.rlib $(CARGO_HOME)config
+ @mkdir -p $(OUTDIR)build-std
+ @mkdir -p $(LIBDIR)
+ @echo [CARGO] $(RUST_SRC)libstd/Cargo.toml
+ $VCARGO_TARGET_DIR=$(OUTDIR)build-std RUSTC=$(BINDIR_S)rustc $(CARGO_ENV) $(BINDIR)cargo build --manifest-path $(RUST_SRC)libstd/Cargo.toml -j 1 --release --features panic-unwind
+ $Vcp --remove-destination $(OUTDIR)build-std/release/deps/*.rlib $(LIBDIR)
+ $Vcp --remove-destination $(OUTDIR)build-std/release/deps/*.so $(LIBDIR)
+# libtest
+$(LIBDIR)libtest.rlib: $(BINDIR)rustc_m $(LIBDIR)libstd.rlib $(CARGO_HOME)config
+ @mkdir -p $(OUTDIR)build-test
+ @echo [CARGO] $(RUST_SRC)libtest/Cargo.toml
+ $VCARGO_TARGET_DIR=$(OUTDIR)build-test RUSTC=$(BINDIR)rustc_m $(CARGO_ENV) $(BINDIR)cargo build --manifest-path $(RUST_SRC)libtest/Cargo.toml -j 1 --release
+ @mkdir -p $(LIBDIR)
+ $Vcp --remove-destination $(OUTDIR)build-test/release/deps/*.rlib $(LIBDIR)
+ $Vcp --remove-destination $(OUTDIR)build-test/release/deps/*.so $(LIBDIR)
-#$(LIBDIR)libstd.rlib-: $(RUSTC) $(BINDIR)cargo $(BINDIR)rustc
-# @mkdir -p ./build/libstd
-# cd $(RUST_SRC)libstd && CARGO_TARGET_DIR=$(abspath ./build/libstd) PATH="$(abspath $(BINDIR)):$$PATH" cargo build
-# cp ./build/libstd/target/libstd.rlib $@
+# - Build rustc with itself (so we have a rustc with the right ABI)
+$(BINDIR)rustc: $(BINDIR)rustc_m $(BINDIR)cargo $(CARGO_HOME)config $(LIBDIR)libtest.rlib
+ @mkdir -p $(PREFIX)tmp
+ @echo [CARGO] $(RUST_SRC)rustc/Cargo.toml
+ $V$(RUSTC_ENV_VARS) TMPDIR=$(abspath $(PREFIX)tmp) CARGO_TARGET_DIR=$(OUTDIR)build-rustc RUSTC=$(BINDIR)rustc_m RUSTC_ERROR_METADATA_DST=$(abspath $(PREFIX)) $(CARGO_ENV) $(BINDIR)cargo build --manifest-path $(RUST_SRC)rustc/Cargo.toml --release -j 1
+ cp $(OUTDIR)build-rustc/release/deps/*.so $(LIBDIR)
+ cp $(OUTDIR)build-rustc/release/deps/*.rlib $(LIBDIR)
+ifeq ($(RUSTC_VERSION),1.19.0)
+ cp $(OUTDIR)build-rustc/release/rustc $(BINDIR)rustc_binary
+else
+ cp $(OUTDIR)build-rustc/release/rustc_binary $(BINDIR)rustc_binary
+endif
+ echo '#!/bin/sh\nd=$$(dirname $$0)\nLD_LIBRARY_PATH="$(abspath $(LIBDIR))" $$d/rustc_binary $$@' >$@
+ chmod +x $@
-$(LIBDIR)%.rlib: $(RUST_SRC)%/lib.rs $(BINDIR)rustc
+$(BINDIR)hello_world: $(RUST_SRC)test/run-pass/hello.rs $(LIBDIR)libstd.rlib $(BINDIR)rustc
@mkdir -p $(dir $@)
@echo "[RUSTC] -o $@"
- $Vtime $(DBG) $(RUSTC) $(RUSTFLAGS_$@) -L $(LIBDIR) -L ../output/libs $< -o $@ $(RUSTFLAGS_$*)
-$(LIBDIR)%.rlib: $(RUST_SRC)%/src/lib.rs $(BINDIR)rustc
+ $Vtime $(DBG) $(BINDIR)rustc $(RUSTFLAGS_$@) -L $(LIBDIR) -L ../output/libs $< -o $@
+
+#
+# - Build libstd in a hacky hard-coded way first, to allow build scripts to work
+#
+$(LIBDIR_S)lib%.rlib: $(RUST_SRC)lib%/lib.rs $(BINDIR_S)rustc
@mkdir -p $(dir $@)
@echo "[RUSTC] -o $@"
- $Vtime $(DBG) $(RUSTC) $(RUSTFLAGS_$@) -L $(LIBDIR) -L ../output/libs $< -o $@ $(RUSTFLAGS_$*)
-
-$(BINDIR)hello_world: $(RUST_SRC)test/run-pass/hello.rs $(LIBDIR)libstd.rlib $(RUSTC)
- $Vmkdir -p $(dir $@)
+ $Vtime $(DBG) $(BINDIR_S)rustc --crate-type rlib --crate-name $* -L $(LIBDIR_S) $< -o $@ $(RUSTFLAGS_$*)
+$(LIBDIR_S)lib%.rlib: $(RUST_SRC)lib%/src/lib.rs $(BINDIR_S)rustc
+ @mkdir -p $(dir $@)
@echo "[RUSTC] -o $@"
- $Vtime $(DBG) $(RUSTC) $(RUSTFLAGS_$@) -L $(LIBDIR) -L ../output/libs $< -o $@
-
-fcn_extcrate = $(patsubst %,$(LIBDIR)lib%.rlib,$(1))
-
-$(LIBDIR)libarena.rlib: $(call fcn_extcrate, std)
-$(LIBDIR)liballoc.rlib: $(call fcn_extcrate, core)
-$(LIBDIR)libstd_unicode.rlib: $(call fcn_extcrate, core)
-$(LIBDIR)libcollections.rlib: $(call fcn_extcrate, core alloc std_unicode)
-$(LIBDIR)librand.rlib: $(call fcn_extcrate, core)
-$(LIBDIR)liblibc.rlib: $(call fcn_extcrate, core)
-$(LIBDIR)libcompiler_builtins.rlib: $(call fcn_extcrate, core)
-$(LIBDIR)libstd.rlib: $(call fcn_extcrate, core collections rand libc unwind compiler_builtins alloc_system panic_unwind)
-$(LIBDIR)libunwind.rlib: $(call fcn_extcrate, core libc)
+ $Vtime $(DBG) $(BINDIR_S)rustc --crate-type rlib --crate-name $* -L $(LIBDIR_S) $< -o $@ $(RUSTFLAGS_$*)
+
+fcn_extcrate = $(patsubst %,$(LIBDIR_S)lib%.rlib,$(1))
+
+$(LIBDIR_S)libarena.rlib: $(call fcn_extcrate, std)
+$(LIBDIR_S)liballoc.rlib: $(call fcn_extcrate, core compiler_builtins)
+ifeq ($(RUSTC_VERSION),1.29.0)
+$(LIBDIR_S)liballoc.rlib: $(call fcn_extcrate, alloc_system)
+endif
+$(LIBDIR_S)liballoc_system.rlib: $(call fcn_extcrate, core libc)
+$(LIBDIR_S)libpanic_unwind.rlib: $(call fcn_extcrate, core alloc libc unwind)
+$(LIBDIR_S)libstd_unicode.rlib: $(call fcn_extcrate, core compiler_builtins)
+$(LIBDIR_S)libcollections.rlib: $(call fcn_extcrate, core alloc std_unicode compiler_builtins)
+$(LIBDIR_S)librand.rlib: $(call fcn_extcrate, core compiler_builtins)
+$(LIBDIR_S)liblibc.rlib: $(call fcn_extcrate, core compiler_builtins)
+$(LIBDIR_S)libcompiler_builtins.rlib: $(call fcn_extcrate, core)
+$(LIBDIR_S)libstd.rlib: $(call fcn_extcrate, core libc unwind compiler_builtins alloc_system panic_unwind)
+ifeq ($(RUSTC_VERSION),1.19.0)
+$(LIBDIR_S)libstd.rlib: $(call fcn_extcrate, collections rand)
+endif
+$(LIBDIR_S)libunwind.rlib: $(call fcn_extcrate, core libc)
diff --git a/rust-nightly-date b/rust-nightly-date
index 69416130..1242c4a4 100644
--- a/rust-nightly-date
+++ b/rust-nightly-date
@@ -1 +1 @@
-2017-07-14
+2018-07-09
diff --git a/rust-version b/rust-version
index 815d5ca0..5e57fb89 100644
--- a/rust-version
+++ b/rust-version
@@ -1 +1 @@
-1.19.0
+1.29.0
diff --git a/rust_src.patch b/rustc-1.19.0-src.patch
index 1cc13242..1cc13242 100644
--- a/rust_src.patch
+++ b/rustc-1.19.0-src.patch
diff --git a/rustc-1.29.0-src.patch b/rustc-1.29.0-src.patch
new file mode 100644
index 00000000..fb47520c
--- /dev/null
+++ b/rustc-1.29.0-src.patch
@@ -0,0 +1,85 @@
+# Add mrustc slice length intrinsics
+--- src/libcore/intrinsics.rs
++++ src/libcore/intrinsics.rs
+@@ -678,5 +678,9 @@
+ pub fn min_align_of_val<T: ?Sized>(_: &T) -> usize;
+
++ /// Obtain the length of a slice pointer
++ #[cfg(rust_compiler="mrustc")]
++ pub fn mrustc_slice_len<T>(pointer: *const [T]) -> usize;
++
+ /// Gets a static string slice containing the name of a type.
+ pub fn type_name<T: ?Sized>() -> &'static str;
+
+--- src/libcore/slice/mod.rs
++++ src/libcore/slice/mod.rs
+@@ -413,5 +413,7 @@
+ pub const fn len(&self) -> usize {
+- unsafe {
+- Repr { rust: self }.raw.len
+- }
++ #[cfg(not(rust_compiler="mrustc"))]
++ const fn len_inner<T>(s: &[T]) -> usize { unsafe { Repr { rust: s }.raw.len } };
++ #[cfg(rust_compiler="mrustc")]
++ const fn len_inner<T>(s: &[T]) -> usize { unsafe { ::intrinsics::mrustc_slice_len(s) } }
++ len_inner(self)
+ }
+# Static-link rustc_codegen_llvm because mrustc doesn't have dylib support
+--- src/librustc_driver/Cargo.toml
++++ src/librustc_driver/Cargo.toml
+@@ -39,1 +39,2 @@
+ syntax_pos = { path = "../libsyntax_pos" }
++rustc_codegen_llvm = { path = "../librustc_codegen_llvm" }
+--- src/librustc_driver/lib.rs
++++ src/librustc_driver/lib.rs
+@@ -63,2 +63,3 @@
+ extern crate syntax_pos;
++extern crate rustc_codegen_llvm;
+
+@@ -296,3 +296,7 @@
+ }
+
++ if backend_name == "llvm" {
++ return rustc_codegen_llvm::__rustc_codegen_backend;
++ }
++
+ let target = session::config::host_triple();
+# No workspace support in minicargo, patch cargo's Cargo.toml
+--- src/tools/cargo/Cargo.toml
++++ src/tools/cargo/Cargo.toml
+@@ -60,5 +60,5 @@
+ # A noop dependency that changes in the Rust repository, it's a bit of a hack.
+ # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
+ # for more information.
+-rustc-workspace-hack = "1.0.0"
++rustc-workspace-hack = { path = "../rustc-workspace-hack" }
+
+# mrustc can't represent a 24 byte version of this enum (no way of storing the
+# tag in padding)
+--- src/librustc/ty/context.rs
++++ src/librustc/ty/context.rs
+@@ -805,5 +805,5 @@
+ // Ensure our type representation does not grow
+- #[cfg(target_pointer_width = "64")]
+- assert!(mem::size_of::<ty::TypeVariants>() <= 24);
+- #[cfg(target_pointer_width = "64")]
+- assert!(mem::size_of::<ty::TyS>() <= 32);
++ //#[cfg(target_pointer_width = "64")]
++ //assert!(mem::size_of::<ty::TypeVariants>() <= 24);
++ //#[cfg(target_pointer_width = "64")]
++ //assert!(mem::size_of::<ty::TyS>() <= 32);
+
+--- src/stdsimd/stdsimd/arch/detect/os/x86.rs
++++ src/stdsimd/stdsimd/arch/detect/os/x86.rs
+@@ -14,5 +14,11 @@
+ /// Performs run-time feature detection.
+ #[inline]
++#[cfg(not(rust_compiler="mrustc"))]
+ pub fn check_for(x: Feature) -> bool {
+ cache::test(x as u32, detect_features)
+ }
++#[inline]
++#[cfg(rust_compiler="mrustc")]
++pub fn check_for(x: Feature) -> bool {
++ false
++}
diff --git a/samples/test/enums.rs b/samples/test/enums.rs
new file mode 100644
index 00000000..38d4eb15
--- /dev/null
+++ b/samples/test/enums.rs
@@ -0,0 +1,15 @@
+
+enum Values
+{
+ One,
+ Two,
+ Three,
+}
+
+fn main()
+{
+ assert!(match Some(&1) { Some(1) => true, _ => false });
+ assert!(match Some(1) { Some(1) => true, _ => false });
+ assert!(match Values::One { Values::One => true, _ => false });
+}
+
diff --git a/samples/test/funny_hash.rs b/samples/test/funny_hash.rs
new file mode 100644
index 00000000..9e93c296
--- /dev/null
+++ b/samples/test/funny_hash.rs
@@ -0,0 +1,39 @@
+use std::hash::{Hash,Hasher};
+extern {
+ type OpaqueSliceContents;
+}
+
+#[repr(C)]
+pub struct Slice<T> {
+ len: usize,
+ data: [T; 0],
+ opaque: OpaqueSliceContents,
+}
+impl<T> Hash for Slice<T> {
+ #[inline]
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ (self as *const Slice<T>).hash(s)
+ }
+}
+
+
+fn main() {
+}
+
+struct MyHasher {
+ count: usize,
+}
+impl Hasher for MyHasher
+{
+ fn finish(&self) -> u64 {
+ self.count as u64
+ }
+ fn write(&mut self, bytes: &[u8]) {
+ self.count += bytes.len();
+ }
+}
+fn do_hash(v: &Slice<u8>) {
+ let mut mh = MyHasher { count: 0 };
+ v.hash(&mut mh);
+ assert_eq!( mh.finish() as usize, ::std::mem::size_of::<usize>() );
+}
diff --git a/samples/test/thread_drop.rs b/samples/test/thread_drop.rs
new file mode 100644
index 00000000..ae2e6be4
--- /dev/null
+++ b/samples/test/thread_drop.rs
@@ -0,0 +1,17 @@
+
+use std::sync::Arc;
+use std::sync::atomic::{Ordering, AtomicBool};
+
+fn main() {
+ struct Foo(Arc<AtomicBool>);
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ self.0.store(true, Ordering::SeqCst);
+ }
+ }
+ let h = Arc::new(AtomicBool::new(false));
+ let h2 = Foo(h.clone());
+ let th = ::std::thread::spawn(move || { let _ = h2; });
+ th.join().unwrap();
+ assert!(h.load(Ordering::SeqCst), "Foo's Drop impl was never called");
+}
diff --git a/samples/test/vec_retain.rs b/samples/test/vec_retain.rs
new file mode 100644
index 00000000..2aad521a
--- /dev/null
+++ b/samples/test/vec_retain.rs
@@ -0,0 +1,6 @@
+fn main()
+{
+ let mut vec = vec![1, 2, 3];
+ vec.retain(|v| { println!("{}", v); true });
+ assert!(vec.len() == 3);
+}
diff --git a/script-overrides/stable-1.29.0-linux/build_compiler_builtins.txt b/script-overrides/stable-1.29.0-linux/build_compiler_builtins.txt
new file mode 100644
index 00000000..06ae3dbf
--- /dev/null
+++ b/script-overrides/stable-1.29.0-linux/build_compiler_builtins.txt
@@ -0,0 +1 @@
+# NOTE: mrustc doesn't need this built fully \ No newline at end of file
diff --git a/script-overrides/stable-1.29.0-linux/build_libc.txt b/script-overrides/stable-1.29.0-linux/build_libc.txt
new file mode 100644
index 00000000..aa2eb983
--- /dev/null
+++ b/script-overrides/stable-1.29.0-linux/build_libc.txt
@@ -0,0 +1,2 @@
+cargo:rustc-cfg=stdbuild
+cargo:rerun-if-changed=build.rs \ No newline at end of file
diff --git a/script-overrides/stable-1.29.0-linux/build_rustc_asan.txt b/script-overrides/stable-1.29.0-linux/build_rustc_asan.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/script-overrides/stable-1.29.0-linux/build_rustc_asan.txt
diff --git a/script-overrides/stable-1.29.0-linux/build_rustc_lsan.txt b/script-overrides/stable-1.29.0-linux/build_rustc_lsan.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/script-overrides/stable-1.29.0-linux/build_rustc_lsan.txt
diff --git a/script-overrides/stable-1.29.0-linux/build_rustc_msan.txt b/script-overrides/stable-1.29.0-linux/build_rustc_msan.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/script-overrides/stable-1.29.0-linux/build_rustc_msan.txt
diff --git a/script-overrides/stable-1.29.0-linux/build_rustc_tsan.txt b/script-overrides/stable-1.29.0-linux/build_rustc_tsan.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/script-overrides/stable-1.29.0-linux/build_rustc_tsan.txt
diff --git a/script-overrides/stable-1.29.0-linux/build_std.txt b/script-overrides/stable-1.29.0-linux/build_std.txt
new file mode 100644
index 00000000..e88dd227
--- /dev/null
+++ b/script-overrides/stable-1.29.0-linux/build_std.txt
@@ -0,0 +1,5 @@
+# TODO: Build libbacktrace
+cargo:rustc-link-lib=dl
+cargo:rustc-link-lib=rt
+cargo:rustc-link-lib=pthread
+
diff --git a/script-overrides/stable-1.29.0-linux/build_unwind.txt b/script-overrides/stable-1.29.0-linux/build_unwind.txt
new file mode 100644
index 00000000..aba1574a
--- /dev/null
+++ b/script-overrides/stable-1.29.0-linux/build_unwind.txt
@@ -0,0 +1 @@
+# On both windows (MSVC) and linux (glibc), nothing is needed \ No newline at end of file
diff --git a/script-overrides/stable-1.29.0-windows/build_compiler_builtins.txt b/script-overrides/stable-1.29.0-windows/build_compiler_builtins.txt
new file mode 100644
index 00000000..06ae3dbf
--- /dev/null
+++ b/script-overrides/stable-1.29.0-windows/build_compiler_builtins.txt
@@ -0,0 +1 @@
+# NOTE: mrustc doesn't need this built fully \ No newline at end of file
diff --git a/script-overrides/stable-1.29.0-windows/build_libc.txt b/script-overrides/stable-1.29.0-windows/build_libc.txt
new file mode 100644
index 00000000..aa2eb983
--- /dev/null
+++ b/script-overrides/stable-1.29.0-windows/build_libc.txt
@@ -0,0 +1,2 @@
+cargo:rustc-cfg=stdbuild
+cargo:rerun-if-changed=build.rs \ No newline at end of file
diff --git a/script-overrides/stable-1.29.0-windows/build_rustc_asan.txt b/script-overrides/stable-1.29.0-windows/build_rustc_asan.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/script-overrides/stable-1.29.0-windows/build_rustc_asan.txt
diff --git a/script-overrides/stable-1.29.0-windows/build_rustc_lsan.txt b/script-overrides/stable-1.29.0-windows/build_rustc_lsan.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/script-overrides/stable-1.29.0-windows/build_rustc_lsan.txt
diff --git a/script-overrides/stable-1.29.0-windows/build_rustc_msan.txt b/script-overrides/stable-1.29.0-windows/build_rustc_msan.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/script-overrides/stable-1.29.0-windows/build_rustc_msan.txt
diff --git a/script-overrides/stable-1.29.0-windows/build_rustc_tsan.txt b/script-overrides/stable-1.29.0-windows/build_rustc_tsan.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/script-overrides/stable-1.29.0-windows/build_rustc_tsan.txt
diff --git a/script-overrides/stable-1.29.0-windows/build_std.txt b/script-overrides/stable-1.29.0-windows/build_std.txt
new file mode 100644
index 00000000..062afd95
--- /dev/null
+++ b/script-overrides/stable-1.29.0-windows/build_std.txt
@@ -0,0 +1,5 @@
+# TODO: THis is the windows set
+cargo:rustc-link-lib=advapi32
+cargo:rustc-link-lib=ws2_32
+cargo:rustc-link-lib=userenv
+cargo:rustc-link-lib=shell32 \ No newline at end of file
diff --git a/script-overrides/stable-1.29.0-windows/build_unwind.txt b/script-overrides/stable-1.29.0-windows/build_unwind.txt
new file mode 100644
index 00000000..aba1574a
--- /dev/null
+++ b/script-overrides/stable-1.29.0-windows/build_unwind.txt
@@ -0,0 +1 @@
+# On both windows (MSVC) and linux (glibc), nothing is needed \ No newline at end of file
diff --git a/scripts/log_get_last_function.py b/scripts/log_get_last_function.py
new file mode 100644
index 00000000..3a54d9c5
--- /dev/null
+++ b/scripts/log_get_last_function.py
@@ -0,0 +1,31 @@
+import argparse
+import sys
+
+def main():
+ argp = argparse.ArgumentParser()
+ argp.add_argument("-o", "--output", type=lambda v: open(v, 'w'), default=sys.stdout)
+ argp.add_argument("logfile", type=open)
+ argp.add_argument("fcn_name", type=str, nargs='?')
+ args = argp.parse_args()
+
+ fcn_lines = []
+ found_fcn = False
+ for line in args.logfile:
+ if 'visit_function: ' in line \
+ or 'evaluate_constant: ' in line \
+ or 'Trans_Monomorphise_List: ' in line \
+ or 'Trans_Codegen: FUNCTION CODE' in line \
+ or 'Trans_Codegen- emit_' in line \
+ :
+ if found_fcn:
+ break
+ fcn_lines = []
+ if args.fcn_name is not None and args.fcn_name in line:
+ found_fcn = True
+ fcn_lines.append(line.strip())
+
+ for l in fcn_lines:
+ args.output.write(l)
+ args.output.write("\n")
+
+main()
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index e4fe49da..827ac2d1 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -107,18 +107,15 @@ Function Function::clone() const
return rv;
}
-void Trait::add_type(::std::string name, AttributeList attrs, TypeRef type) {
- m_items.push_back( Named<Item>(mv$(name), Item::make_Type({TypeAlias(GenericParams(), mv$(type))}), true) );
- m_items.back().data.attrs = mv$(attrs);
+void Trait::add_type(Span sp, RcString name, AttributeList attrs, TypeRef type) {
+ m_items.push_back( Named<Item>(sp, mv$(attrs), true, mv$(name), Item::make_Type({TypeAlias(GenericParams(), mv$(type))})) );
}
-void Trait::add_function(::std::string name, AttributeList attrs, Function fcn) {
+void Trait::add_function(Span sp, RcString name, AttributeList attrs, Function fcn) {
DEBUG("trait fn " << name);
- m_items.push_back( Named<Item>(mv$(name), Item::make_Function({mv$(fcn)}), true) );
- m_items.back().data.attrs = mv$(attrs);
+ m_items.push_back( Named<Item>(sp, mv$(attrs), true, mv$(name), Item::make_Function({mv$(fcn)})) );
}
-void Trait::add_static(::std::string name, AttributeList attrs, Static v) {
- m_items.push_back( Named<Item>(mv$(name), Item::make_Static({mv$(v)}), true) );
- m_items.back().data.attrs = mv$(attrs);
+void Trait::add_static(Span sp, RcString name, AttributeList attrs, Static v) {
+ m_items.push_back( Named<Item>(sp, mv$(attrs), true, mv$(name), Item::make_Static({mv$(v)})) );
}
void Trait::set_is_marker() {
m_is_marker = true;
@@ -126,7 +123,7 @@ void Trait::set_is_marker() {
bool Trait::is_marker() const {
return m_is_marker;
}
-bool Trait::has_named_item(const ::std::string& name, bool& out_is_fcn) const
+bool Trait::has_named_item(const RcString& name, bool& out_is_fcn) const
{
for( const auto& i : m_items )
{
@@ -143,7 +140,7 @@ Trait Trait::clone() const
auto rv = Trait(m_params.clone(), m_supertraits);
for(const auto& item : m_items)
{
- rv.m_items.push_back( Named<Item> { item.name, item.data.clone(), item.is_pub } );
+ rv.m_items.push_back( Named<Item> { item.span, item.attrs.clone(), item.is_pub, item.name, item.data.clone() } );
}
return rv;
}
@@ -208,24 +205,24 @@ Union Union::clone() const
return os << "impl<" << impl.m_params << "> " << impl.m_trait.ent << " for " << impl.m_type << "";
}
-void Impl::add_function(bool is_public, bool is_specialisable, ::std::string name, Function fcn)
+void Impl::add_function(Span sp, AttributeList attrs, bool is_public, bool is_specialisable, RcString name, Function fcn)
{
DEBUG("impl fn " << name);
- m_items.push_back( ImplItem { is_public, is_specialisable, mv$(name), box$( Item::make_Function(mv$(fcn)) ) } );
+ m_items.push_back( ImplItem { sp, mv$(attrs), is_public, is_specialisable, mv$(name), box$( Item::make_Function(mv$(fcn)) ) } );
}
-void Impl::add_type(bool is_public, bool is_specialisable, ::std::string name, TypeRef type)
+void Impl::add_type(Span sp, AttributeList attrs, bool is_public, bool is_specialisable, RcString name, TypeRef type)
{
- m_items.push_back( ImplItem { is_public, is_specialisable, mv$(name), box$( Item::make_Type(TypeAlias(GenericParams(), mv$(type))) ) } );
+ m_items.push_back( ImplItem { sp, mv$(attrs), is_public, is_specialisable, mv$(name), box$( Item::make_Type(TypeAlias(GenericParams(), mv$(type))) ) } );
}
-void Impl::add_static(bool is_public, bool is_specialisable, ::std::string name, Static v)
+void Impl::add_static(Span sp, AttributeList attrs, bool is_public, bool is_specialisable, RcString name, Static v)
{
- m_items.push_back( ImplItem { is_public, is_specialisable, mv$(name), box$( Item::make_Static(mv$(v)) ) } );
+ m_items.push_back( ImplItem { sp, mv$(attrs), is_public, is_specialisable, mv$(name), box$( Item::make_Static(mv$(v)) ) } );
}
void Impl::add_macro_invocation(MacroInvocation item) {
- m_items.push_back( ImplItem { false, false, "", box$( Item::make_MacroInv(mv$(item)) ) } );
+ m_items.push_back( ImplItem { item.span(), {}, false, false, "", box$( Item::make_MacroInv(mv$(item)) ) } );
}
-bool Impl::has_named_item(const ::std::string& name) const
+bool Impl::has_named_item(const RcString& name) const
{
for( const auto& it : this->items() )
{
@@ -241,28 +238,28 @@ bool Impl::has_named_item(const ::std::string& name) const
return os << impl.m_def;
}
-::std::ostream& operator<<(::std::ostream& os, const UseStmt& x)
-{
- os << "Use(" << x.path << ")";
- return os;
-}
-
-
MacroInvocation MacroInvocation::clone() const
{
return MacroInvocation(m_span, m_macro_name, m_ident, m_input.clone());
}
-
-UseStmt UseStmt::clone() const
+UseItem UseItem::clone() const
{
- return UseStmt(sp, path);
+ decltype(this->entries) entries;
+ for(const auto& e : this->entries)
+ {
+ entries.push_back({ e.sp, e.path, e.name });
+ }
+ return UseItem {
+ this->sp,
+ mv$(entries)
+ };
}
void ExternBlock::add_item(Named<Item> named_item)
{
- ASSERT_BUG(named_item.data.span, named_item.data.is_Function() || named_item.data.is_Static(), "Incorrect item type for ExternBlock");
+ ASSERT_BUG(named_item.span, named_item.data.is_Function() || named_item.data.is_Static() || named_item.data.is_Type(), "Incorrect item type for ExternBlock - " << named_item.data.tag_str());
m_items.push_back( mv$(named_item) );
}
ExternBlock ExternBlock::clone() const
@@ -271,7 +268,7 @@ ExternBlock ExternBlock::clone() const
}
::std::shared_ptr<AST::Module> Module::add_anon() {
- auto rv = ::std::shared_ptr<AST::Module>( new Module(m_my_path + FMT("#" << m_anon_modules.size())) );
+ auto rv = ::std::shared_ptr<AST::Module>( new Module(m_my_path + RcString::new_interned(FMT("#" << m_anon_modules.size()))) );
DEBUG("New anon " << rv->m_my_path);
rv->m_file_info = m_file_info;
@@ -286,55 +283,54 @@ void Module::add_item( Named<Item> named_item ) {
if( i.name == "" ) {
}
else {
- DEBUG(m_my_path << "::" << i.name << " = " << i.data.tag_str() << ", attrs = " << i.data.attrs);
+ DEBUG(m_my_path << "::" << i.name << " = " << i.data.tag_str() << ", attrs = " << i.attrs);
}
}
-void Module::add_item(bool is_pub, ::std::string name, Item it, AttributeList attrs) {
- it.attrs = mv$(attrs);
- add_item( Named<Item>( mv$(name), mv$(it), is_pub ) );
-}
-void Module::add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, AttributeList attrs) {
- this->add_item( is_public, imp_name, Item::make_Crate({mv$(ext_name)}), mv$(attrs) );
+void Module::add_item(Span sp, bool is_pub, RcString name, Item it, AttributeList attrs) {
+ add_item( Named<Item>( mv$(sp), mv$(attrs), is_pub, mv$(name), mv$(it) ) );
}
-void Module::add_alias(bool is_public, UseStmt us, ::std::string name, AttributeList attrs) {
- this->add_item( is_public, mv$(name), Item(mv$(us)), mv$(attrs) );
+void Module::add_ext_crate(Span sp, bool is_pub, RcString ext_name, RcString imp_name, AttributeList attrs) {
+ this->add_item( mv$(sp), is_pub, imp_name, Item::make_Crate({mv$(ext_name)}), mv$(attrs) );
}
void Module::add_macro_invocation(MacroInvocation item) {
- this->add_item( false, "", Item( mv$(item) ), ::AST::AttributeList {} );
+ this->add_item( item.span(), false, "", Item( mv$(item) ), ::AST::AttributeList {} );
}
-void Module::add_macro(bool is_exported, ::std::string name, MacroRulesPtr macro) {
- m_macros.push_back( Named<MacroRulesPtr>( mv$(name), mv$(macro), is_exported ) );
+void Module::add_macro(bool is_exported, RcString name, MacroRulesPtr macro) {
+ m_macros.push_back( Named<MacroRulesPtr>( Span(), {}, /*is_pub=*/is_exported, mv$(name), mv$(macro) ) );
}
-void Module::add_macro_import(::std::string name, const MacroRules& mr) {
- m_macro_import_res.push_back( Named<const MacroRules*>( mv$(name), &mr, false ) );
+void Module::add_macro_import(RcString name, const MacroRules& mr) {
+ m_macro_import_res.push_back( Named<const MacroRules*>( Span(), /*attrs=*/{}, /*is_pub=*/false, mv$(name), &mr) );
}
Item Item::clone() const
{
TU_MATCHA( (*this), (e),
(None,
- return AST::Item(e);
+ return Item(e);
),
(MacroInv,
- TODO(this->span, "Clone on Item::MacroInv");
+ TODO(Span(), "Clone on Item::MacroInv");
+ ),
+ (Macro,
+ TODO(Span(), "Clone on Item::Macro");
),
(Use,
- return AST::Item(e.clone());
+ return Item(e.clone());
),
(ExternBlock,
- TODO(this->span, "Clone on Item::" << this->tag_str());
+ TODO(Span(), "Clone on Item::" << this->tag_str());
),
(Impl,
- TODO(this->span, "Clone on Item::Impl");
+ TODO(Span(), "Clone on Item::" << this->tag_str());
),
(NegImpl,
- TODO(this->span, "Clone on Item::NegImpl");
+ TODO(Span(), "Clone on Item::" << this->tag_str());
),
(Module,
- TODO(this->span, "Clone on Item::Module");
+ TODO(Span(), "Clone on Item::" << this->tag_str());
),
(Crate,
- return AST::Item(e);
+ return Item(e);
),
(Type,
return AST::Item(e.clone());
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp
index 0a43cc71..1f42a764 100644
--- a/src/ast/ast.hpp
+++ b/src/ast/ast.hpp
@@ -8,6 +8,8 @@
#ifndef AST_HPP_INCLUDED
#define AST_HPP_INCLUDED
+#include <target_version.hpp>
+
#include <string>
#include <vector>
#include <stdexcept>
@@ -40,11 +42,16 @@ class Item;
using ::std::unique_ptr;
using ::std::move;
+typedef bool Visibility;
+
enum eItemType
{
ITEM_TRAIT,
ITEM_STRUCT,
+ ITEM_ENUM,
+ ITEM_UNION,
ITEM_FN,
+ ITEM_EXTERN_FN,
ITEM_STATIC,
};
@@ -52,12 +59,12 @@ struct StructItem
{
::AST::AttributeList m_attrs;
bool m_is_public;
- ::std::string m_name;
+ RcString m_name;
TypeRef m_type;
//StructItem() {}
- StructItem(::AST::AttributeList attrs, bool is_pub, ::std::string name, TypeRef ty):
+ StructItem(::AST::AttributeList attrs, bool is_pub, RcString name, TypeRef ty):
m_attrs( mv$(attrs) ),
m_is_public(is_pub),
m_name( mv$(name) ),
@@ -216,16 +223,16 @@ public:
const NamedList<Item>& items() const { return m_items; }
NamedList<Item>& items() { return m_items; }
- void add_type(::std::string name, AttributeList attrs, TypeRef type);
- void add_function(::std::string name, AttributeList attrs, Function fcn);
- void add_static(::std::string name, AttributeList attrs, Static v);
+ void add_type(Span sp, RcString name, AttributeList attrs, TypeRef type);
+ void add_function(Span sp, RcString name, AttributeList attrs, Function fcn);
+ void add_static(Span sp, RcString name, AttributeList attrs, Static v);
void set_is_marker();
bool is_marker() const;
void set_is_unsafe() { m_is_unsafe = true; }
bool is_unsafe() const { return m_is_unsafe; }
- bool has_named_item(const ::std::string& name, bool& out_is_fcn) const;
+ bool has_named_item(const RcString& name, bool& out_is_fcn) const;
Trait clone() const;
};
@@ -251,28 +258,28 @@ TAGGED_UNION_EX(EnumVariantData, (), Value,
struct EnumVariant
{
AttributeList m_attrs;
- ::std::string m_name;
+ RcString m_name;
EnumVariantData m_data;
EnumVariant()
{
}
- EnumVariant(AttributeList attrs, ::std::string name, Expr&& value):
+ EnumVariant(AttributeList attrs, RcString name, Expr&& value):
m_attrs( mv$(attrs) ),
m_name( mv$(name) ),
m_data( EnumVariantData::make_Value({mv$(value)}) )
{
}
- EnumVariant(AttributeList attrs, ::std::string name, ::std::vector<TypeRef> sub_types):
+ EnumVariant(AttributeList attrs, RcString name, ::std::vector<TypeRef> sub_types):
m_attrs( mv$(attrs) ),
m_name( ::std::move(name) ),
m_data( EnumVariantData::make_Tuple( {mv$(sub_types)} ) )
{
}
- EnumVariant(AttributeList attrs, ::std::string name, ::std::vector<StructItem> fields):
+ EnumVariant(AttributeList attrs, RcString name, ::std::vector<StructItem> fields):
m_attrs( mv$(attrs) ),
m_name( ::std::move(name) ),
m_data( EnumVariantData::make_Struct( {mv$(fields)} ) )
@@ -417,9 +424,11 @@ class Impl
{
public:
struct ImplItem {
+ Span sp;
+ AttributeList attrs;
bool is_pub; // Ignored for trait impls
bool is_specialisable;
- ::std::string name;
+ RcString name;
::std::unique_ptr<Item> data;
};
@@ -439,9 +448,9 @@ public:
{}
Impl& operator=(Impl&&) = default;
- void add_function(bool is_public, bool is_specialisable, ::std::string name, Function fcn);
- void add_type(bool is_public, bool is_specialisable, ::std::string name, TypeRef type);
- void add_static(bool is_public, bool is_specialisable, ::std::string name, Static v);
+ void add_function(Span sp, AttributeList attrs, bool is_public, bool is_specialisable, RcString name, Function fcn);
+ void add_type(Span sp, AttributeList attrs, bool is_public, bool is_specialisable, RcString name, TypeRef type);
+ void add_static(Span sp, AttributeList attrs, bool is_public, bool is_specialisable, RcString name, Static v);
void add_macro_invocation( MacroInvocation inv );
const ImplDef& def() const { return m_def; }
@@ -449,28 +458,25 @@ public:
const ::std::vector<ImplItem>& items() const { return m_items; }
::std::vector<ImplItem>& items() { return m_items; }
- bool has_named_item(const ::std::string& name) const;
+ bool has_named_item(const RcString& name) const;
friend ::std::ostream& operator<<(::std::ostream& os, const Impl& impl);
private:
};
-struct UseStmt
+struct UseItem
{
- Span sp;
- ::AST::Path path;
- ::AST::PathBinding alt_binding;
-
- UseStmt(Span sp, Path p):
- sp(sp),
- path(p)
- {
- }
-
- UseStmt clone() const;
+ Span sp; // Span covering the entire `use foo;`
+ struct Ent {
+ Span sp; // Span covering just the path (final component)
+ ::AST::Path path;
+ RcString name; // If "", this is a glob/wildcard use
+ };
+ ::std::vector<Ent> entries;
- friend ::std::ostream& operator<<(::std::ostream& os, const UseStmt& x);
+ UseItem clone() const;
+ //friend ::std::ostream& operator<<(::std::ostream& os, const UseItem& x);
};
class ExternBlock
@@ -512,7 +518,11 @@ public:
struct FileInfo
{
bool controls_dir = false;
+ bool force_no_load = false;
+ // Path to this module
::std::string path = "!";
+ // Directory controlled by this module
+ ::std::string dir = "";
};
FileInfo m_file_info;
@@ -526,13 +536,26 @@ public:
};
// TODO: Document difference between namespace and Type
- ::std::unordered_map< ::std::string, IndexEnt > m_namespace_items;
- ::std::unordered_map< ::std::string, IndexEnt > m_type_items;
- ::std::unordered_map< ::std::string, IndexEnt > m_value_items;
+ ::std::unordered_map< RcString, IndexEnt > m_namespace_items;
+ ::std::unordered_map< RcString, IndexEnt > m_type_items;
+ ::std::unordered_map< RcString, IndexEnt > m_value_items;
// List of macros imported from other modules (via #[macro_use], includes proc macros)
// - First value is an absolute path to the macro (including crate name)
- ::std::vector<::std::pair< ::std::vector<::std::string>, const MacroRules* >> m_macro_imports;
+ struct MacroImport {
+ bool is_pub;
+ RcString name; // Can be different, if `use foo as bar` is used
+ ::std::vector<RcString> path; // includes the crate name
+ const MacroRules* macro_ptr;
+ };
+ ::std::vector<MacroImport> m_macro_imports;
+
+ struct Import {
+ bool is_pub;
+ RcString name;
+ ::AST::Path path; // If `name` is "", then this is a module/enum to glob
+ };
+ ::std::vector<Import> m_item_imports;
public:
Module() {}
@@ -542,20 +565,19 @@ public:
}
bool is_anon() const {
- return m_my_path.nodes().size() > 0 && m_my_path.nodes().back().name()[0] == '#';
+ return m_my_path.nodes().size() > 0 && m_my_path.nodes().back().name().c_str()[0] == '#';
}
/// Create an anon module (for use inside expressions)
::std::shared_ptr<AST::Module> add_anon();
void add_item(Named<Item> item);
- void add_item(bool is_pub, ::std::string name, Item it, AttributeList attrs);
- void add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, AttributeList attrs);
- void add_alias(bool is_public, UseStmt path, ::std::string name, AttributeList attrs);
+ void add_item(Span sp, bool is_pub, RcString name, Item it, AttributeList attrs);
+ void add_ext_crate(Span sp, bool is_pub, RcString ext_name, RcString imp_name, AttributeList attrs);
void add_macro_invocation(MacroInvocation item);
- void add_macro(bool is_exported, ::std::string name, MacroRulesPtr macro);
- void add_macro_import(::std::string name, const MacroRules& mr);
+ void add_macro(bool is_exported, RcString name, MacroRulesPtr macro);
+ void add_macro_import(RcString name, const MacroRules& mr);
@@ -571,25 +593,24 @@ public:
NamedList<MacroRulesPtr>& macros() { return m_macros; }
const NamedList<MacroRulesPtr>& macros() const { return m_macros; }
const ::std::vector<Named<const MacroRules*> > macro_imports_res() const { return m_macro_import_res; }
-
-private:
- void resolve_macro_import(const Crate& crate, const ::std::string& modname, const ::std::string& macro_name);
};
TAGGED_UNION_EX(Item, (), None,
(
(None, struct {} ),
(MacroInv, MacroInvocation),
- (Use, UseStmt),
+ // TODO: MacroDefinition
+ (Use, UseItem),
// Nameless items
(ExternBlock, ExternBlock),
(Impl, Impl),
(NegImpl, ImplDef),
+ (Macro, MacroRulesPtr),
(Module, Module),
(Crate, struct {
- ::std::string name;
+ RcString name;
}),
(Type, TypeAlias),
@@ -602,12 +623,8 @@ TAGGED_UNION_EX(Item, (), None,
(Static, Static)
),
- (, attrs(mv$(x.attrs))), (attrs = mv$(x.attrs);),
+ (), (),
(
- public:
- AttributeList attrs;
- Span span;
-
Item clone() const;
)
);
diff --git a/src/ast/attrs.hpp b/src/ast/attrs.hpp
index 0e1c8149..7a6ce864 100644
--- a/src/ast/attrs.hpp
+++ b/src/ast/attrs.hpp
@@ -8,6 +8,7 @@
#ifndef _AST_ATTRS_HPP_
#define _AST_ATTRS_HPP_
+#include <tagged_union.hpp>
namespace AST {
@@ -74,23 +75,24 @@ TAGGED_UNION(AttributeData, None,
class Attribute
{
Span m_span;
- ::std::string m_name;
+ RcString m_name;
AttributeData m_data;
mutable bool m_is_used;
+ // TODO: Parse as a TT then expand?
public:
- Attribute(Span sp, ::std::string name):
+ Attribute(Span sp, RcString name):
m_span(::std::move(sp)),
m_name(name),
m_data( AttributeData::make_None({}) )
{
}
- Attribute(Span sp, ::std::string name, ::std::string str_val):
+ Attribute(Span sp, RcString name, ::std::string str_val):
m_span(::std::move(sp)),
m_name(name),
m_data( AttributeData::make_String({mv$(str_val)}) )
{
}
- Attribute(Span sp, ::std::string name, ::std::vector<Attribute> items):
+ Attribute(Span sp, RcString name, ::std::vector<Attribute> items):
m_span(::std::move(sp)),
m_name(name),
m_data( AttributeData::make_List({mv$(items)}) )
@@ -122,7 +124,7 @@ public:
bool is_used() const { return m_is_used; }
const Span& span() const { return m_span; }
- const ::std::string& name() const { return m_name; }
+ const RcString& name() const { return m_name; }
const AttributeData& data() const { return m_data; }
// Legacy accessors/checkers
diff --git a/src/ast/crate.cpp b/src/ast/crate.cpp
index 3db09f1b..19a19381 100644
--- a/src/ast/crate.cpp
+++ b/src/ast/crate.cpp
@@ -12,6 +12,12 @@
#include <hir/hir.hpp> // HIR::Crate
#include <hir/main_bindings.hpp> // HIR_Deserialise
#include <fstream>
+#ifdef _WIN32
+# define NOGDI // prevent ERROR from being defined
+# include <Windows.h>
+#else
+# include <dirent.h>
+#endif
::std::vector<::std::string> AST::g_crate_load_dirs = { };
::std::map<::std::string, ::std::string> AST::g_crate_overrides;
@@ -31,12 +37,13 @@ namespace {
fcn(mod);
for( auto& sm : mod.items() )
{
- TU_IFLET(::AST::Item, sm.data, Module, e,
- if( check_item_cfg(sm.data.attrs) )
+ if( auto* e = sm.data.opt_Module() )
+ {
+ if( check_item_cfg(sm.attrs) )
{
- iterate_module(e, fcn);
+ iterate_module(*e, fcn);
}
- )
+ }
}
// TODO: What about if an anon mod has been #[cfg]-d out?
// - For now, disable
@@ -60,12 +67,13 @@ void Crate::load_externs()
auto cb = [this](Module& mod) {
for( /*const*/ auto& it : mod.items() )
{
- TU_IFLET(AST::Item, it.data, Crate, c,
- if( check_item_cfg(it.data.attrs) )
+ if( auto* c = it.data.opt_Crate() )
+ {
+ if( check_item_cfg(it.attrs) )
{
- c.name = load_extern_crate( it.data.span, c.name );
+ c->name = load_extern_crate( it.span, c->name.c_str() );
}
- )
+ }
}
};
iterate_module(m_root_module, cb);
@@ -108,57 +116,134 @@ void Crate::load_externs()
}
// TODO: Handle disambiguating crates with the same name (e.g. libc in std and crates.io libc)
// - Crates recorded in rlibs should specify a hash/tag that's passed in to this function.
-::std::string Crate::load_extern_crate(Span sp, const ::std::string& name, const ::std::string& basename/*=""*/)
+RcString Crate::load_extern_crate(Span sp, const RcString& name, const ::std::string& basename/*=""*/)
{
- DEBUG("Loading crate '" << name << "'");
+ TRACE_FUNCTION_F("Loading crate '" << name << "' (basename='" << basename << "')");
::std::string path;
- auto it = g_crate_overrides.find(name);
+ auto it = g_crate_overrides.find(name.c_str());
if(basename == "" && it != g_crate_overrides.end())
{
path = it->second;
if( !::std::ifstream(path).good() ) {
ERROR(sp, E0000, "Unable to open crate '" << name << "' at path " << path);
}
+ DEBUG("path = " << path << " (--extern)");
+ }
+ else if( basename != "" )
+ {
+#if 1
+ path = basename;
+#else
+ // Search a list of load paths for the crate
+ for(const auto& p : g_crate_load_dirs)
+ {
+ path = p + "/" + basename;
+
+ if( ::std::ifstream(path).good() ) {
+ break ;
+ }
+ }
+#endif
+ if( !::std::ifstream(path).good() ) {
+ ERROR(sp, E0000, "Unable to locate crate '" << name << "' with filename " << basename << " in search directories");
+ }
+ DEBUG("path = " << path << " (basename)");
}
else
{
+ ::std::vector<::std::string> paths;
+#define RLIB_SUFFIX ".rlib"
+#define RDYLIB_SUFFIX ".so"
+ auto direct_filename = FMT("lib" << name.c_str() << RLIB_SUFFIX);
+ auto direct_filename_so = FMT("lib" << name.c_str() << RDYLIB_SUFFIX);
+ auto name_prefix = FMT("lib" << name.c_str() << "-");
// Search a list of load paths for the crate
for(const auto& p : g_crate_load_dirs)
{
- if( basename == "" )
- {
- path = p + "/lib" + name + ".hir";
- // TODO: Search for `p+"/lib"+name+"-*.hir" (which would match e.g. libnum-0.11.hir)
+ path = p + "/" + direct_filename;
+ if( ::std::ifstream(path).good() ) {
+ paths.push_back(path);
}
- else
+ path = p + "/" + direct_filename_so;
+ if( ::std::ifstream(path).good() ) {
+ paths.push_back(path);
+ }
+ path = "";
+
+ // Search for `p+"/lib"+name+"-*.rlib" (which would match e.g. libnum-0.11.rlib)
+#ifdef _WIN32
+ WIN32_FIND_DATA find_data;
+ auto mask = p + "\\*";
+ HANDLE find_handle = FindFirstFile( mask.c_str(), &find_data );
+ if( find_handle == INVALID_HANDLE_VALUE ) {
+ continue ;
+ }
+ do
{
- path = p + "/" + basename;
+ const auto* fname = find_data.cFileName;
+#else
+ auto dp = opendir(p.c_str());
+ if( !dp ) {
+ continue ;
}
+ struct dirent *ent;
+ while( (ent = readdir(dp)) != nullptr && path == "" )
+ {
+ const auto* fname = ent->d_name;
+#endif
- if( ::std::ifstream(path).good() ) {
- break ;
+ // AND the start is "lib"+name
+ size_t len = strlen(fname);
+ if( len > (sizeof(RLIB_SUFFIX)-1) && strcmp(fname + len - (sizeof(RLIB_SUFFIX)-1), RLIB_SUFFIX) == 0 )
+ {
+ }
+ else if( len > (sizeof(RDYLIB_SUFFIX)-1) && strcmp(fname + len - (sizeof(RDYLIB_SUFFIX)-1), RDYLIB_SUFFIX) == 0 )
+ {
+ }
+ else
+ {
+ continue ;
+ }
+
+ DEBUG(fname << " vs " << name_prefix);
+ // Check if the entry ends with .rlib
+ if( strncmp(name_prefix.c_str(), fname, name_prefix.size()) != 0 )
+ continue ;
+
+ paths.push_back( p + "/" + fname );
+#ifdef _WIN32
+ } while( FindNextFile(find_handle, &find_data) );
+ FindClose(find_handle);
+#else
}
+ closedir(dp);
+#endif
+ if( paths.size() > 0 )
+ break;
}
- if( !::std::ifstream(path).good() ) {
- if( basename.empty() )
- ERROR(sp, E0000, "Unable to locate crate '" << name << "' in search directories");
- else
- ERROR(sp, E0000, "Unable to locate crate '" << name << "' with filename " << basename << " in search directories");
+ if( paths.size() > 1 ) {
+ ERROR(sp, E0000, "Multiple options for crate '" << name << "' in search directories - " << paths);
+ }
+ if( paths.size() == 0 || !::std::ifstream(paths.front()).good() ) {
+ ERROR(sp, E0000, "Unable to locate crate '" << name << "' in search directories");
}
+ path = paths.front();
+ DEBUG("path = " << path << " (search)");
}
// NOTE: Creating `ExternCrate` loads the crate from the specified path
auto ec = ExternCrate { name, path };
auto real_name = ec.m_hir->m_crate_name;
- assert(!real_name.empty());
+ assert(real_name != "");
auto res = m_extern_crates.insert(::std::make_pair( real_name, mv$(ec) ));
if( !res.second ) {
// Crate already loaded?
}
auto& ext_crate = res.first->second;
// Move the external list out (doesn't need to be kept in the nested crate)
- auto crate_ext_list = mv$( ext_crate.m_hir->m_ext_crates );
+ //auto crate_ext_list = mv$( ext_crate.m_hir->m_ext_crates );
+ const auto& crate_ext_list = ext_crate.m_hir->m_ext_crates;
// Load referenced crates
for( const auto& ext : crate_ext_list )
@@ -178,25 +263,26 @@ void Crate::load_externs()
return real_name;
}
-ExternCrate::ExternCrate(const ::std::string& name, const ::std::string& path):
+ExternCrate::ExternCrate(const RcString& name, const ::std::string& path):
m_name(name),
+ m_short_name(name),
m_filename(path)
{
TRACE_FUNCTION_F("name=" << name << ", path='" << path << "'");
- m_hir = HIR_Deserialise(path, name);
+ m_hir = HIR_Deserialise(path);
m_hir->post_load_update(name);
m_name = m_hir->m_crate_name;
}
-void ExternCrate::with_all_macros(::std::function<void(const ::std::string& , const MacroRules&)> cb) const
+void ExternCrate::with_all_macros(::std::function<void(const RcString& , const MacroRules&)> cb) const
{
for(const auto& m : m_hir->m_exported_macros)
{
cb(m.first, *m.second);
}
}
-const MacroRules* ExternCrate::find_macro_rules(const ::std::string& name) const
+const MacroRules* ExternCrate::find_macro_rules(const RcString& name) const
{
auto i = m_hir->m_exported_macros.find(name);
if(i != m_hir->m_exported_macros.end())
diff --git a/src/ast/crate.hpp b/src/ast/crate.hpp
index 87a9f867..c4e1d5df 100644
--- a/src/ast/crate.hpp
+++ b/src/ast/crate.hpp
@@ -36,7 +36,7 @@ public:
class ProcMacroDef
{
public:
- ::std::string name;
+ RcString name;
::AST::Path path;
::std::vector<::std::string> attributes;
};
@@ -49,15 +49,16 @@ public:
::std::map< ::std::string, ::AST::Path> m_lang_items;
public:
Module m_root_module;
- ::std::map< ::std::string, ExternCrate> m_extern_crates;
+ ::std::map< RcString, ExternCrate> m_extern_crates;
// Mapping filled by searching for (?visible) macros with is_pub=true
- ::std::map< ::std::string, const MacroRules*> m_exported_macros;
+ ::std::map< RcString, const MacroRules*> m_exported_macros;
// List of tests (populated in expand if --test is passed)
bool m_test_harness = false;
::std::vector<TestDesc> m_tests;
- //::std::vector<::std::string> m_extra_files;
+ /// Files loaded using things like include! and include_str!
+ mutable ::std::vector<::std::string> m_extra_files;
// Procedural macros!
::std::vector<ProcMacroDef> m_proc_macros;
@@ -90,26 +91,27 @@ public:
/// Load the named crate and returns the crate's unique name
/// If the parameter `file` is non-empty, only that particular filename will be loaded (from any of the search paths)
- ::std::string load_extern_crate(Span sp, const ::std::string& name, const ::std::string& file="");
+ RcString load_extern_crate(Span sp, const RcString& name, const ::std::string& file="");
};
/// Representation of an imported crate
class ExternCrate
{
public:
- ::std::string m_name;
+ RcString m_name;
+ RcString m_short_name;
::std::string m_filename;
::HIR::CratePtr m_hir;
- ExternCrate(const ::std::string& name, const ::std::string& path);
+ ExternCrate(const RcString& name, const ::std::string& path);
ExternCrate(ExternCrate&&) = default;
ExternCrate& operator=(ExternCrate&&) = default;
ExternCrate(const ExternCrate&) = delete;
ExternCrate& operator=(const ExternCrate& ) = delete;
- void with_all_macros(::std::function<void(const ::std::string& , const MacroRules&)> cb) const;
- const MacroRules* find_macro_rules(const ::std::string& name) const;
+ void with_all_macros(::std::function<void(const RcString& , const MacroRules&)> cb) const;
+ const MacroRules* find_macro_rules(const RcString& name) const;
};
extern ::std::vector<::std::string> g_crate_load_dirs;
diff --git a/src/ast/dump.cpp b/src/ast/dump.cpp
index f1481abf..4e880a76 100644
--- a/src/ast/dump.cpp
+++ b/src/ast/dump.cpp
@@ -36,7 +36,7 @@ public:
void handle_enum(const AST::Enum& s);
void handle_trait(const AST::Trait& s);
- void handle_function(bool is_pub, const ::std::string& name, const AST::Function& f);
+ void handle_function(bool is_pub, const RcString& name, const AST::Function& f);
virtual bool is_const() const override { return true; }
virtual void visit(AST::ExprNode_Block& n) override {
@@ -71,6 +71,10 @@ public:
dec_indent();
m_os << indent() << "}";
}
+ virtual void visit(AST::ExprNode_Try& n) override {
+ m_os << "try ";
+ AST::NodeVisitor::visit(n.m_inner);
+ }
virtual void visit(AST::ExprNode_Macro& n) override {
m_expr_root = false;
m_os << n.m_name << "!( /* TODO: Macro TT */ )";
@@ -619,17 +623,26 @@ void RustPrinter::handle_module(const AST::Module& mod)
// m_os << "\n";
// need_nl = false;
//}
- if( i_data.path == AST::Path() ) {
+ if( i_data.entries.empty() ) {
continue ;
}
- m_os << indent() << (i.is_pub ? "pub " : "") << "use " << i_data;
- if( i.name == "" )
- {
- m_os << "::*";
+ m_os << indent() << (i.is_pub ? "pub " : "") << "use ";
+ if( i_data.entries.size() > 1 ) {
+ m_os << "{";
}
- else if( i_data.path.nodes().back().name() != i.name )
+ for(const auto& ent : i_data.entries)
{
- m_os << " as " << i.name;
+ if( &ent != &i_data.entries.front() )
+ m_os << ", ";
+ m_os << ent.path;
+ if( ent.name == "" ) {
+ m_os << "::*";
+ }
+ else if( ent.name != ent.path.nodes().back().name() ) {
+ m_os << " as " << ent.name;
+ }
+ else {
+ }
}
m_os << ";\n";
}
@@ -640,7 +653,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
if( !item.data.is_Crate() ) continue ;
const auto& e = item.data.as_Crate();
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << "extern crate \"" << e.name << "\" as " << item.name << ";\n";
}
@@ -649,7 +662,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
if( !item.data.is_ExternBlock() ) continue ;
const auto& e = item.data.as_ExternBlock();
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << "extern \"" << e.abi() << "\" {}\n";
}
@@ -677,7 +690,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
m_os << "\n";
need_nl = false;
}
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << (item.is_pub ? "pub " : "") << "type " << item.name;
print_params(e.params());
m_os << " = " << e.type();
@@ -692,7 +705,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
const auto& e = item.data.as_Struct();
m_os << "\n";
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << (item.is_pub ? "pub " : "") << "struct " << item.name;
handle_struct(e);
}
@@ -703,7 +716,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
const auto& e = item.data.as_Enum();
m_os << "\n";
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << (item.is_pub ? "pub " : "") << "enum " << item.name;
handle_enum(e);
}
@@ -714,7 +727,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
const auto& e = item.data.as_Trait();
m_os << "\n";
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << (item.is_pub ? "pub " : "") << "trait " << item.name;
handle_trait(e);
}
@@ -728,7 +741,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
m_os << "\n";
need_nl = false;
}
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
m_os << indent() << (item.is_pub ? "pub " : "");
switch( e.s_class() )
{
@@ -747,7 +760,7 @@ void RustPrinter::handle_module(const AST::Module& mod)
const auto& e = item.data.as_Function();
m_os << "\n";
- print_attrs(item.data.attrs);
+ print_attrs(item.attrs);
handle_function(item.is_pub, item.name, e);
}
@@ -1029,7 +1042,7 @@ void RustPrinter::handle_struct(const AST::Struct& s)
(Tuple,
m_os << "(";
for( const auto& i : e.ents )
- m_os << i.m_type << ", ";
+ m_os << (i.m_is_public ? "pub " : "") << i.m_type << ", ";
m_os << ")\n";
print_bounds(s.params());
m_os << indent() << ";\n";
@@ -1120,7 +1133,7 @@ void RustPrinter::handle_trait(const AST::Trait& s)
m_os << "\n";
}
-void RustPrinter::handle_function(bool is_pub, const ::std::string& name, const AST::Function& f)
+void RustPrinter::handle_function(bool is_pub, const RcString& name, const AST::Function& f)
{
m_os << indent();
m_os << (is_pub ? "pub " : "");
diff --git a/src/ast/expr.cpp b/src/ast/expr.cpp
index 1525ed12..dc006212 100644
--- a/src/ast/expr.cpp
+++ b/src/ast/expr.cpp
@@ -93,6 +93,12 @@ NODE(ExprNode_Block, {
return NEWNODE(ExprNode_Block, m_is_unsafe, m_yields_final_value, mv$(nodes), m_local_mod);
})
+NODE(ExprNode_Try, {
+ os << "try " << *m_inner;
+},{
+ return NEWNODE(ExprNode_Try, m_inner->clone());
+})
+
NODE(ExprNode_Macro, {
os << m_name << "!";
if( m_ident.size() > 0 )
@@ -358,7 +364,8 @@ NODE(ExprNode_Tuple, {
})
NODE(ExprNode_NamedValue, {
- os << m_path;
+ m_path.print_pretty(os, false);
+ //os << m_path;
},{
return NEWNODE(ExprNode_NamedValue, AST::Path(m_path));
})
@@ -470,6 +477,9 @@ NV(ExprNode_Block, {
visit(child);
//UNINDENT();
})
+NV(ExprNode_Try, {
+ visit(node.m_inner);
+})
NV(ExprNode_Macro,
{
BUG(node.span(), "Hit unexpanded macro in expression - " << node);
diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp
index 264b37e9..6cfda001 100644
--- a/src/ast/expr.hpp
+++ b/src/ast/expr.hpp
@@ -74,14 +74,27 @@ struct ExprNode_Block:
NODE_METHODS();
};
+struct ExprNode_Try:
+ public ExprNode
+{
+ ExprNodeP m_inner;
+
+ ExprNode_Try(ExprNodeP inner):
+ m_inner(mv$(inner))
+ {
+ }
+
+ NODE_METHODS();
+};
+
struct ExprNode_Macro:
public ExprNode
{
- ::std::string m_name;
- ::std::string m_ident;
+ RcString m_name;
+ RcString m_ident;
::TokenTree m_tokens;
- ExprNode_Macro(::std::string name, ::std::string ident, ::TokenTree&& tokens):
+ ExprNode_Macro(RcString name, RcString ident, ::TokenTree&& tokens):
m_name(name),
m_ident(ident),
m_tokens( move(tokens) )
@@ -127,10 +140,10 @@ struct ExprNode_Flow:
CONTINUE,
BREAK,
} m_type;
- ::std::string m_target;
+ RcString m_target;
unique_ptr<ExprNode> m_value;
- ExprNode_Flow(Type type, ::std::string target, unique_ptr<ExprNode>&& value):
+ ExprNode_Flow(Type type, RcString target, unique_ptr<ExprNode>&& value):
m_type(type),
m_target( move(target) ),
m_value( move(value) )
@@ -232,24 +245,24 @@ struct ExprNode_Loop:
WHILELET,
FOR,
} m_type;
- ::std::string m_label;
+ RcString m_label;
AST::Pattern m_pattern;
unique_ptr<ExprNode> m_cond; // if NULL, loop is a 'loop'
unique_ptr<ExprNode> m_code;
ExprNode_Loop(): m_type(LOOP) {}
- ExprNode_Loop(::std::string label, unique_ptr<ExprNode> code):
+ ExprNode_Loop(RcString label, unique_ptr<ExprNode> code):
m_type(LOOP),
m_label( ::std::move(label) ),
m_code( ::std::move(code) )
{}
- ExprNode_Loop(::std::string label, unique_ptr<ExprNode> cond, unique_ptr<ExprNode> code):
+ ExprNode_Loop(RcString label, unique_ptr<ExprNode> cond, unique_ptr<ExprNode> code):
m_type(WHILE),
m_label( ::std::move(label) ),
m_cond( ::std::move(cond) ),
m_code( ::std::move(code) )
{}
- ExprNode_Loop(::std::string label, Type type, AST::Pattern pattern, unique_ptr<ExprNode> val, unique_ptr<ExprNode> code):
+ ExprNode_Loop(RcString label, Type type, AST::Pattern pattern, unique_ptr<ExprNode> val, unique_ptr<ExprNode> code):
m_type(type),
m_label( ::std::move(label) ),
m_pattern( ::std::move(pattern) ),
@@ -417,7 +430,7 @@ struct ExprNode_StructLiteral:
{
struct Ent {
AttributeList attrs;
- ::std::string name;
+ RcString name;
unique_ptr<ExprNode> value;
};
typedef ::std::vector<Ent> t_values;
@@ -480,9 +493,9 @@ struct ExprNode_Field:
public ExprNode
{
::std::unique_ptr<ExprNode> m_obj;
- ::std::string m_name;
+ RcString m_name;
- ExprNode_Field(::std::unique_ptr<ExprNode>&& obj, ::std::string name):
+ ExprNode_Field(::std::unique_ptr<ExprNode>&& obj, RcString name):
m_obj( ::std::move(obj) ),
m_name( ::std::move(name) )
{
@@ -634,6 +647,7 @@ public:
virtual void visit(nt& node) = 0/*; \
virtual void visit(const nt& node) = 0*/
NT(ExprNode_Block);
+ NT(ExprNode_Try);
NT(ExprNode_Macro);
NT(ExprNode_Asm);
NT(ExprNode_Flow);
@@ -679,6 +693,7 @@ public:
virtual void visit(nt& node) override;/* \
virtual void visit(const nt& node) override*/
NT(ExprNode_Block);
+ NT(ExprNode_Try);
NT(ExprNode_Macro);
NT(ExprNode_Asm);
NT(ExprNode_Flow);
diff --git a/src/ast/expr_ptr.hpp b/src/ast/expr_ptr.hpp
index cae519cc..022c548a 100644
--- a/src/ast/expr_ptr.hpp
+++ b/src/ast/expr_ptr.hpp
@@ -23,6 +23,7 @@ public:
Expr(ExprNode* node);
Expr();
+ operator bool() const { return is_valid(); }
bool is_valid() const { return m_node.get() != nullptr; }
const ExprNode& node() const { assert(m_node.get()); return *m_node; }
ExprNode& node() { assert(m_node.get()); return *m_node; }
diff --git a/src/ast/generics.hpp b/src/ast/generics.hpp
index c222044c..bfc7080b 100644
--- a/src/ast/generics.hpp
+++ b/src/ast/generics.hpp
@@ -17,7 +17,7 @@ class TypeParam
::AST::AttributeList m_attrs;
Span m_span;
// TODO: use an Ident?
- ::std::string m_name;
+ RcString m_name;
::TypeRef m_default;
public:
TypeParam(TypeParam&& x) = default;
@@ -30,7 +30,7 @@ public:
{
}
- TypeParam(Span sp, ::AST::AttributeList attrs, ::std::string name):
+ TypeParam(Span sp, ::AST::AttributeList attrs, RcString name):
m_attrs( ::std::move(attrs) ),
m_span( ::std::move(sp) ),
m_name( ::std::move(name) ),
@@ -44,7 +44,7 @@ public:
const ::AST::AttributeList& attrs() const { return m_attrs; }
const Span& span() const { return m_span; }
- const ::std::string& name() const { return m_name; }
+ const RcString& name() const { return m_name; }
const TypeRef& get_default() const { return m_default; }
TypeRef& get_default() { return m_default; }
diff --git a/src/ast/item.hpp b/src/ast/item.hpp
index 0074ce9a..a5b0b1a5 100644
--- a/src/ast/item.hpp
+++ b/src/ast/item.hpp
@@ -9,15 +9,18 @@
#include <string>
#include <vector>
+#include "attrs.hpp"
namespace AST {
template <typename T>
struct Named
{
- ::std::string name;
- T data;
+ Span span;
+ AttributeList attrs;
bool is_pub;
+ RcString name;
+ T data;
Named():
is_pub(false)
@@ -25,10 +28,12 @@ struct Named
Named(Named&&) = default;
Named(const Named&) = default;
Named& operator=(Named&&) = default;
- Named(::std::string name, T data, bool is_pub):
+ Named(Span sp, AttributeList attrs, bool is_pub, RcString name, T data):
+ span(sp),
+ attrs( ::std::move(attrs) ),
+ is_pub( is_pub ),
name( ::std::move(name) ),
- data( ::std::move(data) ),
- is_pub( is_pub )
+ data( ::std::move(data) )
{
}
};
diff --git a/src/ast/macro.hpp b/src/ast/macro.hpp
index 5b2223ce..e94de8f1 100644
--- a/src/ast/macro.hpp
+++ b/src/ast/macro.hpp
@@ -18,8 +18,8 @@ class MacroInvocation
{
Span m_span;
- ::std::string m_macro_name;
- ::std::string m_ident;
+ RcString m_macro_name;
+ RcString m_ident;
TokenTree m_input;
public:
MacroInvocation(MacroInvocation&&) = default;
@@ -31,7 +31,7 @@ public:
{
}
- MacroInvocation(Span span, ::std::string macro, ::std::string ident, TokenTree input):
+ MacroInvocation(Span span, RcString macro, RcString ident, TokenTree input):
m_span( mv$(span) ),
m_macro_name( mv$(macro) ),
m_ident( mv$(ident) ),
@@ -48,9 +48,9 @@ public:
}
const Span& span() const { return m_span; }
- const ::std::string& name() const { return m_macro_name; }
+ const RcString& name() const { return m_macro_name; }
- const ::std::string& input_ident() const { return m_ident; }
+ const RcString& input_ident() const { return m_ident; }
const TokenTree& input_tt() const { return m_input; }
TokenTree& input_tt() { return m_input; }
diff --git a/src/ast/path.cpp b/src/ast/path.cpp
index 6fdf1e40..830e7372 100644
--- a/src/ast/path.cpp
+++ b/src/ast/path.cpp
@@ -17,8 +17,8 @@
namespace AST {
// --- AST::PathBinding
-::std::ostream& operator<<(::std::ostream& os, const PathBinding& x) {
- TU_MATCH(PathBinding, (x), (i),
+::std::ostream& operator<<(::std::ostream& os, const PathBinding_Type& x) {
+ TU_MATCHA( (x), (i),
(Unbound, os << "_"; ),
(Crate , os << "Crate"; ),
(Module, os << "Module"; ),
@@ -26,39 +26,80 @@ namespace AST {
(Struct, os << "Struct"; ),
(Enum, os << "Enum"; ),
(Union, os << "Union"; ),
+ (EnumVar, os << "EnumVar(" << i.idx << ")"; ),
+ (TypeAlias, os << "TypeAlias";),
+ (TypeParameter, os << "TyParam(" << i.level << " # " << i.idx << ")"; )
+ )
+ return os;
+}
+PathBinding_Type PathBinding_Type::clone() const
+{
+ TU_MATCHA( (*this), (e),
+ (Unbound , return PathBinding_Type::make_Unbound({}); ),
+ (Module , return PathBinding_Type::make_Module(e); ),
+ (Crate , return PathBinding_Type(e); ),
+ (Trait , return PathBinding_Type(e); ),
+ (Struct , return PathBinding_Type(e); ),
+ (Enum , return PathBinding_Type(e); ),
+ (Union , return PathBinding_Type(e); ),
+ (TypeAlias, return PathBinding_Type::make_TypeAlias(e); ),
+ (EnumVar , return PathBinding_Type::make_EnumVar(e); ),
+
+ (TypeParameter, return PathBinding_Type::make_TypeParameter(e); )
+ )
+ throw "BUG: Fell off the end of PathBinding_Type::clone";
+}
+::std::ostream& operator<<(::std::ostream& os, const PathBinding_Value& x) {
+ TU_MATCHA( (x), (i),
+ (Unbound, os << "_"; ),
+ (Struct, os << "Struct"; ),
(Static, os << "Static"; ),
(Function, os << "Function";),
(EnumVar, os << "EnumVar(" << i.idx << ")"; ),
- (TypeAlias, os << "TypeAlias";),
- (StructMethod, os << "StructMethod"; ),
- (TraitMethod, os << "TraitMethod"; ),
-
- (TypeParameter, os << "TyParam(" << i.level << " # " << i.idx << ")"; ),
(Variable, os << "Var(" << i.slot << ")"; )
)
return os;
}
-PathBinding PathBinding::clone() const
+PathBinding_Value PathBinding_Value::clone() const
{
- TU_MATCH(::AST::PathBinding, (*this), (e),
- (Unbound , return PathBinding::make_Unbound({}); ),
- (Module , return PathBinding::make_Module(e); ),
- (Crate , return PathBinding(e); ),
- (Trait , return PathBinding(e); ),
- (Struct , return PathBinding(e); ),
- (Enum , return PathBinding(e); ),
- (Union , return PathBinding(e); ),
- (Static , return PathBinding(e); ),
- (Function, return PathBinding(e); ),
- (TypeAlias, return PathBinding::make_TypeAlias(e); ),
- (EnumVar , return PathBinding::make_EnumVar(e); ),
- (StructMethod, return PathBinding::make_StructMethod(e); ),
- (TraitMethod, return PathBinding::make_TraitMethod(e); ),
-
- (TypeParameter, return PathBinding::make_TypeParameter(e); ),
- (Variable, return PathBinding::make_Variable(e); )
+ TU_MATCHA( (*this), (e),
+ (Unbound , return PathBinding_Value::make_Unbound({}); ),
+ (Struct , return PathBinding_Value(e); ),
+ (Static , return PathBinding_Value(e); ),
+ (Function, return PathBinding_Value(e); ),
+ (EnumVar , return PathBinding_Value::make_EnumVar(e); ),
+ (Variable, return PathBinding_Value::make_Variable(e); )
)
- throw "BUG: Fell off the end of PathBinding::clone";
+ throw "BUG: Fell off the end of PathBinding_Value::clone";
+}
+::std::ostream& operator<<(::std::ostream& os, const PathBinding_Macro& x) {
+ TU_MATCHA( (x), (i),
+ (Unbound, os << "_"; ),
+ (ProcMacroDerive,
+ os << "ProcMacroDerive(? " << i.mac_name << ")";
+ ),
+ (ProcMacroAttribute,
+ os << "ProcMacroAttribute(? " << i.mac_name << ")";
+ ),
+ (ProcMacro,
+ os << "ProcMacro(? " << i.mac_name << ")";
+ ),
+ (MacroRules,
+ os << "MacroRules(? ?)";
+ )
+ )
+ return os;
+}
+PathBinding_Macro PathBinding_Macro::clone() const
+{
+ TU_MATCHA( (*this), (e),
+ (Unbound , return PathBinding_Macro::make_Unbound({}); ),
+ (ProcMacroDerive, return PathBinding_Macro(e); ),
+ (ProcMacroAttribute, return PathBinding_Macro(e); ),
+ (ProcMacro, return PathBinding_Macro(e); ),
+ (MacroRules, return PathBinding_Macro(e); )
+ )
+ throw "BUG: Fell off the end of PathBinding_Macro::clone";
}
::std::ostream& operator<<(::std::ostream& os, const PathParams& x)
@@ -68,7 +109,7 @@ PathBinding PathBinding::clone() const
for(const auto& v : x.m_lifetimes) {
if(needs_comma) os << ", ";
needs_comma = true;
- os << "'" << v;
+ os << v;
}
for(const auto& v : x.m_types) {
if(needs_comma) os << ", ";
@@ -107,7 +148,7 @@ Ordering PathParams::ord(const PathParams& x) const
}
// --- AST::PathNode
-PathNode::PathNode(::std::string name, PathParams args):
+PathNode::PathNode(RcString name, PathParams args):
m_name( mv$(name) ),
m_params( mv$(args) )
{
@@ -159,8 +200,10 @@ AST::Path::Path(TagUfcs, TypeRef type, Path trait, ::std::vector<AST::PathNode>
}
AST::Path::Path(const Path& x):
m_class()
- //m_binding(x.m_binding)
+ //,m_bindings(x.m_bindings)
{
+ memcpy(&m_bindings, &x.m_bindings, sizeof(Bindings));
+
TU_MATCH(Class, (x.m_class), (ent),
(Invalid, m_class = Class::make_Invalid({});),
(Local,
@@ -185,15 +228,35 @@ AST::Path::Path(const Path& x):
m_class = Class::make_UFCS({ box$(ent.type->clone()), nullptr, ent.nodes });
)
)
+}
+
+bool Path::is_parent_of(const Path& x) const
+{
+ if( !this->m_class.is_Absolute() || !x.m_class.is_Absolute() )
+ return false;
+ const auto& te = this->m_class.as_Absolute();
+ const auto& xe = x.m_class.as_Absolute();
+
+ if( te.crate != xe.crate )
+ return false;
- memcpy(&m_binding, &x.m_binding, sizeof(PathBinding));
+ if( te.nodes.size() > xe.nodes.size() )
+ return false;
+
+ for(size_t i = 0; i < te.nodes.size(); i ++)
+ {
+ if( te.nodes[i].name() != xe.nodes[i].name() )
+ return false;
+ }
+
+ return true;
}
void Path::bind_variable(unsigned int slot)
{
- m_binding = PathBinding::make_Variable({slot});
+ m_bindings.value = PathBinding_Value::make_Variable({slot});
}
-void Path::bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector<TypeRef>& /*args*/)
+void Path::bind_enum_var(const Enum& ent, const RcString& name)
{
auto it = ::std::find_if(ent.variants().begin(), ent.variants().end(), [&](const auto& x) { return x.m_name == name; });
if( it == ent.variants().end() )
@@ -203,10 +266,8 @@ void Path::bind_enum_var(const Enum& ent, const ::std::string& name, const ::std
unsigned int idx = it - ent.variants().begin();
DEBUG("Bound to enum variant '" << name << "' (#" << idx << ")");
- ::AST::PathBinding::Data_EnumVar tmp = {};
- tmp.enum_ = &ent;
- tmp.idx = idx;
- m_binding = PathBinding::make_EnumVar( mv$(tmp) );
+ m_bindings.type = PathBinding_Type::make_EnumVar({ &ent, idx });
+ m_bindings.value = PathBinding_Value::make_EnumVar({ &ent, idx });
}
Path& Path::operator+=(const Path& other)
@@ -214,7 +275,7 @@ Path& Path::operator+=(const Path& other)
for(auto& node : other.nodes())
append(node);
// If the path is modified, clear the binding
- m_binding = PathBinding();
+ m_bindings = Bindings();
return *this;
}
@@ -268,13 +329,13 @@ void Path::print_pretty(::std::ostream& os, bool is_type_context, bool is_debug)
),
(Local,
// Only print comment if there's no binding
- if( m_binding.is_Unbound() )
+ if( m_bindings.value.is_Unbound() )
{
if( is_debug )
os << "/*var*/";
}
else
- assert( m_binding.is_Variable() );
+ assert( m_bindings.value.is_Variable() );
os << ent.name;
),
(Relative,
@@ -334,8 +395,29 @@ void Path::print_pretty(::std::ostream& os, bool is_type_context, bool is_debug)
}
)
)
- if( is_debug )
- os << "/*" << m_binding << "*/";
+ if( is_debug ) {
+ os << "/*";
+ bool printed = false;
+ if( !m_bindings.value.is_Unbound() ) {
+ if(printed) os << ",";
+ os << "v:" << m_bindings.value;
+ printed = true;
+ }
+ if( !m_bindings.type.is_Unbound() ) {
+ if(printed) os << ",";
+ os << "t:" << m_bindings.type;
+ printed = true;
+ }
+ if( !m_bindings.macro.is_Unbound() ) {
+ if(printed) os << ",";
+ os << "m:" << m_bindings.macro;
+ printed = true;
+ }
+ if( !printed ) {
+ os << "?";
+ }
+ os << "*/";
+ }
}
::std::ostream& operator<<(::std::ostream& os, const Path& path)
diff --git a/src/ast/path.hpp b/src/ast/path.hpp
index c2d13d73..c611c819 100644
--- a/src/ast/path.hpp
+++ b/src/ast/path.hpp
@@ -20,6 +20,7 @@
#include "../include/ident.hpp"
class TypeRef;
+class MacroRules;
namespace HIR {
class Module;
@@ -45,7 +46,36 @@ class Static;
class Function;
class ExternCrate;
-TAGGED_UNION_EX(PathBinding, (), Unbound, (
+TAGGED_UNION_EX(PathBinding_Value, (), Unbound, (
+ (Unbound, struct {
+ }),
+ (Struct, struct {
+ const Struct* struct_;
+ const ::HIR::Struct* hir;
+ }),
+ (Static, struct {
+ const Static* static_;
+ const ::HIR::Static* hir; // if nullptr and static_ == nullptr, points to a `const`
+ }),
+ (Function, struct {
+ const Function* func_;
+ }),
+ (EnumVar, struct {
+ const Enum* enum_;
+ unsigned int idx;
+ const ::HIR::Enum* hir;
+ }),
+ (Variable, struct {
+ unsigned int slot;
+ })
+ ),
+ (), (),
+ (
+ public:
+ PathBinding_Value clone() const;
+ )
+ );
+TAGGED_UNION_EX(PathBinding_Type, (), Unbound, (
(Unbound, struct {
}),
(Crate, struct {
@@ -71,13 +101,7 @@ TAGGED_UNION_EX(PathBinding, (), Unbound, (
const Trait* trait_;
const ::HIR::Trait* hir;
}),
- (Static, struct {
- const Static* static_;
- const ::HIR::Static* hir; // if nullptr and static_ == nullptr, points to a `const`
- }),
- (Function, struct {
- const Function* func_;
- }),
+
(EnumVar, struct {
const Enum* enum_;
unsigned int idx;
@@ -86,42 +110,59 @@ TAGGED_UNION_EX(PathBinding, (), Unbound, (
(TypeAlias, struct {
const TypeAlias* alias_;
}),
- (StructMethod, struct {
- const Struct* struct_;
- ::std::string name;
- }),
- (TraitMethod, struct {
- const Trait* trait_;
- ::std::string name;
- }),
(TypeParameter, struct {
unsigned int level;
unsigned int idx;
+ })
+ ),
+ (), (),
+ (
+ public:
+ PathBinding_Type clone() const;
+ )
+ );
+TAGGED_UNION_EX(PathBinding_Macro, (), Unbound, (
+ (Unbound, struct {
}),
- (Variable, struct {
- unsigned int slot;
+ (ProcMacroDerive, struct {
+ const ExternCrate* crate_;
+ RcString mac_name;
+ }),
+ (ProcMacroAttribute, struct {
+ const ExternCrate* crate_;
+ RcString mac_name;
+ }),
+ (ProcMacro, struct {
+ const ExternCrate* crate_;
+ RcString mac_name;
+ }),
+ (MacroRules, struct {
+ const ExternCrate* crate_; // Can be NULL
+ const MacroRules* mac;
})
),
(), (),
(
public:
- PathBinding clone() const;
+ PathBinding_Macro clone() const;
)
);
-extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding& x);
+extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding_Value& x);
+extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding_Type& x);
+extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding_Macro& x);
struct PathParams
{
::std::vector< LifetimeRef > m_lifetimes;
::std::vector< TypeRef > m_types;
- ::std::vector< ::std::pair< ::std::string, TypeRef> > m_assoc;
+ ::std::vector< ::std::pair< RcString, TypeRef> > m_assoc;
PathParams(PathParams&& x) = default;
PathParams(const PathParams& x);
PathParams() {}
- PathParams(::std::vector<LifetimeRef> lfts, ::std::vector<TypeRef> tys, ::std::vector<::std::pair<::std::string,TypeRef>> a):
+ PathParams(::std::vector<LifetimeRef> lfts, ::std::vector<TypeRef> tys, ::std::vector<::std::pair<RcString,TypeRef>> a):
m_lifetimes(mv$(lfts)),
m_types(mv$(tys)),
m_assoc(mv$(a))
@@ -141,12 +182,12 @@ struct PathParams
class PathNode
{
- ::std::string m_name;
+ RcString m_name;
PathParams m_params;
public:
PathNode() {}
- PathNode(::std::string name, PathParams args = {});
- const ::std::string& name() const { return m_name; }
+ PathNode(RcString name, PathParams args = {});
+ const RcString& name() const { return m_name; }
const ::AST::PathParams& args() const { return m_params; }
::AST::PathParams& args() { return m_params; }
@@ -164,7 +205,7 @@ public:
TAGGED_UNION(Class, Invalid,
(Invalid, struct {}),
(Local, struct { // Variable / Type param (resolved)
- ::std::string name;
+ RcString name;
} ),
(Relative, struct { // General relative
Ident::Hygiene hygiene;
@@ -178,7 +219,7 @@ public:
::std::vector<PathNode> nodes;
} ),
(Absolute, struct { // Absolute
- ::std::string crate;
+ RcString crate;
::std::vector<PathNode> nodes;
} ),
(UFCS, struct { // Type-relative
@@ -191,27 +232,42 @@ public:
public:
Class m_class;
-private:
- PathBinding m_binding;
-public:
+ struct Bindings {
+ PathBinding_Value value;
+ PathBinding_Type type;
+ PathBinding_Macro macro;
+
+ Bindings clone() const {
+ return Bindings {
+ value.clone(), type.clone(), macro.clone()
+ };
+ }
+ bool has_binding() const {
+ return !value.is_Unbound() || !type.is_Unbound() || !macro.is_Unbound();
+ }
+ void merge_from(const Bindings& x) {
+ if(value.is_Unbound())
+ value = x.value.clone();
+ if(type.is_Unbound())
+ type = x.type.clone();
+ if(macro.is_Unbound())
+ macro = x.macro.clone();
+ }
+ } m_bindings;
+
virtual ~Path();
// INVALID
Path():
m_class()
{}
Path(Path&&) = default;
- Path& operator=(AST::Path&& x) {
- m_class = mv$(x.m_class);
- m_binding = mv$(x.m_binding);
- //DEBUG("Path, " << x);
- return *this;
- }
+ Path& operator=(AST::Path&& x) = default;
- Path(const Path& x);
+ /*explicit*/ Path(const Path& x);
Path& operator=(const AST::Path&) = delete;
// ABSOLUTE
- Path(::std::string crate, ::std::vector<PathNode> nodes):
+ Path(RcString crate, ::std::vector<PathNode> nodes):
m_class( Class::make_Absolute({ mv$(crate), mv$(nodes)}) )
{}
@@ -222,10 +278,10 @@ public:
// VARIABLE
struct TagLocal {};
- Path(TagLocal, ::std::string name):
+ Path(TagLocal, RcString name):
m_class( Class::make_Local({ mv$(name) }) )
{}
- Path(::std::string name):
+ Path(RcString name):
m_class( Class::make_Local({ mv$(name) }) )
{}
@@ -245,14 +301,6 @@ public:
m_class( Class::make_Super({ count, mv$(nodes) }) )
{}
- //void set_crate(::std::string crate) {
- // if( m_crate == "" ) {
- // m_crate = crate;
- // DEBUG("crate set to " << m_crate);
- // }
- //}
-
-
Class::Tag class_tag() const {
return m_class.tag();
}
@@ -262,7 +310,7 @@ public:
tmp.nodes().push_back( mv$(pn) );
return tmp;
}
- Path operator+(const ::std::string& s) const {
+ Path operator+(const RcString& s) const {
Path tmp = Path(*this);
tmp.append(PathNode(s, {}));
return tmp;
@@ -271,13 +319,17 @@ public:
return Path(*this) += x;
}
Path& operator+=(const Path& x);
+ Path& operator+=(PathNode pn) {
+ this->nodes().push_back( mv$(pn) );
+ return *this;
+ }
void append(PathNode node) {
assert( !m_class.is_Invalid() );
//if( m_class.is_Invalid() )
// m_class = Class::make_Relative({});
nodes().push_back( mv$(node) );
- m_binding = PathBinding();
+ m_bindings = Bindings();
}
bool is_trivial() const {
@@ -310,12 +362,9 @@ public:
)
throw ::std::runtime_error("Path::nodes() fell off");
}
- //const ::std::string& crate() const { return m_crate; }
- bool is_concrete() const;
+ bool is_parent_of(const Path& x) const;
- bool is_bound() const { return !m_binding.is_Unbound(); }
- const PathBinding& binding() const { return m_binding; }
void bind_variable(unsigned int slot);
::std::vector<PathNode>& nodes() {
@@ -349,14 +398,9 @@ private:
void check_param_counts(const GenericParams& params, bool expect_params, PathNode& node);
public:
- void bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector<TypeRef>& args={});
- void bind_function(const Function& ent, const ::std::vector<TypeRef>& args={}) {
- (void)args;
- m_binding = PathBinding::make_Function({&ent});
- }
-
- void bind(::AST::PathBinding pb) {
- m_binding = mv$(pb);
+ void bind_enum_var(const Enum& ent, const RcString& name);
+ void bind_function(const Function& ent) {
+ m_bindings.value = PathBinding_Value::make_Function({&ent});
}
};
diff --git a/src/ast/pattern.cpp b/src/ast/pattern.cpp
index 72087d95..e13662fe 100644
--- a/src/ast/pattern.cpp
+++ b/src/ast/pattern.cpp
@@ -223,7 +223,7 @@ AST::Pattern AST::Pattern::clone() const
rv.m_data = Data::make_StructTuple({ ::AST::Path(e.path), H::clone_tup(e.tup_pat) });
),
(Struct,
- ::std::vector< ::std::pair< ::std::string, Pattern> > sps;
+ ::std::vector< ::std::pair< RcString, Pattern> > sps;
for(const auto& sp : e.sub_patterns)
sps.push_back( ::std::make_pair(sp.first, sp.second.clone()) );
rv.m_data = Data::make_Struct({ ::AST::Path(e.path), mv$(sps) });
diff --git a/src/ast/pattern.hpp b/src/ast/pattern.hpp
index 40cfa927..81c1126a 100644
--- a/src/ast/pattern.hpp
+++ b/src/ast/pattern.hpp
@@ -88,7 +88,7 @@ public:
(Value, struct { Value start; Value end; } ),
(Tuple, TuplePat ),
(StructTuple, struct { Path path; TuplePat tup_pat; } ),
- (Struct, struct { Path path; ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns; bool is_exhaustive; } ),
+ (Struct, struct { Path path; ::std::vector< ::std::pair< RcString, Pattern> > sub_patterns; bool is_exhaustive; } ),
(Slice, struct { ::std::vector<Pattern> sub_pats; }),
(SplitSlice, struct { ::std::vector<Pattern> leading; PatternBinding extra_bind; ::std::vector<Pattern> trailing; } )
);
@@ -171,7 +171,7 @@ public:
{}
struct TagStruct {};
- Pattern(TagStruct, Span sp, Path path, ::std::vector< ::std::pair< ::std::string,Pattern> > sub_patterns, bool is_exhaustive):
+ Pattern(TagStruct, Span sp, Path path, ::std::vector< ::std::pair< RcString,Pattern> > sub_patterns, bool is_exhaustive):
m_span( mv$(sp) ),
m_data( Data::make_Struct( { ::std::move(path), ::std::move(sub_patterns), is_exhaustive } ) )
{}
diff --git a/src/ast/types.cpp b/src/ast/types.cpp
index 98bc6ee1..496cf694 100644
--- a/src/ast/types.cpp
+++ b/src/ast/types.cpp
@@ -40,13 +40,14 @@ static const struct {
{"usize", CORETYPE_UINT},
};
-enum eCoreType coretype_fromstring(const ::std::string& name)
+enum eCoreType coretype_fromstring(const char* name)
{
for(unsigned int i = 0; i < sizeof(CORETYPES)/sizeof(CORETYPES[0]); i ++)
{
- if( name < CORETYPES[i].name )
+ int cmp = strcmp(name, CORETYPES[i].name);
+ if( cmp < 0 )
break;
- if( name == CORETYPES[i].name )
+ if( cmp == 0 )
return CORETYPES[i].type;
}
return CORETYPE_INVAL;
@@ -323,7 +324,7 @@ namespace AST {
os << "'_";
}
else {
- os << "'" << x.m_name;
+ os << "'" << x.m_name.name;
if( x.m_binding != LifetimeRef::BINDING_UNBOUND ) {
os << "/*" << x.m_binding << "*/";
}
diff --git a/src/ast/types.hpp b/src/ast/types.hpp
index af07ba2d..15cb1383 100644
--- a/src/ast/types.hpp
+++ b/src/ast/types.hpp
@@ -41,10 +41,12 @@ namespace AST {
class LifetimeRef
{
+ public:
static const uint16_t BINDING_STATIC = 0xFFFF;
static const uint16_t BINDING_UNBOUND = 0xFFFE;
static const uint16_t BINDING_INFER = 0xFFFD;
+ private:
Ident m_name;
uint16_t m_binding;
@@ -71,6 +73,7 @@ namespace AST {
bool is_infer() const { return m_binding == BINDING_INFER; }
const Ident& name() const { return m_name; }
+ uint16_t binding() const { return m_binding; }
Ordering ord(const LifetimeRef& x) const { return ::ord(m_name.name, x.m_name.name); }
bool operator==(const LifetimeRef& x) const { return ord(x) == OrdEqual; }
bool operator!=(const LifetimeRef& x) const { return ord(x) != OrdEqual; }
@@ -95,7 +98,7 @@ public:
struct TypeArgRef
{
- ::std::string name;
+ RcString name;
unsigned int level;
const AST::GenericParams* params;
};
@@ -163,7 +166,7 @@ TAGGED_UNION(TypeData, None,
::std::shared_ptr<AST::ExprNode> size;
}),
(Generic, struct {
- ::std::string name;
+ RcString name;
unsigned int index;
}),
(Path, struct {
@@ -274,11 +277,11 @@ public:
{}
struct TagArg {};
- TypeRef(TagArg, Span sp, ::std::string name, unsigned int binding = ~0u):
+ TypeRef(TagArg, Span sp, RcString name, unsigned int binding = ~0u):
m_span( mv$(sp) ),
m_data(TypeData::make_Generic({ name, binding }))
{}
- TypeRef(Span sp, ::std::string name, unsigned int binding = ~0u):
+ TypeRef(Span sp, RcString name, unsigned int binding = ~0u):
TypeRef(TagArg(), mv$(sp), mv$(name), binding)
{}
@@ -312,7 +315,7 @@ public:
AST::Path& path() { return m_data.as_Path().path; }
bool is_type_param() const { return m_data.is_Generic(); }
- const ::std::string& type_param() const { return m_data.as_Generic().name; }
+ const RcString& type_param() const { return m_data.as_Generic().name; }
bool is_reference() const { return m_data.is_Borrow(); }
bool is_pointer() const { return m_data.is_Pointer(); }
diff --git a/src/common.hpp b/src/common.hpp
index f46f93fd..0363c334 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -105,6 +105,10 @@ static inline Ordering ord(signed char l, signed char r)
{
return (l == r ? OrdEqual : (l > r ? OrdGreater : OrdLess));
}
+static inline Ordering ord(int l, int r)
+{
+ return (l == r ? OrdEqual : (l > r ? OrdGreater : OrdLess));
+}
static inline Ordering ord(short l, short r)
{
return (l == r ? OrdEqual : (l > r ? OrdGreater : OrdLess));
@@ -244,6 +248,11 @@ inline Join<T> join(const char *sep, const ::std::vector<T> v) {
namespace std {
template <typename T>
+inline auto operator<<(::std::ostream& os, const T& v) -> decltype(v.fmt(os)) {
+ return v.fmt(os);
+}
+
+template <typename T>
inline ::std::ostream& operator<<(::std::ostream& os, const ::std::vector<T*>& v) {
if( v.size() > 0 )
{
@@ -403,5 +412,17 @@ RunIterable<T> runs(const ::std::vector<T>& x) {
return RunIterable<T>(x);
}
+template<typename T>
+class NullOnDrop {
+ T*& ptr;
+public:
+ NullOnDrop(T*& ptr):
+ ptr(ptr)
+ {}
+ ~NullOnDrop() {
+ ptr = nullptr;
+ }
+};
+
#endif
diff --git a/src/coretypes.hpp b/src/coretypes.hpp
index 7665f5ba..692473e5 100644
--- a/src/coretypes.hpp
+++ b/src/coretypes.hpp
@@ -24,7 +24,7 @@ enum eCoreType
CORETYPE_F64,
};
-extern enum eCoreType coretype_fromstring(const ::std::string& name);
+extern enum eCoreType coretype_fromstring(const char* name);
extern const char* coretype_name(const eCoreType ct);
#endif // CORETYPES_HPP_INCLUDED
diff --git a/src/debug.cpp b/src/debug.cpp
index 43e2795e..8a0d1f3c 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -11,7 +11,7 @@ TraceLog::TraceLog(const char* tag, ::std::function<void(::std::ostream&)> info_
m_tag(tag),
m_ret(ret)
{
- if(debug_enabled()) {
+ if(debug_enabled() && m_tag) {
auto& os = debug_output(g_debug_indent_level, m_tag);
os << ">> (";
info_cb(os);
@@ -23,7 +23,7 @@ TraceLog::TraceLog(const char* tag, ::std::function<void(::std::ostream&)> info_
m_tag(tag),
m_ret([](const auto&){})
{
- if(debug_enabled()) {
+ if(debug_enabled() && m_tag) {
auto& os = debug_output(g_debug_indent_level, m_tag);
os << ">> (";
info_cb(os);
@@ -35,7 +35,7 @@ TraceLog::TraceLog(const char* tag):
m_tag(tag),
m_ret([](const auto&){})
{
- if(debug_enabled()) {
+ if(debug_enabled() && m_tag) {
auto& os = debug_output(g_debug_indent_level, m_tag);
os << ">>" << ::std::endl;
}
@@ -43,7 +43,7 @@ TraceLog::TraceLog(const char* tag):
}
TraceLog::~TraceLog() {
UNINDENT();
- if(debug_enabled()) {
+ if(debug_enabled() && m_tag) {
auto& os = debug_output(g_debug_indent_level, m_tag);
os << "<< (";
m_ret(os);
diff --git a/src/expand/asm.cpp b/src/expand/asm.cpp
index d895c32d..90612758 100644
--- a/src/expand/asm.cpp
+++ b/src/expand/asm.cpp
@@ -35,12 +35,10 @@ namespace
class CAsmExpander:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
Token tok;
auto lex = TTStream(sp, tt);
- if( ident != "" )
- ERROR(sp, E0000, "asm! doesn't take an ident");
auto template_text = get_string(sp, lex, crate, mod);
::std::vector<::AST::ExprNode_Asm::ValRef> outputs;
@@ -168,7 +166,7 @@ class CAsmExpander:
{
GET_TOK(tok, lex);
- if( GET_TOK(tok, lex) == TOK_IDENT && tok.str() == "volatile" )
+ if( GET_TOK(tok, lex) == TOK_IDENT && tok.istr() == "volatile" )
{
flags.push_back( "volatile" );
}
diff --git a/src/expand/assert.cpp b/src/expand/assert.cpp
new file mode 100644
index 00000000..ffba7b98
--- /dev/null
+++ b/src/expand/assert.cpp
@@ -0,0 +1,88 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * expand/assert.cpp
+ * - assert! built-in macro (1.29)
+ */
+#include <synext_macro.hpp>
+#include <synext.hpp> // for Expand_BareExpr
+#include <parse/interpolated_fragment.hpp>
+#include "../parse/ttstream.hpp"
+#include "../parse/common.hpp"
+#include "../parse/parseerror.hpp"
+
+class CExpander_assert:
+ public ExpandProcMacro
+{
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
+ {
+ Token tok;
+
+ auto lex = TTStream(sp, tt);
+ lex.parse_state().module = &mod;
+
+ // assertion condition
+ auto n = Parse_Expr0(lex);
+ ASSERT_BUG(sp, n, "No expression returned");
+
+ ::std::vector<TokenTree> toks;
+
+ toks.push_back( Token(TOK_RWORD_IF) );
+ toks.push_back( Token(TOK_EXCLAM) );
+
+ GET_TOK(tok, lex);
+ if( tok == TOK_COMMA )
+ {
+ toks.push_back( Token(InterpolatedFragment(InterpolatedFragment::EXPR, n.release())) );
+ toks.push_back( Token(TOK_BRACE_OPEN) );
+ // User-provided message
+ toks.push_back( Token(TOK_IDENT, RcString::new_interned("panic")) );
+ toks.push_back( Token(TOK_EXCLAM) );
+ toks.push_back( Token(TOK_PAREN_OPEN) );
+ while(lex.lookahead(0) != TOK_EOF )
+ {
+ toks.push_back( Token(InterpolatedFragment(InterpolatedFragment::EXPR, Parse_Expr0(lex).release())) );
+ if( lex.lookahead(0) != TOK_COMMA )
+ break;
+ GET_CHECK_TOK(tok, lex, TOK_COMMA);
+ toks.push_back( Token(TOK_COMMA) );
+ }
+ GET_CHECK_TOK(tok, lex, TOK_EOF);
+ toks.push_back( Token(TOK_PAREN_CLOSE) );
+ }
+ else if( tok == TOK_EOF )
+ {
+ ::std::stringstream ss;
+ ss << "assertion failed: ";
+ n->print(ss);
+
+ toks.push_back( Token(InterpolatedFragment(InterpolatedFragment::EXPR, n.release())) );
+
+ toks.push_back( Token(TOK_BRACE_OPEN) );
+ // Auto-generated message
+ toks.push_back( Token(TOK_IDENT, RcString::new_interned("panic")) );
+ toks.push_back( Token(TOK_EXCLAM) );
+ toks.push_back( Token(TOK_PAREN_OPEN) );
+ toks.push_back( Token(TOK_STRING, ss.str()) );
+ toks.push_back( Token(TOK_PAREN_CLOSE) );
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok, {TOK_COMMA, TOK_EOF});
+ }
+
+ toks.push_back( Token(TOK_BRACE_CLOSE) );
+
+ return box$( TTStreamO(sp, TokenTree(Ident::Hygiene::new_scope(), mv$(toks))) );
+ }
+};
+
+void Expand_init_assert()
+{
+ if( TARGETVER_1_29 )
+ {
+ Register_Synext_Macro("assert", ::std::unique_ptr<ExpandProcMacro>(new CExpander_assert));
+ }
+}
+
diff --git a/src/expand/cfg.cpp b/src/expand/cfg.cpp
index 773a38c4..3475b87b 100644
--- a/src/expand/cfg.cpp
+++ b/src/expand/cfg.cpp
@@ -60,7 +60,7 @@ bool check_cfg(const Span& sp, const ::AST::Attribute& mi) {
}
else if( mi.has_string() ) {
// Equaliy
- auto its = g_cfg_values.equal_range(mi.name());
+ auto its = g_cfg_values.equal_range(mi.name().c_str());
for(auto it = its.first; it != its.second; ++it)
{
DEBUG(""<<mi.name()<<": '"<<it->second<<"' == '"<<mi.string()<<"'");
@@ -70,7 +70,7 @@ bool check_cfg(const Span& sp, const ::AST::Attribute& mi) {
if( its.first != its.second )
return false;
- auto it2 = g_cfg_value_fcns.find(mi.name());
+ auto it2 = g_cfg_value_fcns.find(mi.name().c_str());
if(it2 != g_cfg_value_fcns.end() )
{
DEBUG(""<<mi.name()<<": ('"<<mi.string()<<"')?");
@@ -82,7 +82,7 @@ bool check_cfg(const Span& sp, const ::AST::Attribute& mi) {
}
else {
// Flag
- auto it = g_cfg_flags.find(mi.name());
+ auto it = g_cfg_flags.find(mi.name().c_str());
return (it != g_cfg_flags.end());
}
BUG(sp, "Fell off the end of check_cfg");
@@ -91,12 +91,8 @@ bool check_cfg(const Span& sp, const ::AST::Attribute& mi) {
class CCfgExpander:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" ) {
- ERROR(sp, E0000, "cfg! doesn't take an identifier");
- }
-
auto lex = TTStream(sp, tt);
auto attrs = Parse_MetaItem(lex);
DEBUG("cfg!() - " << attrs);
@@ -126,7 +122,7 @@ class CCfgHandler:
crate.m_root_module.items().clear();
}
}
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
TRACE_FUNCTION_FR("#[cfg] item - " << mi, (i.is_None() ? "Deleted" : ""));
if( check_cfg(sp, mi) ) {
// Leave
diff --git a/src/expand/concat.cpp b/src/expand/concat.cpp
index 29a066df..bd741e2f 100644
--- a/src/expand/concat.cpp
+++ b/src/expand/concat.cpp
@@ -16,13 +16,11 @@
class CConcatExpander:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
Token tok;
auto lex = TTStream(sp, tt);
- if( ident != "" )
- ERROR(sp, E0000, "format_args! doesn't take an ident");
::std::string rv;
do {
diff --git a/src/expand/crate_tags.cpp b/src/expand/crate_tags.cpp
index 0e7d8447..31bb8abd 100644
--- a/src/expand/crate_tags.cpp
+++ b/src/expand/crate_tags.cpp
@@ -15,10 +15,10 @@ public:
AttrStage stage() const override { return AttrStage::Pre; }
void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const override {
- if( crate.m_crate_type != AST::Crate::Type::Unknown ) {
- //ERROR(sp, E0000, "Multiple #![crate_type] attributes");
- return ;
- }
+ //if( crate.m_crate_type != AST::Crate::Type::Unknown ) {
+ // //ERROR(sp, E0000, "Multiple #![crate_type] attributes");
+ // return ;
+ //}
if( !mi.has_string() ) {
ERROR(sp, E0000, "#![crate_type] requires a string argument");
}
@@ -42,9 +42,9 @@ public:
AttrStage stage() const override { return AttrStage::Pre; }
void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const override {
- if( crate.m_crate_name != "" ) {
- ERROR(sp, E0000, "Multiple #![crate_name] attributes");
- }
+ //if( crate.m_crate_name != "" ) {
+ // ERROR(sp, E0000, "Multiple #![crate_name] attributes");
+ //}
if( !mi.has_string() || mi.string() == "" ) {
ERROR(sp, E0000, "#![crate_name] requires a non-empty string argument");
}
@@ -62,6 +62,14 @@ public:
// TODO: Check for an existing allocator crate
crate.m_lang_items.insert(::std::make_pair( "mrustc-allocator", AST::Path("",{}) ));
}
+
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
+ if( ! i.is_Function() ) {
+ ERROR(sp, E0000, "#[allocator] can only be put on functions and the crate - found on " << i.tag_str());
+ }
+ // TODO: Ensure that this is an extern { fn }
+ // TODO: Does this need to do anything?
+ }
};
class Decorator_PanicRuntime:
public ExpandDecorator
diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp
index 5bbef62c..a14a12a3 100644
--- a/src/expand/derive.cpp
+++ b/src/expand/derive.cpp
@@ -58,14 +58,98 @@ static inline ::std::vector<T> vec$(T v1, T v2, T v3, T v4, T v5) {
tmp.push_back( mv$(v5) );
return mv$(tmp);
}
+static AST::Path get_path(const RcString& core_name, const char* c1, const char* c2)
+{
+ return AST::Path(core_name, { AST::PathNode(RcString::new_interned(c1), {}), AST::PathNode(RcString::new_interned(c2), {}) });
+}
+static AST::Path get_path(const RcString& core_name, const char* c1, const char* c2, const char* c3)
+{
+ return AST::Path(core_name, { AST::PathNode(RcString::new_interned(c1), {}), AST::PathNode(RcString::new_interned(c2), {}), AST::PathNode(RcString::new_interned(c3), {}) });
+}
static inline AST::ExprNodeP mk_exprnodep(AST::ExprNode* en){ return AST::ExprNodeP(en); }
//#define NEWNODE(type, ...) mk_exprnodep(new type(__VA_ARGS__))
#define NEWNODE(type, ...) mk_exprnodep(new AST::ExprNode_##type(__VA_ARGS__))
+static ::std::vector<AST::ExprNodeP> make_refpat_a(
+ const Span& sp,
+ ::std::vector<AST::Pattern>& pats_a,
+ const ::std::vector<TypeRef>& sub_types,
+ ::std::function<AST::ExprNodeP(size_t, AST::ExprNodeP)> cb
+ )
+{
+ ::std::vector<AST::ExprNodeP> nodes;
+ for( size_t idx = 0; idx < sub_types.size(); idx ++ )
+ {
+ auto name_a = RcString::new_interned(FMT("a" << idx));
+ pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
+ nodes.push_back( cb(idx, NEWNODE(NamedValue, AST::Path(name_a))) );
+ }
+ return nodes;
+}
+static ::std::vector<AST::ExprNodeP> make_refpat_a(
+ const Span& sp,
+ ::std::vector< ::std::pair<RcString, AST::Pattern> >& pats_a,
+ const ::std::vector<AST::StructItem>& fields,
+ ::std::function<AST::ExprNodeP(size_t, AST::ExprNodeP)> cb
+ )
+{
+ ::std::vector<AST::ExprNodeP> nodes;
+ size_t idx = 0;
+ for( const auto& fld : fields )
+ {
+ auto name_a = RcString::new_interned(FMT("a" << fld.m_name));
+ pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
+ nodes.push_back( cb(idx, NEWNODE(NamedValue, AST::Path(name_a))) );
+ idx ++;
+ }
+ return nodes;
+}
+static ::std::vector<AST::ExprNodeP> make_refpat_ab(
+ const Span& sp,
+ ::std::vector<AST::Pattern>& pats_a,
+ ::std::vector<AST::Pattern>& pats_b,
+ const ::std::vector<TypeRef>& sub_types,
+ ::std::function<AST::ExprNodeP(size_t, AST::ExprNodeP, AST::ExprNodeP)> cb
+ )
+{
+ ::std::vector<AST::ExprNodeP> nodes;
+ for( size_t idx = 0; idx < sub_types.size(); idx ++ )
+ {
+ auto name_a = RcString::new_interned(FMT("a" << idx));
+ auto name_b = RcString::new_interned(FMT("b" << idx));
+ pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
+ pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) );
+ nodes.push_back( cb(idx, NEWNODE(NamedValue, AST::Path(name_a)), NEWNODE(NamedValue, AST::Path(name_b))) );
+ }
+ return nodes;
+}
+static ::std::vector<AST::ExprNodeP> make_refpat_ab(
+ const Span& sp,
+ ::std::vector< ::std::pair<RcString, AST::Pattern> >& pats_a,
+ ::std::vector< ::std::pair<RcString, AST::Pattern> >& pats_b,
+ const ::std::vector<AST::StructItem>& fields,
+ ::std::function<AST::ExprNodeP(size_t, AST::ExprNodeP, AST::ExprNodeP)> cb
+ )
+{
+ ::std::vector<AST::ExprNodeP> nodes;
+ size_t idx = 0;
+ for( const auto& fld : fields )
+ {
+ auto name_a = RcString::new_interned(FMT("a" << fld.m_name));
+ auto name_b = RcString::new_interned(FMT("b" << fld.m_name));
+ pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
+ pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) );
+ nodes.push_back( cb(idx, NEWNODE(NamedValue, AST::Path(name_a)), NEWNODE(NamedValue, AST::Path(name_b))) );
+ idx ++;
+ }
+ return nodes;
+}
+
+
struct DeriveOpts
{
- ::std::string core_name;
+ RcString core_name;
const ::std::vector<::AST::Attribute>& derive_items;
};
@@ -289,21 +373,20 @@ class Deriver_Debug:
// throw CompileError::Todo("derive(Debug) - _try");
//}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
- const AST::Path debug_trait = AST::Path(core_name, { AST::PathNode("fmt", {}), AST::PathNode("Debug", {}) });
- TypeRef f_type(TypeRef::TagReference(), sp, AST::LifetimeRef(), true,
- TypeRef(sp, AST::Path(core_name, {AST::PathNode("fmt",{}), AST::PathNode("Formatter", {})}))
- );
+ const AST::Path debug_trait = get_path(core_name, "fmt", "Debug");
AST::Function fcn(
sp,
AST::GenericParams(),
ABI_RUST, false, false, false,
- TypeRef(sp, AST::Path(core_name, {AST::PathNode("fmt",{}), AST::PathNode("Result",{})}) ),
+ TypeRef(sp, get_path(core_name, "fmt", "Result")),
vec$(
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ),
- ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "f"), mv$(f_type) )
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"),
+ TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ),
+ ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "f"),
+ TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), true, TypeRef(sp, get_path(core_name, "fmt", "Formatter")) ) )
)
);
fcn.set_code( NEWNODE(Block, vec$(mv$(node))) );
@@ -311,7 +394,7 @@ class Deriver_Debug:
AST::GenericParams params = get_params_with_bounds(sp, p, debug_trait, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, debug_trait), type.clone() ) );
- rv.add_function(false, false, "fmt", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "fmt", mv$(fcn));
return mv$(rv);
}
@@ -320,7 +403,7 @@ public:
AST::Impl handle_item(Span sp, const DeriveOpts& opts, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override
{
- const ::std::string& name = type.path().nodes().back().name();
+ ::std::string name = type.path().nodes().back().name().c_str();
// Generate code for Debug
AST::ExprNodeP node;
@@ -338,12 +421,13 @@ public:
mv$(node), AST::PathNode("debug_struct",{}),
vec$( NEWNODE(String, name) )
);
+ // TODO: use a block instead of chaining
for( const auto& fld : e.ents )
{
node = NEWNODE(CallMethod,
mv$(node), AST::PathNode("field",{}),
vec$(
- NEWNODE(String, fld.m_name),
+ NEWNODE(String, fld.m_name.c_str()),
NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(UniOp, AST::ExprNode_UniOp::REF,
NEWNODE(Field,
NEWNODE(NamedValue, AST::Path("self")),
@@ -369,7 +453,7 @@ public:
NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(UniOp, AST::ExprNode_UniOp::REF,
NEWNODE(Field,
NEWNODE(NamedValue, AST::Path("self")),
- FMT(idx)
+ RcString::new_interned(FMT(idx))
)
))
)
@@ -397,61 +481,46 @@ public:
code = NEWNODE(CallMethod,
NEWNODE(NamedValue, AST::Path("f")),
AST::PathNode("write_str",{}),
- vec$( NEWNODE(String, v.m_name) )
+ vec$( NEWNODE(String, v.m_name.c_str()) )
);
pat_a = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name));
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
- AST::ExprNodeP node;
- node = NEWNODE(NamedValue, AST::Path("f"));
- node = NEWNODE(CallMethod,
- mv$(node), AST::PathNode("debug_tuple",{}),
- vec$( NEWNODE(String, v.m_name) )
- );
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
-
- node = NEWNODE(CallMethod,
- mv$(node), AST::PathNode("field",{}),
- vec$(
- NEWNODE(NamedValue, AST::Path(name_a))
- )
- );
- }
-
- code = NEWNODE(CallMethod, mv$(node), AST::PathNode("finish",{}), {});
+ auto s_ent = NEWNODE(NamedValue, AST::Path("s"));
+ auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t idx, auto a){
+ return NEWNODE(CallMethod, s_ent->clone(), AST::PathNode("field", {}), vec$( mv$(a) ));
+ });
+ nodes.insert(nodes.begin(), NEWNODE(LetBinding, AST::Pattern(AST::Pattern::TagBind(), sp, "s"), TypeRef(sp),
+ NEWNODE(CallMethod, NEWNODE(NamedValue, AST::Path("f")), AST::PathNode("debug_tuple",{}),
+ vec$( NEWNODE(String, v.m_name.c_str()) )
+ )
+ ));
+ nodes.push_back( NEWNODE(CallMethod, mv$(s_ent), AST::PathNode("finish",{}), {}) );
+ code = NEWNODE(Block, mv$(nodes));
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- AST::ExprNodeP node;
-
- node = NEWNODE(NamedValue, AST::Path("f"));
- node = NEWNODE(CallMethod,
- mv$(node), AST::PathNode("debug_struct",{}),
- vec$( NEWNODE(String, v.m_name) )
- );
-
- for( const auto& fld : e.m_fields )
- {
- auto name_a = FMT("a" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
-
- node = NEWNODE(CallMethod,
- mv$(node), AST::PathNode("field",{}),
- vec$(
- NEWNODE(String, fld.m_name),
- NEWNODE(NamedValue, AST::Path(name_a))
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+
+ auto s_ent = NEWNODE(NamedValue, AST::Path("s"));
+ auto nodes = make_refpat_a(sp, pats_a, e.m_fields, [&](size_t idx, auto a){
+ return NEWNODE(CallMethod, s_ent->clone(), AST::PathNode("field", {}),
+ vec$(
+ NEWNODE(String, e.m_fields[idx].m_name.c_str()),
+ mv$(a)
+ )
+ );
+ });
+ nodes.insert(nodes.begin(), NEWNODE(LetBinding, AST::Pattern(AST::Pattern::TagBind(), sp, "s"), TypeRef(sp),
+ NEWNODE(CallMethod, NEWNODE(NamedValue, AST::Path("f")), AST::PathNode("debug_struct",{}),
+ vec$( NEWNODE(String, v.m_name.c_str()) )
)
- );
- }
+ ));
+ nodes.push_back( NEWNODE(CallMethod, mv$(s_ent), AST::PathNode("finish",{}), {}) );
- code = NEWNODE(CallMethod, mv$(node), AST::PathNode("finish",{}), {});
+ code = NEWNODE(Block, mv$(nodes));
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
)
)
@@ -477,9 +546,9 @@ public:
class Deriver_PartialEq:
public Deriver
{
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
- const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("PartialEq", {}) });
+ const AST::Path trait_path = get_path(core_name, "cmp", "PartialEq");
AST::Function fcn(
sp,
@@ -496,10 +565,10 @@ class Deriver_PartialEq:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "eq", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "eq", mv$(fcn));
return mv$(rv);
}
- AST::ExprNodeP compare_and_ret(Span sp, const ::std::string& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const
+ AST::ExprNodeP compare_and_ret(Span sp, const RcString& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const
{
return NEWNODE(If,
NEWNODE(BinOp, AST::ExprNode_BinOp::CMPNEQU, mv$(v1), mv$(v2)),
@@ -529,7 +598,7 @@ public:
(Tuple,
for( unsigned int idx = 0; idx < e.ents.size(); idx ++ )
{
- auto fld_name = FMT(idx);
+ auto fld_name = RcString::new_interned(FMT(idx));
nodes.push_back(this->compare_and_ret( sp, opts.core_name,
NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), fld_name),
NEWNODE(Field, NEWNODE(NamedValue, AST::Path("v" )), fld_name)
@@ -563,43 +632,25 @@ public:
(Tuple,
::std::vector<AST::Pattern> pats_a;
::std::vector<AST::Pattern> pats_b;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- auto name_b = FMT("b" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) );
- nodes.push_back(this->compare_and_ret(sp, opts.core_name,
- NEWNODE(NamedValue, AST::Path(name_a)),
- NEWNODE(NamedValue, AST::Path(name_b))
- ));
- }
+ auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_sub_types, [&](auto idx, auto a, auto b){
+ return this->compare_and_ret(sp, opts.core_name, mv$(a), mv$(b));
+ });
nodes.push_back( NEWNODE(Bool, true) );
+
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_b));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_b;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( const auto& fld : e.m_fields )
- {
- auto name_a = FMT("a" << fld.m_name);
- auto name_b = FMT("b" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
- pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) );
- nodes.push_back(this->compare_and_ret(sp, opts.core_name,
- NEWNODE(NamedValue, AST::Path(name_a)),
- NEWNODE(NamedValue, AST::Path(name_b))
- ));
- }
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_b;
+ auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_fields, [&](const auto& name, auto a, auto b){
+ return this->compare_and_ret(sp, opts.core_name, mv$(a), mv$(b));
+ });
nodes.push_back( NEWNODE(Bool, true) );
+
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
pat_b = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_b), true);
code = NEWNODE(Block, mv$(nodes));
@@ -643,21 +694,12 @@ public:
class Deriver_PartialOrd:
public Deriver
{
- AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2) const
- {
- return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}) });
- }
- AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2, ::std::string c3) const
- {
- return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}), AST::PathNode(c3, {}) });
- }
-
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
- const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("PartialOrd", {}) });
- const AST::Path path_ordering(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ordering", {}) });
+ const AST::Path trait_path = get_path(core_name, "cmp", "PartialOrd");
+ const AST::Path path_ordering = get_path(core_name, "cmp", "Ordering");
- AST::Path path_option_ordering(core_name, { AST::PathNode("option", {}), AST::PathNode("Option", {}) });
+ AST::Path path_option_ordering = get_path(core_name, "option", "Option");
path_option_ordering.nodes().back().args().m_types.push_back( TypeRef(sp, path_ordering) );
AST::Function fcn(
@@ -675,14 +717,14 @@ class Deriver_PartialOrd:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "partial_cmp", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "partial_cmp", mv$(fcn));
return mv$(rv);
}
- AST::ExprNodeP make_compare_and_ret(Span sp, const ::std::string& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const
+ AST::ExprNodeP make_compare_and_ret(Span sp, const RcString& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const
{
return NEWNODE(Match,
- NEWNODE(CallPath, this->get_path(core_name, "cmp", "PartialOrd", "partial_cmp"),
+ NEWNODE(CallPath, get_path(core_name, "cmp", "PartialOrd", "partial_cmp"),
::make_vec2(
NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(v1)),
NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(v2))
@@ -690,13 +732,13 @@ class Deriver_PartialOrd:
),
::make_vec3(
::AST::ExprNode_Match_Arm(
- ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, this->get_path(core_name, "option", "Option", "None")) ),
+ ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, get_path(core_name, "option", "Option", "None")) ),
nullptr,
- NEWNODE(Flow, AST::ExprNode_Flow::RETURN, "", NEWNODE(NamedValue, this->get_path(core_name, "option", "Option", "None")))
+ NEWNODE(Flow, AST::ExprNode_Flow::RETURN, "", NEWNODE(NamedValue, get_path(core_name, "option", "Option", "None")))
),
::AST::ExprNode_Match_Arm(
- ::make_vec1( AST::Pattern(AST::Pattern::TagNamedTuple(), sp, this->get_path(core_name, "option", "Option", "Some"),
- ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, this->get_path(core_name, "cmp", "Ordering", "Equal")) )
+ ::make_vec1( AST::Pattern(AST::Pattern::TagNamedTuple(), sp, get_path(core_name, "option", "Option", "Some"),
+ ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, get_path(core_name, "cmp", "Ordering", "Equal")) )
) ),
nullptr,
NEWNODE(Tuple, ::std::vector<AST::ExprNodeP>())
@@ -709,10 +751,10 @@ class Deriver_PartialOrd:
)
);
}
- AST::ExprNodeP make_ret_equal(const ::std::string& core_name) const
+ AST::ExprNodeP make_ret_equal(const RcString& core_name) const
{
- return NEWNODE(CallPath, this->get_path(core_name, "option", "Option", "Some"),
- ::make_vec1( NEWNODE(NamedValue, this->get_path(core_name, "cmp", "Ordering", "Equal")) )
+ return NEWNODE(CallPath, get_path(core_name, "option", "Option", "Some"),
+ ::make_vec1( NEWNODE(NamedValue, get_path(core_name, "cmp", "Ordering", "Equal")) )
);
}
public:
@@ -737,7 +779,7 @@ public:
(Tuple,
for( unsigned int idx = 0; idx < e.ents.size(); idx ++ )
{
- auto fld_name = FMT(idx);
+ auto fld_name = RcString::new_interned(FMT(idx));
nodes.push_back(this->make_compare_and_ret( sp, opts.core_name,
NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), fld_name),
NEWNODE(Field, NEWNODE(NamedValue, AST::Path("v" )), fld_name)
@@ -771,45 +813,25 @@ public:
(Tuple,
::std::vector<AST::Pattern> pats_a;
::std::vector<AST::Pattern> pats_b;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- auto name_b = FMT("b" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) );
-
- nodes.push_back(this->make_compare_and_ret( sp, opts.core_name,
- NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_a))),
- NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_b)))
- ));
- }
+ auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_sub_types, [&](size_t , auto a, auto b){
+ return this->make_compare_and_ret(sp, opts.core_name, NEWNODE(Deref, mv$(a)), NEWNODE(Deref, mv$(b)));
+ });
nodes.push_back( this->make_ret_equal(opts.core_name) );
+
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_b));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_b;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( const auto& fld : e.m_fields )
- {
- auto name_a = FMT("a" << fld.m_name);
- auto name_b = FMT("b" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
- pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) );
-
- nodes.push_back(this->make_compare_and_ret( sp, opts.core_name,
- NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_a))),
- NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_b)))
- ));
- }
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_b;
+ auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_fields, [&](size_t /*idx*/, auto a, auto b){
+ return this->make_compare_and_ret(sp, opts.core_name, NEWNODE(Deref, mv$(a)), NEWNODE(Deref, mv$(b)));
+ });
nodes.push_back( this->make_ret_equal(opts.core_name) );
+
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
pat_b = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_b), true);
code = NEWNODE(Block, mv$(nodes));
@@ -833,54 +855,21 @@ public:
// TODO: Compare the discriminants using the `discriminant_value` intrinsic
// - Requires a way of emitting said intrinsic into the AST
- for(unsigned int a = 0; a < enm.variants().size(); a ++ )
+ // - LAZY WAY - hard-code ::"core"::intrinsics::discriminant_value
{
- for(unsigned int b = 0; b < enm.variants().size(); b ++ )
- {
- if( a == b )
- continue ;
-
- struct H {
- static ::AST::Pattern get_pat_nc(const Span& sp, const AST::Path& base_path, const AST::EnumVariant& v) {
- AST::Path var_path = base_path + v.m_name;
-
- TU_MATCH(::AST::EnumVariantData, (v.m_data), (e),
- (Value,
- return AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(var_path));
- ),
- (Tuple,
- return AST::Pattern(AST::Pattern::TagNamedTuple(), sp, var_path, AST::Pattern::TuplePat { {}, true, {} });
- ),
- (Struct,
- return AST::Pattern(AST::Pattern::TagStruct(), sp, var_path, {}, false);
- )
- )
- throw "";
- }
- };
- ::AST::Pattern pat_a = H::get_pat_nc(sp, base_path, enm.variants()[a]);
- ::AST::Pattern pat_b = H::get_pat_nc(sp, base_path, enm.variants()[b]);
-
- ::std::vector< AST::Pattern> pats;
- {
- ::std::vector< AST::Pattern> tuple_pats;
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_b)) );
- pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), sp, mv$(tuple_pats)) );
- }
-
- auto code = NEWNODE(CallPath, this->get_path(opts.core_name, "option", "Option", "Some"),
- ::make_vec1(
- NEWNODE(NamedValue, this->get_path(opts.core_name, "cmp", "Ordering", (a < b ? "Less" : "Greater")))
- )
- );
+ auto code = NEWNODE(CallPath, get_path(opts.core_name, "cmp", "PartialOrd", "partial_cmp"),
+ ::make_vec2(
+ NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("self")) )) ),
+ NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("v")) )) )
+ )
+ );
+ ::std::vector< AST::Pattern> pats = make_vec1( AST::Pattern() );
- arms.push_back(AST::ExprNode_Match_Arm(
- mv$(pats),
- nullptr,
- mv$(code)
- ));
- }
+ arms.push_back(AST::ExprNode_Match_Arm(
+ mv$(pats),
+ nullptr,
+ mv$(code)
+ ));
}
::std::vector<AST::ExprNodeP> vals;
@@ -896,11 +885,11 @@ public:
class Deriver_Eq:
public Deriver
{
- AST::Path get_trait_path(const ::std::string& core_name) const {
- return AST::Path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Eq", {}) });
+ AST::Path get_trait_path(const RcString& core_name) const {
+ return get_path(core_name, "cmp", "Eq");
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path(core_name);
@@ -918,7 +907,7 @@ class Deriver_Eq:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "assert_receiver_is_total_eq", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "assert_receiver_is_total_eq", mv$(fcn));
return mv$(rv);
}
AST::ExprNodeP assert_is_eq(const AST::Path& method_path, AST::ExprNodeP val) const {
@@ -928,6 +917,9 @@ class Deriver_Eq:
);
}
AST::ExprNodeP field(const ::std::string& name) const {
+ return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), RcString::new_interned(name));
+ }
+ AST::ExprNodeP field(const RcString& name) const {
return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name);
}
@@ -979,28 +971,18 @@ public:
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) );
- }
+ auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t idx, auto a){
+ return this->assert_is_eq(assert_method_path, mv$(a));
+ });
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( const auto& fld : e.m_fields )
- {
- auto name_a = FMT("a" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
- nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) );
- }
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+ auto nodes = make_refpat_a(sp, pats_a, e.m_fields, [&](size_t idx, auto a){
+ return this->assert_is_eq(assert_method_path, mv$(a));
+ });
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
code = NEWNODE(Block, mv$(nodes));
@@ -1041,19 +1023,10 @@ public:
class Deriver_Ord:
public Deriver
{
- AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2) const
- {
- return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}) });
- }
- AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2, ::std::string c3) const
- {
- return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}), AST::PathNode(c3, {}) });
- }
-
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
- const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ord", {}) });
- const AST::Path path_ordering(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ordering", {}) });
+ const AST::Path trait_path = get_path(core_name, "cmp", "Ord");
+ const AST::Path path_ordering = get_path(core_name, "cmp", "Ordering");
AST::Function fcn(
sp,
@@ -1070,14 +1043,14 @@ class Deriver_Ord:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "cmp", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "cmp", mv$(fcn));
return mv$(rv);
}
- AST::ExprNodeP make_compare_and_ret(Span sp, const ::std::string& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const
+ AST::ExprNodeP make_compare_and_ret(Span sp, const RcString& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const
{
return NEWNODE(Match,
- NEWNODE(CallPath, this->get_path(core_name, "cmp", "Ord", "cmp"),
+ NEWNODE(CallPath, get_path(core_name, "cmp", "Ord", "cmp"),
// TODO: Optional Ref?
::make_vec2(
NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(v1)),
@@ -1086,7 +1059,7 @@ class Deriver_Ord:
),
::make_vec2(
::AST::ExprNode_Match_Arm(
- ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, this->get_path(core_name, "cmp", "Ordering", "Equal")) ),
+ ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, get_path(core_name, "cmp", "Ordering", "Equal")) ),
nullptr,
NEWNODE(Tuple, ::std::vector<AST::ExprNodeP>())
),
@@ -1098,9 +1071,9 @@ class Deriver_Ord:
)
);
}
- AST::ExprNodeP make_ret_equal(const ::std::string& core_name) const
+ AST::ExprNodeP make_ret_equal(const RcString& core_name) const
{
- return NEWNODE(NamedValue, this->get_path(core_name, "cmp", "Ordering", "Equal"));
+ return NEWNODE(NamedValue, get_path(core_name, "cmp", "Ordering", "Equal"));
}
public:
const char* trait_name() const override { return "Ord"; }
@@ -1124,7 +1097,7 @@ public:
(Tuple,
for( unsigned int idx = 0; idx < e.ents.size(); idx ++ )
{
- auto fld_name = FMT(idx);
+ auto fld_name = RcString::new_interned(FMT(idx));
nodes.push_back(this->make_compare_and_ret( sp, opts.core_name,
NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), fld_name),
NEWNODE(Field, NEWNODE(NamedValue, AST::Path("v" )), fld_name)
@@ -1158,45 +1131,25 @@ public:
(Tuple,
::std::vector<AST::Pattern> pats_a;
::std::vector<AST::Pattern> pats_b;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- auto name_b = FMT("b" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) );
-
- nodes.push_back(this->make_compare_and_ret( sp, opts.core_name,
- NEWNODE(NamedValue, AST::Path(name_a)),
- NEWNODE(NamedValue, AST::Path(name_b))
- ));
- }
+ auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_sub_types, [&](size_t, auto a, auto b){
+ return this->make_compare_and_ret(sp, opts.core_name, mv$(a), mv$(b));
+ });
nodes.push_back( this->make_ret_equal(opts.core_name) );
+
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_b));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_b;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( const auto& fld : e.m_fields )
- {
- auto name_a = FMT("a" << fld.m_name);
- auto name_b = FMT("b" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
- pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) );
-
- nodes.push_back(this->make_compare_and_ret( sp, opts.core_name,
- NEWNODE(NamedValue, AST::Path(name_a)),
- NEWNODE(NamedValue, AST::Path(name_b))
- ));
- }
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_b;
+ auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_fields, [&](const auto& /*name*/, auto a, auto b) {
+ return this->make_compare_and_ret(sp, opts.core_name, mv$(a), mv$(b));
+ });
nodes.push_back( this->make_ret_equal(opts.core_name) );
+
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
pat_b = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_b), true);
code = NEWNODE(Block, mv$(nodes));
@@ -1218,50 +1171,21 @@ public:
));
}
- for(unsigned int a = 0; a < enm.variants().size(); a ++ )
- {
- for(unsigned int b = 0; b < enm.variants().size(); b ++ )
- {
- if( a == b )
- continue ;
-
- struct H {
- static ::AST::Pattern get_pat_nc(const Span& sp, const AST::Path& base_path, const AST::EnumVariant& v) {
- AST::Path var_path = base_path + v.m_name;
-
- TU_MATCH(::AST::EnumVariantData, (v.m_data), (e),
- (Value,
- return AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(var_path));
- ),
- (Tuple,
- return AST::Pattern(AST::Pattern::TagNamedTuple(), sp, var_path, AST::Pattern::TuplePat { {}, true, {} });
- ),
- (Struct,
- return AST::Pattern(AST::Pattern::TagStruct(), sp, var_path, {}, false);
- )
- )
- throw "";
- }
- };
- ::AST::Pattern pat_a = H::get_pat_nc(sp, base_path, enm.variants()[a]);
- ::AST::Pattern pat_b = H::get_pat_nc(sp, base_path, enm.variants()[b]);
-
- ::std::vector< AST::Pattern> pats;
- {
- ::std::vector< AST::Pattern> tuple_pats;
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) );
- tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_b)) );
- pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), sp, mv$(tuple_pats)) );
- }
- auto code = NEWNODE(NamedValue, this->get_path(opts.core_name, "cmp", "Ordering", (a < b ? "Less" : "Greater")));
+ {
+ auto code = NEWNODE(CallPath, get_path(opts.core_name, "cmp", "Ord", "cmp"),
+ ::make_vec2(
+ NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("self")) )) ),
+ NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("v")) )) )
+ )
+ );
+ ::std::vector< AST::Pattern> pats = make_vec1( AST::Pattern() );
- arms.push_back(AST::ExprNode_Match_Arm(
- mv$(pats),
- nullptr,
- mv$(code)
- ));
- }
+ arms.push_back(AST::ExprNode_Match_Arm(
+ mv$(pats),
+ nullptr,
+ mv$(code)
+ ));
}
::std::vector<AST::ExprNodeP> vals;
@@ -1277,14 +1201,14 @@ public:
class Deriver_Clone:
public Deriver
{
- AST::Path get_trait_path(const ::std::string& core_name) const {
+ AST::Path get_trait_path(const RcString& core_name) const {
return AST::Path(core_name, { AST::PathNode("clone", {}), AST::PathNode("Clone", {}) });
}
- AST::Path get_method_path(const ::std::string& core_name) const {
+ AST::Path get_method_path(const RcString& core_name) const {
return get_trait_path(core_name) + "clone";
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path(core_name);
@@ -1302,25 +1226,28 @@ class Deriver_Clone:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "clone", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "clone", mv$(fcn));
return mv$(rv);
}
- AST::ExprNodeP clone_val_ref(const ::std::string& core_name, AST::ExprNodeP val) const {
+ AST::ExprNodeP clone_val_ref(const RcString& core_name, AST::ExprNodeP val) const {
// TODO: Hack for zero-sized arrays? (Not a 1.19 feature)
return NEWNODE(CallPath,
this->get_method_path(core_name),
vec$( NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(val) ) )
);
}
- AST::ExprNodeP clone_val_direct(const ::std::string& core_name, AST::ExprNodeP val) const {
+ AST::ExprNodeP clone_val_direct(const RcString& core_name, AST::ExprNodeP val) const {
return NEWNODE(CallPath,
this->get_method_path(core_name),
vec$( mv$(val) )
);
}
- AST::ExprNodeP field(const ::std::string& name) const {
+ AST::ExprNodeP field(const RcString& name) const {
return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name);
}
+ AST::ExprNodeP field(const ::std::string& name) const {
+ return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), RcString::new_interned(name));
+ }
public:
const char* trait_name() const override { return "Clone"; }
@@ -1373,25 +1300,20 @@ public:
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- nodes.push_back( this->clone_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) );
- }
+ auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t , auto a) {
+ return this->clone_val_direct(opts.core_name, mv$(a));
+ });
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
code = NEWNODE(CallPath, base_path + v.m_name, mv$(nodes));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
::AST::ExprNode_StructLiteral::t_values vals;
for( const auto& fld : e.m_fields )
{
- auto name_a = FMT("a" << fld.m_name);
+ auto name_a = RcString::new_interned(FMT("a" << fld.m_name));
pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
vals.push_back({ {}, fld.m_name, this->clone_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) });
}
@@ -1436,7 +1358,7 @@ private:
for(auto& b : ret.def().params().bounds())
{
auto& be = b.as_IsTrait();
- be.trait = AST::Path(opts.core_name, { AST::PathNode("marker", {}), AST::PathNode("Copy", {}) });
+ be.trait = get_path(opts.core_name, "marker", "Copy");
}
return ret;
@@ -1446,11 +1368,11 @@ private:
class Deriver_Copy:
public Deriver
{
- AST::Path get_trait_path(const ::std::string& core_name) const {
- return AST::Path(core_name, { AST::PathNode("marker", {}), AST::PathNode("Copy", {}) });
+ AST::Path get_trait_path(const RcString& core_name) const {
+ return get_path(core_name, "marker", "Copy");
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path(core_name);
@@ -1481,14 +1403,14 @@ public:
class Deriver_Default:
public Deriver
{
- AST::Path get_trait_path(const ::std::string& core_name) const {
- return AST::Path(core_name, { AST::PathNode("default", {}), AST::PathNode("Default", {}) });
+ AST::Path get_trait_path(const RcString& core_name) const {
+ return get_path(core_name, "default", "Default");
}
- AST::Path get_method_path(const ::std::string& core_name) const {
+ AST::Path get_method_path(const RcString& core_name) const {
return AST::Path(AST::Path::TagUfcs(), ::TypeRef(Span()), get_trait_path(core_name), { AST::PathNode("default", {}) } );
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path(core_name);
@@ -1504,10 +1426,10 @@ class Deriver_Default:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "default", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "default", mv$(fcn));
return mv$(rv);
}
- AST::ExprNodeP default_call(const ::std::string& core_name) const {
+ AST::ExprNodeP default_call(const RcString& core_name) const {
return NEWNODE(CallPath,
this->get_method_path(core_name),
{}
@@ -1556,17 +1478,17 @@ public:
class Deriver_Hash:
public Deriver
{
- AST::Path get_trait_path(const ::std::string& core_name) const {
- return AST::Path(core_name, { AST::PathNode("hash", {}), AST::PathNode("Hash", {}) });
+ AST::Path get_trait_path(const RcString& core_name) const {
+ return get_path(core_name, "hash", "Hash");
}
- AST::Path get_trait_path_Hasher(const ::std::string& core_name) const {
- return AST::Path(core_name, { AST::PathNode("hash", {}), AST::PathNode("Hasher", {}) });
+ AST::Path get_trait_path_Hasher(const RcString& core_name) const {
+ return get_path(core_name, "hash", "Hasher");
}
- AST::Path get_method_path(const ::std::string& core_name) const {
+ AST::Path get_method_path(const RcString& core_name) const {
return get_trait_path(core_name) + "hash";
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path(core_name);
@@ -1590,21 +1512,24 @@ class Deriver_Hash:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "hash", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "hash", mv$(fcn));
return mv$(rv);
}
- AST::ExprNodeP hash_val_ref(const ::std::string& core_name, AST::ExprNodeP val) const {
+ AST::ExprNodeP hash_val_ref(const RcString& core_name, AST::ExprNodeP val) const {
return this->hash_val_direct(core_name, NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(val)) );
}
- AST::ExprNodeP hash_val_direct(const ::std::string& core_name, AST::ExprNodeP val) const {
+ AST::ExprNodeP hash_val_direct(const RcString& core_name, AST::ExprNodeP val) const {
return NEWNODE(CallPath,
this->get_method_path(core_name),
vec$( mv$(val), NEWNODE(NamedValue, AST::Path("state")) )
);
}
- AST::ExprNodeP field(const ::std::string& name) const {
+ AST::ExprNodeP field(const RcString& name) const {
return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name);
}
+ AST::ExprNodeP field(const std::string& name) const {
+ return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), RcString::new_interned(name));
+ }
public:
const char* trait_name() const override { return "Hash"; }
@@ -1654,30 +1579,20 @@ public:
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
- ::std::vector<AST::ExprNodeP> nodes;
- nodes.push_back( mv$(var_idx_hash) );
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- nodes.push_back( this->hash_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) );
- }
+ auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t , auto a) {
+ return this->hash_val_direct(opts.core_name, mv$(a));
+ });
+ nodes.insert(nodes.begin(), mv$(var_idx_hash));
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
code = NEWNODE(Block, mv$(nodes));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- ::std::vector< AST::ExprNodeP > nodes;
- nodes.push_back( mv$(var_idx_hash) );
-
- for( const auto& fld : e.m_fields )
- {
- auto name_a = FMT("a" << fld.m_name);
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) );
- nodes.push_back( this->hash_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) );
- }
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+ auto nodes = make_refpat_a(sp, pats_a, e.m_fields, [&](size_t , auto a) {
+ return this->hash_val_direct(opts.core_name, mv$(a));
+ });
+ nodes.insert(nodes.begin(), mv$(var_idx_hash));
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
code = NEWNODE(Block, mv$(nodes));
@@ -1706,20 +1621,20 @@ class Deriver_RustcEncodable:
{
// NOTE: This emits paths like `::rustc_serialize::Encodable` - rustc and crates.io have subtly different crate names
AST::Path get_trait_path() const {
- return AST::Path("", { AST::PathNode("rustc_serialize", {}), AST::PathNode("Encodable", {}) });
+ return get_path("", "rustc_serialize", "Encodable");
}
AST::Path get_trait_path_Encoder() const {
- return AST::Path("", { AST::PathNode("rustc_serialize", {}), AST::PathNode("Encoder", {}) });
+ return get_path("", "rustc_serialize", "Encoder");
}
AST::Path get_method_path() const {
return get_trait_path() + "encode";
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path();
- AST::Path result_path = AST::Path(core_name, { AST::PathNode("result", {}), AST::PathNode("Result", {}) });
+ AST::Path result_path = get_path(core_name, "result", "Result");
result_path.nodes()[1].args().m_types.push_back( TypeRef(TypeRef::TagUnit(), sp) );
result_path.nodes()[1].args().m_types.push_back(TypeRef( sp, AST::Path(AST::Path::TagUfcs(), TypeRef(sp, "S", 0x100|0), this->get_trait_path_Encoder(), { AST::PathNode("Error",{}) }) ));
@@ -1743,7 +1658,7 @@ class Deriver_RustcEncodable:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "encode", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "encode", mv$(fcn));
return mv$(rv);
}
AST::ExprNodeP enc_val_direct(AST::ExprNodeP val) const {
@@ -1752,9 +1667,12 @@ class Deriver_RustcEncodable:
AST::ExprNodeP enc_val_ref(AST::ExprNodeP val) const {
return this->enc_val_direct(NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(val)) );
}
- AST::ExprNodeP field(const ::std::string& name) const {
+ AST::ExprNodeP field(const RcString& name) const {
return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name);
}
+ AST::ExprNodeP field(::std::string name) const {
+ return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), RcString::new_interned(name));
+ }
AST::ExprNodeP enc_closure(Span sp, AST::ExprNodeP code) const {
return NEWNODE(Closure,
@@ -1762,8 +1680,8 @@ class Deriver_RustcEncodable:
mv$(code), false
);
}
- AST::ExprNodeP get_val_ok(const ::std::string& core_name) const {
- return NEWNODE(CallPath, AST::Path(core_name, {AST::PathNode("result",{}), AST::PathNode("Result",{}), AST::PathNode("Ok",{})}), vec$( NEWNODE(Tuple, {})) );
+ AST::ExprNodeP get_val_ok(const RcString& core_name) const {
+ return NEWNODE(CallPath, get_path(core_name, "result", "Result", "Ok"), vec$( NEWNODE(Tuple, {})) );
}
public:
@@ -1771,7 +1689,7 @@ public:
AST::Impl handle_item(Span sp, const DeriveOpts& opts, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override
{
- const ::std::string& struct_name = type.m_data.as_Path().path.nodes().back().name();
+ ::std::string struct_name = type.m_data.as_Path().path.nodes().back().name().c_str();
::std::vector<AST::ExprNodeP> nodes;
TU_MATCH(AST::StructData, (str.m_data), (e),
@@ -1783,7 +1701,12 @@ public:
{
nodes.push_back( NEWNODE(CallPath,
this->get_trait_path_Encoder() + "emit_struct_field",
- vec$( NEWNODE(NamedValue, AST::Path("s")), NEWNODE(String, fld.m_name), NEWNODE(Integer, idx, CORETYPE_UINT), this->enc_closure( sp, this->enc_val_ref(this->field(fld.m_name)) ) )
+ vec$(
+ NEWNODE(NamedValue, AST::Path("s")),
+ NEWNODE(String, fld.m_name.c_str()),
+ NEWNODE(Integer, idx, CORETYPE_UINT),
+ this->enc_closure( sp, this->enc_val_ref(this->field(fld.m_name)) )
+ )
) );
idx ++;
}
@@ -1830,6 +1753,8 @@ public:
base_path.nodes().back().args() = ::AST::PathParams();
::std::vector<AST::ExprNode_Match_Arm> arms;
+ auto s_ent = NEWNODE(NamedValue, AST::Path("s"));
+
for(unsigned int var_idx = 0; var_idx < enm.variants().size(); var_idx ++)
{
const auto& v = enm.variants()[var_idx];
@@ -1840,8 +1765,8 @@ public:
(Value,
code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant",
vec$(
- NEWNODE(NamedValue, AST::Path("s")),
- NEWNODE(String, v.m_name),
+ s_ent->clone(),
+ NEWNODE(String, v.m_name.c_str()),
NEWNODE(Integer, var_idx, CORETYPE_UINT),
NEWNODE(Integer, 0, CORETYPE_UINT),
this->enc_closure(sp, this->get_val_ok(opts.core_name))
@@ -1851,26 +1776,21 @@ public:
),
(Tuple,
::std::vector<AST::Pattern> pats_a;
- ::std::vector<AST::ExprNodeP> nodes;
-
- for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
- {
- auto name_a = FMT("a" << idx);
- pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) );
- nodes.push_back( NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant_arg",
+ auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t idx, auto a){
+ return NEWNODE(CallPath, this->get_trait_path_Encoder() + RcString::new_interned("emit_enum_variant_arg"),
vec$(
- NEWNODE(NamedValue, AST::Path("s")),
+ s_ent->clone(),
NEWNODE(Integer, idx, CORETYPE_UINT),
- this->enc_closure(sp, this->enc_val_direct(NEWNODE(NamedValue, AST::Path(name_a))))
+ this->enc_closure(sp, this->enc_val_direct(mv$(a)))
)
- ) );
- }
+ );
+ });
nodes.push_back( this->get_val_ok(opts.core_name) );
code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant",
vec$(
- NEWNODE(NamedValue, AST::Path("s")),
- NEWNODE(String, v.m_name),
+ s_ent->clone(),
+ NEWNODE(String, v.m_name.c_str()),
NEWNODE(Integer, var_idx, CORETYPE_UINT),
NEWNODE(Integer, e.m_sub_types.size(), CORETYPE_UINT),
this->enc_closure(sp, NEWNODE(Block, mv$(nodes)))
@@ -1879,32 +1799,24 @@ public:
pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a));
),
(Struct,
- ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a;
- ::std::vector< AST::ExprNodeP > nodes;
-
- unsigned int idx = 0;
- for( const auto& fld : e.m_fields )
- {
- auto name_a = Ident( FMT("a" << fld.m_name) );
- pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, Ident(name_a), ::AST::PatternBinding::Type::REF)) );
-
- nodes.push_back( NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_struct_variant_field",
+ ::std::vector< ::std::pair<RcString, AST::Pattern> > pats_a;
+ auto nodes = make_refpat_a(sp, pats_a, e.m_fields, [&](size_t idx, auto a){
+ return NEWNODE(CallPath, this->get_trait_path_Encoder() + RcString::new_interned("emit_enum_struct_variant_field"),
vec$(
- NEWNODE(NamedValue, AST::Path("s")),
- NEWNODE(String, fld.m_name),
+ s_ent->clone(),
+ NEWNODE(String, e.m_fields[idx].m_name.c_str()),
NEWNODE(Integer, idx, CORETYPE_UINT),
- this->enc_closure(sp, this->enc_val_direct(NEWNODE(NamedValue, AST::Path(name_a.name))))
+ this->enc_closure(sp, this->enc_val_direct(mv$(a)))
)
- ) );
- idx ++;
- }
+ );
+ });
nodes.push_back( this->get_val_ok(opts.core_name) );
pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true);
code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_struct_variant",
vec$(
- NEWNODE(NamedValue, AST::Path("s")),
- NEWNODE(String, v.m_name),
+ s_ent->clone(),
+ NEWNODE(String, v.m_name.c_str()),
NEWNODE(Integer, var_idx, CORETYPE_UINT),
NEWNODE(Integer, e.m_fields.size(), CORETYPE_UINT),
this->enc_closure(sp, NEWNODE(Block, mv$(nodes)))
@@ -1925,9 +1837,9 @@ public:
auto node_match = NEWNODE(Match, NEWNODE(NamedValue, AST::Path("self")), mv$(arms));
- const ::std::string& enum_name = type.m_data.as_Path().path.nodes().back().name();
+ ::std::string enum_name = type.m_data.as_Path().path.nodes().back().name().c_str();
auto node = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum",
- vec$( NEWNODE(NamedValue, AST::Path("s")), NEWNODE(String, enum_name), this->enc_closure(sp, mv$(node_match)) )
+ vec$( mv$(s_ent), NEWNODE(String, enum_name), this->enc_closure(sp, mv$(node_match)) )
);
return this->make_ret(sp, opts.core_name, p, type, this->get_field_bounds(enm), mv$(node));
@@ -1939,20 +1851,20 @@ class Deriver_RustcDecodable:
{
// NOTE: This emits paths like `::rustc_serialize::Encodable` - rustc and crates.io have subtly different crate names
AST::Path get_trait_path() const {
- return AST::Path("", { AST::PathNode("rustc_serialize", {}), AST::PathNode("Decodable", {}) });
+ return get_path("", "rustc_serialize", "Decodable");
}
AST::Path get_trait_path_Decoder() const {
- return AST::Path("", { AST::PathNode("rustc_serialize", {}), AST::PathNode("Decoder", {}) });
+ return get_path("", "rustc_serialize", "Decoder");
}
AST::Path get_method_path() const {
return get_trait_path() + "decode";
}
- AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
+ AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const
{
const AST::Path trait_path = this->get_trait_path();
- AST::Path result_path = AST::Path(core_name, { AST::PathNode("result", {}), AST::PathNode("Result", {}) });
+ AST::Path result_path = get_path(core_name, "result", "Result");
result_path.nodes()[1].args().m_types.push_back( TypeRef(sp, "Self", 0xFFFF) );
result_path.nodes()[1].args().m_types.push_back( TypeRef(sp, AST::Path(AST::Path::TagUfcs(), TypeRef(sp, "D", 0x100|0), this->get_trait_path_Decoder(), { AST::PathNode("Error",{}) })) );
@@ -1976,14 +1888,14 @@ class Deriver_RustcDecodable:
AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound));
AST::Impl rv( AST::ImplDef( AST::AttributeList(), mv$(params), make_spanned(sp, trait_path), type.clone() ) );
- rv.add_function(false, false, "decode", mv$(fcn));
+ rv.add_function(sp, {}, false, false, "decode", mv$(fcn));
return mv$(rv);
}
AST::ExprNodeP dec_val() const {
return NEWNODE(CallPath, this->get_method_path(), vec$( NEWNODE(NamedValue, AST::Path("d")) ));
}
AST::ExprNodeP field(const ::std::string& name) const {
- return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name);
+ return NEWNODE(Field, NEWNODE(NamedValue, AST::Path(RcString::new_interned("self"))), RcString::new_interned(name));
}
AST::ExprNodeP dec_closure(Span sp, AST::ExprNodeP code) const {
@@ -1992,8 +1904,8 @@ class Deriver_RustcDecodable:
mv$(code), false
);
}
- AST::ExprNodeP get_val_err_str(const ::std::string& core_name, ::std::string err_str) const {
- return NEWNODE(CallPath, AST::Path(core_name, {AST::PathNode("result",{}), AST::PathNode("Result",{}), AST::PathNode("Err",{})}), vec$(
+ AST::ExprNodeP get_val_err_str(const RcString& core_name, ::std::string err_str) const {
+ return NEWNODE(CallPath, get_path(core_name, "result", "Result", "Err"), vec$(
NEWNODE(CallMethod,
NEWNODE(NamedValue, AST::Path("d")),
AST::PathNode("error"),
@@ -2001,10 +1913,10 @@ class Deriver_RustcDecodable:
)
) );
}
- AST::ExprNodeP get_val_ok(const ::std::string& core_name, AST::ExprNodeP inner) const {
- return NEWNODE(CallPath, AST::Path(core_name, {AST::PathNode("result",{}), AST::PathNode("Result",{}), AST::PathNode("Ok",{})}), vec$( mv$(inner) ) );
+ AST::ExprNodeP get_val_ok(const RcString& core_name, AST::ExprNodeP inner) const {
+ return NEWNODE(CallPath, get_path(core_name, "result", "Result", "Ok"), vec$( mv$(inner) ) );
}
- AST::ExprNodeP get_val_ok_unit(const ::std::string& core_name) const {
+ AST::ExprNodeP get_val_ok_unit(const RcString& core_name) const {
return get_val_ok(core_name, NEWNODE(Tuple, {}));
}
@@ -2014,7 +1926,7 @@ public:
AST::Impl handle_item(Span sp, const DeriveOpts& opts, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override
{
AST::Path base_path = type.m_data.as_Path().path;
- const ::std::string& struct_name = type.m_data.as_Path().path.nodes().back().name();
+ ::std::string struct_name = type.m_data.as_Path().path.nodes().back().name().c_str();
AST::ExprNodeP node_v;
TU_MATCH(AST::StructData, (str.m_data), (e),
@@ -2027,7 +1939,7 @@ public:
{
vals.push_back({ {}, fld.m_name, NEWNODE(UniOp, ::AST::ExprNode_UniOp::QMARK, NEWNODE(CallPath,
this->get_trait_path_Decoder() + "read_struct_field",
- vec$( NEWNODE(NamedValue, AST::Path("d")), NEWNODE(String, fld.m_name), NEWNODE(Integer, idx, CORETYPE_UINT), this->dec_closure( sp, this->dec_val() ) )
+ vec$( NEWNODE(NamedValue, AST::Path("d")), NEWNODE(String, fld.m_name.c_str()), NEWNODE(Integer, idx, CORETYPE_UINT), this->dec_closure( sp, this->dec_val() ) )
)) });
idx ++;
}
@@ -2094,7 +2006,6 @@ public:
for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ )
{
- auto name_a = FMT("a" << idx);
args.push_back( NEWNODE(UniOp, ::AST::ExprNode_UniOp::QMARK, NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_enum_variant_arg",
vec$(
NEWNODE(NamedValue, AST::Path("d")),
@@ -2111,12 +2022,10 @@ public:
unsigned int idx = 0;
for( const auto& fld : e.m_fields )
{
- auto name_a = FMT("a" << fld.m_name);
-
vals.push_back({ {}, fld.m_name, NEWNODE(UniOp, ::AST::ExprNode_UniOp::QMARK, NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_enum_struct_variant_field",
vec$(
NEWNODE(NamedValue, AST::Path("d")),
- NEWNODE(String, fld.m_name),
+ NEWNODE(String, fld.m_name.c_str()),
NEWNODE(Integer, idx, CORETYPE_UINT),
this->dec_closure(sp, this->dec_val())
)
@@ -2136,7 +2045,7 @@ public:
nullptr,
this->get_val_ok(opts.core_name, mv$(code))
));
- var_name_strs.push_back( NEWNODE(String, v.m_name) );
+ var_name_strs.push_back( NEWNODE(String, v.m_name.c_str()) );
}
// Default arm
@@ -2158,7 +2067,7 @@ public:
mv$(node_match),
false
);
- const ::std::string& enum_name = type.m_data.as_Path().path.nodes().back().name();
+ ::std::string enum_name = type.m_data.as_Path().path.nodes().back().name().c_str();
auto node_rev = NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_enum_variant",
vec$(
@@ -2180,7 +2089,7 @@ public:
// --------------------------------------------------------------------
// Select and dispatch the correct derive() handler
// --------------------------------------------------------------------
-static const Deriver* find_impl(const ::std::string& trait_name)
+static const Deriver* find_impl(const RcString& trait_name)
{
#define _(obj) if(trait_name == obj.trait_name()) return &obj;
_(g_derive_debug)
@@ -2199,7 +2108,7 @@ static const Deriver* find_impl(const ::std::string& trait_name)
}
template<typename T>
-static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mod, const AST::Attribute& attr, const AST::Path& path, const T& item)
+static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mod, const AST::Attribute& attr, const AST::Path& path, slice<const AST::Attribute> attrs, const T& item)
{
if( !attr.has_sub_items() ) {
//ERROR(sp, E0000, "#[derive()] requires a list of known traits to derive");
@@ -2221,13 +2130,13 @@ static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mo
attr.items()
};
- ::std::vector< ::std::string> missing_handlers;
+ ::std::vector< RcString> missing_handlers;
for( const auto& trait : attr.items() )
{
DEBUG("- " << trait.name());
auto dp = find_impl(trait.name());
if( dp ) {
- mod.add_item(false, "", dp->handle_item(sp, opts, params, type, item), {} );
+ mod.add_item(sp, false, "", dp->handle_item(sp, opts, params, type, item), {} );
continue ;
}
@@ -2237,15 +2146,16 @@ static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mo
bool found = false;
for(const auto& mac_path : mod.m_macro_imports)
{
- if( mac_path.first.back() == mac_name )
+ if( mac_path.name == mac_name )
{
- if( mac_path.second ) {
+ if( mac_path.macro_ptr ) {
// macro_rules! based derive?
TODO(sp, "Custom derive using macro_rules?");
}
else {
// proc_macro - Invoke the handler.
- auto lex = ProcMacro_Invoke(sp, crate, mac_path.first, path.nodes().back().name(), item);
+ DEBUG("proc_macro " << mac_path.path << ", attrs = " << attrs);
+ auto lex = ProcMacro_Invoke(sp, crate, mac_path.path, attrs, path.nodes().back().name().c_str(), item);
if( lex )
{
Parse_ModRoot_Items(*lex, mod);
@@ -2276,7 +2186,7 @@ class Decorator_Derive:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& attr, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
TU_MATCH_DEF(::AST::Item, (i), (e),
(
@@ -2286,13 +2196,13 @@ public:
// Ignore, it's been deleted
),
(Union,
- derive_item(sp, crate, mod, attr, path, e);
+ derive_item(sp, crate, mod, attr, path, attrs, e);
),
(Enum,
- derive_item(sp, crate, mod, attr, path, e);
+ derive_item(sp, crate, mod, attr, path, attrs, e);
),
(Struct,
- derive_item(sp, crate, mod, attr, path, e);
+ derive_item(sp, crate, mod, attr, path, attrs, e);
)
)
}
diff --git a/src/expand/env.cpp b/src/expand/env.cpp
index f4577ef1..825c895a 100644
--- a/src/expand/env.cpp
+++ b/src/expand/env.cpp
@@ -34,48 +34,44 @@ namespace {
class CExpanderEnv:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" )
- ERROR(sp, E0000, "env! doesn't take an ident");
::std::string varname = get_string(sp, crate, mod, tt);
const char* var_val_cstr = getenv(varname.c_str());
if( !var_val_cstr ) {
ERROR(sp, E0000, "Environment variable '" << varname << "' not defined");
}
- return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, var_val_cstr))) );
+ return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, ::std::string(var_val_cstr)))) );
}
};
class CExpanderOptionEnv:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" )
- ERROR(sp, E0000, "option_env! doesn't take an ident");
::std::string varname = get_string(sp, crate, mod, tt);
const char* var_val_cstr = getenv(varname.c_str());
if( !var_val_cstr ) {
::std::vector< TokenTree> rv;
rv.reserve(7);
- rv.push_back( Token(TOK_IDENT, "None") );
+ rv.push_back( Token(TOK_IDENT, RcString::new_interned("None")) );
rv.push_back( Token(TOK_DOUBLE_COLON) );
rv.push_back( Token(TOK_LT) );
rv.push_back( Token(TOK_AMP) );
- rv.push_back( Token(TOK_LIFETIME, "static") );
- rv.push_back( Token(TOK_IDENT, "str") );
+ rv.push_back( Token(TOK_LIFETIME, RcString::new_interned("static")) );
+ rv.push_back( Token(TOK_IDENT, RcString::new_interned("str")) );
rv.push_back( Token(TOK_GT) );
return box$( TTStreamO(sp, TokenTree( {}, mv$(rv) )) );
}
else {
::std::vector< TokenTree> rv;
rv.reserve(4);
- rv.push_back( Token(TOK_IDENT, "Some") );
+ rv.push_back( Token(TOK_IDENT, RcString::new_interned("Some")) );
rv.push_back( Token(TOK_PAREN_OPEN) );
- rv.push_back( Token(TOK_STRING, var_val_cstr) );
+ rv.push_back( Token(TOK_STRING, ::std::string(var_val_cstr)) );
rv.push_back( Token(TOK_PAREN_CLOSE) );
return box$( TTStreamO(sp, TokenTree( {}, mv$(rv) )) );
}
diff --git a/src/expand/file_line.cpp b/src/expand/file_line.cpp
index 7a827ccf..cfe859bd 100644
--- a/src/expand/file_line.cpp
+++ b/src/expand/file_line.cpp
@@ -8,6 +8,7 @@
#include <synext.hpp>
#include "../parse/common.hpp"
#include "../parse/ttstream.hpp"
+#include <ast/crate.hpp>
namespace {
const Span& get_top_span(const Span& sp) {
@@ -23,16 +24,16 @@ namespace {
class CExpanderFile:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, get_top_span(sp).filename.c_str()))) );
+ return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, ::std::string(get_top_span(sp).filename.c_str())))) );
}
};
class CExpanderLine:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
return box$( TTStreamO(sp, TokenTree(Token((uint64_t)get_top_span(sp).start_line, CORETYPE_U32))) );
}
@@ -41,7 +42,15 @@ class CExpanderLine:
class CExpanderColumn:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
+ {
+ return box$( TTStreamO(sp, TokenTree(Token((uint64_t)get_top_span(sp).start_ofs, CORETYPE_U32))) );
+ }
+};
+class CExpanderUnstableColumn:
+ public ExpandProcMacro
+{
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
return box$( TTStreamO(sp, TokenTree(Token((uint64_t)get_top_span(sp).start_ofs, CORETYPE_U32))) );
}
@@ -50,13 +59,13 @@ class CExpanderColumn:
class CExpanderModulePath:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
::std::string path_str;
+ path_str += crate.m_crate_name;
for(const auto& comp : mod.path().nodes()) {
- if( &comp != &mod.path().nodes().front() )
- path_str += "::";
- path_str += comp.name();
+ path_str += "::";
+ path_str += comp.name().c_str();
}
return box$( TTStreamO(sp, TokenTree( Token(TOK_STRING, mv$(path_str)) )) );
}
@@ -65,5 +74,6 @@ class CExpanderModulePath:
STATIC_MACRO("file", CExpanderFile);
STATIC_MACRO("line", CExpanderLine);
STATIC_MACRO("column", CExpanderColumn);
+STATIC_MACRO("__rust_unstable_column", CExpanderUnstableColumn);
STATIC_MACRO("module_path", CExpanderModulePath);
diff --git a/src/expand/format_args.cpp b/src/expand/format_args.cpp
index 915af2af..7f33eb6d 100644
--- a/src/expand/format_args.cpp
+++ b/src/expand/format_args.cpp
@@ -34,7 +34,7 @@ namespace {
};
Align align = Align::Unspec;
- char align_char = ' ';
+ uint32_t align_char = ' ';
Sign sign = Sign::Unspec;
bool alternate = false;
@@ -118,17 +118,82 @@ namespace {
}
};
+ uint32_t parse_utf8(const char* s, int& out_len)
+ {
+ uint8_t v1 = s[0];
+ if( v1 < 0x80 )
+ {
+ out_len = 1;
+ return v1;
+ }
+ else if( (v1 & 0xC0) == 0x80 )
+ {
+ // Invalid (continuation)
+ out_len = 1;
+ return 0xFFFE;
+ }
+ else if( (v1 & 0xE0) == 0xC0 ) {
+ // Two bytes
+ out_len = 2;
+
+ uint8_t e1 = s[1];
+ if( (e1 & 0xC0) != 0x80 ) return 0xFFFE;
+
+ uint32_t outval
+ = ((v1 & 0x1F) << 6)
+ | ((e1 & 0x3F) <<0)
+ ;
+ return outval;
+ }
+ else if( (v1 & 0xF0) == 0xE0 ) {
+ // Three bytes
+ out_len = 3;
+ uint8_t e1 = s[1];
+ if( (e1 & 0xC0) != 0x80 ) return 0xFFFE;
+ uint8_t e2 = s[2];
+ if( (e2 & 0xC0) != 0x80 ) return 0xFFFE;
+
+ uint32_t outval
+ = ((v1 & 0x0F) << 12)
+ | ((e1 & 0x3F) << 6)
+ | ((e2 & 0x3F) << 0)
+ ;
+ return outval;
+ }
+ else if( (v1 & 0xF8) == 0xF0 ) {
+ // Four bytes
+ out_len = 4;
+ uint8_t e1 = s[1];
+ if( (e1 & 0xC0) != 0x80 ) return 0xFFFE;
+ uint8_t e2 = s[2];
+ if( (e2 & 0xC0) != 0x80 ) return 0xFFFE;
+ uint8_t e3 = s[3];
+ if( (e3 & 0xC0) != 0x80 ) return 0xFFFE;
+
+ uint32_t outval
+ = ((v1 & 0x07) << 18)
+ | ((e1 & 0x3F) << 12)
+ | ((e2 & 0x3F) << 6)
+ | ((e3 & 0x3F) << 0)
+ ;
+ return outval;
+ }
+ else {
+ throw ""; // Should be impossible.
+ }
+ }
+
/// Parse a format string into a sequence of fragments.
///
/// Returns a list of fragments, and the remaining free text after the last format sequence
::std::tuple< ::std::vector<FmtFrag>, ::std::string> parse_format_string(
const Span& sp,
const ::std::string& format_string,
- const ::std::map< ::std::string,unsigned int>& named,
+ const ::std::map<RcString,unsigned int>& named,
unsigned int n_free
)
{
- unsigned int n_named = named.size();
+ //unsigned int n_named = named.size();
unsigned int next_free = 0;
::std::vector<FmtFrag> frags;
@@ -183,7 +248,7 @@ namespace {
s ++;
} while(isdigit(*s));
if( arg_idx >= n_free )
- ERROR(sp, E0000, "Positional argument " << arg_idx << " out of range");
+ ERROR(sp, E0000, "Positional argument " << arg_idx << " out of range in \"" << format_string << "\"");
index = arg_idx;
}
else {
@@ -191,7 +256,7 @@ namespace {
while( isalnum(*s) || *s == '_' || (*s < 0 || *s > 127) ) {
s ++;
}
- ::std::string ident { start, s };
+ auto ident = RcString(start, s - start);
auto it = named.find(ident);
if( it == named.end() )
ERROR(sp, E0000, "Named argument '"<<ident<<"' not found");
@@ -209,9 +274,15 @@ namespace {
s ++; // eat ':'
// Alignment
- if( s[0] != '\0' && (s[1] == '<' || s[1] == '^' || s[1] == '>') ) {
- args.align_char = s[0];
- s ++;
+ // - Padding character, a single unicode codepoint followed by '<'/'^'/'>'
+ {
+ int next_c_i;
+ uint32_t ch = parse_utf8(s, next_c_i);
+ char next_c = s[next_c_i];
+ if( ch != '}' && ch != '\0' && (next_c == '<' || next_c == '^' || next_c == '>') ) {
+ args.align_char = ch;
+ s += next_c_i;
+ }
}
if( *s == '<' ) {
args.align = FmtArgs::Align::Left;
@@ -288,7 +359,7 @@ namespace {
}
if( *s == '$' )
{
- ::std::string ident { start, s };
+ auto ident = RcString(start, s - start);
auto it = named.find(ident);
if( it == named.end() )
ERROR(sp, E0000, "Named argument '"<<ident<<"' not found");
@@ -312,7 +383,7 @@ namespace {
if( next_free == n_free ) {
ERROR(sp, E0000, "Not enough arguments passed, expected at least " << n_free+1);
}
- args.prec = next_free + n_named;
+ args.prec = next_free;
next_free ++;
}
else if( ::std::isdigit(*s) ) {
@@ -338,16 +409,17 @@ namespace {
}
}
+ if( s[0] == '\0' )
+ ERROR(sp, E0000, "Unexpected end of formatting string");
+
// Parse ident?
// - Lazy way is to just handle a single char and ensure that it is just a single char
- if( s[0] != '}' && s[0] != '\0' && s[1] != '}' ) {
- TODO(sp, "Parse formatting fragment at \"" << fmt_frag_str << "\" (long type)");
+ if( s[0] != '}' && s[1] != '}' ) {
+ TODO(sp, "Parse formatting fragment at \"" << fmt_frag_str << "\" (long type) - s=...\"" << s << "\"");
}
switch(s[0])
{
- case '\0':
- ERROR(sp, E0000, "Unexpected end of formatting string");
default:
ERROR(sp, E0000, "Unknown formatting type specifier '" << *s << "'");
case '}': trait_name = "Display"; break;
@@ -375,7 +447,7 @@ namespace {
if( next_free == n_free ) {
ERROR(sp, E0000, "Not enough arguments passed, expected at least " << n_free+1);
}
- index = next_free + n_named;
+ index = next_free;
next_free ++;
}
@@ -392,6 +464,9 @@ namespace {
}
namespace {
+ Token ident(const char* s) {
+ return Token(TOK_IDENT, RcString::new_interned(s));
+ }
void push_path(::std::vector<TokenTree>& toks, const AST::Crate& crate, ::std::initializer_list<const char*> il)
{
switch(crate.m_load_std)
@@ -400,17 +475,17 @@ namespace {
break;
case ::AST::Crate::LOAD_CORE:
toks.push_back( TokenTree(TOK_DOUBLE_COLON) );
- toks.push_back( Token(TOK_IDENT, "core") );
+ toks.push_back( ident("core") );
break;
case ::AST::Crate::LOAD_STD:
toks.push_back( TokenTree(TOK_DOUBLE_COLON) );
- toks.push_back( Token(TOK_IDENT, "std") );
+ toks.push_back( ident("std") );
break;
}
for(auto ent : il)
{
toks.push_back( TokenTree(TOK_DOUBLE_COLON) );
- toks.push_back( Token(TOK_IDENT, ent) );
+ toks.push_back( ident(ent) );
}
}
void push_toks(::std::vector<TokenTree>& toks, Token t1) {
@@ -431,32 +506,23 @@ namespace {
toks.push_back( mv$(t3) );
toks.push_back( mv$(t4) );
}
-}
-class CFormatArgsExpander:
- public ExpandProcMacro
-{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand_format_args(const Span& sp, const ::AST::Crate& crate, TTStream& lex, bool add_newline)
{
Token tok;
- auto lex = TTStream(sp, tt);
- lex.parse_state().module = &mod;
- if( ident != "" )
- ERROR(sp, E0000, "format_args! doesn't take an ident");
-
- auto n = Parse_ExprVal(lex);
- ASSERT_BUG(sp, n, "No expression returned");
- Expand_BareExpr(crate, mod, n);
+ auto format_string_node = Parse_ExprVal(lex);
+ ASSERT_BUG(sp, format_string_node, "No expression returned");
+ Expand_BareExpr(crate, lex.parse_state().get_current_mod(), format_string_node);
- auto* format_string_np = dynamic_cast<AST::ExprNode_String*>(&*n);
+ auto* format_string_np = dynamic_cast<AST::ExprNode_String*>(&*format_string_node);
if( !format_string_np ) {
- ERROR(sp, E0000, "format_args! requires a string literal - got " << *n);
+ ERROR(sp, E0000, "format_args! requires a string literal - got " << *format_string_node);
}
const auto& format_string_sp = format_string_np->span();
const auto& format_string = format_string_np->m_value;
- ::std::map< ::std::string, unsigned int> named_args_index;
+ ::std::map<RcString, unsigned int> named_args_index;
::std::vector<TokenTree> named_args;
::std::vector<TokenTree> free_args;
@@ -472,7 +538,7 @@ class CFormatArgsExpander:
if( lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_EQUAL )
{
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_EQUAL);
@@ -497,6 +563,10 @@ class CFormatArgsExpander:
::std::vector< FmtFrag> fragments;
::std::string tail;
::std::tie( fragments, tail ) = parse_format_string(format_string_sp, format_string, named_args_index, free_args.size());
+ if( add_newline )
+ {
+ tail += "\n";
+ }
bool is_simple = true;
for(unsigned int i = 0; i < fragments.size(); i ++)
@@ -533,7 +603,7 @@ class CFormatArgsExpander:
toks.push_back( TokenTree(TOK_PAREN_OPEN) );
for(unsigned int i = 0; i < free_args.size() + named_args.size(); i ++ )
{
- toks.push_back( Token(TOK_IDENT, FMT("a" << i)) );
+ toks.push_back( ident(FMT("a" << i).c_str()) );
toks.push_back( TokenTree(TOK_COMMA) );
}
toks.push_back( TokenTree(TOK_PAREN_CLOSE) );
@@ -545,13 +615,13 @@ class CFormatArgsExpander:
// - Contains N+1 entries, where N is the number of fragments
{
toks.push_back( TokenTree(TOK_RWORD_STATIC) );
- toks.push_back( Token(TOK_IDENT, "FRAGMENTS") );
+ toks.push_back( ident("FRAGMENTS") );
toks.push_back( TokenTree(TOK_COLON) );
toks.push_back( TokenTree(TOK_SQUARE_OPEN) );
toks.push_back( Token(TOK_AMP) );
- toks.push_back( Token(TOK_LIFETIME, "static") );
- toks.push_back( Token(TOK_IDENT, "str") );
+ toks.push_back( Token(TOK_LIFETIME, RcString::new_interned("static")) );
+ toks.push_back( ident("str") );
toks.push_back( Token(TOK_SEMICOLON) );
toks.push_back( Token(static_cast<uint64_t>(fragments.size() + 1), CORETYPE_UINT) );
toks.push_back( TokenTree(TOK_SQUARE_CLOSE) );
@@ -577,7 +647,7 @@ class CFormatArgsExpander:
toks.push_back( TokenTree(TOK_PAREN_OPEN) );
{
toks.push_back( TokenTree(TOK_AMP) );
- toks.push_back( Token(TOK_IDENT, "FRAGMENTS") );
+ toks.push_back( ident("FRAGMENTS") );
toks.push_back( TokenTree(TOK_COMMA) );
toks.push_back( TokenTree(TOK_AMP) );
@@ -586,7 +656,7 @@ class CFormatArgsExpander:
{
push_path(toks, crate, {"fmt", "ArgumentV1", "new"});
toks.push_back( Token(TOK_PAREN_OPEN) );
- toks.push_back( Token(TOK_IDENT, FMT("a" << frag.arg_index)) );
+ toks.push_back( ident( FMT("a" << frag.arg_index).c_str() ) );
toks.push_back( TokenTree(TOK_COMMA) );
@@ -611,7 +681,7 @@ class CFormatArgsExpander:
toks.push_back( TokenTree(TOK_PAREN_OPEN) );
{
toks.push_back( TokenTree(TOK_AMP) );
- toks.push_back( Token(TOK_IDENT, "FRAGMENTS") );
+ toks.push_back( ident("FRAGMENTS") );
toks.push_back( TokenTree(TOK_COMMA) );
// TODO: Fragments to format
@@ -622,7 +692,7 @@ class CFormatArgsExpander:
{
push_path(toks, crate, {"fmt", "ArgumentV1", "new"});
toks.push_back( Token(TOK_PAREN_OPEN) );
- toks.push_back( Token(TOK_IDENT, FMT("a" << frag.arg_index)) );
+ toks.push_back( ident(FMT("a" << frag.arg_index).c_str()) );
toks.push_back( TokenTree(TOK_COMMA) );
@@ -640,17 +710,17 @@ class CFormatArgsExpander:
push_path(toks, crate, {"fmt", "rt", "v1", "Argument"});
toks.push_back( TokenTree(TOK_BRACE_OPEN) );
- push_toks(toks, Token(TOK_IDENT, "position"), TOK_COLON );
+ push_toks(toks, ident("position"), TOK_COLON );
push_path(toks, crate, {"fmt", "rt", "v1", "Position", "Next"});
push_toks(toks, TOK_COMMA);
- push_toks(toks, Token(TOK_IDENT, "format"), TOK_COLON );
+ push_toks(toks, ident("format"), TOK_COLON );
push_path(toks, crate, {"fmt", "rt", "v1", "FormatSpec"});
toks.push_back( TokenTree(TOK_BRACE_OPEN) );
{
- push_toks(toks, Token(TOK_IDENT, "fill"), TOK_COLON, Token(uint64_t(frag.args.align_char), CORETYPE_CHAR), TOK_COMMA );
+ push_toks(toks, ident("fill"), TOK_COLON, Token(uint64_t(frag.args.align_char), CORETYPE_CHAR), TOK_COMMA );
- push_toks(toks, Token(TOK_IDENT, "align"), TOK_COLON);
+ push_toks(toks, ident("align"), TOK_COLON);
const char* align_var_name = nullptr;
switch( frag.args.align )
{
@@ -662,19 +732,19 @@ class CFormatArgsExpander:
push_path(toks, crate, {"fmt", "rt", "v1", "Alignment", align_var_name});
push_toks(toks, TOK_COMMA);
- push_toks(toks, Token(TOK_IDENT, "flags"), TOK_COLON);
+ push_toks(toks, ident("flags"), TOK_COLON);
uint64_t flags = 0;
if(frag.args.alternate)
flags |= 1 << 2;
push_toks(toks, Token(uint64_t(flags), CORETYPE_U32));
push_toks(toks, TOK_COMMA);
- push_toks(toks, Token(TOK_IDENT, "precision"), TOK_COLON );
+ push_toks(toks, ident("precision"), TOK_COLON );
if( frag.args.prec_is_arg || frag.args.prec != 0 ) {
push_path(toks, crate, {"fmt", "rt", "v1", "Count", "Is"});
push_toks(toks, TOK_PAREN_OPEN);
if( frag.args.prec_is_arg ) {
- push_toks(toks, TOK_STAR, Token(TOK_IDENT, FMT("a" << frag.args.prec)) );
+ push_toks(toks, TOK_STAR, ident(FMT("a" << frag.args.prec).c_str()) );
}
else {
push_toks(toks, Token(uint64_t(frag.args.prec), CORETYPE_UINT) );
@@ -686,12 +756,12 @@ class CFormatArgsExpander:
}
toks.push_back( TokenTree(TOK_COMMA) );
- push_toks(toks, Token(TOK_IDENT, "width"), TOK_COLON );
+ push_toks(toks, ident("width"), TOK_COLON );
if( frag.args.width_is_arg || frag.args.width != 0 ) {
push_path(toks, crate, {"fmt", "rt", "v1", "Count", "Is"});
push_toks(toks, TOK_PAREN_OPEN);
if( frag.args.width_is_arg ) {
- push_toks(toks, TOK_STAR, Token(TOK_IDENT, FMT("a" << frag.args.width)) );
+ push_toks(toks, TOK_STAR, ident(FMT("a" << frag.args.width).c_str()) );
}
else {
push_toks(toks, Token(uint64_t(frag.args.width), CORETYPE_UINT) );
@@ -719,7 +789,36 @@ class CFormatArgsExpander:
return box$( TTStreamO(sp, TokenTree(Ident::Hygiene::new_scope(), mv$(toks))) );
}
+}
+
+class CFormatArgsExpander:
+ public ExpandProcMacro
+{
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
+ {
+ Token tok;
+
+ auto lex = TTStream(sp, tt);
+ lex.parse_state().module = &mod;
+
+ return expand_format_args(sp, crate, lex, /*add_newline=*/false);
+ }
+};
+
+class CFormatArgsNlExpander:
+ public ExpandProcMacro
+{
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
+ {
+ Token tok;
+
+ auto lex = TTStream(sp, tt);
+ lex.parse_state().module = &mod;
+
+ return expand_format_args(sp, crate, lex, /*add_newline=*/true);
+ }
};
STATIC_MACRO("format_args", CFormatArgsExpander);
+STATIC_MACRO("format_args_nl", CFormatArgsNlExpander);
diff --git a/src/expand/include.cpp b/src/expand/include.cpp
index 59f33d47..14a7bc7b 100644
--- a/src/expand/include.cpp
+++ b/src/expand/include.cpp
@@ -12,6 +12,7 @@
#include <parse/ttstream.hpp>
#include <parse/lex.hpp> // Lexer (new files)
#include <ast/expr.hpp>
+#include <ast/crate.hpp>
namespace {
@@ -63,11 +64,8 @@ namespace {
class CIncludeExpander:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" )
- ERROR(sp, E0000, "include! doesn't take an ident");
-
Token tok;
auto lex = TTStream(sp, tt);
@@ -75,6 +73,7 @@ class CIncludeExpander:
GET_CHECK_TOK(tok, lex, TOK_EOF);
::std::string file_path = get_path_relative_to(mod.m_file_info.path, mv$(path));
+ crate.m_extra_files.push_back(file_path);
try {
return box$( Lexer(file_path) );
@@ -89,11 +88,8 @@ class CIncludeExpander:
class CIncludeBytesExpander:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" )
- ERROR(sp, E0000, "include_bytes! doesn't take an ident");
-
Token tok;
auto lex = TTStream(sp, tt);
@@ -101,6 +97,7 @@ class CIncludeBytesExpander:
GET_CHECK_TOK(tok, lex, TOK_EOF);
::std::string file_path = get_path_relative_to(mod.m_file_info.path, mv$(path));
+ crate.m_extra_files.push_back(file_path);
::std::ifstream is(file_path);
if( !is.good() ) {
@@ -118,11 +115,8 @@ class CIncludeBytesExpander:
class CIncludeStrExpander:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" )
- ERROR(sp, E0000, "include_str! doesn't take an ident");
-
Token tok;
auto lex = TTStream(sp, tt);
@@ -130,6 +124,7 @@ class CIncludeStrExpander:
GET_CHECK_TOK(tok, lex, TOK_EOF);
::std::string file_path = get_path_relative_to(mod.m_file_info.path, mv$(path));
+ crate.m_extra_files.push_back(file_path);
::std::ifstream is(file_path);
if( !is.good() ) {
diff --git a/src/expand/lang_item.cpp b/src/expand/lang_item.cpp
index 789ad88e..328bce9c 100644
--- a/src/expand/lang_item.cpp
+++ b/src/expand/lang_item.cpp
@@ -30,6 +30,7 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path,
else if( name == "copy" ) {
DEBUG("Bind 'copy' to " << path);
}
+ else if( TARGETVER_1_29 && name == "clone" ) {} // - Trait
// ops traits
else if( name == "drop" ) { DEBUG("Bind '"<<name<<"' to " << path); }
else if( name == "add" ) { DEBUG("Bind '"<<name<<"' to " << path); }
@@ -67,7 +68,8 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path,
else if( name == "fn_once" ) { DEBUG("Bind '"<<name<<"' to " << path); }
else if( name == "eq" ) { DEBUG("Bind '"<<name<<"' to " << path); }
- else if( name == "ord" ) { DEBUG("Bind '"<<name<<"' to " << path); }
+ else if( name == "ord" ) { DEBUG("Bind '"<<name<<"' to " << path); } // In 1.29 this is Ord, before it was PartialOrd
+ else if( TARGETVER_1_29 && name == "partial_ord" ) { DEBUG("Bind '"<<name<<"' to " << path); } // New name for v1.29
else if( name == "unsize" ) { DEBUG("Bind '"<<name<<"' to " << path); }
else if( name == "coerce_unsized" ) { DEBUG("Bind '"<<name<<"' to " << path); }
else if( name == "freeze" ) { DEBUG("Bind '"<<name<<"' to " << path); }
@@ -76,6 +78,8 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path,
else if( name == "debug_trait" ) { /* TODO: Poke derive() with this */ }
+ else if( TARGETVER_1_29 && name == "termination" ) { } // 1.29 - trait used for non-() main
+
// Structs
else if( name == "non_zero" ) { }
else if( name == "phantom_data" ) { }
@@ -84,18 +88,30 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path,
else if( name == "range_from" ) { }
else if( name == "range_to" ) { }
else if( name == "unsafe_cell" ) { }
+ else if( TARGETVER_1_29 && name == "alloc_layout") { }
+ else if( TARGETVER_1_29 && name == "panic_info" ) {} // Struct
+ else if( TARGETVER_1_29 && name == "manually_drop" ) {} // Struct
+
+ // Generators
+ else if( TARGETVER_1_29 && name == "generator" ) {} // - Trait
+ else if( TARGETVER_1_29 && name == "generator_state" ) {} // - State enum
// Statics
else if( name == "msvc_try_filter" ) { }
+ // Extern functions
+ else if( name == "panic_impl" ) {
+ }
+ else if( name == "oom" ) {
+ }
+
// Functions
else if( name == "panic" ) { }
else if( name == "panic_bounds_check" ) { }
- else if( name == "panic_fmt" ) {
-
- }
+ else if( name == "panic_fmt" ) { }
else if( name == "str_eq" ) { }
else if( name == "drop_in_place" ) { }
+ else if( name == "align_offset" ) { }
// - builtin `box` support
else if( name == "exchange_malloc" ) { }
else if( name == "exchange_free" ) { }
@@ -105,11 +121,43 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path,
else if( name == "start" ) { }
else if( name == "eh_personality" ) { }
+ // libcompiler_builtins
+ // - i128/u128 helpers (not used by mrustc)
+ else if( name == "i128_add" ) { }
+ else if( name == "i128_addo" ) { }
+ else if( name == "u128_add" ) { }
+ else if( name == "u128_addo" ) { }
+ else if( name == "i128_sub" ) { }
+ else if( name == "i128_subo" ) { }
+ else if( name == "u128_sub" ) { }
+ else if( name == "u128_subo" ) { }
+ else if( name == "i128_mul" ) { }
+ else if( name == "i128_mulo" ) { }
+ else if( name == "u128_mul" ) { }
+ else if( name == "u128_mulo" ) { }
+ else if( name == "i128_div" ) { }
+ else if( name == "i128_rem" ) { }
+ else if( name == "u128_div" ) { }
+ else if( name == "u128_rem" ) { }
+ else if( name == "i128_shl" ) { }
+ else if( name == "i128_shlo" ) { }
+ else if( name == "u128_shl" ) { }
+ else if( name == "u128_shlo" ) { }
+ else if( name == "i128_shr" ) { }
+ else if( name == "i128_shro" ) { }
+ else if( name == "u128_shr" ) { }
+ else if( name == "u128_shro" ) { }
else {
ERROR(sp, E0000, "Unknown language item '" << name << "'");
}
+ if( type == AST::ITEM_EXTERN_FN )
+ {
+ // TODO: This should force a specific link name instead
+ return ;
+ }
+
auto rv = crate.m_lang_items.insert( ::std::make_pair( name, ::AST::Path(path) ) );
if( !rv.second ) {
const auto& other_path = rv.first->second;
@@ -125,7 +173,7 @@ class Decorator_LangItem:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
TU_MATCH_DEF(::AST::Item, (i), (e),
(
@@ -139,7 +187,7 @@ public:
handle_lang_item(sp, crate, path, attr.string(), AST::ITEM_FN);
}
else {
- //handle_lang_item(sp, crate, path, attr.string(), AST::ITEM_EXTERN_FN);
+ handle_lang_item(sp, crate, path, attr.string(), AST::ITEM_EXTERN_FN);
}
),
(Static,
@@ -148,6 +196,9 @@ public:
(Struct,
handle_lang_item(sp, crate, path, attr.string(), AST::ITEM_STRUCT);
),
+ (Enum,
+ handle_lang_item(sp, crate, path, attr.string(), AST::ITEM_ENUM);
+ ),
(Trait,
handle_lang_item(sp, crate, path, attr.string(), AST::ITEM_TRAIT);
)
@@ -176,9 +227,15 @@ public:
// collections
else if( name == "str" ) {}
else if( name == "slice" ) {}
+ else if( TARGETVER_1_29 && name == "slice_u8" ) {} // libcore now, `impl [u8]`
+ else if( TARGETVER_1_29 && name == "slice_alloc" ) {} // liballoc's impls on [T]
+ else if( TARGETVER_1_29 && name == "slice_u8_alloc" ) {} // liballoc's impls on [u8]
+ else if( TARGETVER_1_29 && name == "str_alloc" ) {} // liballoc's impls on str
// std - interestingly
else if( name == "f32" ) {}
else if( name == "f64" ) {}
+ else if( TARGETVER_1_29 && name == "f32_runtime" ) {}
+ else if( TARGETVER_1_29 && name == "f64_runtime" ) {}
else {
ERROR(sp, E0000, "Unknown lang item '" << name << "' on impl");
}
@@ -193,7 +250,7 @@ class Decorator_Main:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
if( i.is_None() ) {
// Ignore.
@@ -217,7 +274,7 @@ class Decorator_Start:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
TU_IFLET(::AST::Item, i, Function, e,
auto rv = crate.m_lang_items.insert(::std::make_pair( ::std::string("mrustc-start"), ::AST::Path(path) ));
@@ -233,9 +290,30 @@ public:
}
};
+class Decorator_PanicImplementation:
+ public ExpandDecorator
+{
+public:
+ AttrStage stage() const override { return AttrStage::Post; }
+ void handle(const Span& sp, const AST::Attribute& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
+ {
+ TU_IFLET(::AST::Item, i, Function, e,
+ auto rv = crate.m_lang_items.insert(::std::make_pair( ::std::string("mrustc-panic_implementation"), ::AST::Path(path) ));
+ if( !rv.second )
+ {
+ const auto& other_path = rv.first->second;
+ ERROR(sp, E0000, "Duplicate definition of #[panic_implementation] - " << other_path << " and " << path);
+ }
+ )
+ else {
+ ERROR(sp, E0000, "#[panic_implementation] on non-function " << path);
+ }
+ }
+};
STATIC_DECORATOR("lang", Decorator_LangItem)
STATIC_DECORATOR("main", Decorator_Main);
STATIC_DECORATOR("start", Decorator_Start);
+STATIC_DECORATOR("panic_implementation", Decorator_PanicImplementation);
diff --git a/src/expand/macro_rules.cpp b/src/expand/macro_rules.cpp
index 89f394e1..3b6e4efa 100644
--- a/src/expand/macro_rules.cpp
+++ b/src/expand/macro_rules.cpp
@@ -21,11 +21,12 @@
class CMacroRulesExpander:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
+ {
+ ERROR(sp, E0000, "macro_rules! requires an identifier" );
+ }
+ ::std::unique_ptr<TokenStream> expand_ident(const Span& sp, const ::AST::Crate& crate, const RcString& ident, const TokenTree& tt, AST::Module& mod) override
{
- if( ident == "" )
- ERROR(sp, E0000, "macro_rules! requires an identifier" );
-
DEBUG("Parsing macro_rules! " << ident);
TTStream lex(sp, tt);
auto mac = Parse_MacroRules(lex);
@@ -40,7 +41,7 @@ class CMacroUseHandler:
{
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
TRACE_FUNCTION_F("path=" << path);
@@ -48,7 +49,7 @@ class CMacroUseHandler:
// Just ignore
)
else TU_IFLET( ::AST::Item, i, Crate, ec_name,
- const auto& ec = crate.m_extern_crates.at(ec_name.name);
+ const auto& ec = crate.m_extern_crates.at(ec_name.name.c_str());
if( mi.has_sub_items() )
{
TODO(sp, "Named import from extern crate");
@@ -61,8 +62,13 @@ class CMacroUseHandler:
});
for(const auto& p : ec.m_hir->m_proc_macros)
{
- mod.m_macro_imports.push_back(::std::make_pair( p.path.m_components, nullptr ));
- mod.m_macro_imports.back().first.insert( mod.m_macro_imports.back().first.begin(), p.path.m_crate_name );
+ mod.m_macro_imports.push_back(AST::Module::MacroImport{ false, p.path.m_components.back(), p.path.m_components, nullptr });
+ mod.m_macro_imports.back().path.insert( mod.m_macro_imports.back().path.begin(), p.path.m_crate_name );
+ }
+ for(const auto& p : ec.m_hir->m_proc_macro_reexports)
+ {
+ mod.m_macro_imports.push_back(AST::Module::MacroImport{ /*is_pub=*/ false, p.first, p.second.path.m_components, nullptr });
+ mod.m_macro_imports.back().path.insert( mod.m_macro_imports.back().path.begin(), p.second.path.m_crate_name );
}
}
)
@@ -119,7 +125,7 @@ class CMacroExportHandler:
{
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
if( i.is_None() ) {
}
@@ -146,14 +152,14 @@ class CMacroReexportHandler:
public ExpandDecorator
{
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
if( !i.is_Crate() ) {
ERROR(sp, E0000, "Use of #[macro_reexport] on non-crate - " << i.tag_str());
}
const auto& crate_name = i.as_Crate().name;
- auto& ext_crate = *crate.m_extern_crates.at(crate_name).m_hir;
+ auto& ext_crate = *crate.m_extern_crates.at(crate_name.c_str()).m_hir;
if( mi.has_sub_items() )
{
diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp
index 5d6d3234..53358473 100644
--- a/src/expand/mod.cpp
+++ b/src/expand/mod.cpp
@@ -41,6 +41,12 @@ void Register_Synext_Macro_Static(MacroDef* def) {
g_macros_list = def;
}
+void Expand_Init()
+{
+ // TODO: Initialise all macros here.
+ void Expand_init_assert(); Expand_init_assert();
+}
+
void ExpandDecorator::unexpected(const Span& sp, const AST::Attribute& mi, const char* loc_str) const
{
@@ -49,46 +55,67 @@ void ExpandDecorator::unexpected(const Span& sp, const AST::Attribute& mi, const
void Expand_Attr(const Span& sp, const ::AST::Attribute& a, AttrStage stage, ::std::function<void(const Span& sp, const ExpandDecorator& d,const ::AST::Attribute& a)> f)
{
+ bool found = false;
for( auto& d : g_decorators ) {
- if( d.first == a.name() ) {
+ if( a.name() == d.first ) {
DEBUG("#[" << d.first << "] " << (int)d.second->stage() << "-" << (int)stage);
if( d.second->stage() == stage ) {
f(sp, *d.second, a);
+ // TODO: Early return?
+ // TODO: Annotate the attribute as having been handled
}
+ found = true;
}
}
+ if( !found ) {
+ // TODO: Create no-op handlers for a whole heap of attributes
+ //WARNING(sp, W0000, "Unknown attribute " << a.name());
+ }
}
-void Expand_Attrs(/*const */::AST::AttributeList& attrs, AttrStage stage, ::std::function<void(const Span& sp, const ExpandDecorator& d,const ::AST::Attribute& a)> f)
+void Expand_Attrs(const ::AST::AttributeList& attrs, AttrStage stage, ::std::function<void(const Span& sp, const ExpandDecorator& d,const ::AST::Attribute& a)> f)
{
for( auto& a : attrs.m_items )
{
+ Expand_Attr(a.span(), a, stage, f);
+ }
+}
+void Expand_Attrs_CfgAttr(AST::AttributeList& attrs)
+{
+ for(auto it = attrs.m_items.begin(); it != attrs.m_items.end(); )
+ {
+ auto& a = *it;
if( a.name() == "cfg_attr" ) {
if( check_cfg(a.span(), a.items().at(0)) ) {
- // Wait? Why move?
auto inner_attr = mv$(a.items().at(1));
- Expand_Attr(inner_attr.span(), inner_attr, stage, f);
a = mv$(inner_attr);
+ ++ it;
}
else {
+ it = attrs.m_items.erase(it);
}
}
else {
- Expand_Attr(a.span(), a, stage, f);
+ ++ it;
}
}
}
-void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& crate, const ::AST::Path& path, ::AST::Module& mod, ::AST::Item& item)
+void Expand_Attrs(const ::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& crate, const ::AST::Path& path, ::AST::Module& mod, ::AST::Item& item)
{
- Expand_Attrs(attrs, stage, [&](const auto& sp, const auto& d, const auto& a){ if(!item.is_None()) d.handle(sp, a, crate, path, mod, item); });
+ Expand_Attrs(attrs, stage, [&](const auto& sp, const auto& d, const auto& a){
+ if(!item.is_None()) {
+ // TODO: Pass attributes _after_ this attribute
+ d.handle(sp, a, crate, path, mod, slice<const AST::Attribute>(&a, &attrs.m_items.back() - &a + 1), item);
+ }
+ });
}
-void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& crate, ::AST::Module& mod, ::AST::ImplDef& impl)
+void Expand_Attrs(const ::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& crate, ::AST::Module& mod, ::AST::ImplDef& impl)
{
Expand_Attrs(attrs, stage, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, mod, impl); });
}
-::std::unique_ptr<TokenStream> Expand_Macro(
+::std::unique_ptr<TokenStream> Expand_Macro_Inner(
const ::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Module& mod,
- Span mi_span, const ::std::string& name, const ::std::string& input_ident, TokenTree& input_tt
+ Span mi_span, const RcString& name, const RcString& input_ident, TokenTree& input_tt
)
{
if( name == "" ) {
@@ -99,7 +126,10 @@ void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& c
{
if( name == m.first )
{
- auto e = m.second->expand(mi_span, crate, input_ident, input_tt, mod);
+ auto e = input_ident == ""
+ ? m.second->expand(mi_span, crate, input_tt, mod)
+ : m.second->expand_ident(mi_span, crate, input_ident, input_tt, mod)
+ ;
return e;
}
}
@@ -144,6 +174,17 @@ void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& c
// Error - Unknown macro name
ERROR(mi_span, E0000, "Unknown macro '" << name << "'");
}
+::std::unique_ptr<TokenStream> Expand_Macro(
+ const ::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Module& mod,
+ Span mi_span, const RcString& name, const RcString& input_ident, TokenTree& input_tt
+ )
+{
+ auto rv = Expand_Macro_Inner(crate, modstack, mod, mi_span, name, input_ident, input_tt);
+ assert(rv);
+ rv->parse_state().module = &mod;
+ rv->parse_state().crate = &crate;
+ return rv;
+}
::std::unique_ptr<TokenStream> Expand_Macro(const ::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Module& mod, ::AST::MacroInvocation& mi)
{
return Expand_Macro(crate, modstack, mod, mi.span(), mi.name(), mi.input_ident(), mi.input_tt());
@@ -330,6 +371,10 @@ struct CExpandExpr:
LList<const AST::Module*> modstack;
::std::unique_ptr<::AST::ExprNode> replacement;
+ // Stack of `try { ... }` blocks (the string is the loop label for the desugaring)
+ ::std::vector<RcString> m_try_stack;
+ unsigned m_try_index = 0;
+
AST::ExprNode_Block* current_block = nullptr;
CExpandExpr(::AST::Crate& crate, LList<const AST::Module*> ms):
@@ -346,6 +391,7 @@ struct CExpandExpr:
if(cnode.get())
{
auto attrs = mv$(cnode->attrs());
+ Expand_Attrs_CfgAttr(attrs);
Expand_Attrs(attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, this->crate, cnode); });
if(cnode.get())
cnode->attrs() = mv$(attrs);
@@ -494,6 +540,7 @@ struct CExpandExpr:
if( auto* node_mac = dynamic_cast<::AST::ExprNode_Macro*>(it->get()) )
{
+ Expand_Attrs_CfgAttr( (*it)->attrs() );
Expand_Attrs((*it)->attrs(), AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, this->crate, *it); });
if( !it->get() ) {
it = node.m_nodes.erase( it );
@@ -530,6 +577,25 @@ struct CExpandExpr:
this->modstack = mv$(prev_modstack);
}
+ void visit(::AST::ExprNode_Try& node) override {
+ // Desugar into
+ // ```
+ // loop '#tryNNN {
+ // break '#tryNNN { ... }
+ // }
+ // ```
+ // NOTE: MIR lowering and HIR typecheck need to know to skip these (OR resolve should handle naming all loop blocks)
+ m_try_stack.push_back(RcString::new_interned(FMT("#try" << m_try_index++)));
+ this->visit_nodelete(node, node.m_inner);
+ auto loop_name = mv$(m_try_stack.back());
+ m_try_stack.pop_back();
+
+ auto core_crate = (crate.m_load_std == ::AST::Crate::LOAD_NONE ? "" : "core");
+ auto path_Ok = ::AST::Path(core_crate, {::AST::PathNode("result"), ::AST::PathNode("Result"), ::AST::PathNode("Ok")});
+ auto ok_node = ::AST::ExprNodeP(new ::AST::ExprNode_CallPath( mv$(path_Ok), ::make_vec1(mv$(node.m_inner)) ));
+ auto break_node = AST::ExprNodeP(new AST::ExprNode_Flow(AST::ExprNode_Flow::BREAK, loop_name, mv$(ok_node)));
+ this->replacement = AST::ExprNodeP(new AST::ExprNode_Loop(loop_name, mv$(break_node)));
+ }
void visit(::AST::ExprNode_Asm& node) override {
for(auto& v : node.m_output)
this->visit_nodelete(node, v.value);
@@ -627,6 +693,7 @@ struct CExpandExpr:
this->visit_nodelete(node, node.m_val);
for(auto& arm : node.m_arms)
{
+ Expand_Attrs_CfgAttr( arm.m_attrs );
Expand_Attrs(arm.m_attrs, AttrStage::Pre , [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, arm); });
if( arm.m_patterns.size() == 0 )
continue ;
@@ -673,6 +740,7 @@ struct CExpandExpr:
this->visit_nodelete(node, node.m_base_value);
for(auto& val : node.m_values)
{
+ Expand_Attrs_CfgAttr(val.attrs);
Expand_Attrs(val.attrs, AttrStage::Pre , [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, val); });
if( !val.value )
continue ;
@@ -755,6 +823,7 @@ struct CExpandExpr:
case ::AST::ExprNode_BinOp::RANGE_INC: {
// NOTE: Not language items
auto core_crate = (crate.m_load_std == ::AST::Crate::LOAD_NONE ? "" : "core");
+ auto path_None = ::AST::Path(core_crate, { ::AST::PathNode("option"), ::AST::PathNode("Option"), ::AST::PathNode("None") });
auto path_RangeInclusive_NonEmpty = ::AST::Path(core_crate, { ::AST::PathNode("ops"), ::AST::PathNode("RangeInclusive") });
auto path_RangeToInclusive = ::AST::Path(core_crate, { ::AST::PathNode("ops"), ::AST::PathNode("RangeToInclusive") });
@@ -763,6 +832,8 @@ struct CExpandExpr:
::AST::ExprNode_StructLiteral::t_values values;
values.push_back({ {}, "start", mv$(node.m_left) });
values.push_back({ {}, "end" , mv$(node.m_right) });
+ if( TARGETVER_1_29 )
+ values.push_back({ {}, "is_empty", ::AST::ExprNodeP(new ::AST::ExprNode_NamedValue(mv$(path_None))) });
replacement.reset( new ::AST::ExprNode_StructLiteral(mv$(path_RangeInclusive_NonEmpty), nullptr, mv$(values)) );
}
else
@@ -786,12 +857,19 @@ struct CExpandExpr:
auto path_Err = ::AST::Path(core_crate, {::AST::PathNode("result"), ::AST::PathNode("Result"), ::AST::PathNode("Err")});
auto path_From = ::AST::Path(core_crate, {::AST::PathNode("convert"), ::AST::PathNode("From")});
path_From.nodes().back().args().m_types.push_back( ::TypeRef(node.span()) );
+ // TODO: Lang item (needs lang items enumerated earlier)
+ //auto it = crate.m_lang_items.find("try");
+ //ASSERT_BUG(node.span(), it != crate.m_lang_items.end(), "Can't find the `try` lang item");
+ //auto path_Try = it->second;
+ auto path_Try = ::AST::Path(core_crate, {::AST::PathNode("ops"), ::AST::PathNode("Try")});
+ auto path_Try_into_result = ::AST::Path(::AST::Path::TagUfcs(), ::TypeRef(node.span()), path_Try, { ::AST::PathNode("into_result") });
+ auto path_Try_from_error = ::AST::Path(::AST::Path::TagUfcs(), ::TypeRef(node.span()), path_Try, { ::AST::PathNode("from_error") });
// Desugars into
// ```
- // match `m_value` {
+ // match `Try::into_result(m_value)` {
// Ok(v) => v,
- // Err(e) => return Err(From::from(e)),
+ // Err(e) => return Try::from_error(From::from(e)),
// }
// ```
@@ -802,15 +880,15 @@ struct CExpandExpr:
nullptr,
::AST::ExprNodeP( new ::AST::ExprNode_NamedValue( ::AST::Path(::AST::Path::TagLocal(), "v") ) )
));
- // `Err(e) => return Err(From::from(e)),`
+ // `Err(e) => return Try::from_error(From::from(e)),`
arms.push_back(::AST::ExprNode_Match_Arm(
::make_vec1( ::AST::Pattern(::AST::Pattern::TagNamedTuple(), node.span(), path_Err, ::make_vec1( ::AST::Pattern(::AST::Pattern::TagBind(), node.span(), "e") )) ),
nullptr,
::AST::ExprNodeP(new ::AST::ExprNode_Flow(
- ::AST::ExprNode_Flow::RETURN,
- "",
+ (m_try_stack.empty() ? ::AST::ExprNode_Flow::RETURN : ::AST::ExprNode_Flow::BREAK), // NOTE: uses `break 'tryblock` instead of return if in a try block.
+ (m_try_stack.empty() ? RcString("") : m_try_stack.back()),
::AST::ExprNodeP(new ::AST::ExprNode_CallPath(
- ::AST::Path(path_Err),
+ ::AST::Path(path_Try_from_error),
::make_vec1(
::AST::ExprNodeP(new ::AST::ExprNode_CallPath(
::AST::Path(::AST::Path::TagUfcs(), ::TypeRef(node.span()), mv$(path_From), { ::AST::PathNode("from") }),
@@ -821,7 +899,13 @@ struct CExpandExpr:
))
));
- replacement.reset(new ::AST::ExprNode_Match( mv$(node.m_value), mv$(arms) ));
+ replacement.reset(new ::AST::ExprNode_Match(
+ ::AST::ExprNodeP(new AST::ExprNode_CallPath(
+ mv$(path_Try_into_result),
+ ::make_vec1( mv$(node.m_value) )
+ )),
+ mv$(arms)
+ ));
}
}
};
@@ -895,6 +979,7 @@ void Expand_BareExpr(const ::AST::Crate& crate, const AST::Module& mod, ::std::u
void Expand_Impl(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Path modpath, ::AST::Module& mod, ::AST::Impl& impl)
{
TRACE_FUNCTION_F(impl.def());
+ Expand_Attrs_CfgAttr(impl.def().attrs());
Expand_Attrs(impl.def().attrs(), AttrStage::Pre, crate, mod, impl.def());
if( impl.def().type().is_wildcard() ) {
DEBUG("Deleted");
@@ -909,18 +994,19 @@ void Expand_Impl(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:
for( unsigned int idx = 0; idx < impl.items().size(); idx ++ )
{
auto& i = impl.items()[idx];
- DEBUG(" - " << i.name << " :: " << i.data->attrs);
+ DEBUG(" - " << i.name << " :: " << i.attrs);
// TODO: Make a path from the impl definition? Requires having the impl def resolved to be correct
// - Does it? the namespace is essentially the same. There may be issues with wherever the path is used though
//::AST::Path path = modpath + i.name;
- auto attrs = mv$(i.data->attrs);
+ auto attrs = mv$(i.attrs);
+ Expand_Attrs_CfgAttr(attrs);
Expand_Attrs(attrs, AttrStage::Pre, crate, AST::Path(), mod, *i.data);
TU_MATCH_DEF(AST::Item, (*i.data), (e),
(
- throw ::std::runtime_error("BUG: Unknown item type in impl block");
+ BUG(Span(), "Unknown item type in impl block - " << i.data->tag_str());
),
(None, ),
(MacroInv,
@@ -970,8 +1056,8 @@ void Expand_Impl(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:
auto& i = impl.items()[idx];
Expand_Attrs(attrs, AttrStage::Post, crate, AST::Path(), mod, *i.data);
// TODO: How would this be populated? It got moved out?
- if( i.data->attrs.m_items.size() == 0 )
- i.data->attrs = mv$(attrs);
+ if( i.attrs.m_items.size() == 0 )
+ i.attrs = mv$(attrs);
}
}
@@ -979,6 +1065,7 @@ void Expand_Impl(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:
}
void Expand_ImplDef(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Path modpath, ::AST::Module& mod, ::AST::ImplDef& impl_def)
{
+ Expand_Attrs_CfgAttr(impl_def.attrs());
Expand_Attrs(impl_def.attrs(), AttrStage::Pre, crate, mod, impl_def);
if( impl_def.type().is_wildcard() ) {
DEBUG("Deleted");
@@ -1011,14 +1098,14 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
}
}
for( const auto& mi: mod.m_macro_imports )
- DEBUG("- Imports '" << mi.first << "'");
+ DEBUG("- Imports '" << mi.path << "'");
}
// Insert prelude if: Enabled for this module, present for the crate, and this module is not an anon
if( crate.m_prelude_path != AST::Path() )
{
if( mod.m_insert_prelude && ! mod.is_anon() ) {
- mod.add_alias(false, ::AST::UseStmt(Span(), crate.m_prelude_path), "", {});
+ mod.add_item(Span(), false, "", ::AST::UseItem { Span(), ::make_vec1(::AST::UseItem::Ent { Span(), crate.m_prelude_path, "" }) }, {});
}
}
@@ -1027,19 +1114,20 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
{
auto& i = mod.items()[idx];
- DEBUG("- " << modpath << "::" << i.name << " (" << ::AST::Item::tag_to_str(i.data.tag()) << ") :: " << i.data.attrs);
+ DEBUG("- " << modpath << "::" << i.name << " (" << ::AST::Item::tag_to_str(i.data.tag()) << ") :: " << i.attrs);
::AST::Path path = modpath + i.name;
- auto attrs = mv$(i.data.attrs);
+ auto attrs = mv$(i.attrs);
+ Expand_Attrs_CfgAttr(attrs);
Expand_Attrs(attrs, AttrStage::Pre, crate, path, mod, i.data);
auto dat = mv$(i.data);
- TU_MATCH(::AST::Item, (dat), (e),
- (None,
- // Skip, nothing
- ),
- (MacroInv,
+ TU_MATCH_HDRA( (dat), {)
+ TU_ARMA(None, e) {
+ // Skip: nothing
+ }
+ TU_ARMA(MacroInv, e) {
// Move out of the module to avoid invalidation if a new macro invocation is added
auto mi_owned = mv$(e);
@@ -1056,11 +1144,14 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
Parse_ModRoot_Items(*ttl, mod);
}
dat.as_MacroInv() = mv$(mi_owned);
- ),
- (Use,
+ }
+ TU_ARMA(Macro, e) {
+ mod.add_macro(i.is_pub, i.name, mv$(e));
+ }
+ TU_ARMA(Use, e) {
// No inner expand.
- ),
- (ExternBlock,
+ }
+ TU_ARMA(ExternBlock, e) {
// TODO: Run expand on inner items?
// HACK: Just convert inner items into outer items
auto items = mv$( e.items() );
@@ -1068,32 +1159,32 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
{
mod.items().push_back( mv$(i2) );
}
- ),
- (Impl,
+ }
+ TU_ARMA(Impl, e) {
Expand_Impl(crate, modstack, modpath, mod, e);
if( e.def().type().is_wildcard() ) {
dat = AST::Item();
}
- ),
- (NegImpl,
+ }
+ TU_ARMA(NegImpl, e) {
Expand_ImplDef(crate, modstack, modpath, mod, e);
if( e.type().is_wildcard() ) {
dat = AST::Item();
}
- ),
- (Module,
+ }
+ TU_ARMA(Module, e) {
LList<const AST::Module*> sub_modstack(&modstack, &e);
Expand_Mod(crate, sub_modstack, path, e);
- ),
- (Crate,
+ }
+ TU_ARMA(Crate, e) {
// Can't recurse into an `extern crate`
if(crate.m_extern_crates.count(e.name) == 0)
{
- e.name = crate.load_extern_crate( i.data.span, e.name );
+ e.name = crate.load_extern_crate( i.span, e.name );
+ }
}
- ),
- (Struct,
+ TU_ARMA(Struct, e) {
Expand_GenericParams(crate, modstack, mod, e.params());
TU_MATCH(AST::StructData, (e.m_data), (sd),
(Unit,
@@ -1101,6 +1192,7 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
(Struct,
for(auto it = sd.ents.begin(); it != sd.ents.end(); ) {
auto& si = *it;
+ Expand_Attrs_CfgAttr(si.m_attrs);
Expand_Attrs(si.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
Expand_Type(crate, modstack, mod, si.m_type);
Expand_Attrs(si.m_attrs, AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
@@ -1114,6 +1206,7 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
(Tuple,
for(auto it = sd.ents.begin(); it != sd.ents.end(); ) {
auto& si = *it;
+ Expand_Attrs_CfgAttr(si.m_attrs);
Expand_Attrs(si.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
Expand_Type(crate, modstack, mod, si.m_type);
Expand_Attrs(si.m_attrs, AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
@@ -1125,10 +1218,11 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
}
)
)
- ),
- (Enum,
+ }
+ TU_ARMA(Enum, e) {
Expand_GenericParams(crate, modstack, mod, e.params());
for(auto& var : e.variants()) {
+ Expand_Attrs_CfgAttr(var.m_attrs);
Expand_Attrs(var.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, var); });
TU_MATCH(::AST::EnumVariantData, (var.m_data), (e),
(Value,
@@ -1142,6 +1236,7 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
(Struct,
for(auto it = e.m_fields.begin(); it != e.m_fields.end(); ) {
auto& si = *it;
+ Expand_Attrs_CfgAttr(si.m_attrs);
Expand_Attrs(si.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
Expand_Type(crate, modstack, mod, si.m_type);
Expand_Attrs(si.m_attrs, AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
@@ -1155,11 +1250,22 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
)
Expand_Attrs(var.m_attrs, AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, var); });
}
- ),
- (Union,
+ // Handle cfg on variants (kinda hacky)
+ for(auto it = e.variants().begin(); it != e.variants().end(); ) {
+ if( it->m_name == "" ) {
+ it = e.variants().erase(it);
+ }
+ else {
+ ++ it;
+ }
+ }
+ }
+ TU_ARMA(Union, e) {
Expand_GenericParams(crate, modstack, mod, e.m_params);
- for(auto it = e.m_variants.begin(); it != e.m_variants.end(); ) {
+ for(auto it = e.m_variants.begin(); it != e.m_variants.end(); )
+ {
auto& si = *it;
+ Expand_Attrs_CfgAttr(si.m_attrs);
Expand_Attrs(si.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
Expand_Type(crate, modstack, mod, si.m_type);
Expand_Attrs(si.m_attrs, AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); });
@@ -1169,20 +1275,48 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
else
++it;
}
- ),
- (Trait,
+ }
+ TU_ARMA(Trait, e) {
Expand_GenericParams(crate, modstack, mod, e.params());
- for(auto& ti : e.items())
+ auto& trait_items = e.items();
+ for(size_t idx = 0; idx < trait_items.size(); idx ++)
{
+ auto& ti = trait_items[idx];
DEBUG(" - " << ti.name << " " << ti.data.tag_str());
- auto attrs = mv$(ti.data.attrs);
+ auto attrs = mv$(ti.attrs);
+ Expand_Attrs_CfgAttr(attrs);
Expand_Attrs(attrs, AttrStage::Pre, crate, AST::Path(), mod, ti.data);
TU_MATCH_DEF(AST::Item, (ti.data), (e),
(
- throw ::std::runtime_error("BUG: Unknown item type in impl block");
+ BUG(Span(), "Unknown item type in trait block - " << ti.data.tag_str());
),
(None, ),
+ (MacroInv,
+ if( e.name() != "" )
+ {
+ TRACE_FUNCTION_F("Macro invoke " << e.name());
+ // Move out of the module to avoid invalidation if a new macro invocation is added
+ auto mi_owned = mv$(e);
+
+ auto ttl = Expand_Macro(crate, modstack, mod, mi_owned);
+
+ if( ttl.get() )
+ {
+ // Re-parse tt
+ size_t insert_pos = idx+1;
+ while( ttl->lookahead(0) != TOK_EOF )
+ {
+ auto i = Parse_Trait_Item(*ttl);
+ trait_items.insert( trait_items.begin() + insert_pos, mv$(i) );
+ insert_pos ++;
+ }
+ // - Any new macro invocations ends up at the end of the list and handled
+ }
+ // Move back in (using the index, as the old pointer may be invalid)
+ trait_items[idx].data.as_MacroInv() = mv$(mi_owned);
+ }
+ ),
(Function,
Expand_GenericParams(crate, modstack, mod, e.params());
for(auto& arg : e.args()) {
@@ -1201,16 +1335,20 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
)
)
- Expand_Attrs(attrs, AttrStage::Post, crate, AST::Path(), mod, ti.data);
- if( ti.data.attrs.m_items.size() == 0 )
- ti.data.attrs = mv$(attrs);
+ {
+ auto& ti = trait_items[idx];
+
+ Expand_Attrs(attrs, AttrStage::Post, crate, AST::Path(), mod, ti.data);
+ if( ti.attrs.m_items.size() == 0 )
+ ti.attrs = mv$(attrs);
+ }
}
- ),
- (Type,
+ }
+ TU_ARMA(Type, e) {
Expand_Type(crate, modstack, mod, e.type());
- ),
+ }
- (Function,
+ TU_ARMA(Function, e) {
Expand_GenericParams(crate, modstack, mod, e.params());
for(auto& arg : e.args()) {
Expand_Pattern(crate, modstack, mod, arg.first, false);
@@ -1218,12 +1356,12 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
}
Expand_Type(crate, modstack, mod, e.rettype());
Expand_Expr(crate, modstack, e.code());
- ),
- (Static,
+ }
+ TU_ARMA(Static, e) {
Expand_Expr(crate, modstack, e.value());
Expand_Type(crate, modstack, mod, e.type());
- )
- )
+ }
+ }
Expand_Attrs(attrs, AttrStage::Post, crate, path, mod, dat);
{
@@ -1233,8 +1371,8 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::
i.data = mv$(dat);
}
// TODO: When would this _not_ be empty?
- if( i.data.attrs.m_items.size() == 0 )
- i.data.attrs = mv$(attrs);
+ if( i.attrs.m_items.size() == 0 )
+ i.attrs = mv$(attrs);
}
}
@@ -1285,6 +1423,7 @@ void Expand(::AST::Crate& crate)
auto modstack = LList<const ::AST::Module*>(nullptr, &crate.m_root_module);
// 1. Crate attributes
+ Expand_Attrs_CfgAttr(crate.m_attrs);
Expand_Attrs(crate.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate); });
// Insert magic for libstd/libcore
@@ -1297,7 +1436,7 @@ void Expand(::AST::Crate& crate)
crate.m_extern_crates.at("std").with_all_macros([&](const auto& name, const auto& mac) {
crate.m_root_module.add_macro_import( name, mac );
});
- crate.m_root_module.add_ext_crate(false, "std", "std", ::AST::AttributeList {});
+ crate.m_root_module.add_ext_crate(Span(), /*is_pub=*/false, "std", "std", /*attrs=*/{});
break;
case ::AST::Crate::LOAD_CORE:
if( crate.m_prelude_path == AST::Path() )
@@ -1305,7 +1444,7 @@ void Expand(::AST::Crate& crate)
crate.m_extern_crates.at("core").with_all_macros([&](const auto& name, const auto& mac) {
crate.m_root_module.add_macro_import( name, mac );
});
- crate.m_root_module.add_ext_crate(false, "core", "core", ::AST::AttributeList {});
+ crate.m_root_module.add_ext_crate(Span(), /*is_pub=*/false, "core", "core", /*attrs=*/{});
break;
case ::AST::Crate::LOAD_NONE:
break;
@@ -1315,7 +1454,7 @@ void Expand(::AST::Crate& crate)
for( auto& a : crate.m_attrs.m_items )
{
for( auto& d : g_decorators ) {
- if( d.first == a.name() && d.second->stage() == AttrStage::Pre ) {
+ if( a.name() == d.first && d.second->stage() == AttrStage::Pre ) {
//d.second->handle(a, crate, ::AST::Path(), crate.m_root_module, crate.m_root_module);
}
}
@@ -1324,6 +1463,8 @@ void Expand(::AST::Crate& crate)
// 3. Module tree
Expand_Mod(crate, modstack, ::AST::Path("",{}), crate.m_root_module);
+ //Expand_Attrs(crate.m_attrs, AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate); });
+
// Post-process
Expand_Mod_IndexAnon(crate, crate.m_root_module);
}
diff --git a/src/expand/proc_macro.cpp b/src/expand/proc_macro.cpp
index b61851b3..bc882d77 100644
--- a/src/expand/proc_macro.cpp
+++ b/src/expand/proc_macro.cpp
@@ -35,7 +35,7 @@ class Decorator_ProcMacroDerive:
{
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& attr, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override
+ void handle(const Span& sp, const AST::Attribute& attr, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item& i) const override
{
if( i.is_None() )
return;
@@ -49,13 +49,13 @@ public:
{
if( attr.items()[i].name() == "attributes") {
for(const auto& si : attr.items()[i].items()) {
- attributes.push_back( si.name() );
+ attributes.push_back( si.name().c_str() );
}
}
}
// TODO: Store attributes for later use.
- crate.m_proc_macros.push_back(AST::ProcMacroDef { FMT("derive#" << trait_name), path, mv$(attributes) });
+ crate.m_proc_macros.push_back(AST::ProcMacroDef { RcString::new_interned(FMT("derive#" << trait_name)), path, mv$(attributes) });
}
};
@@ -100,7 +100,7 @@ void Expand_ProcMacro(::AST::Crate& crate)
{
::AST::ExprNode_StructLiteral::t_values desc_vals;
// `name: "foo",`
- desc_vals.push_back({ {}, "name", NEWNODE(_String, desc.name) });
+ desc_vals.push_back({ {}, "name", NEWNODE(_String, desc.name.c_str()) });
// `handler`: ::foo
desc_vals.push_back({ {}, "handler", NEWNODE(_NamedValue, AST::Path(desc.path)) });
@@ -121,12 +121,12 @@ void Expand_ProcMacro(::AST::Crate& crate)
auto newmod = ::AST::Module { ::AST::Path("", { ::AST::PathNode("proc_macro#") }) };
// - TODO: These need to be loaded too.
// > They don't actually need to exist here, just be loaded (and use absolute paths)
- newmod.add_ext_crate(false, "proc_macro", "proc_macro", {});
+ newmod.add_ext_crate(Span(), false, "proc_macro", "proc_macro", {});
- newmod.add_item(false, "main", mv$(main_fn), {});
- newmod.add_item(false, "MACROS", mv$(tests_list), {});
+ newmod.add_item(Span(), false, "main", mv$(main_fn), {});
+ newmod.add_item(Span(), false, "MACROS", mv$(tests_list), {});
- crate.m_root_module.add_item(false, "proc_macro#", mv$(newmod), {});
+ crate.m_root_module.add_item(Span(), false, "proc_macro#", mv$(newmod), {});
crate.m_lang_items["mrustc-main"] = ::AST::Path("", { AST::PathNode("proc_macro#"), AST::PathNode("main") });
}
@@ -211,7 +211,7 @@ public:
void send_float(eCoreType ct, double v);
//void send_fragment();
- bool attr_is_used(const ::std::string& n) const {
+ bool attr_is_used(const RcString& n) const {
return ::std::find(m_proc_macro_desc.attributes.begin(), m_proc_macro_desc.attributes.end(), n) != m_proc_macro_desc.attributes.end();
}
@@ -229,8 +229,9 @@ private:
uint64_t recv_v128u();
};
-ProcMacroInv ProcMacro_Invoke_int(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path)
+ProcMacroInv ProcMacro_Invoke_int(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path)
{
+ TRACE_FUNCTION_F(mac_path);
// 1. Locate macro in HIR list
const auto& crate_name = mac_path.front();
const auto& ext_crate = crate.m_extern_crates.at(crate_name);
@@ -259,7 +260,8 @@ ProcMacroInv ProcMacro_Invoke_int(const Span& sp, const ::AST::Crate& crate, con
}
// 2. Get executable and macro name
- ::std::string proc_macro_exe_name = (ext_crate.m_filename + "-plugin");
+ // TODO: Windows will have .exe?
+ ::std::string proc_macro_exe_name = ext_crate.m_filename;
// 3. Create ProcMacroInv
return ProcMacroInv(sp, proc_macro_exe_name.c_str(), *pmp);
@@ -516,6 +518,9 @@ namespace {
TODO(sp, "");
m_pmi.send_symbol("}");
}
+ void visit(::AST::ExprNode_Try& node) {
+ TODO(sp, "ExprNode_Try");
+ }
void visit(::AST::ExprNode_Macro& node) {
TODO(sp, "ExprNode_Macro");
}
@@ -606,12 +611,27 @@ namespace {
TODO(sp, "ExprNode_UniOp");
}
+ void visit_top_attrs(slice<const ::AST::Attribute>& attrs)
+ {
+ for(const auto& a : attrs)
+ {
+ if( m_pmi.attr_is_used(a.name()) )
+ {
+ DEBUG("Send " << a);
+ m_pmi.send_symbol("#");
+ m_pmi.send_symbol("[");
+ this->visit_meta_item(a);
+ m_pmi.send_symbol("]");
+ }
+ }
+ }
void visit_attrs(const ::AST::AttributeList& attrs)
{
for(const auto& a : attrs.m_items)
{
if( m_pmi.attr_is_used(a.name()) )
{
+ DEBUG("Send " << a);
m_pmi.send_symbol("#");
m_pmi.send_symbol("[");
this->visit_meta_item(a);
@@ -704,12 +724,15 @@ namespace {
{
this->visit_attrs(v.m_attrs);
m_pmi.send_ident(v.m_name.c_str());
- TU_MATCH(AST::EnumVariantData, (v.m_data), (e),
- (Value,
- m_pmi.send_symbol("=");
- this->visit_nodes(e.m_value);
- ),
- (Tuple,
+ TU_MATCH_HDRA( (v.m_data), { )
+ TU_ARMA(Value, e) {
+ if( e.m_value )
+ {
+ m_pmi.send_symbol("=");
+ this->visit_nodes(e.m_value);
+ }
+ }
+ TU_ARMA(Tuple, e) {
m_pmi.send_symbol("(");
for(const auto& st : e.m_sub_types)
{
@@ -718,8 +741,8 @@ namespace {
m_pmi.send_symbol(",");
}
m_pmi.send_symbol(")");
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, e) {
m_pmi.send_symbol("{");
for(const auto& f : e.m_fields)
{
@@ -730,8 +753,8 @@ namespace {
m_pmi.send_symbol(",");
}
m_pmi.send_symbol("}");
- )
- )
+ }
+ }
m_pmi.send_symbol(",");
}
m_pmi.send_symbol("}");
@@ -742,38 +765,45 @@ namespace {
}
};
}
-::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& item_name, const ::AST::Struct& i)
+::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, slice<const AST::Attribute> attrs, const ::std::string& item_name, const ::AST::Struct& i)
{
// 1. Create ProcMacroInv instance
auto pmi = ProcMacro_Invoke_int(sp, crate, mac_path);
if( !pmi.check_good() )
return ::std::unique_ptr<TokenStream>();
// 2. Feed item as a token stream.
- Visitor(sp, pmi).visit_struct(item_name, false, i);
+ // TODO: Get attributes from the caller, filter based on the macro's options then pass to the child.
+ Visitor v(sp, pmi);
+ v.visit_top_attrs(attrs);
+ v.visit_struct(item_name, false, i);
pmi.send_done();
// 3. Return boxed invocation instance
return box$(pmi);
}
-::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& item_name, const ::AST::Enum& i)
+::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, slice<const AST::Attribute> attrs, const ::std::string& item_name, const ::AST::Enum& i)
{
// 1. Create ProcMacroInv instance
auto pmi = ProcMacro_Invoke_int(sp, crate, mac_path);
if( !pmi.check_good() )
return ::std::unique_ptr<TokenStream>();
// 2. Feed item as a token stream.
- Visitor(sp, pmi).visit_enum(item_name, false, i);
+ Visitor v(sp, pmi);
+ v.visit_top_attrs(attrs);
+ v.visit_enum(item_name, false, i);
pmi.send_done();
// 3. Return boxed invocation instance
return box$(pmi);
}
-::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& item_name, const ::AST::Union& i)
+::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, slice<const AST::Attribute> attrs, const ::std::string& item_name, const ::AST::Union& i)
{
// 1. Create ProcMacroInv instance
auto pmi = ProcMacro_Invoke_int(sp, crate, mac_path);
if( !pmi.check_good() )
return ::std::unique_ptr<TokenStream>();
// 2. Feed item as a token stream.
- Visitor(sp, pmi).visit_union(item_name, false, i);
+ Visitor v(sp, pmi);
+ v.visit_top_attrs(attrs);
+ v.visit_union(item_name, false, i);
pmi.send_done();
// 3. Return boxed invocation instance
return box$(pmi);
@@ -813,11 +843,12 @@ ProcMacroInv::ProcMacroInv(const Span& sp, const char* executable, const ::HIR::
posix_spawn_file_actions_addclose(&file_actions, stdout_pipes[1]);
char* argv[3] = { const_cast<char*>(executable), const_cast<char*>(proc_macro_desc.name.c_str()), nullptr };
+ DEBUG(argv[0] << " " << argv[1]);
//char* envp[] = { nullptr };
int rv = posix_spawn(&this->child_pid, executable, &file_actions, nullptr, argv, environ);
if( rv != 0 )
{
- BUG(sp, "Error in posix_spawn - " << rv);
+ BUG(sp, "Error in posix_spawn - " << rv << " - can't start `" << executable << "`");
}
posix_spawn_file_actions_destroy(&file_actions);
@@ -1015,11 +1046,11 @@ Token ProcMacroInv::realGetToken_() {
auto t = Lex_FindReservedWord(val);
if( t != TOK_NULL )
return t;
- return Token(TOK_IDENT, mv$(val));
+ return Token(TOK_IDENT, RcString::new_interned(val));
}
case TokenClass::Lifetime: {
auto val = this->recv_bytes();
- return Token(TOK_LIFETIME, mv$(val));
+ return Token(TOK_LIFETIME, RcString::new_interned(val));
}
case TokenClass::String: {
auto val = this->recv_bytes();
diff --git a/src/expand/proc_macro.hpp b/src/expand/proc_macro.hpp
index 8c5b71c7..a4a190e8 100644
--- a/src/expand/proc_macro.hpp
+++ b/src/expand/proc_macro.hpp
@@ -8,8 +8,8 @@
#pragma once
#include <parse/tokenstream.hpp>
-extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& name, const ::AST::Struct& i);
-extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& name, const ::AST::Enum& i);
-extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& name, const ::AST::Union& i);
-//extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const TokenStream& tt);
+extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, slice<const AST::Attribute> attrs, const ::std::string& name, const ::AST::Struct& i);
+extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, slice<const AST::Attribute> attrs, const ::std::string& name, const ::AST::Enum& i);
+extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, slice<const AST::Attribute> attrs, const ::std::string& name, const ::AST::Union& i);
+//extern ::std::unique_ptr<TokenStream> ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<RcString>& mac_path, const TokenStream& tt);
diff --git a/src/expand/rustc_diagnostics.cpp b/src/expand/rustc_diagnostics.cpp
index 0e95bb7c..b36bf586 100644
--- a/src/expand/rustc_diagnostics.cpp
+++ b/src/expand/rustc_diagnostics.cpp
@@ -13,7 +13,7 @@
class CExpanderRegisterDiagnostic:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
return box$( TTStreamO(sp, TokenTree()) );
}
@@ -21,7 +21,7 @@ class CExpanderRegisterDiagnostic:
class CExpanderDiagnosticUsed:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
return box$( TTStreamO(sp, TokenTree()) );
}
@@ -29,10 +29,8 @@ class CExpanderDiagnosticUsed:
class CExpanderBuildDiagnosticArray:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
- if( ident != "" )
- ERROR(sp, E0000, "__build_diagnostic_array! doesn't take an ident");
auto lex = TTStream(sp, tt);
Token tok;
@@ -41,7 +39,7 @@ class CExpanderBuildDiagnosticArray:
//auto crate_name = mv$(tok.str());
GET_CHECK_TOK(tok, lex, TOK_COMMA);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto item_name = mv$(tok.str());
+ auto item_name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_EOF);
::std::vector<TokenTree> toks;
@@ -51,9 +49,9 @@ class CExpanderBuildDiagnosticArray:
toks.push_back( TOK_COLON );
toks.push_back( TOK_SQUARE_OPEN );
toks.push_back( TOK_PAREN_OPEN );
- toks.push_back( TOK_AMP ); toks.push_back( Token(TOK_LIFETIME, "static") ); toks.push_back( Token(TOK_IDENT, "str") );
+ toks.push_back( TOK_AMP ); toks.push_back( Token(TOK_LIFETIME, RcString::new_interned("static")) ); toks.push_back( Token(TOK_IDENT, RcString::new_interned("str")) );
toks.push_back( TOK_COMMA );
- toks.push_back( TOK_AMP ); toks.push_back( Token(TOK_LIFETIME, "static") ); toks.push_back( Token(TOK_IDENT, "str") );
+ toks.push_back( TOK_AMP ); toks.push_back( Token(TOK_LIFETIME, RcString::new_interned("static")) ); toks.push_back( Token(TOK_IDENT, RcString::new_interned("str")) );
toks.push_back( TOK_PAREN_CLOSE );
toks.push_back( TOK_SEMICOLON );
toks.push_back( Token(static_cast<uint64_t>(0), CORETYPE_UINT) );
diff --git a/src/expand/std_prelude.cpp b/src/expand/std_prelude.cpp
index d6022959..58b56cf7 100644
--- a/src/expand/std_prelude.cpp
+++ b/src/expand/std_prelude.cpp
@@ -47,7 +47,7 @@ class Decorator_NoPrelude:
public:
AttrStage stage() const override { return AttrStage::Pre; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
if( i.is_Module() ) {
i.as_Module().m_insert_prelude = false;
}
@@ -63,14 +63,14 @@ class Decorator_PreludeImport:
public:
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
if( i.is_Use() ) {
- const auto& p = i.as_Use().path;
+ const auto& p = i.as_Use().entries.front().path;
// TODO: Ensure that this statement is a glob (has a name of "")
crate.m_prelude_path = AST::Path(p);
}
else {
- ERROR(sp, E0000, "Invalid use of #[no_prelude] on non-module");
+ ERROR(sp, E0000, "Invalid use of #[prelude_import] on non-module");
}
}
};
diff --git a/src/expand/stringify.cpp b/src/expand/stringify.cpp
index 06c65c02..561177ef 100644
--- a/src/expand/stringify.cpp
+++ b/src/expand/stringify.cpp
@@ -12,7 +12,7 @@
class CExpander:
public ExpandProcMacro
{
- ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
+ ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override
{
Token tok;
::std::string rv;
@@ -22,9 +22,13 @@ class CExpander:
{
if(!rv.empty())
rv += " ";
+ DEBUG(" += " << tok);
rv += tok.to_str();
}
+ // TODO: Strip out any `{...}` sequences that aren't from nested
+ // strings.
+
return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, mv$(rv)))) );
}
};
diff --git a/src/expand/test.cpp b/src/expand/test.cpp
index 9497c692..eec1414d 100644
--- a/src/expand/test.cpp
+++ b/src/expand/test.cpp
@@ -14,7 +14,7 @@ class CTestHandler:
{
AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
if( ! i.is_Function() ) {
ERROR(sp, E0000, "#[test] can only be put on functions - found on " << i.tag_str());
}
@@ -25,7 +25,7 @@ class CTestHandler:
for(const auto& node : path.nodes())
{
td.name += "::";
- td.name += node.name();
+ td.name += node.name().c_str();
}
td.path = ::AST::Path(path);
@@ -40,15 +40,16 @@ class CTestHandler:
class CTestHandler_SP:
public ExpandDecorator
{
- AttrStage stage() const override { return AttrStage::Pre; }
+ AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
if( ! i.is_Function() ) {
ERROR(sp, E0000, "#[should_panic] can only be put on functions - found on " << i.tag_str());
}
if( crate.m_test_harness )
{
+ // TODO: If this test doesn't yet exist, create it (but as disabled)?
for(auto& td : crate.m_tests)
{
if( td.path != path )
@@ -73,11 +74,11 @@ class CTestHandler_SP:
class CTestHandler_Ignore:
public ExpandDecorator
{
- AttrStage stage() const override { return AttrStage::Pre; }
+ AttrStage stage() const override { return AttrStage::Post; }
- void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
+ void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const override {
if( ! i.is_Function() ) {
- ERROR(sp, E0000, "#[should_panic] can only be put on functions - found on " << i.tag_str());
+ ERROR(sp, E0000, "#[ignore] can only be put on functions - found on " << i.tag_str());
}
if( crate.m_test_harness )
diff --git a/src/expand/test_harness.cpp b/src/expand/test_harness.cpp
index 204ca75e..456f90e4 100644
--- a/src/expand/test_harness.cpp
+++ b/src/expand/test_harness.cpp
@@ -81,13 +81,18 @@ void Expand_TestHarness(::AST::Crate& crate)
}
desc_vals.push_back({ {}, "should_panic", mv$(should_panic_val) });
}
+ if( TARGETVER_1_29 )
+ {
+ // TODO: Get this from attributes
+ desc_vals.push_back({ {}, "allow_fail", NEWNODE(_Bool, false) });
+ }
auto desc_expr = NEWNODE(_StructLiteral, ::AST::Path("test", { ::AST::PathNode("TestDesc")}), nullptr, mv$(desc_vals));
::AST::ExprNode_StructLiteral::t_values descandfn_vals;
- descandfn_vals.push_back({ {}, ::std::string("desc"), mv$(desc_expr) });
+ descandfn_vals.push_back({ {}, RcString::new_interned("desc"), mv$(desc_expr) });
auto test_type_var_name = test.is_benchmark ? "StaticBenchFn" : "StaticTestFn";
- descandfn_vals.push_back({ {}, ::std::string("testfn"), NEWNODE(_CallPath,
+ descandfn_vals.push_back({ {}, RcString::new_interned("testfn"), NEWNODE(_CallPath,
::AST::Path("test", { ::AST::PathNode(test_type_var_name) }),
::make_vec1( NEWNODE(_NamedValue, AST::Path(test.path)) )
) });
@@ -109,12 +114,12 @@ void Expand_TestHarness(::AST::Crate& crate)
auto newmod = ::AST::Module { ::AST::Path("", { ::AST::PathNode("test#") }) };
// - TODO: These need to be loaded too.
// > They don't actually need to exist here, just be loaded (and use absolute paths)
- newmod.add_ext_crate(false, "std", "std", {});
- newmod.add_ext_crate(false, "test", "test", {});
+ newmod.add_ext_crate(Span(), false, "std", "std", {});
+ newmod.add_ext_crate(Span(), false, "test", "test", {});
- newmod.add_item(false, "main", mv$(main_fn), {});
- newmod.add_item(false, "TESTS", mv$(tests_list), {});
+ newmod.add_item(Span(), false, "main", mv$(main_fn), {});
+ newmod.add_item(Span(), false, "TESTS", mv$(tests_list), {});
- crate.m_root_module.add_item(false, "test#", mv$(newmod), {});
+ crate.m_root_module.add_item(Span(), false, "test#", mv$(newmod), {});
crate.m_lang_items["mrustc-main"] = ::AST::Path("", { AST::PathNode("test#"), AST::PathNode("main") });
}
diff --git a/src/hir/crate_post_load.cpp b/src/hir/crate_post_load.cpp
index 81c5b029..a0733987 100644
--- a/src/hir/crate_post_load.cpp
+++ b/src/hir/crate_post_load.cpp
@@ -9,7 +9,7 @@
#include <macro_rules/macro_rules.hpp> // Used to update the crate name
-void HIR::Crate::post_load_update(const ::std::string& name)
+void HIR::Crate::post_load_update(const RcString& name)
{
// TODO: Do a pass across m_hir that
// 1. Updates all absolute paths with the crate name
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp
index afce2fe4..23b8fdf1 100644
--- a/src/hir/deserialise.cpp
+++ b/src/hir/deserialise.cpp
@@ -5,6 +5,8 @@
* hir/serialise.cpp
* - HIR (De)Serialisation for crate metadata
*/
+// TODO: Have an environment variable that controls if debug is enabled here.
+#define DEBUG_EXTRA_ENABLE && false
//#define DISABLE_DEBUG // Disable debug for this function - too hot
#include "hir.hpp"
#include "main_bindings.hpp"
@@ -22,13 +24,14 @@
class HirDeserialiser
{
- ::std::string m_crate_name;
+ RcString m_crate_name;
::HIR::serialise::Reader& m_in;
public:
HirDeserialiser(::HIR::serialise::Reader& in):
m_in(in)
{}
+ RcString read_istring() { return m_in.read_istring(); }
::std::string read_string() { return m_in.read_string(); }
bool read_bool() { return m_in.read_bool(); }
size_t deserialise_count() { return m_in.read_count(); }
@@ -78,10 +81,69 @@
return rv;
}
+ template<typename V>
+ ::std::map< RcString,V> deserialise_istrmap()
+ {
+ TRACE_FUNCTION_F("<" << typeid(V).name() << ">");
+ size_t n = m_in.read_count();
+ ::std::map< RcString, V> rv;
+ //rv.reserve(n);
+ for(size_t i = 0; i < n; i ++)
+ {
+ auto s = m_in.read_istring();
+ rv.insert( ::std::make_pair( mv$(s), D<V>::des(*this) ) );
+ }
+ return rv;
+ }
+ template<typename V>
+ ::std::unordered_map< RcString,V> deserialise_istrumap()
+ {
+ TRACE_FUNCTION_F("<" << typeid(V).name() << ">");
+ size_t n = m_in.read_count();
+ ::std::unordered_map<RcString, V> rv;
+ //rv.reserve(n);
+ for(size_t i = 0; i < n; i ++)
+ {
+ auto s = m_in.read_istring();
+ DEBUG("- " << s);
+ rv.insert( ::std::make_pair( mv$(s), D<V>::des(*this) ) );
+ }
+ return rv;
+ }
+ template<typename V>
+ ::std::unordered_multimap<RcString,V> deserialise_istrummap()
+ {
+ TRACE_FUNCTION_F("<" << typeid(V).name() << ">");
+ size_t n = m_in.read_count();
+ ::std::unordered_multimap<RcString, V> rv;
+ //rv.reserve(n);
+ for(size_t i = 0; i < n; i ++)
+ {
+ auto s = m_in.read_istring();
+ DEBUG("- " << s);
+ rv.insert( ::std::make_pair( mv$(s), D<V>::des(*this) ) );
+ }
+ return rv;
+ }
+ template<typename V>
+ ::std::map< ::HIR::SimplePath,V> deserialise_pathmap()
+ {
+ TRACE_FUNCTION_F("<" << typeid(V).name() << ">");
+ size_t n = m_in.read_count();
+ ::std::map< ::HIR::SimplePath, V> rv;
+ //rv.reserve(n);
+ for(size_t i = 0; i < n; i ++)
+ {
+ auto s = deserialise_simplepath();
+ rv.insert( ::std::make_pair( mv$(s), D<V>::des(*this) ) );
+ }
+ return rv;
+ }
+
template<typename T>
::std::vector<T> deserialise_vec()
{
- TRACE_FUNCTION_F("<" << typeid(T).name() << ">");
+ TRACE_FUNCTION_FR("<" << typeid(T).name() << ">", m_in.get_pos());
size_t n = m_in.read_count();
DEBUG("n = " << n);
::std::vector<T> rv;
@@ -101,10 +163,14 @@
rv.push_back( cb() );
return rv;
}
+ ::HIR::Publicity deserialise_pub()
+ {
+ return (m_in.read_bool() ? ::HIR::Publicity::new_global() : ::HIR::Publicity::new_none());
+ }
template<typename T>
::HIR::VisEnt<T> deserialise_visent()
{
- return ::HIR::VisEnt<T> { m_in.read_bool(), D<T>::des(*this) };
+ return ::HIR::VisEnt<T> { deserialise_pub(), D<T>::des(*this) };
}
template<typename T>
@@ -113,6 +179,7 @@
}
+ ::HIR::LifetimeDef deserialise_lifetimedef();
::HIR::LifetimeRef deserialise_lifetimeref();
::HIR::TypeRef deserialise_type();
::HIR::SimplePath deserialise_simplepath();
@@ -133,7 +200,7 @@
{
::HIR::ProcMacro pm;
TRACE_FUNCTION_FR("", "ProcMacro { " << pm.name << ", " << pm.path << ", [" << pm.attributes << "]}");
- pm.name = m_in.read_string();
+ pm.name = m_in.read_istring();
pm.path = deserialise_simplepath();
pm.attributes = deserialise_vec< ::std::string>();
DEBUG("pm = ProcMacro { " << pm.name << ", " << pm.path << ", [" << pm.attributes << "]}");
@@ -151,17 +218,17 @@
size_t method_count = m_in.read_count();
for(size_t i = 0; i < method_count; i ++)
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
rv.m_methods.insert( ::std::make_pair( mv$(name), ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> {
- m_in.read_bool(), m_in.read_bool(), deserialise_function()
+ deserialise_pub(), m_in.read_bool(), deserialise_function()
} ) );
}
size_t const_count = m_in.read_count();
for(size_t i = 0; i < const_count; i ++)
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
rv.m_constants.insert( ::std::make_pair( mv$(name), ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> {
- m_in.read_bool(), m_in.read_bool(), deserialise_constant()
+ deserialise_pub(), m_in.read_bool(), deserialise_constant()
} ) );
}
// m_src_module doesn't matter after typeck
@@ -180,7 +247,7 @@
size_t method_count = m_in.read_count();
for(size_t i = 0; i < method_count; i ++)
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
auto is_spec = m_in.read_bool();
rv.m_methods.insert( ::std::make_pair( mv$(name), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> {
is_spec, deserialise_function()
@@ -189,7 +256,7 @@
size_t const_count = m_in.read_count();
for(size_t i = 0; i < const_count; i ++)
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
auto is_spec = m_in.read_bool();
rv.m_constants.insert( ::std::make_pair( mv$(name), ::HIR::TraitImpl::ImplEnt< ::HIR::Constant> {
is_spec, deserialise_constant()
@@ -198,7 +265,7 @@
size_t static_count = m_in.read_count();
for(size_t i = 0; i < static_count; i ++)
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
auto is_spec = m_in.read_bool();
rv.m_statics.insert( ::std::make_pair( mv$(name), ::HIR::TraitImpl::ImplEnt< ::HIR::Static> {
is_spec, deserialise_static()
@@ -207,7 +274,7 @@
size_t type_count = m_in.read_count();
for(size_t i = 0; i < type_count; i ++)
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
auto is_spec = m_in.read_bool();
rv.m_types.insert( ::std::make_pair( mv$(name), ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> {
is_spec, deserialise_type()
@@ -236,16 +303,55 @@
// NOTE: This is set after loading.
//rv.m_exported = true;
rv.m_rules = deserialise_vec_c< ::MacroRulesArm>( [&](){ return deserialise_macrorulesarm(); });
- rv.m_source_crate = m_in.read_string();
+ rv.m_source_crate = m_in.read_istring();
if(rv.m_source_crate == "")
{
- assert(!m_crate_name.empty());
+ assert(m_crate_name != "");
rv.m_source_crate = m_crate_name;
}
return rv;
}
+ ::SimplePatIfCheck deserialise_simplepatifcheck() {
+ return ::SimplePatIfCheck {
+ static_cast<::MacroPatEnt::Type>(m_in.read_tag()),
+ deserialise_token()
+ };
+ }
+ ::SimplePatEnt deserialise_simplepatent() {
+ auto tag = static_cast< ::SimplePatEnt::Tag>( m_in.read_tag() );
+ switch(tag)
+ {
+ case ::SimplePatEnt::TAG_End:
+ return ::SimplePatEnt::make_End({});
+ case ::SimplePatEnt::TAG_LoopStart:
+ return ::SimplePatEnt::make_LoopStart({});
+ case ::SimplePatEnt::TAG_LoopNext:
+ return ::SimplePatEnt::make_LoopNext({});
+ case ::SimplePatEnt::TAG_LoopEnd:
+ return ::SimplePatEnt::make_LoopEnd({});
+ case ::SimplePatEnt::TAG_Jump:
+ return ::SimplePatEnt::make_Jump({ m_in.read_count() });
+ case ::SimplePatEnt::TAG_ExpectTok:
+ return SimplePatEnt::make_ExpectTok({
+ deserialise_token()
+ });
+ case ::SimplePatEnt::TAG_ExpectPat:
+ return SimplePatEnt::make_ExpectPat({
+ static_cast<::MacroPatEnt::Type>(m_in.read_tag()),
+ static_cast<unsigned>(m_in.read_count())
+ });
+ case SimplePatEnt::TAG_If:
+ return SimplePatEnt::make_If({
+ m_in.read_bool(),
+ m_in.read_count(),
+ deserialise_vec_c< SimplePatIfCheck>([&](){ return deserialise_simplepatifcheck(); })
+ });
+ default:
+ BUG(Span(), "Bad tag for MacroPatEnt - #" << static_cast<int>(tag));
+ }
+ }
::MacroPatEnt deserialise_macropatent() {
- auto s = m_in.read_string();
+ auto s = m_in.read_istring();
auto n = static_cast<unsigned int>(m_in.read_count());
auto type = static_cast< ::MacroPatEnt::Type>(m_in.read_tag());
::MacroPatEnt rv { mv$(s), mv$(n), mv$(type) };
@@ -268,21 +374,22 @@
case ::MacroPatEnt::PAT_BLOCK:
case ::MacroPatEnt::PAT_META:
case ::MacroPatEnt::PAT_ITEM:
+ case ::MacroPatEnt::PAT_VIS:
break;
default:
- throw "";
+ BUG(Span(), "Bad tag for MacroPatEnt - #" << static_cast<int>(rv.type) << " " << rv.type);
}
return rv;
}
::MacroRulesArm deserialise_macrorulesarm() {
::MacroRulesArm rv;
- rv.m_param_names = deserialise_vec< ::std::string>();
- rv.m_pattern = deserialise_vec_c< ::MacroPatEnt>( [&](){ return deserialise_macropatent(); } );
+ rv.m_param_names = deserialise_vec<RcString>();
+ rv.m_pattern = deserialise_vec_c< ::SimplePatEnt>( [&](){ return deserialise_simplepatent(); } );
rv.m_contents = deserialise_vec_c< ::MacroExpansionEnt>( [&](){ return deserialise_macroexpansionent(); } );
return rv;
}
::MacroExpansionEnt deserialise_macroexpansionent() {
- switch(m_in.read_tag())
+ switch(auto tag = m_in.read_tag())
{
case 0:
return ::MacroExpansionEnt( deserialise_token() );
@@ -305,7 +412,7 @@
});
}
default:
- throw "";
+ BUG(Span(), "Bad tag for MacroExpansionEnt - " << tag);
}
}
@@ -322,6 +429,8 @@
return ::Token::Data::make_None({});
case ::Token::Data::TAG_String:
return ::Token::Data::make_String( m_in.read_string() );
+ case ::Token::Data::TAG_IString:
+ return ::Token::Data::make_IString( m_in.read_istring() );
case ::Token::Data::TAG_Integer: {
auto dty = static_cast<eCoreType>(m_in.read_tag());
return ::Token::Data::make_Integer({ dty, m_in.read_u64c() });
@@ -331,7 +440,7 @@
return ::Token::Data::make_Float({ dty, m_in.read_double() });
}
default:
- throw ::std::runtime_error(FMT("Invalid Token data tag - " << tag));
+ BUG(Span(), "Bad tag for Token::Data - " << static_cast<int>(tag));
}
}
@@ -362,7 +471,7 @@
case ::MIR::Param::TAG_LValue: return deserialise_mir_lvalue();
case ::MIR::Param::TAG_Constant: return deserialise_mir_constant();
default:
- throw ::std::runtime_error(FMT("Invalid MIR LValue tag - " << tag));
+ BUG(Span(), "Bad tag for MIR::Param - " << tag);
}
}
::MIR::LValue deserialise_mir_lvalue() {
@@ -371,38 +480,21 @@
rv = deserialise_mir_lvalue_();
return rv;
}
+ ::MIR::LValue::Wrapper deserialise_mir_lvalue_wrapper()
+ {
+ return ::MIR::LValue::Wrapper::from_inner(m_in.read_count());
+ }
::MIR::LValue deserialise_mir_lvalue_()
{
- switch(auto tag = m_in.read_tag())
- {
- #define _(x, ...) case ::MIR::LValue::TAG_##x: return ::MIR::LValue::make_##x( __VA_ARGS__ );
- _(Return, {})
- _(Argument, { static_cast<unsigned int>(m_in.read_count()) } )
- _(Local, static_cast<unsigned int>(m_in.read_count()) )
- _(Static, deserialise_path() )
- _(Field, {
- box$( deserialise_mir_lvalue() ),
- static_cast<unsigned int>(m_in.read_count())
- } )
- _(Deref, { box$( deserialise_mir_lvalue() ) })
- _(Index, {
- box$( deserialise_mir_lvalue() ),
- box$( deserialise_mir_lvalue() )
- } )
- _(Downcast, {
- box$( deserialise_mir_lvalue() ),
- static_cast<unsigned int>(m_in.read_count())
- } )
- #undef _
- default:
- throw ::std::runtime_error(FMT("Invalid MIR LValue tag - " << tag));
- }
+ auto root_v = m_in.read_count();
+ auto root = (root_v == 3 ? ::MIR::LValue::Storage::new_Static(deserialise_path()) : ::MIR::LValue::Storage::from_inner(root_v));
+ return ::MIR::LValue( mv$(root), deserialise_vec<::MIR::LValue::Wrapper>() );
}
::MIR::RValue deserialise_mir_rvalue()
{
TRACE_FUNCTION;
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
#define _(x, ...) case ::MIR::RValue::TAG_##x: return ::MIR::RValue::make_##x( __VA_ARGS__ );
_(Use, deserialise_mir_lvalue() )
@@ -456,14 +548,14 @@
})
#undef _
default:
- throw "";
+ BUG(Span(), "Bad tag for MIR::RValue - " << tag);
}
}
::MIR::Constant deserialise_mir_constant()
{
TRACE_FUNCTION;
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
#define _(x, ...) case ::MIR::Constant::TAG_##x: DEBUG("- " #x); return ::MIR::Constant::make_##x( __VA_ARGS__ );
_(Int, {
@@ -488,17 +580,24 @@
return ::MIR::Constant::make_Bytes( mv$(bytes) );
}
_(StaticString, m_in.read_string() )
- _(Const, { deserialise_path() } )
- _(ItemAddr, deserialise_path() )
+ _(Const, { box$(deserialise_path()) } )
+ _(ItemAddr, box$(deserialise_path()) )
#undef _
default:
- throw "";
+ BUG(Span(), "Bad tag for MIR::Const - " << tag);
}
}
+ ::HIR::ExternType deserialise_externtype()
+ {
+ return ::HIR::ExternType {
+ deserialise_markings()
+ };
+ }
+
::HIR::TypeItem deserialise_typeitem()
{
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
case 0: {
auto spath = deserialise_simplepath();
@@ -517,13 +616,15 @@
return ::HIR::TypeItem( deserialise_trait() );
case 6:
return ::HIR::TypeItem( deserialise_union() );
+ case 7:
+ return ::HIR::TypeItem( deserialise_externtype() );
default:
- throw "";
+ BUG(Span(), "Bad tag for HIR::TypeItem - " << tag);
}
}
::HIR::ValueItem deserialise_valueitem()
{
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
case 0: {
auto spath = deserialise_simplepath();
@@ -541,7 +642,7 @@
case 5:
return ::HIR::ValueItem::make_StructConstructor({ deserialise_simplepath() });
default:
- throw "";
+ BUG(Span(), "Bad tag for HIR::ValueItem - " << tag);
}
}
@@ -655,7 +756,7 @@
::HIR::TraitValueItem deserialise_traitvalueitem()
{
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
#define _(x, ...) case ::HIR::TraitValueItem::TAG_##x: DEBUG("- " #x); return ::HIR::TraitValueItem::make_##x( __VA_ARGS__ ); break;
_(Constant, deserialise_constant() )
@@ -663,15 +764,14 @@
_(Function, deserialise_function() )
#undef _
default:
- DEBUG("Invalid TraitValueItem tag");
- throw "";
+ BUG(Span(), "Bad tag for HIR::TraitValueItem - " << tag);
}
}
::HIR::AssociatedType deserialise_associatedtype()
{
return ::HIR::AssociatedType {
m_in.read_bool(),
- "", // TODO: Better lifetime type
+ deserialise_lifetimeref(),
deserialise_vec< ::HIR::TraitPath>(),
deserialise_type()
};
@@ -685,6 +785,9 @@
DEF_D( ::std::string,
return d.read_string(); );
template<>
+ DEF_D( RcString,
+ return d.read_istring(); );
+ template<>
DEF_D( bool,
return d.read_bool(); );
@@ -692,6 +795,9 @@
DEF_D( ::std::unique_ptr<T>,
return d.deserialise_ptr<T>(); )
+ template<typename T>
+ DEF_D( ::std::vector<T>,
+ return d.deserialise_vec<T>(); )
template<typename T, typename U>
struct D< ::std::pair<T,U> > { static ::std::pair<T,U> des(HirDeserialiser& d) {
auto a = D<T>::des(d);
@@ -702,6 +808,8 @@
DEF_D( ::HIR::VisEnt<T>,
return d.deserialise_visent<T>(); )
+ template<> DEF_D( ::HIR::LifetimeDef, return d.deserialise_lifetimedef(); )
+ template<> DEF_D( ::HIR::LifetimeRef, return d.deserialise_lifetimeref(); )
template<> DEF_D( ::HIR::TypeRef, return d.deserialise_type(); )
template<> DEF_D( ::HIR::SimplePath, return d.deserialise_simplepath(); )
template<> DEF_D( ::HIR::GenericPath, return d.deserialise_genericpath(); )
@@ -721,17 +829,40 @@
template<> DEF_D( ::HIR::TraitValueItem, return d.deserialise_traitvalueitem(); )
template<> DEF_D( ::MIR::Param, return d.deserialise_mir_param(); )
+ template<> DEF_D( ::MIR::LValue::Wrapper, return d.deserialise_mir_lvalue_wrapper(); )
template<> DEF_D( ::MIR::LValue, return d.deserialise_mir_lvalue(); )
template<> DEF_D( ::MIR::Statement, return d.deserialise_mir_statement(); )
template<> DEF_D( ::MIR::BasicBlock, return d.deserialise_mir_basicblock(); )
template<> DEF_D( ::HIR::ProcMacro, return d.deserialise_procmacro(); )
template<> DEF_D( ::HIR::TypeImpl, return d.deserialise_typeimpl(); )
+ template<> DEF_D( ::HIR::TraitImpl, return d.deserialise_traitimpl(); )
+ template<> DEF_D( ::HIR::MarkerImpl, return d.deserialise_markerimpl(); )
template<> DEF_D( ::MacroRulesPtr, return d.deserialise_macrorulesptr(); )
template<> DEF_D( unsigned int, return static_cast<unsigned int>(d.deserialise_count()); )
+ template<typename T>
+ DEF_D( ::HIR::Crate::ImplGroup<T>,
+ ::HIR::Crate::ImplGroup<T> rv;
+ rv.named = d.deserialise_pathmap< ::std::vector<::std::unique_ptr<T> > >();
+ rv.non_named = d.deserialise_vec< ::std::unique_ptr<T> >();
+ rv.generic = d.deserialise_vec< ::std::unique_ptr<T> >();
+ return rv;
+ )
+ template<>
+ DEF_D( ::HIR::Crate::MacroImport,
+ ::HIR::Crate::MacroImport rv;
+ rv.path = d.deserialise_simplepath();
+ return rv;
+ )
template<> DEF_D( ::HIR::ExternLibrary, return d.deserialise_extlib(); )
+ ::HIR::LifetimeDef HirDeserialiser::deserialise_lifetimedef()
+ {
+ ::HIR::LifetimeDef rv;
+ rv.m_name = m_in.read_istring();
+ return rv;
+ }
::HIR::LifetimeRef HirDeserialiser::deserialise_lifetimeref()
{
::HIR::LifetimeRef rv;
@@ -756,7 +887,7 @@
{}
})
_(Generic, {
- m_in.read_string(),
+ m_in.read_istring(),
m_in.read_u16()
})
_(TraitObject, {
@@ -798,7 +929,7 @@
})
#undef _
default:
- throw ::std::runtime_error(FMT("Bad TypeRef tag - " << tag));
+ BUG(Span(), "Bad tag for HIR::TypeRef - " << tag);
}
return rv;
}
@@ -807,11 +938,11 @@
{
TRACE_FUNCTION;
// HACK! If the read crate name is empty, replace it with the name we're loaded with
- auto crate_name = m_in.read_string();
- auto components = deserialise_vec< ::std::string>();
+ auto crate_name = m_in.read_istring();
+ auto components = deserialise_vec< RcString>();
if( crate_name == "" && components.size() > 0)
{
- assert(!m_crate_name.empty());
+ assert(m_crate_name != "");
crate_name = m_crate_name;
}
return ::HIR::SimplePath {
@@ -837,13 +968,13 @@
::HIR::TraitPath HirDeserialiser::deserialise_traitpath()
{
auto gpath = deserialise_genericpath();
- auto tys = deserialise_strmap< ::HIR::TypeRef>();
+ auto tys = deserialise_istrmap< ::HIR::TypeRef>();
return ::HIR::TraitPath { mv$(gpath), {}, mv$(tys) };
}
::HIR::Path HirDeserialiser::deserialise_path()
{
TRACE_FUNCTION;
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
case 0:
DEBUG("Generic");
@@ -852,7 +983,7 @@
DEBUG("Inherent");
return ::HIR::Path( ::HIR::Path::Data::Data_UfcsInherent {
box$( deserialise_type() ),
- m_in.read_string(),
+ m_in.read_istring(),
deserialise_pathparams(),
deserialise_pathparams()
} );
@@ -861,11 +992,11 @@
return ::HIR::Path( ::HIR::Path::Data::Data_UfcsKnown {
box$( deserialise_type() ),
deserialise_genericpath(),
- m_in.read_string(),
+ m_in.read_istring(),
deserialise_pathparams()
} );
default:
- throw "";
+ BUG(Span(), "Bad tag for HIR::Path - " << tag);
}
}
@@ -874,7 +1005,7 @@
TRACE_FUNCTION;
::HIR::GenericParams params;
params.m_types = deserialise_vec< ::HIR::TypeParamDef>();
- params.m_lifetimes = deserialise_vec< ::std::string>();
+ params.m_lifetimes = deserialise_vec< ::HIR::LifetimeDef>();
params.m_bounds = deserialise_vec< ::HIR::GenericBound>();
DEBUG("params = " << params.fmt_args() << ", " << params.fmt_bounds());
return params;
@@ -882,7 +1013,7 @@
::HIR::TypeParamDef HirDeserialiser::deserialise_typaramdef()
{
auto rv = ::HIR::TypeParamDef {
- m_in.read_string(),
+ m_in.read_istring(),
deserialise_type(),
m_in.read_bool()
};
@@ -891,7 +1022,7 @@
}
::HIR::GenericBound HirDeserialiser::deserialise_genericbound()
{
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
case 0:
return ::HIR::GenericBound::make_Lifetime({});
@@ -908,8 +1039,7 @@
deserialise_type()
});
default:
- DEBUG("Bad GenericBound tag");
- throw "";
+ BUG(Span(), "Bad tag for HIR::GenericBound - " << tag);
}
}
@@ -918,7 +1048,7 @@
TRACE_FUNCTION;
struct H {
static ::HIR::Enum::Class deserialise_enumclass(HirDeserialiser& des) {
- switch( des.m_in.read_tag() )
+ switch( auto tag = des.m_in.read_tag() )
{
case ::HIR::Enum::Class::TAG_Data:
return ::HIR::Enum::Class::make_Data( des.deserialise_vec<::HIR::Enum::DataVariant>() );
@@ -928,7 +1058,7 @@
des.deserialise_vec<::HIR::Enum::ValueVariant>()
});
default:
- throw "";
+ BUG(Span(), "Bad tag for HIR::Enum::Class - " << tag);
}
}
};
@@ -940,7 +1070,7 @@
}
::HIR::Enum::DataVariant HirDeserialiser::deserialise_enumdatavariant()
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
DEBUG("Enum::DataVariant " << name);
return ::HIR::Enum::DataVariant {
mv$(name),
@@ -950,7 +1080,7 @@
}
::HIR::Enum::ValueVariant HirDeserialiser::deserialise_enumvaluevariant()
{
- auto name = m_in.read_string();
+ auto name = m_in.read_istring();
DEBUG("Enum::ValueVariant " << name);
return ::HIR::Enum::ValueVariant {
mv$(name),
@@ -963,7 +1093,7 @@
TRACE_FUNCTION;
auto params = deserialise_genericparams();
auto repr = static_cast< ::HIR::Union::Repr>( m_in.read_tag() );
- auto variants = deserialise_vec< ::std::pair< ::std::string, ::HIR::VisEnt< ::HIR::TypeRef> > >();
+ auto variants = deserialise_vec< ::std::pair< RcString, ::HIR::VisEnt< ::HIR::TypeRef> > >();
auto markings = deserialise_markings();
return ::HIR::Union {
@@ -972,13 +1102,13 @@
}
::HIR::Struct HirDeserialiser::deserialise_struct()
{
- TRACE_FUNCTION;
+ TRACE_FUNCTION_FR("", m_in.get_pos());
auto params = deserialise_genericparams();
auto repr = static_cast< ::HIR::Struct::Repr>( m_in.read_tag() );
DEBUG("params = " << params.fmt_args() << params.fmt_bounds());
::HIR::Struct::Data data;
- switch( m_in.read_tag() )
+ switch( auto tag = m_in.read_tag() )
{
case ::HIR::Struct::Data::TAG_Unit:
DEBUG("Unit");
@@ -990,16 +1120,18 @@
break;
case ::HIR::Struct::Data::TAG_Named:
DEBUG("Named");
- data = ::HIR::Struct::Data( deserialise_vec< ::std::pair< ::std::string, ::HIR::VisEnt< ::HIR::TypeRef> > >() );
+ data = ::HIR::Struct::Data( deserialise_vec< ::std::pair< RcString, ::HIR::VisEnt< ::HIR::TypeRef> > >() );
break;
default:
- throw "";
+ BUG(Span(), "Bad tag for HIR::Struct::Data - " << tag);
}
+ auto align = static_cast<unsigned>(m_in.read_u64c());
+ DEBUG("align = " << align);
auto markings = deserialise_markings();
auto str_markings = deserialise_str_markings();
return ::HIR::Struct {
- mv$(params), repr, mv$(data), mv$(markings), mv$(str_markings)
+ mv$(params), repr, mv$(data), align, mv$(markings), mv$(str_markings)
};
}
::HIR::Trait HirDeserialiser::deserialise_trait()
@@ -1008,24 +1140,26 @@
::HIR::Trait rv {
deserialise_genericparams(),
- "", // TODO: Better type for lifetime
+ ::HIR::LifetimeRef(), // TODO: Better type for lifetime
{}
};
rv.m_is_marker = m_in.read_bool();
- rv.m_types = deserialise_strumap< ::HIR::AssociatedType>();
- rv.m_values = deserialise_strumap< ::HIR::TraitValueItem>();
- rv.m_value_indexes = deserialise_strummap< ::std::pair<unsigned int, ::HIR::GenericPath> >();
- rv.m_type_indexes = deserialise_strumap< unsigned int>();
+ rv.m_types = deserialise_istrumap< ::HIR::AssociatedType>();
+ rv.m_values = deserialise_istrumap< ::HIR::TraitValueItem>();
+ rv.m_value_indexes = deserialise_istrummap< ::std::pair<unsigned int, ::HIR::GenericPath> >();
+ rv.m_type_indexes = deserialise_istrumap< unsigned int>();
rv.m_all_parent_traits = deserialise_vec< ::HIR::TraitPath>();
+ rv.m_vtable_path = deserialise_simplepath();
return rv;
}
::HIR::Literal HirDeserialiser::deserialise_literal()
{
- switch( m_in.read_tag() )
+ switch( auto tag = m_in.read_tag() )
{
#define _(x, ...) case ::HIR::Literal::TAG_##x: return ::HIR::Literal::make_##x(__VA_ARGS__);
_(Invalid, {})
+ _(Defer, {})
_(List, deserialise_vec< ::HIR::Literal>() )
_(Variant, {
static_cast<unsigned int>(m_in.read_count()),
@@ -1038,7 +1172,7 @@
_(String, m_in.read_string() )
#undef _
default:
- throw "";
+ BUG(Span(), "Unknown HIR::Literal tag when deserialising - " << tag);
}
}
@@ -1068,7 +1202,7 @@
{
TRACE_FUNCTION;
- switch( m_in.read_tag() )
+ switch( auto tag = m_in.read_tag() )
{
case 0:
return ::MIR::Statement::make_Assign({
@@ -1101,8 +1235,7 @@
deserialise_vec<unsigned int>()
});
default:
- ::std::cerr << "Bad tag for a MIR Statement" << ::std::endl;
- throw "";
+ BUG(Span(), "Bad tag for MIR::Statement - " << tag);
}
}
::MIR::Terminator HirDeserialiser::deserialise_mir_terminator()
@@ -1114,7 +1247,7 @@
}
::MIR::Terminator HirDeserialiser::deserialise_mir_terminator_()
{
- switch( m_in.read_tag() )
+ switch( auto tag = m_in.read_tag() )
{
#define _(x, ...) case ::MIR::Terminator::TAG_##x: return ::MIR::Terminator::make_##x( __VA_ARGS__ );
_(Incomplete, {})
@@ -1146,13 +1279,13 @@
})
#undef _
default:
- throw "";
+ BUG(Span(), "Bad tag for MIR::Terminator - " << tag);
}
}
::MIR::SwitchValues HirDeserialiser::deserialise_mir_switchvalues()
{
TRACE_FUNCTION;
- switch(m_in.read_tag())
+ switch(auto tag = m_in.read_tag())
{
#define _(x, ...) case ::MIR::SwitchValues::TAG_##x: return ::MIR::SwitchValues::make_##x( __VA_ARGS__ );
_(Unsigned, deserialise_vec_c<uint64_t>([&](){ return m_in.read_u64c(); }))
@@ -1160,24 +1293,24 @@
_(String , deserialise_vec<::std::string>())
#undef _
default:
- throw "";
+ BUG(Span(), "Bad tag for MIR::SwitchValues - " << tag);
}
}
::MIR::CallTarget HirDeserialiser::deserialise_mir_calltarget()
{
- switch( m_in.read_tag() )
+ switch(auto tag = m_in.read_tag())
{
#define _(x, ...) case ::MIR::CallTarget::TAG_##x: return ::MIR::CallTarget::make_##x( __VA_ARGS__ );
_(Value, deserialise_mir_lvalue() )
_(Path, deserialise_path() )
_(Intrinsic, {
- m_in.read_string(),
+ m_in.read_istring(),
deserialise_pathparams()
})
#undef _
default:
- throw "";
+ BUG(Span(), "Bad tag for MIR::CallTarget - " << tag);
}
}
@@ -1188,8 +1321,8 @@
::HIR::Module rv;
// m_traits doesn't need to be serialised
- rv.m_value_items = deserialise_strumap< ::std::unique_ptr< ::HIR::VisEnt< ::HIR::ValueItem> > >();
- rv.m_mod_items = deserialise_strumap< ::std::unique_ptr< ::HIR::VisEnt< ::HIR::TypeItem> > >();
+ rv.m_value_items = deserialise_istrumap< ::std::unique_ptr< ::HIR::VisEnt< ::HIR::ValueItem> > >();
+ rv.m_mod_items = deserialise_istrumap< ::std::unique_ptr< ::HIR::VisEnt< ::HIR::TypeItem> > >();
return rv;
}
@@ -1203,41 +1336,28 @@
{
::HIR::Crate rv;
- this->m_crate_name = m_in.read_string();
- assert(!this->m_crate_name.empty() && "Empty crate name loaded from metadata");
+ this->m_crate_name = m_in.read_istring();
+ assert(this->m_crate_name != "" && "Empty crate name loaded from metadata");
rv.m_crate_name = this->m_crate_name;
rv.m_root_module = deserialise_module();
- rv.m_type_impls = deserialise_vec< ::HIR::TypeImpl>();
-
- {
- size_t n = m_in.read_count();
- for(size_t i = 0; i < n; i ++)
- {
- auto p = deserialise_simplepath();
- rv.m_trait_impls.insert( ::std::make_pair( mv$(p), deserialise_traitimpl() ) );
- }
- }
- {
- size_t n = m_in.read_count();
- for(size_t i = 0; i < n; i ++)
- {
- auto p = deserialise_simplepath();
- rv.m_marker_impls.insert( ::std::make_pair( mv$(p), deserialise_markerimpl() ) );
- }
- }
+ rv.m_type_impls = D< ::HIR::Crate::ImplGroup<::HIR::TypeImpl> >::des(*this);
+ rv.m_trait_impls = deserialise_pathmap< ::HIR::Crate::ImplGroup<::HIR::TraitImpl>>();
+ rv.m_marker_impls = deserialise_pathmap< ::HIR::Crate::ImplGroup<::HIR::MarkerImpl>>();
- rv.m_exported_macros = deserialise_strumap< ::MacroRulesPtr>();
+ rv.m_exported_macros = deserialise_istrumap< ::MacroRulesPtr>();
+ rv.m_proc_macro_reexports = deserialise_istrumap< ::HIR::Crate::MacroImport>();
rv.m_lang_items = deserialise_strumap< ::HIR::SimplePath>();
{
size_t n = m_in.read_count();
for(size_t i = 0; i < n; i ++)
{
- auto ext_crate_name = m_in.read_string();
+ auto ext_crate_name = m_in.read_istring();
auto ext_crate_file = m_in.read_string();
auto ext_crate = ::HIR::ExternCrate {};
ext_crate.m_basename = ext_crate_file;
+ ext_crate.m_path = ext_crate_file;
rv.m_ext_crates.insert( ::std::make_pair( mv$(ext_crate_name), mv$(ext_crate) ) );
}
}
@@ -1251,11 +1371,11 @@
}
//}
-::HIR::CratePtr HIR_Deserialise(const ::std::string& filename, const ::std::string& loaded_name)
+::HIR::CratePtr HIR_Deserialise(const ::std::string& filename)
{
try
{
- ::HIR::serialise::Reader in{ filename };
+ ::HIR::serialise::Reader in{ filename + ".hir" }; // HACK!
HirDeserialiser s { in };
::HIR::Crate rv = s.deserialise_crate();
diff --git a/src/hir/dump.cpp b/src/hir/dump.cpp
index 874a80a7..3b981e26 100644
--- a/src/hir/dump.cpp
+++ b/src/hir/dump.cpp
@@ -89,13 +89,46 @@ namespace {
void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override
{
m_os << indent() << "trait " << p.get_name() << item.m_params.fmt_args() << "\n";
+ if( ! item.m_parent_traits.empty() )
+ {
+ m_os << indent() << " " << ": ";
+ bool is_first = true;
+ for(auto& bound : item.m_parent_traits)
+ {
+ if( !is_first )
+ m_os << indent() << " " << "+ ";
+ m_os << bound << "\n";
+ is_first = false;
+ }
+ }
if( ! item.m_params.m_bounds.empty() )
{
m_os << indent() << " " << item.m_params.fmt_bounds() << "\n";
}
m_os << indent() << "{\n";
inc_indent();
+
+ for(auto& i : item.m_types)
+ {
+ m_os << indent() << "type " << i.first;
+ if( ! i.second.m_trait_bounds.empty() )
+ {
+ m_os << ": ";
+ bool is_first = true;
+ for(auto& bound : i.second.m_trait_bounds)
+ {
+ if( !is_first )
+ m_os << " + ";
+ m_os << bound;
+ is_first = false;
+ }
+ }
+ //this->visit_type(i.second.m_default);
+ m_os << ";\n";
+ }
+
::HIR::Visitor::visit_trait(p, item);
+
dec_indent();
m_os << indent() << "}\n";
}
@@ -119,7 +152,7 @@ namespace {
m_os << "(";
for(const auto& fld : flds)
{
- m_os << (fld.is_public ? "pub " : "") << fld.ent << ", ";
+ m_os << fld.publicity << " " << fld.ent << ", ";
}
if( item.m_params.m_bounds.empty() )
{
@@ -142,7 +175,7 @@ namespace {
inc_indent();
for(const auto& fld : flds)
{
- m_os << indent() << (fld.second.is_public ? "pub " : "") << fld.first << ": " << fld.second.ent << ",\n";
+ m_os << indent() << fld.second.publicity << " " << fld.first << ": " << fld.second.ent << ",\n";
}
dec_indent();
m_os << indent() << "}\n";
@@ -298,33 +331,21 @@ namespace {
void visit(::HIR::ExprNode_Block& node) override
{
- if( node.m_nodes.size() == 0 ) {
- m_os << "{";
- if( node.m_value_node )
- {
- m_os << " ";
- this->visit_node_ptr(node.m_value_node);
- }
- m_os << " }";
+ m_os << "{\n";
+ inc_indent();
+ for(auto& sn : node.m_nodes) {
+ m_os << indent();
+ this->visit_node_ptr(sn);
+ m_os << ";\n";
}
- else {
- m_os << "{\n";
- inc_indent();
- for(auto& sn : node.m_nodes) {
- m_os << "\n";
- m_os << indent();
- this->visit_node_ptr(sn);
- m_os << ";\n";
- }
- if( node.m_value_node )
- {
- m_os << indent();
- this->visit_node_ptr(node.m_value_node);
- m_os << "\n";
- }
- dec_indent();
- m_os << indent() << "}";
+ if( node.m_value_node )
+ {
+ m_os << indent();
+ this->visit_node_ptr(node.m_value_node);
+ m_os << "\n";
}
+ dec_indent();
+ m_os << indent() << "}";
}
void visit(::HIR::ExprNode_Asm& node) override
@@ -363,6 +384,10 @@ namespace {
if( node.m_label != "" ) {
m_os << " '" << node.m_label;
}
+ if( node.m_value ) {
+ m_os << " ";
+ this->visit_node_ptr(node.m_value);
+ }
}
void visit(::HIR::ExprNode_Match& node) override
{
diff --git a/src/hir/expr.cpp b/src/hir/expr.cpp
index 07504ea7..0512e557 100644
--- a/src/hir/expr.cpp
+++ b/src/hir/expr.cpp
@@ -19,6 +19,12 @@ void ::HIR::ExprVisitor::visit_node_ptr(::std::unique_ptr< ::HIR::ExprNode>& nod
}
void ::HIR::ExprVisitor::visit_node(::HIR::ExprNode& node) {
}
+void ::HIR::ExprVisitorDef::visit_node_ptr(::std::unique_ptr< ::HIR::ExprNode>& node_ptr) {
+ assert(node_ptr);
+ TRACE_FUNCTION_F(&*node_ptr << " " << typeid(*node_ptr).name());
+ node_ptr->visit(*this);
+ visit_type(node_ptr->m_res_type);
+}
DEF_VISIT(ExprNode_Block, node,
for(auto& subnode : node.m_nodes) {
visit_node_ptr(subnode);
@@ -83,6 +89,7 @@ DEF_VISIT(ExprNode_Borrow, node,
visit_node_ptr(node.m_value);
)
DEF_VISIT(ExprNode_Cast, node,
+ TRACE_FUNCTION_F("_Cast " << node.m_res_type);
visit_node_ptr(node.m_value);
)
DEF_VISIT(ExprNode_Unsize, node,
@@ -152,7 +159,7 @@ DEF_VISIT(ExprNode_PathValue, node,
)
DEF_VISIT(ExprNode_Variable, , )
DEF_VISIT(ExprNode_StructLiteral, node,
- visit_generic_path(::HIR::Visitor::PathContext::VALUE, node.m_path);
+ visit_path(::HIR::Visitor::PathContext::VALUE, node.m_path);
if( node.m_base_value )
visit_node_ptr(node.m_base_value);
for(auto& val : node.m_values)
diff --git a/src/hir/expr.hpp b/src/hir/expr.hpp
index 00d22c00..c87ae3a7 100644
--- a/src/hir/expr.hpp
+++ b/src/hir/expr.hpp
@@ -133,11 +133,11 @@ struct ExprNode_Return:
struct ExprNode_Loop:
public ExprNode
{
- ::std::string m_label;
+ RcString m_label;
::HIR::ExprNodeP m_code;
bool m_diverges = false;
- ExprNode_Loop(Span sp, ::std::string label, ::HIR::ExprNodeP code):
+ ExprNode_Loop(Span sp, RcString label, ::HIR::ExprNodeP code):
//ExprNode(mv$(sp), ::HIR::TypeRef::new_unit()),
ExprNode(mv$(sp), ::HIR::TypeRef()),
m_label( mv$(label) ),
@@ -149,11 +149,11 @@ struct ExprNode_Loop:
struct ExprNode_LoopControl:
public ExprNode
{
- ::std::string m_label;
+ RcString m_label;
bool m_continue;
::HIR::ExprNodeP m_value;
- ExprNode_LoopControl(Span sp, ::std::string label, bool cont, ::HIR::ExprNodeP value={}):
+ ExprNode_LoopControl(Span sp, RcString label, bool cont, ::HIR::ExprNodeP value={}):
ExprNode(mv$(sp), ::HIR::TypeRef::new_diverge()),
m_label( mv$(label) ),
m_continue( cont ),
@@ -409,6 +409,10 @@ struct ExprNode_Index:
::HIR::ExprNodeP m_value;
::HIR::ExprNodeP m_index;
+ struct {
+ ::HIR::TypeRef index_ty;
+ } m_cache;
+
ExprNode_Index(Span sp, ::HIR::ExprNodeP val, ::HIR::ExprNodeP index):
ExprNode(mv$(sp)),
m_value( mv$(val) ),
@@ -539,7 +543,7 @@ struct ExprNode_CallMethod:
public ExprNode
{
::HIR::ExprNodeP m_value;
- ::std::string m_method;
+ RcString m_method;
::HIR::PathParams m_params;
::std::vector< ::HIR::ExprNodeP> m_args;
@@ -553,7 +557,7 @@ struct ExprNode_CallMethod:
// - A pool of ivars to use for searching for trait impls
::std::vector<unsigned int> m_trait_param_ivars;
- ExprNode_CallMethod(Span sp, ::HIR::ExprNodeP val, ::std::string method_name, ::HIR::PathParams params, ::std::vector< ::HIR::ExprNodeP> args):
+ ExprNode_CallMethod(Span sp, ::HIR::ExprNodeP val, RcString method_name, ::HIR::PathParams params, ::std::vector< ::HIR::ExprNodeP> args):
ExprNode( mv$(sp) ),
m_value( mv$(val) ),
m_method( mv$(method_name) ),
@@ -570,9 +574,9 @@ struct ExprNode_Field:
public ExprNode
{
::HIR::ExprNodeP m_value;
- ::std::string m_field;
+ RcString m_field;
- ExprNode_Field(Span sp, ::HIR::ExprNodeP val, ::std::string field):
+ ExprNode_Field(Span sp, ::HIR::ExprNodeP val, RcString field):
ExprNode(mv$(sp)),
m_value( mv$(val) ),
m_field( mv$(field) )
@@ -677,10 +681,10 @@ struct ExprNode_PathValue:
struct ExprNode_Variable:
public ExprNode
{
- ::std::string m_name;
+ RcString m_name;
unsigned int m_slot;
- ExprNode_Variable(Span sp, ::std::string name, unsigned int slot):
+ ExprNode_Variable(Span sp, RcString name, unsigned int slot):
ExprNode(mv$(sp)),
m_name( mv$(name) ),
m_slot( slot )
@@ -692,9 +696,9 @@ struct ExprNode_Variable:
struct ExprNode_StructLiteral:
public ExprNode
{
- typedef ::std::vector< ::std::pair< ::std::string, ExprNodeP > > t_values;
+ typedef ::std::vector< ::std::pair< RcString, ExprNodeP > > t_values;
- ::HIR::GenericPath m_path;
+ ::HIR::Path m_path;
bool m_is_struct;
::HIR::ExprNodeP m_base_value;
t_values m_values;
@@ -702,7 +706,7 @@ struct ExprNode_StructLiteral:
/// Monomorphised types of each field.
::std::vector< ::HIR::TypeRef> m_value_types;
- ExprNode_StructLiteral(Span sp, ::HIR::GenericPath path, bool is_struct, ::HIR::ExprNodeP base_value, t_values values):
+ ExprNode_StructLiteral(Span sp, ::HIR::Path path, bool is_struct, ::HIR::ExprNodeP base_value, t_values values):
ExprNode( mv$(sp) ),
m_path( mv$(path) ),
m_is_struct( is_struct ),
@@ -719,12 +723,12 @@ struct ExprNode_UnionLiteral:
public ExprNode
{
::HIR::GenericPath m_path;
- ::std::string m_variant_name;
+ RcString m_variant_name;
::HIR::ExprNodeP m_value;
unsigned int m_variant_index = ~0;
- ExprNode_UnionLiteral(Span sp, ::HIR::GenericPath path, ::std::string name, ::HIR::ExprNodeP value):
+ ExprNode_UnionLiteral(Span sp, ::HIR::GenericPath path, RcString name, ::HIR::ExprNodeP value):
ExprNode( mv$(sp) ),
m_path( mv$(path) ),
m_variant_name( mv$(name) ),
@@ -793,8 +797,10 @@ struct ExprNode_Closure:
Mut,
Once,
} m_class = Class::Unknown;
+ bool m_is_copy = false;
// - Path to the generated closure type
+ const ::HIR::Struct* m_obj_ptr = nullptr;
::HIR::GenericPath m_obj_path_base;
::HIR::GenericPath m_obj_path;
::std::vector< ::HIR::ExprNodeP> m_captures;
@@ -866,6 +872,8 @@ class ExprVisitorDef:
public:
#define NV(nt) virtual void visit(nt& n);
+ virtual void visit_node_ptr(::std::unique_ptr<ExprNode>& node_ptr) override;
+
NV(ExprNode_Block)
NV(ExprNode_Asm)
NV(ExprNode_Return)
diff --git a/src/hir/expr_ptr.cpp b/src/hir/expr_ptr.cpp
index fcef34bd..7f493a0d 100644
--- a/src/hir/expr_ptr.cpp
+++ b/src/hir/expr_ptr.cpp
@@ -45,6 +45,13 @@
}
+const Span& HIR::ExprPtr::span() const
+{
+ static Span static_sp;
+ if( *this )
+ return (*this)->span();
+ return static_sp;
+}
const ::MIR::Function* HIR::ExprPtr::get_mir_opt() const
{
if(!this->m_mir)
@@ -83,6 +90,15 @@ void HIR::ExprPtr::set_mir(::MIR::FunctionPointer mir)
{
assert( !this->m_mir );
m_mir = ::std::move(mir);
+ // Reset the HIR tree to be a placeholder node (thus freeing the backing memory)
+ if( false && node )
+ {
+ auto sp = node->span();
+ node = ExprPtrInner(::std::unique_ptr<HIR::ExprNode>(new ::HIR::ExprNode_Loop(
+ sp, "",
+ ::std::unique_ptr<HIR::ExprNode>(new ::HIR::ExprNode_Tuple(sp, {}))
+ )));
+ }
}
diff --git a/src/hir/expr_ptr.hpp b/src/hir/expr_ptr.hpp
index 2f0f30e4..512921eb 100644
--- a/src/hir/expr_ptr.hpp
+++ b/src/hir/expr_ptr.hpp
@@ -105,6 +105,7 @@ public:
::HIR::ExprNode* get() const { return node.get(); }
void reset(::HIR::ExprNode* p) { node.reset(p); }
+ const Span& span() const;
::HIR::ExprNode& operator*() { return *node; }
const ::HIR::ExprNode& operator*() const { return *node; }
::HIR::ExprNode* operator->() { return &*node; }
diff --git a/src/hir/expr_state.hpp b/src/hir/expr_state.hpp
index 11fffe67..139c400d 100644
--- a/src/hir/expr_state.hpp
+++ b/src/hir/expr_state.hpp
@@ -16,13 +16,15 @@ public:
::HIR::SimplePath m_mod_path;
const ::HIR::Module& m_module;
- ::HIR::GenericParams* m_impl_generics;
- ::HIR::GenericParams* m_item_generics;
+ const ::HIR::GenericParams* m_impl_generics;
+ const ::HIR::GenericParams* m_item_generics;
::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > m_traits;
enum class Stage {
Created,
+ ConstEvalRequest,
+ ConstEval,
TypecheckRequest,
Typecheck,
MirRequest,
diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp
index 7d1b05a8..e3cba9e9 100644
--- a/src/hir/from_ast.cpp
+++ b/src/hir/from_ast.cpp
@@ -23,15 +23,18 @@
::HIR::TraitPath LowerHIR_TraitPath(const Span& sp, const ::AST::Path& path);
::HIR::SimplePath path_Sized;
-::std::string g_core_crate;
-::std::string g_crate_name;
+RcString g_core_crate;
+RcString g_crate_name;
::HIR::Crate* g_crate_ptr = nullptr;
const ::AST::Crate* g_ast_crate_ptr;
// --------------------------------------------------------------------
-::std::string LowerHIR_LifetimeRef(const ::AST::LifetimeRef& r)
+HIR::LifetimeRef LowerHIR_LifetimeRef(const ::AST::LifetimeRef& r)
{
- return r.name().name;
+ return HIR::LifetimeRef(
+ // TODO: names?
+ r.binding()
+ );
}
::HIR::GenericParams LowerHIR_GenericParams(const ::AST::GenericParams& gp, bool* self_is_sized)
@@ -48,7 +51,7 @@ const ::AST::Crate* g_ast_crate_ptr;
if( gp.lft_params().size() > 0 )
{
for(const auto& lft_def : gp.lft_params())
- rv.m_lifetimes.push_back( lft_def.name().name );
+ rv.m_lifetimes.push_back( HIR::LifetimeDef { lft_def.name().name } );
}
if( gp.bounds().size() > 0 )
{
@@ -156,28 +159,26 @@ const ::AST::Crate* g_ast_crate_ptr;
}
};
- TU_MATCH(::AST::Pattern::Data, (pat.data()), (e),
- (MaybeBind,
+ TU_MATCH_HDRA( (pat.data()), {)
+ TU_ARMA(MaybeBind, e) {
BUG(pat.span(), "Encountered MaybeBind pattern");
- ),
- (Macro,
+ }
+ TU_ARMA(Macro, e) {
BUG(pat.span(), "Encountered Macro pattern");
- ),
- (Any,
+ }
+ TU_ARMA(Any, e)
return ::HIR::Pattern {
mv$(binding),
::HIR::Pattern::Data::make_Any({})
};
- ),
- (Box,
+ TU_ARMA(Box, e)
return ::HIR::Pattern {
mv$(binding),
::HIR::Pattern::Data::make_Box({
box$(LowerHIR_Pattern( *e.sub ))
})
};
- ),
- (Ref,
+ TU_ARMA(Ref, e)
return ::HIR::Pattern {
mv$(binding),
::HIR::Pattern::Data::make_Ref({
@@ -185,8 +186,7 @@ const ::AST::Crate* g_ast_crate_ptr;
box$(LowerHIR_Pattern( *e.sub ))
})
};
- ),
- (Tuple,
+ TU_ARMA(Tuple, e) {
auto leading = H::lowerhir_patternvec( e.start );
auto trailing = H::lowerhir_patternvec( e.end );
@@ -209,16 +209,14 @@ const ::AST::Crate* g_ast_crate_ptr;
})
};
}
- ),
-
- (StructTuple,
+ }
+ TU_ARMA(StructTuple, e) {
unsigned int leading_count = e.tup_pat.start.size();
unsigned int trailing_count = e.tup_pat.end .size();
- TU_MATCH_DEF(::AST::PathBinding, (e.path.binding()), (pb),
- (
+ TU_MATCH_HDRA( (e.path.m_bindings.value), {)
+ default:
BUG(pat.span(), "Encountered StructTuple pattern not pointing to a enum variant or a struct - " << e.path);
- ),
- (EnumVar,
+ TU_ARMA(EnumVar, pb) {
assert( pb.enum_ || pb.hir );
unsigned int field_count;
if( pb.enum_ ) {
@@ -268,8 +266,8 @@ const ::AST::Crate* g_ast_crate_ptr;
mv$(sub_patterns)
})
};
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, pb) {
assert( pb.struct_ || pb.hir );
unsigned int field_count;
if( pb.struct_ ) {
@@ -317,20 +315,32 @@ const ::AST::Crate* g_ast_crate_ptr;
mv$(sub_patterns)
})
};
- )
- )
- ),
- (Struct,
- ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> > sub_patterns;
+ }
+ }
+ }
+ TU_ARMA(Struct, e) {
+ ::std::vector< ::std::pair< RcString, ::HIR::Pattern> > sub_patterns;
for(const auto& sp : e.sub_patterns)
sub_patterns.push_back( ::std::make_pair(sp.first, LowerHIR_Pattern(sp.second)) );
+ if( e.sub_patterns.empty() && !e.is_exhaustive ) {
+ if( e.path.m_bindings.value.is_EnumVar() ) {
+ return ::HIR::Pattern {
+ mv$(binding),
+ ::HIR::Pattern::Data::make_EnumStruct({
+ LowerHIR_GenericPath(pat.span(), e.path),
+ nullptr, 0,
+ mv$(sub_patterns),
+ e.is_exhaustive
+ })
+ };
+ }
+ }
- TU_MATCH_DEF(::AST::PathBinding, (e.path.binding()), (pb),
- (
+ TU_MATCH_HDRA( (e.path.m_bindings.type), {)
+ default:
BUG(pat.span(), "Encountered Struct pattern not pointing to a enum variant or a struct - " << e.path);
- ),
- (EnumVar,
+ TU_ARMA(EnumVar, pb) {
return ::HIR::Pattern {
mv$(binding),
::HIR::Pattern::Data::make_EnumStruct({
@@ -340,8 +350,8 @@ const ::AST::Crate* g_ast_crate_ptr;
e.is_exhaustive
})
};
- ),
- (TypeAlias,
+ }
+ TU_ARMA(TypeAlias, pb) {
return ::HIR::Pattern {
mv$(binding),
::HIR::Pattern::Data::make_Struct({
@@ -351,8 +361,8 @@ const ::AST::Crate* g_ast_crate_ptr;
e.is_exhaustive
})
};
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, pb) {
return ::HIR::Pattern {
mv$(binding),
::HIR::Pattern::Data::make_Struct({
@@ -362,11 +372,11 @@ const ::AST::Crate* g_ast_crate_ptr;
e.is_exhaustive
})
};
- )
- )
- ),
+ }
+ }
+ }
- (Value,
+ TU_ARMA(Value, e) {
struct H {
static ::HIR::CoreType get_int_type(const Span& sp, const ::eCoreType ct) {
switch(ct)
@@ -450,8 +460,8 @@ const ::AST::Crate* g_ast_crate_ptr;
})
};
}
- ),
- (Slice,
+ }
+ TU_ARMA(Slice, e) {
::std::vector< ::HIR::Pattern> leading;
for(const auto& sp : e.sub_pats)
leading.push_back( LowerHIR_Pattern(sp) );
@@ -461,8 +471,8 @@ const ::AST::Crate* g_ast_crate_ptr;
mv$(leading)
})
};
- ),
- (SplitSlice,
+ }
+ TU_ARMA(SplitSlice, e) {
::std::vector< ::HIR::Pattern> leading;
for(const auto& sp : e.leading)
leading.push_back( LowerHIR_Pattern(sp) );
@@ -485,8 +495,8 @@ const ::AST::Crate* g_ast_crate_ptr;
mv$(trailing)
})
};
- )
- )
+ }
+ }
throw "unreachable";
}
@@ -621,7 +631,17 @@ const ::AST::Crate* g_ast_crate_ptr;
return ::HIR::Path( LowerHIR_GenericPath(sp, path) );
),
(UFCS,
- if( e.nodes.size() != 1 )
+ if( e.nodes.size() == 0 )
+ {
+ if( !e.trait )
+ TODO(sp, "Handle UFCS inherent and no nodes - " << path);
+ if( e.trait->is_valid() )
+ TODO(sp, "Handle UFCS w/ trait and no nodes - " << path);
+ auto type = LowerHIR_Type(*e.type);
+ ASSERT_BUG(sp, type.m_data.is_Path(), "No nodes and non-Path type - " << path);
+ return mv$(type.m_data.as_Path().path);
+ }
+ if( e.nodes.size() > 1 )
TODO(sp, "Handle UFCS with multiple nodes - " << path);
// - No associated type bounds allowed in UFCS paths
auto params = LowerHIR_PathParams(sp, e.nodes.front().args(), false);
@@ -731,8 +751,9 @@ const ::AST::Crate* g_ast_crate_ptr;
{
if( ptr->m_datatype == CORETYPE_UINT || ptr->m_datatype == CORETYPE_ANY )
{
- if( ptr->m_value > UINT_MAX ) {
- ERROR(ty.span(), E0000, "Array size out of bounds - " << ptr->m_value << " > " << UINT_MAX);
+ // TODO: Chage the HIR format to support very large arrays
+ if( ptr->m_value >= UINT64_MAX ) {
+ ERROR(ty.span(), E0000, "Array size out of bounds - 0x" << ::std::hex << ptr->m_value << " > 0x" << UINT64_MAX << " in " << ::std::dec << ty);
}
auto size_val = static_cast<unsigned int>( ptr->m_value );
return ::HIR::TypeRef::new_array( mv$(inner), size_val );
@@ -750,9 +771,9 @@ const ::AST::Crate* g_ast_crate_ptr;
TU_IFLET(::AST::Path::Class, e.path.m_class, Local, l,
unsigned int slot;
// NOTE: TypeParameter is unused
- TU_IFLET(::AST::PathBinding, e.path.binding(), Variable, p,
- slot = p.slot;
- )
+ if( const auto* p = e.path.m_bindings.value.opt_Variable() ) {
+ slot = p->slot;
+ }
else {
BUG(ty.span(), "Unbound local encountered in " << e.path);
}
@@ -768,7 +789,7 @@ const ::AST::Crate* g_ast_crate_ptr;
for(const auto& t : e.traits)
{
DEBUG("t = " << t.path);
- const auto& tb = t.path.binding().as_Trait();
+ const auto& tb = t.path.m_bindings.type.as_Trait();
assert( tb.trait_ || tb.hir );
if( (tb.trait_ ? tb.trait_->is_marker() : tb.hir->m_is_marker) )
{
@@ -851,9 +872,20 @@ const ::AST::Crate* g_ast_crate_ptr;
namespace {
template<typename T>
- ::HIR::VisEnt<T> new_visent(bool pub, T v) {
+ ::HIR::VisEnt<T> new_visent(HIR::Publicity pub, T v) {
return ::HIR::VisEnt<T> { pub, mv$(v) };
}
+
+ ::HIR::SimplePath get_parent_module(const ::HIR::ItemPath& p) {
+ const ::HIR::ItemPath* parent_ip = p.parent;
+ assert(parent_ip);
+ while(parent_ip->name && parent_ip->name[0] == '#')
+ {
+ parent_ip = parent_ip->parent;
+ assert(parent_ip);
+ }
+ return parent_ip->get_simple_path();
+ }
}
::HIR::Struct LowerHIR_Struct(::HIR::ItemPath path, const ::AST::Struct& ent, const ::AST::AttributeList& attrs)
@@ -861,6 +893,9 @@ namespace {
TRACE_FUNCTION_F(path);
::HIR::Struct::Data data;
+ auto priv_path = ::HIR::Publicity::new_priv( get_parent_module(path) );
+ auto get_pub = [&](bool is_pub){ return is_pub ? ::HIR::Publicity::new_global() : priv_path; };
+
TU_MATCH(::AST::StructData, (ent.m_data), (e),
(Unit,
data = ::HIR::Struct::Data::make_Unit({});
@@ -869,70 +904,76 @@ namespace {
::HIR::Struct::Data::Data_Tuple fields;
for(const auto& field : e.ents)
- fields.push_back( { field.m_is_public, LowerHIR_Type(field.m_type) } );
+ fields.push_back( { get_pub(field.m_is_public), LowerHIR_Type(field.m_type) } );
data = ::HIR::Struct::Data::make_Tuple( mv$(fields) );
),
(Struct,
::HIR::Struct::Data::Data_Named fields;
for(const auto& field : e.ents)
- fields.push_back( ::std::make_pair( field.m_name, new_visent(field.m_is_public, LowerHIR_Type(field.m_type)) ) );
+ fields.push_back( ::std::make_pair( field.m_name, new_visent( get_pub(field.m_is_public), LowerHIR_Type(field.m_type)) ) );
data = ::HIR::Struct::Data::make_Named( mv$(fields) );
)
)
- auto struct_repr = ::HIR::Struct::Repr::Rust;
+ auto rv = ::HIR::Struct {
+ LowerHIR_GenericParams(ent.params(), nullptr),
+ ::HIR::Struct::Repr::Rust,
+ mv$(data)
+ };
+
if( const auto* attr_repr = attrs.get("repr") )
{
- ASSERT_BUG(Span(), attr_repr->has_sub_items(), "#[repr] attribute malformed, " << *attr_repr);
- bool is_c = false;
- bool is_simd = false;
- bool is_packed = false;
- ASSERT_BUG(Span(), attr_repr->items().size() > 0, "#[repr] attribute malformed, " << *attr_repr);
+ ASSERT_BUG(attr_repr->span(), attr_repr->has_sub_items(), "#[repr] attribute malformed, " << *attr_repr);
+ ASSERT_BUG(attr_repr->span(), attr_repr->items().size() > 0, "#[repr] attribute malformed, " << *attr_repr);
+ // TODO: Change reprs to be a flag set (instead of an enum)?
+ // (Or at least make C be a flag)
for( const auto& a : attr_repr->items() )
{
- ASSERT_BUG(Span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr);
const auto& repr_str = a.name();
if( repr_str == "C" ) {
- is_c = true;
+ ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr);
+ if( rv.m_repr == ::HIR::Struct::Repr::Aligned )
+ {
+ }
+ else if( rv.m_repr != ::HIR::Struct::Repr::Packed )
+ {
+ ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str);
+ rv.m_repr = ::HIR::Struct::Repr::C;
+ }
}
else if( repr_str == "packed" ) {
- is_packed = true;
+ ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr);
+ ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust || rv.m_repr == ::HIR::Struct::Repr::C, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str);
+ rv.m_repr = ::HIR::Struct::Repr::Packed;
}
else if( repr_str == "simd" ) {
- is_simd = true;
+ ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr);
+ ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str);
+ rv.m_repr = ::HIR::Struct::Repr::Simd;
+ }
+ else if( repr_str == "transparent" ) {
+ ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr);
+ ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str);
+ rv.m_repr = ::HIR::Struct::Repr::Transparent;
+ }
+ else if( repr_str == "align" ) {
+ //ASSERT_BUG(a.span(), a.has_string(), "#[repr(aligned)] attribute malformed, " << *attr_repr);
+ ASSERT_BUG(a.span(), rv.m_repr != ::HIR::Struct::Repr::Packed, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str);
+ //rv.m_repr = ::HIR::Struct::Repr::Aligned;
+ //rv.m_forced_alignment = ::std::stol(a.string());
}
else {
TODO(a.span(), "Handle struct repr '" << repr_str << "'");
}
}
-
- if( is_packed ) {
- // TODO: What if `simd` is present?
- // NOTE: repr(packed,C) is treated as the same as repr(packed) in mrustc
- struct_repr = ::HIR::Struct::Repr::Packed;
- }
- else if( is_c ) {
- // TODO: What if `simd` is present?
- struct_repr = ::HIR::Struct::Repr::C;
- }
- else if( is_simd ) {
- struct_repr = ::HIR::Struct::Repr::Simd;
- }
- else {
- }
}
- return ::HIR::Struct {
- LowerHIR_GenericParams(ent.params(), nullptr),
- struct_repr,
- mv$(data)
- };
+ return rv;
}
-::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& ent, const ::AST::AttributeList& attrs, ::std::function<void(::std::string, ::HIR::Struct)> push_struct)
+::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& ent, const ::AST::AttributeList& attrs, ::std::function<void(RcString, ::HIR::Struct)> push_struct)
{
-
// 1. Figure out what sort of enum this is (value or data)
bool has_value = false;
bool has_data = false;
@@ -1029,14 +1070,14 @@ namespace {
{
::HIR::Struct::Data::Data_Tuple fields;
for(const auto& field : ve->m_sub_types)
- fields.push_back( new_visent(true, LowerHIR_Type(field)) );
+ fields.push_back( new_visent(::HIR::Publicity::new_global(), LowerHIR_Type(field)) );
data = ::HIR::Struct::Data::make_Tuple( mv$(fields) );
}
else if( const auto* ve = var.m_data.opt_Struct() )
{
::HIR::Struct::Data::Data_Named fields;
for(const auto& field : ve->m_fields)
- fields.push_back( ::std::make_pair( field.m_name, new_visent(true, LowerHIR_Type(field.m_type)) ) );
+ fields.push_back( ::std::make_pair( field.m_name, new_visent(::HIR::Publicity::new_global(), LowerHIR_Type(field.m_type)) ) );
data = ::HIR::Struct::Data::make_Named( mv$(fields) );
}
else
@@ -1044,7 +1085,7 @@ namespace {
throw "";
}
- auto ty_name = FMT(path.name << "#" << var.m_name);
+ auto ty_name = RcString::new_interned(FMT(path.name << "#" << var.m_name));
push_struct(
ty_name,
::HIR::Struct {
@@ -1082,6 +1123,9 @@ namespace {
}
::HIR::Union LowerHIR_Union(::HIR::ItemPath path, const ::AST::Union& f, const ::AST::AttributeList& attrs)
{
+ auto priv_path = ::HIR::Publicity::new_priv( get_parent_module(path) );
+ auto get_pub = [&](bool is_pub){ return is_pub ? ::HIR::Publicity::new_global() : priv_path; };
+
auto repr = ::HIR::Union::Repr::Rust;
if( const auto* attr_repr = attrs.get("repr") )
@@ -1100,7 +1144,7 @@ namespace {
::HIR::Struct::Data::Data_Named variants;
for(const auto& field : f.m_variants)
- variants.push_back( ::std::make_pair( field.m_name, new_visent(field.m_is_public, LowerHIR_Type(field.m_type)) ) );
+ variants.push_back( ::std::make_pair( field.m_name, new_visent(get_pub(field.m_is_public), LowerHIR_Type(field.m_type)) ) );
return ::HIR::Union {
LowerHIR_GenericParams(f.m_params, nullptr),
@@ -1116,14 +1160,14 @@ namespace {
bool trait_reqires_sized = false;
auto params = LowerHIR_GenericParams(f.params(), &trait_reqires_sized);
- ::std::string lifetime;
+ ::HIR::LifetimeRef lifetime;
::std::vector< ::HIR::TraitPath> supertraits;
for(const auto& st : f.supertraits()) {
if( st.ent.path.is_valid() ) {
supertraits.push_back( LowerHIR_TraitPath(st.sp, st.ent.path) );
}
else {
- lifetime = "static";
+ lifetime = ::HIR::LifetimeRef::new_static();
}
}
::HIR::Trait rv {
@@ -1150,32 +1194,36 @@ namespace {
TU_MATCH_DEF(::AST::Item, (item.data), (i),
(
- BUG(item.data.span, "Encountered unexpected item type in trait");
+ BUG(item.span, "Encountered unexpected item type in trait");
),
(None,
// Ignore.
),
+ (MacroInv,
+ // Ignore.
+ ),
(Type,
bool is_sized = true;
::std::vector< ::HIR::TraitPath> trait_bounds;
- ::std::string lifetime_bound;
+ ::HIR::LifetimeRef lifetime_bound;
auto gps = LowerHIR_GenericParams(i.params(), &is_sized);
+
for(auto& b : gps.m_bounds)
{
TU_MATCH(::HIR::GenericBound, (b), (be),
(TypeLifetime,
- ASSERT_BUG(item.data.span, be.type == ::HIR::TypeRef("Self", 0xFFFF), "Invalid lifetime bound on associated type");
+ ASSERT_BUG(item.span, be.type == ::HIR::TypeRef("Self", 0xFFFF), "Invalid lifetime bound on associated type");
lifetime_bound = mv$(be.valid_for);
),
(TraitBound,
- ASSERT_BUG(item.data.span, be.type == ::HIR::TypeRef("Self", 0xFFFF), "Invalid trait bound on associated type");
+ ASSERT_BUG(item.span, be.type == ::HIR::TypeRef("Self", 0xFFFF), "Invalid trait bound on associated type");
trait_bounds.push_back( mv$(be.trait) );
),
(Lifetime,
- BUG(item.data.span, "Unexpected lifetime-lifetime bound on associated type");
+ BUG(item.span, "Unexpected lifetime-lifetime bound on associated type");
),
(TypeEquality,
- BUG(item.data.span, "Unexpected type equality bound on associated type");
+ BUG(item.span, "Unexpected type equality bound on associated type");
)
)
}
@@ -1188,7 +1236,7 @@ namespace {
),
(Function,
::HIR::TypeRef self_type {"Self", 0xFFFF};
- auto fcn = LowerHIR_Function(item_path, item.data.attrs, i, self_type);
+ auto fcn = LowerHIR_Function(item_path, item.attrs, i, self_type);
fcn.m_save_code = true;
rv.m_values.insert( ::std::make_pair(item.name, ::HIR::TraitValueItem::make_Function( mv$(fcn) )) );
),
@@ -1248,13 +1296,29 @@ namespace {
else TU_IFLET(::HIR::TypeRef::Data, arg_self_ty.m_data, Path, e,
// Box - Compare with `owned_box` lang item
TU_IFLET(::HIR::Path::Data, e.path.m_data, Generic, pe,
- if( pe.m_path == g_crate_ptr->get_lang_item_path(sp, "owned_box") )
+ auto p = g_crate_ptr->get_lang_item_path_opt("owned_box");
+ if( pe.m_path == p )
{
if( pe.m_params.m_types.size() == 1 && pe.m_params.m_types[0] == self_type )
{
receiver = ::HIR::Function::Receiver::Box;
}
}
+ // TODO: for other types, support arbitary structs/paths.
+ // - The path must include Self as a (the only?) type param.
+ if( receiver == ::HIR::Function::Receiver::Free )
+ {
+ if( pe.m_params.m_types.size() == 0 ) {
+ ERROR(sp, E0000, "Unsupported receiver type - " << arg_self_ty);
+ }
+ if( pe.m_params.m_types.size() != 1 ) {
+ TODO(sp, "Receiver types with more than one param - " << arg_self_ty);
+ }
+ if( pe.m_params.m_types[0] != self_type ) {
+ ERROR(sp, E0000, "Unsupported receiver type - " << arg_self_ty);
+ }
+ receiver = ::HIR::Function::Receiver::Custom;
+ }
)
)
else {
@@ -1325,12 +1389,15 @@ namespace {
};
}
-void _add_mod_ns_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::HIR::TypeItem ti) {
+void _add_mod_ns_item(::HIR::Module& mod, RcString name, ::HIR::Publicity is_pub, ::HIR::TypeItem ti) {
mod.m_mod_items.insert( ::std::make_pair( mv$(name), ::make_unique_ptr(::HIR::VisEnt< ::HIR::TypeItem> { is_pub, mv$(ti) }) ) );
}
-void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::HIR::ValueItem ti) {
+void _add_mod_val_item(::HIR::Module& mod, RcString name, ::HIR::Publicity is_pub, ::HIR::ValueItem ti) {
mod.m_value_items.insert( ::std::make_pair( mv$(name), ::make_unique_ptr(::HIR::VisEnt< ::HIR::ValueItem> { is_pub, mv$(ti) }) ) );
}
+void _add_mod_mac_item(::HIR::Module& mod, RcString name, ::HIR::Publicity is_pub, ::HIR::MacroItem ti) {
+ mod.m_macro_items.insert( ::std::make_pair( mv$(name), ::make_unique_ptr(::HIR::VisEnt< ::HIR::MacroItem> { is_pub, mv$(ti) }) ) );
+}
::HIR::Module LowerHIR_Module(const ::AST::Module& ast_mod, ::HIR::ItemPath path, ::std::vector< ::HIR::SimplePath> traits)
{
@@ -1339,10 +1406,13 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
mod.m_traits = mv$(traits);
+ auto priv_path = ::HIR::Publicity::new_priv( path.get_simple_path() );
+ auto get_pub = [&](bool is_pub)->::HIR::Publicity{ return (is_pub ? ::HIR::Publicity::new_global() : priv_path); };
+
// Populate trait list
for(const auto& item : ast_mod.m_type_items)
{
- if( item.second.path.binding().is_Trait() ) {
+ if( item.second.path.m_bindings.type.is_Trait() ) {
auto sp = LowerHIR_SimplePath(Span(), item.second.path);
if( ::std::find(mod.m_traits.begin(), mod.m_traits.end(), sp) == mod.m_traits.end() )
mod.m_traits.push_back( mv$(sp) );
@@ -1355,21 +1425,23 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
if( submod_ptr )
{
auto& submod = *submod_ptr;
- ::std::string name = FMT("#" << i);
+ auto name = RcString::new_interned(FMT("#" << i));
auto item_path = ::HIR::ItemPath(path, name.c_str());
auto ti = ::HIR::TypeItem::make_Module( LowerHIR_Module(submod, item_path, mod.m_traits) );
- _add_mod_ns_item( mod, mv$(name), false, mv$(ti) );
+ _add_mod_ns_item( mod, mv$(name), get_pub(false), mv$(ti) );
}
}
for( const auto& item : ast_mod.items() )
{
- const auto& sp = item.data.span;
+ const auto& sp = item.span;
auto item_path = ::HIR::ItemPath(path, item.name.c_str());
DEBUG(item_path << " " << item.data.tag_str());
TU_MATCH(::AST::Item, (item.data), (e),
(None,
),
+ (Macro,
+ ),
(MacroInv,
// Valid.
//BUG(sp, "Stray macro invocation in " << path);
@@ -1380,7 +1452,7 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
TODO(sp, "Expand ExternBlock");
}
// Insert a record of the `link` attribute
- for(const auto& a : item.data.attrs.m_items)
+ for(const auto& a : item.attrs.m_items)
{
if( a.name() != "link" ) continue ;
@@ -1412,44 +1484,53 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
// Ignore - The index is used to add `Import`s
),
(Module,
- _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Module(e, mv$(item_path)) );
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), LowerHIR_Module(e, mv$(item_path)) );
),
(Crate,
// All 'extern crate' items should be normalised into a list in the crate root
// - If public, add a namespace import here referring to the root of the imported crate
- _add_mod_ns_item( mod, item.name, item.is_pub, ::HIR::TypeItem::make_Import({ ::HIR::SimplePath(e.name, {}), false, 0} ) );
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), ::HIR::TypeItem::make_Import({ ::HIR::SimplePath(e.name, {}), false, 0} ) );
),
(Type,
- _add_mod_ns_item( mod, item.name, item.is_pub, ::HIR::TypeItem::make_TypeAlias( LowerHIR_TypeAlias(e) ) );
+ if( e.type().m_data.is_Any() )
+ {
+ if( !e.params().lft_params().empty() || !e.params().ty_params().empty() || !e.params().bounds().empty() )
+ {
+ ERROR(item.span, E0000, "Generics on extern type");
+ }
+ _add_mod_ns_item(mod, item.name, get_pub(item.is_pub), ::HIR::ExternType {});
+ break;
+ }
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), ::HIR::TypeItem::make_TypeAlias( LowerHIR_TypeAlias(e) ) );
),
(Struct,
/// Add value reference
if( e.m_data.is_Unit() ) {
- _add_mod_val_item( mod, item.name, item.is_pub, ::HIR::ValueItem::make_StructConstant({item_path.get_simple_path()}) );
+ _add_mod_val_item( mod, item.name, get_pub(item.is_pub), ::HIR::ValueItem::make_StructConstant({item_path.get_simple_path()}) );
}
else if( e.m_data.is_Tuple() ) {
- _add_mod_val_item( mod, item.name, item.is_pub, ::HIR::ValueItem::make_StructConstructor({item_path.get_simple_path()}) );
+ _add_mod_val_item( mod, item.name, get_pub(item.is_pub), ::HIR::ValueItem::make_StructConstructor({item_path.get_simple_path()}) );
}
else {
}
- _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Struct(item_path, e, item.data.attrs) );
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), LowerHIR_Struct(item_path, e, item.attrs) );
),
(Enum,
- auto enm = LowerHIR_Enum(item_path, e, item.data.attrs, [&](auto name, auto str){ _add_mod_ns_item(mod, name, item.is_pub, mv$(str)); });
- _add_mod_ns_item( mod, item.name, item.is_pub, mv$(enm) );
+ auto enm = LowerHIR_Enum(item_path, e, item.attrs, [&](auto name, auto str){ _add_mod_ns_item(mod, name, get_pub(item.is_pub), mv$(str)); });
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), mv$(enm) );
),
(Union,
- _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Union(item_path, e, item.data.attrs) );
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), LowerHIR_Union(item_path, e, item.attrs) );
),
(Trait,
- _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Trait(item_path.get_simple_path(), e) );
+ _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), LowerHIR_Trait(item_path.get_simple_path(), e) );
),
(Function,
- _add_mod_val_item(mod, item.name, item.is_pub, LowerHIR_Function(item_path, item.data.attrs, e, ::HIR::TypeRef{}));
+ _add_mod_val_item(mod, item.name, get_pub(item.is_pub), LowerHIR_Function(item_path, item.attrs, e, ::HIR::TypeRef{}));
),
(Static,
if( e.s_class() == ::AST::Static::CONST )
- _add_mod_val_item(mod, item.name, item.is_pub, ::HIR::ValueItem::make_Constant(::HIR::Constant {
+ _add_mod_val_item(mod, item.name, get_pub(item.is_pub), ::HIR::ValueItem::make_Constant(::HIR::Constant {
::HIR::GenericParams {},
LowerHIR_Type( e.type() ),
LowerHIR_Expr( e.value() )
@@ -1460,10 +1541,10 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
// If there's no code, demangle the name (TODO: By ABI) and set linkage.
if( linkage.name == "" && ! e.value().is_valid() )
{
- linkage.name = item.name;
+ linkage.name = item.name.c_str();
}
- _add_mod_val_item(mod, item.name, item.is_pub, ::HIR::ValueItem::make_Static(::HIR::Static {
+ _add_mod_val_item(mod, item.name, get_pub(item.is_pub), ::HIR::ValueItem::make_Static(::HIR::Static {
mv$(linkage),
(e.s_class() == ::AST::Static::MUT),
LowerHIR_Type( e.type() ),
@@ -1481,17 +1562,15 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
if( ie.second.is_import ) {
auto hir_path = LowerHIR_SimplePath( sp, ie.second.path );
::HIR::TypeItem ti;
- TU_MATCH_DEF( ::AST::PathBinding, (ie.second.path.binding()), (pb),
- (
+ if( const auto* pb = ie.second.path.m_bindings.type.opt_EnumVar() ) {
+ DEBUG("Import NS " << ie.first << " = " << hir_path << " (Enum Variant)");
+ ti = ::HIR::TypeItem::make_Import({ mv$(hir_path), true, pb->idx });
+ }
+ else {
DEBUG("Import NS " << ie.first << " = " << hir_path);
ti = ::HIR::TypeItem::make_Import({ mv$(hir_path), false, 0 });
- ),
- (EnumVar,
- DEBUG("Import NS " << ie.first << " = " << hir_path << " (Enum Variant)");
- ti = ::HIR::TypeItem::make_Import({ mv$(hir_path), true, pb.idx });
- )
- )
- _add_mod_ns_item(mod, ie.first, ie.second.is_pub, mv$(ti));
+ }
+ _add_mod_ns_item(mod, ie.first, get_pub(ie.second.is_pub), mv$(ti));
}
}
for( const auto& ie : ast_mod.m_value_items )
@@ -1501,17 +1580,26 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H
auto hir_path = LowerHIR_SimplePath( sp, ie.second.path );
::HIR::ValueItem vi;
- TU_MATCH_DEF( ::AST::PathBinding, (ie.second.path.binding()), (pb),
- (
+ TU_MATCH_HDRA( (ie.second.path.m_bindings.value), {)
+ default:
DEBUG("Import VAL " << ie.first << " = " << hir_path);
vi = ::HIR::ValueItem::make_Import({ mv$(hir_path), false, 0 });
- ),
- (EnumVar,
+ TU_ARMA(EnumVar, pb) {
DEBUG("Import VAL " << ie.first << " = " << hir_path << " (Enum Variant)");
vi = ::HIR::ValueItem::make_Import({ mv$(hir_path), true, pb.idx });
- )
- )
- _add_mod_val_item(mod, ie.first, ie.second.is_pub, mv$(vi));
+ }
+ }
+ _add_mod_val_item(mod, ie.first, get_pub(ie.second.is_pub), mv$(vi));
+ }
+ }
+
+ for( const auto& ie : ast_mod.m_macro_imports )
+ {
+ //const auto& sp = mod_span;
+ if( ie.is_pub )
+ {
+ auto mi = ::HIR::MacroItem::make_Import({ ::HIR::SimplePath(ie.path.front(), ::std::vector<RcString>(ie.path.begin()+1, ie.path.end())) });
+ _add_mod_mac_item( mod, ie.name, get_pub(true), mv$(mi) );
}
}
@@ -1541,13 +1629,14 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
{
if( !i.data.is_Impl() ) continue;
const auto& impl = i.data.as_Impl();
+ const Span impl_span;
auto params = LowerHIR_GenericParams(impl.def().params(), nullptr);
TRACE_FUNCTION_F("IMPL " << impl.def());
if( impl.def().trait().ent.is_valid() )
{
- const auto& pb = impl.def().trait().ent.binding();
+ const auto& pb = impl.def().trait().ent.m_bindings.type;
ASSERT_BUG(Span(), pb.is_Trait(), "Binding for trait path in impl isn't a Trait - " << impl.def().trait().ent);
ASSERT_BUG(Span(), pb.as_Trait().trait_ || pb.as_Trait().hir, "Trait pointer for trait path in impl isn't set");
bool is_marker = (pb.as_Trait().trait_ ? pb.as_Trait().trait_->is_marker() : pb.as_Trait().hir->m_is_marker);
@@ -1562,16 +1651,16 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
::HIR::ItemPath path(type, trait_name, trait_args);
DEBUG(path);
- ::std::map< ::std::string, ::HIR::TraitImpl::ImplEnt< ::HIR::Function> > methods;
- ::std::map< ::std::string, ::HIR::TraitImpl::ImplEnt< ::HIR::Constant> > constants;
- ::std::map< ::std::string, ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> > types;
+ ::std::map< RcString, ::HIR::TraitImpl::ImplEnt< ::HIR::Function> > methods;
+ ::std::map< RcString, ::HIR::TraitImpl::ImplEnt< ::HIR::Constant> > constants;
+ ::std::map< RcString, ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> > types;
for(const auto& item : impl.items())
{
::HIR::ItemPath item_path(path, item.name.c_str());
TU_MATCH_DEF(::AST::Item, (*item.data), (e),
(
- BUG(item.data->span, "Unexpected item type in trait impl - " << item.data->tag_str());
+ BUG(item.sp, "Unexpected item type in trait impl - " << item.data->tag_str());
),
(None,
),
@@ -1587,7 +1676,7 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
} }) );
}
else {
- TODO(item.data->span, "Associated statics in trait impl");
+ TODO(item.sp, "Associated statics in trait impl");
}
),
(Type,
@@ -1596,12 +1685,13 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
),
(Function,
DEBUG("- method " << item.name);
- methods.insert( ::std::make_pair(item.name, ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { item.is_specialisable, LowerHIR_Function(item_path, item.data->attrs, e, type) }) );
+ methods.insert( ::std::make_pair(item.name, ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { item.is_specialisable, LowerHIR_Function(item_path, item.attrs, e, type) }) );
)
)
}
- hir_crate.m_trait_impls.insert( ::std::make_pair(mv$(trait_name), ::HIR::TraitImpl {
+ // Sorted later on
+ hir_crate.m_trait_impls[mv$(trait_name)].generic.push_back(box$(::HIR::TraitImpl {
mv$(params),
mv$(trait_args),
mv$(type),
@@ -1612,7 +1702,7 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
mv$(types),
LowerHIR_SimplePath(Span(), ast_mod.path())
- }) );
+ }));
}
else if( impl.def().type().m_data.is_None() )
{
@@ -1621,14 +1711,14 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
else
{
auto type = LowerHIR_Type(impl.def().type());
- hir_crate.m_marker_impls.insert( ::std::make_pair( mv$(trait_name), ::HIR::MarkerImpl {
+ hir_crate.m_marker_impls[mv$(trait_name)].generic.push_back(box$(::HIR::MarkerImpl {
mv$(params),
mv$(trait_args),
true,
mv$(type),
LowerHIR_SimplePath(Span(), ast_mod.path())
- } ) );
+ }));
}
}
else
@@ -1637,15 +1727,18 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
auto type = LowerHIR_Type(impl.def().type());
::HIR::ItemPath path(type);
- ::std::map< ::std::string, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> > methods;
- ::std::map< ::std::string, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> > constants;
+ auto priv_path = ::HIR::Publicity::new_priv( LowerHIR_SimplePath(Span(), ast_mod.path()) ); // TODO: Does this need to consume anon modules?
+ auto get_pub = [&](bool is_pub){ return is_pub ? ::HIR::Publicity::new_global() : priv_path; };
+
+ ::std::map< RcString, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> > methods;
+ ::std::map< RcString, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> > constants;
for(const auto& item : impl.items())
{
::HIR::ItemPath item_path(path, item.name.c_str());
TU_MATCH_DEF(::AST::Item, (*item.data), (e),
(
- BUG(item.data->span, "Unexpected item type in inherent impl - " << item.data->tag_str());
+ BUG(item.sp, "Unexpected item type in inherent impl - " << item.data->tag_str());
),
(None,
),
@@ -1653,32 +1746,33 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
),
(Static,
if( e.s_class() == ::AST::Static::CONST ) {
- constants.insert( ::std::make_pair(item.name, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> { item.is_pub, item.is_specialisable, ::HIR::Constant {
+ constants.insert( ::std::make_pair(item.name, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> { get_pub(item.is_pub), item.is_specialisable, ::HIR::Constant {
::HIR::GenericParams {},
LowerHIR_Type( e.type() ),
LowerHIR_Expr( e.value() )
} }) );
}
else {
- TODO(item.data->span, "Associated statics in inherent impl");
+ TODO(item.sp, "Associated statics in inherent impl");
}
),
(Function,
methods.insert( ::std::make_pair(item.name, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> {
- item.is_pub, item.is_specialisable, LowerHIR_Function(item_path, item.data->attrs, e, type)
+ get_pub(item.is_pub), item.is_specialisable, LowerHIR_Function(item_path, item.attrs, e, type)
} ) );
)
)
}
- hir_crate.m_type_impls.push_back( ::HIR::TypeImpl {
+ // Sorted later on
+ hir_crate.m_type_impls.generic.push_back( box$(::HIR::TypeImpl {
mv$(params),
mv$(type),
mv$(methods),
mv$(constants),
LowerHIR_SimplePath(Span(), ast_mod.path())
- } );
+ }) );
}
}
for( const auto& i : ast_mod.items() )
@@ -1692,14 +1786,15 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat
auto trait_name = mv$(trait.m_path);
auto trait_args = mv$(trait.m_params);
- hir_crate.m_marker_impls.insert( ::std::make_pair( mv$(trait_name), ::HIR::MarkerImpl {
+ // Sorting done later
+ hir_crate.m_marker_impls[mv$(trait_name)].generic.push_back(box$(::HIR::MarkerImpl {
mv$(params),
mv$(trait_args),
false,
mv$(type),
LowerHIR_SimplePath(Span(), ast_mod.path())
- } ) );
+ }) );
}
}
@@ -1735,18 +1830,20 @@ public:
if(crate.m_crate_type != ::AST::Crate::Type::Executable)
{
- rv.m_crate_name = crate.m_crate_name;
if(crate.m_crate_name_suffix != "")
{
- rv.m_crate_name += "-";
- rv.m_crate_name += crate.m_crate_name_suffix;
+ rv.m_crate_name = RcString::new_interned(FMT(crate.m_crate_name + "-" + crate.m_crate_name_suffix));
+ }
+ else
+ {
+ rv.m_crate_name = RcString::new_interned(crate.m_crate_name);
}
}
g_crate_ptr = &rv;
g_ast_crate_ptr = &crate;
g_crate_name = rv.m_crate_name;
- g_core_crate = (crate.m_load_std == ::AST::Crate::LOAD_NONE ? rv.m_crate_name : "core");
+ g_core_crate = (crate.m_load_std == ::AST::Crate::LOAD_NONE ? rv.m_crate_name : RcString::new_interned("core"));
auto& macros = rv.m_exported_macros;
// - Extract exported macros
@@ -1784,6 +1881,37 @@ public:
auto res = macros.insert( mv$(v) );
DEBUG("- Import " << mac.name << "! (from \"" << res.first->second->m_source_crate << "\")");
}
+ else if( v.second->m_rules.empty() ) {
+ // Skip
+ }
+ else {
+ DEBUG("- Replace " << mac.name << "! (from \"" << it->second->m_source_crate << "\") with one from \"" << v.second->m_source_crate << "\"");
+ it->second = mv$( v.second );
+ }
+ }
+ }
+ for( const auto& mac : crate.m_root_module.m_macro_imports )
+ {
+ if( mac.is_pub )
+ {
+ if( !mac.macro_ptr ) {
+ // Add to the re-export list
+ auto path = ::HIR::SimplePath(mac.path.front(), ::std::vector<RcString>(mac.path.begin()+1, mac.path.end()));;
+ rv.m_proc_macro_reexports.insert( ::std::make_pair( mac.name, ::HIR::Crate::MacroImport { path } ));
+ continue ;
+ }
+ // TODO: Why does this to such a move?
+ auto v = ::std::make_pair( mac.name, MacroRulesPtr(new MacroRules( mv$(*const_cast<MacroRules*>(mac.macro_ptr)) )) );
+
+ auto it = macros.find(mac.name);
+ if( it == macros.end() )
+ {
+ auto res = macros.insert( mv$(v) );
+ DEBUG("- Import " << mac.name << "! (from \"" << res.first->second->m_source_crate << "\")");
+ }
+ else if( v.second->m_rules.empty() ) {
+ // Skip
+ }
else {
DEBUG("- Replace " << mac.name << "! (from \"" << it->second->m_source_crate << "\") with one from \"" << v.second->m_source_crate << "\"");
it->second = mv$( v.second );
@@ -1797,7 +1925,7 @@ public:
for(const auto& ent : crate.m_proc_macros)
{
// Register under an invalid simplepath
- rv.m_proc_macros.push_back( ::HIR::ProcMacro { ent.name, ::HIR::SimplePath("", { ent.name}), ent.attributes } );
+ rv.m_proc_macros.push_back( ::HIR::ProcMacro { ent.name, ::HIR::SimplePath(RcString(""), { ent.name }), ent.attributes } );
}
}
else
@@ -1913,25 +2041,28 @@ public:
}
};
// Check for existing defintions of lang items before adding magic ones
- if( rv.m_lang_items.count("boxed_trait") == 0 )
- {
- rv.m_lang_items.insert(::std::make_pair( ::std::string("boxed_trait"), H::resolve_path(rv, false, {"ops", "Boxed"}) ));
- }
- if( rv.m_lang_items.count("placer_trait") == 0 )
- {
- rv.m_lang_items.insert(::std::make_pair( ::std::string("placer_trait"), H::resolve_path(rv, false, {"ops", "Placer"}) ));
- }
- if( rv.m_lang_items.count("place_trait") == 0 )
+ if( TARGETVER_1_19 )
{
- rv.m_lang_items.insert(::std::make_pair( ::std::string("place_trait"), H::resolve_path(rv, false, {"ops", "Place"}) ));
- }
- if( rv.m_lang_items.count("box_place_trait") == 0 )
- {
- rv.m_lang_items.insert(::std::make_pair( ::std::string("box_place_trait"), H::resolve_path(rv, false, {"ops", "BoxPlace"}) ));
- }
- if( rv.m_lang_items.count("in_place_trait") == 0 )
- {
- rv.m_lang_items.insert(::std::make_pair( ::std::string("in_place_trait"), H::resolve_path(rv, false, {"ops", "InPlace"}) ));
+ if( rv.m_lang_items.count("boxed_trait") == 0 )
+ {
+ rv.m_lang_items.insert(::std::make_pair( ::std::string("boxed_trait"), H::resolve_path(rv, false, {"ops", "Boxed"}) ));
+ }
+ if( rv.m_lang_items.count("placer_trait") == 0 )
+ {
+ rv.m_lang_items.insert(::std::make_pair( ::std::string("placer_trait"), H::resolve_path(rv, false, {"ops", "Placer"}) ));
+ }
+ if( rv.m_lang_items.count("place_trait") == 0 )
+ {
+ rv.m_lang_items.insert(::std::make_pair( ::std::string("place_trait"), H::resolve_path(rv, false, {"ops", "Place"}) ));
+ }
+ if( rv.m_lang_items.count("box_place_trait") == 0 )
+ {
+ rv.m_lang_items.insert(::std::make_pair( ::std::string("box_place_trait"), H::resolve_path(rv, false, {"ops", "BoxPlace"}) ));
+ }
+ if( rv.m_lang_items.count("in_place_trait") == 0 )
+ {
+ rv.m_lang_items.insert(::std::make_pair( ::std::string("in_place_trait"), H::resolve_path(rv, false, {"ops", "InPlace"}) ));
+ }
}
}
diff --git a/src/hir/from_ast.hpp b/src/hir/from_ast.hpp
index 4625f479..3eeaaa48 100644
--- a/src/hir/from_ast.hpp
+++ b/src/hir/from_ast.hpp
@@ -16,5 +16,5 @@ extern ::HIR::SimplePath LowerHIR_SimplePath(const Span& sp, const ::AST::Pat
extern ::HIR::TypeRef LowerHIR_Type(const ::TypeRef& ty);
extern ::HIR::Pattern LowerHIR_Pattern(const ::AST::Pattern& pat);
-extern ::std::string g_core_crate;
+extern RcString g_core_crate;
extern ::HIR::Crate* g_crate_ptr;
diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp
index 6daf49c3..baca8d75 100644
--- a/src/hir/from_ast_expr.cpp
+++ b/src/hir/from_ast_expr.cpp
@@ -47,6 +47,9 @@ struct LowerHIR_ExprNode_Visitor:
m_rv.reset( static_cast< ::HIR::ExprNode*>(rv) );
}
+ virtual void visit(::AST::ExprNode_Try& v) override {
+ TODO(v.span(), "Handle _Try");
+ }
virtual void visit(::AST::ExprNode_Macro& v) override {
BUG(v.span(), "Hit ExprNode_Macro");
}
@@ -211,22 +214,28 @@ struct LowerHIR_ExprNode_Visitor:
TU_IFLET(::AST::Path::Class, v.m_path.m_class, Local, e,
m_rv.reset( new ::HIR::ExprNode_CallValue( v.span(),
- ::HIR::ExprNodeP(new ::HIR::ExprNode_Variable( v.span(), e.name, v.m_path.binding().as_Variable().slot )),
+ ::HIR::ExprNodeP(new ::HIR::ExprNode_Variable( v.span(), e.name, v.m_path.m_bindings.value.as_Variable().slot )),
mv$(args)
) );
)
else
{
- TU_MATCH_DEF(::AST::PathBinding, (v.m_path.binding()), (e),
+ TU_MATCH_DEF(::AST::PathBinding_Value, (v.m_path.m_bindings.value), (e),
(
m_rv.reset( new ::HIR::ExprNode_CallPath( v.span(),
LowerHIR_Path(v.span(), v.m_path),
mv$( args )
) );
),
- (TypeAlias,
- TODO(v.span(), "CallPath -> TupleVariant TypeAlias");
+ (Static,
+ m_rv.reset( new ::HIR::ExprNode_CallValue( v.span(),
+ ::HIR::ExprNodeP(new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::STATIC )),
+ mv$(args)
+ ) );
),
+ //(TypeAlias,
+ // TODO(v.span(), "CallPath -> TupleVariant TypeAlias");
+ // ),
(EnumVar,
m_rv.reset( new ::HIR::ExprNode_TupleVariant( v.span(),
LowerHIR_GenericPath(v.span(), v.m_path), false,
@@ -323,16 +332,16 @@ struct LowerHIR_ExprNode_Visitor:
break;
}
- // TODO: Iterate the constructed loop and determine if there are any `break` statements pointing to it
+ // Iterate the constructed loop and determine if there are any `break` statements pointing to it
{
struct LoopVisitor:
public ::HIR::ExprVisitorDef
{
- const ::std::string& top_label;
+ const RcString& top_label;
bool top_is_broken;
- ::std::vector< const ::std::string*> name_stack;
+ ::std::vector< const RcString*> name_stack;
- LoopVisitor(const ::std::string& top_label):
+ LoopVisitor(const RcString& top_label):
top_label(top_label),
top_is_broken(false),
name_stack()
@@ -508,7 +517,7 @@ struct LowerHIR_ExprNode_Visitor:
) );
}
virtual void visit(::AST::ExprNode_StructLiteral& v) override {
- if( v.m_path.binding().is_Union() )
+ if( v.m_path.m_bindings.type.is_Union() )
{
if( v.m_values.size() != 1 )
ERROR(v.span(), E0000, "Union constructors can only specify a single field");
@@ -526,9 +535,10 @@ struct LowerHIR_ExprNode_Visitor:
::HIR::ExprNode_StructLiteral::t_values values;
for(const auto& val : v.m_values)
values.push_back( ::std::make_pair(val.name, LowerHIR_ExprNode_Inner(*val.value)) );
+ // TODO: What if `v.m_path` is an associated type (that's known to be a struct)
m_rv.reset( new ::HIR::ExprNode_StructLiteral( v.span(),
- LowerHIR_GenericPath(v.span(), v.m_path),
- ! v.m_path.binding().is_EnumVar(),
+ LowerHIR_Path(v.span(), v.m_path),
+ ! v.m_path.m_bindings.type.is_EnumVar(),
LowerHIR_ExprNode_Inner_Opt(v.m_base_value.get()),
mv$(values)
) );
@@ -559,22 +569,14 @@ struct LowerHIR_ExprNode_Visitor:
}
virtual void visit(::AST::ExprNode_NamedValue& v) override {
TU_IFLET(::AST::Path::Class, v.m_path.m_class, Local, e,
- if( !v.m_path.binding().is_Variable() ) {
- BUG(v.span(), "Named value was a local, but wasn't bound - " << v.m_path);
- }
- auto slot = v.m_path.binding().as_Variable().slot;
+ ASSERT_BUG(v.span(), v.m_path.m_bindings.value.is_Variable(), "Named value was a local, but wasn't bound - " << v.m_path);
+ auto slot = v.m_path.m_bindings.value.as_Variable().slot;
m_rv.reset( new ::HIR::ExprNode_Variable( v.span(), e.name, slot ) );
)
- else {
- TU_MATCH_DEF(::AST::PathBinding, (v.m_path.binding()), (e),
- (
- auto p = LowerHIR_Path(v.span(), v.m_path);
- if( p.m_data.is_Generic() ) {
- BUG(v.span(), "Unknown binding for PathValue but path is generic - " << v.m_path);
- }
- m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), mv$(p), ::HIR::ExprNode_PathValue::UNKNOWN ) );
- ),
- (Struct,
+ else
+ {
+ TU_MATCH_HDRA( (v.m_path.m_bindings.value), {)
+ TU_ARMA(Struct, e) {
ASSERT_BUG(v.span(), e.struct_ || e.hir, "PathValue bound to a struct but pointer not set - " << v.m_path);
// Check the form and emit a PathValue if not a unit
bool is_tuple_constructor = false;
@@ -604,8 +606,8 @@ struct LowerHIR_ExprNode_Visitor:
else {
m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(v.span(), v.m_path), true ) );
}
- ),
- (EnumVar,
+ }
+ TU_ARMA(EnumVar, e) {
ASSERT_BUG(v.span(), e.enum_ || e.hir, "PathValue bound to an enum but pointer not set - " << v.m_path);
const auto& var_name = v.m_path.nodes().back().name();
bool is_tuple_constructor = false;
@@ -646,11 +648,11 @@ struct LowerHIR_ExprNode_Visitor:
else {
m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(v.span(), v.m_path), false ) );
}
- ),
- (Function,
+ }
+ TU_ARMA(Function, e) {
m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::FUNCTION ) );
- ),
- (Static,
+ }
+ TU_ARMA(Static, e) {
if( e.static_ )
{
if( e.static_->s_class() != ::AST::Static::CONST ) {
@@ -669,8 +671,12 @@ struct LowerHIR_ExprNode_Visitor:
{
m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::CONSTANT ) );
}
- )
- )
+ }
+ break; default:
+ auto p = LowerHIR_Path(v.span(), v.m_path);
+ ASSERT_BUG(v.span(), !p.m_data.is_Generic(), "Unknown binding for PathValue but path is generic - " << v.m_path);
+ m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), mv$(p), ::HIR::ExprNode_PathValue::UNKNOWN ) );
+ }
}
}
diff --git a/src/hir/generic_params.cpp b/src/hir/generic_params.cpp
index 381277fc..3f6559a7 100644
--- a/src/hir/generic_params.cpp
+++ b/src/hir/generic_params.cpp
@@ -33,7 +33,7 @@ namespace HIR {
{
os << "<";
for(const auto& lft : x.gp.m_lifetimes) {
- os << "'" << lft << ",";
+ os << "'" << lft.m_name << ",";
}
for(const auto& typ : x.gp.m_types) {
os << typ.m_name;
diff --git a/src/hir/generic_params.hpp b/src/hir/generic_params.hpp
index ef83bda7..afa1c682 100644
--- a/src/hir/generic_params.hpp
+++ b/src/hir/generic_params.hpp
@@ -15,19 +15,23 @@ namespace HIR {
struct TypeParamDef
{
- ::std::string m_name;
+ RcString m_name;
::HIR::TypeRef m_default;
bool m_is_sized;
};
+struct LifetimeDef
+{
+ RcString m_name;
+};
TAGGED_UNION(GenericBound, Lifetime,
(Lifetime, struct {
- ::std::string test;
- ::std::string valid_for;
+ LifetimeRef test;
+ LifetimeRef valid_for;
}),
(TypeLifetime, struct {
::HIR::TypeRef type;
- ::std::string valid_for;
+ LifetimeRef valid_for;
}),
(TraitBound, struct {
::HIR::TypeRef type;
@@ -47,8 +51,8 @@ extern ::std::ostream& operator<<(::std::ostream& os, const GenericBound& x);
class GenericParams
{
public:
- ::std::vector<TypeParamDef> m_types;
- ::std::vector< ::std::string> m_lifetimes;
+ ::std::vector<TypeParamDef> m_types;
+ ::std::vector<LifetimeDef> m_lifetimes;
::std::vector<GenericBound> m_bounds;
diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp
index 5d67ac5f..88b1cb8c 100644
--- a/src/hir/hir.cpp
+++ b/src/hir/hir.cpp
@@ -17,12 +17,29 @@
#include <mir/main_bindings.hpp>
namespace HIR {
+ ::std::ostream& operator<<(::std::ostream& os, const Publicity& x)
+ {
+ if( !x.vis_path ) {
+ os << "pub";
+ }
+ else if( *x.vis_path == *Publicity::none_path ) {
+ os << "priv";
+ }
+ else {
+ os << "pub(" << *x.vis_path << ")";
+ }
+ return os;
+ }
+
::std::ostream& operator<<(::std::ostream& os, const ::HIR::Literal& v)
{
TU_MATCH(::HIR::Literal, (v), (e),
(Invalid,
os << "!";
),
+ (Defer,
+ os << "?";
+ ),
(List,
os << "[";
for(const auto& val : e)
@@ -58,6 +75,8 @@ namespace HIR {
TU_MATCH(::HIR::Literal, (l,r), (le,re),
(Invalid,
),
+ (Defer,
+ ),
(List,
if( le.size() != re.size() )
return false;
@@ -88,9 +107,49 @@ namespace HIR {
)
return true;
}
+
+ ::std::ostream& operator<<(::std::ostream& os, const Struct::Repr& x) {
+ os << "repr(";
+ switch(x)
+ {
+ case Struct::Repr::Rust: os << "Rust"; break;
+ case Struct::Repr::C: os << "C"; break;
+ case Struct::Repr::Packed: os << "packed"; break;
+ case Struct::Repr::Simd: os << "simd"; break;
+ case Struct::Repr::Aligned: os << "align(?)"; break;
+ case Struct::Repr::Transparent: os << "transparent"; break;
+ }
+ os << ")";
+ return os;
+ }
+}
+
+::std::shared_ptr<::HIR::SimplePath> HIR::Publicity::none_path = ::std::make_shared<HIR::SimplePath>(::HIR::SimplePath{"#", {}});
+
+bool HIR::Publicity::is_visible(const ::HIR::SimplePath& p) const
+{
+ // No path = global public
+ if( !vis_path )
+ return true;
+ // Empty simple path = full private
+ if( *vis_path == *none_path ) {
+ return false;
+ }
+ // Crate names must match
+ if(p.m_crate_name != vis_path->m_crate_name)
+ return false;
+ // `p` must be a child of vis_path
+ if(p.m_components.size() < vis_path->m_components.size())
+ return false;
+ for(size_t i = 0; i < vis_path->m_components.size(); i ++)
+ {
+ if(p.m_components[i] != vis_path->m_components[i])
+ return false;
+ }
+ return true;
}
-size_t HIR::Enum::find_variant(const ::std::string& name) const
+size_t HIR::Enum::find_variant(const RcString& name) const
{
if( m_data.is_Value() )
{
@@ -130,933 +189,6 @@ uint32_t HIR::Enum::get_value(size_t idx) const
}
}
-namespace {
- bool matches_genericpath(const ::HIR::GenericParams& params, const ::HIR::GenericPath& left, const ::HIR::GenericPath& right, ::HIR::t_cb_resolve_type ty_res, bool expand_generic);
-
- bool matches_type_int(const ::HIR::GenericParams& params, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right_in, ::HIR::t_cb_resolve_type ty_res, bool expand_generic)
- {
- assert(! left.m_data.is_Infer() );
- const auto& right = (right_in.m_data.is_Infer() || (right_in.m_data.is_Generic() && expand_generic) ? ty_res(right_in) : right_in);
- if( right_in.m_data.is_Generic() )
- expand_generic = false;
-
- //DEBUG("left = " << left << ", right = " << right);
-
- // TODO: What indicates what out of ty_res?
-
- if( const auto* re = right.m_data.opt_Infer() )
- {
- //DEBUG("left = " << left << ", right = " << right);
- switch(re->ty_class)
- {
- case ::HIR::InferClass::None:
- case ::HIR::InferClass::Diverge:
- //return left.m_data.is_Generic();
- return true;
- case ::HIR::InferClass::Integer:
- TU_IFLET(::HIR::TypeRef::Data, left.m_data, Primitive, le,
- return is_integer(le);
- )
- else {
- return left.m_data.is_Generic();
- }
- break;
- case ::HIR::InferClass::Float:
- TU_IFLET(::HIR::TypeRef::Data, left.m_data, Primitive, le,
- return is_float(le);
- )
- else {
- return left.m_data.is_Generic();
- }
- break;
- }
- throw "";
- }
-
- // A local generic could match anything, leave that up to the caller
- if( left.m_data.is_Generic() ) {
- DEBUG("> Generic left, success");
- return true;
- }
- // A local UfcsKnown can only be becuase it couldn't be expanded earlier, assume it could match
- if( left.m_data.is_Path() && left.m_data.as_Path().path.m_data.is_UfcsKnown() ) {
- // True?
- //DEBUG("> UFCS Unknown left, success");
- return true;
- }
-
- // If the RHS (provided) is generic, it can only match if it binds to a local type parameter
- if( right.m_data.is_Generic() ) {
- // TODO: This is handled above?
- //DEBUG("> Generic right, only if left generic");
- return left.m_data.is_Generic();
- }
- // If the RHS (provided) is generic, it can only match if it binds to a local type parameter
- if( TU_TEST1(right.m_data, Path, .binding.is_Unbound()) ) {
- //DEBUG("> UFCS Unknown right, fuzzy");
- return true;
- }
-
- if( left.m_data.tag() != right.m_data.tag() ) {
- //DEBUG("> Tag mismatch, failure");
- return false;
- }
- TU_MATCH(::HIR::TypeRef::Data, (left.m_data, right.m_data), (le, re),
- (Infer, assert(!"infer");),
- (Diverge, return true; ),
- (Primitive, return le == re;),
- (Path,
- if( le.path.m_data.tag() != re.path.m_data.tag() )
- return false;
- TU_MATCH_DEF(::HIR::Path::Data, (le.path.m_data, re.path.m_data), (ple, pre),
- (
- return false;
- ),
- (Generic,
- return matches_genericpath(params, ple, pre, ty_res, expand_generic);
- )
- )
- ),
- (Generic,
- throw "";
- ),
- (TraitObject,
- if( !matches_genericpath(params, le.m_trait.m_path, re.m_trait.m_path, ty_res, expand_generic) )
- return false;
- if( le.m_markers.size() != re.m_markers.size() )
- return false;
- for(unsigned int i = 0; i < le.m_markers.size(); i ++)
- {
- const auto& lm = le.m_markers[i];
- const auto& rm = re.m_markers[i];
- if( !matches_genericpath(params, lm, rm, ty_res, expand_generic) )
- return false;
- }
- return true;
- ),
- (ErasedType,
- throw "Unexpected ErasedType in matches_type_int";
- ),
- (Array,
- if( ! matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic) )
- return false;
- if( le.size_val != re.size_val )
- return false;
- return true;
- ),
- (Slice,
- return matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic);
- ),
- (Tuple,
- if( le.size() != re.size() )
- return false;
- for( unsigned int i = 0; i < le.size(); i ++ )
- if( !matches_type_int(params, le[i], re[i], ty_res, expand_generic) )
- return false;
- return true;
- ),
- (Borrow,
- if( le.type != re.type )
- return false;
- return matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic);
- ),
- (Pointer,
- if( le.type != re.type )
- return false;
- return matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic);
- ),
- (Function,
- if( le.is_unsafe != re.is_unsafe )
- return false;
- if( le.m_abi != re.m_abi )
- return false;
- if( le.m_arg_types.size() != re.m_arg_types.size() )
- return false;
- for( unsigned int i = 0; i < le.m_arg_types.size(); i ++ )
- if( !matches_type_int(params, le.m_arg_types[i], re.m_arg_types[i], ty_res, expand_generic) )
- return false;
- return matches_type_int(params, *le.m_rettype, *re.m_rettype, ty_res, expand_generic);
- ),
- (Closure,
- return le.node == re.node;
- )
- )
- return false;
- }
- bool matches_genericpath(const ::HIR::GenericParams& params, const ::HIR::GenericPath& left, const ::HIR::GenericPath& right, ::HIR::t_cb_resolve_type ty_res, bool expand_generic)
- {
- if( left.m_path.m_crate_name != right.m_path.m_crate_name )
- return false;
- if( left.m_path.m_components.size() != right.m_path.m_components.size() )
- return false;
- for(unsigned int i = 0; i < left.m_path.m_components.size(); i ++ )
- {
- if( left.m_path.m_components[i] != right.m_path.m_components[i] )
- return false;
- }
-
- if( left.m_params.m_types.size() > 0 || right.m_params.m_types.size() > 0 )
- {
- // Count mismatch. Allow due to defaults.
- if( left.m_params.m_types.size() != right.m_params.m_types.size() ) {
- return true;
- //TODO(Span(), "Match generic paths " << left << " and " << right << " - count mismatch");
- }
- for( unsigned int i = 0; i < right.m_params.m_types.size(); i ++ )
- {
- if( ! matches_type_int(params, left.m_params.m_types[i], right.m_params.m_types[i], ty_res, expand_generic) )
- return false;
- }
- }
- return true;
- }
-}
-
-//::HIR::TypeRef HIR::Function::make_ty(const Span& sp, const ::HIR::PathParams& params) const
-//{
-// // TODO: Obtain function type for this function (i.e. a type that is specifically for this function)
-// auto fcn_ty_data = ::HIR::FunctionType {
-// m_is_unsafe,
-// m_abi,
-// box$( monomorphise_type(sp, m_params, params, m_return) ),
-// {}
-// };
-// fcn_ty_data.m_arg_types.reserve( m_args.size() );
-// for(const auto& arg : m_args)
-// {
-// fcn_ty_data.m_arg_types.push_back( monomorphise_type(sp, m_params, params, arg.second) );
-// }
-// return ::HIR::TypeRef( mv$(fcn_ty_data) );
-//}
-
-namespace {
- bool is_unbounded_infer(const ::HIR::TypeRef& type) {
- TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Infer, e,
- return e.ty_class == ::HIR::InferClass::None || e.ty_class == ::HIR::InferClass::Diverge;
- )
- else {
- return false;
- }
- }
-}
-
-bool ::HIR::TraitImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const
-{
- // NOTE: Don't return any impls when the type is an unbouned ivar. Wouldn't be able to pick anything anyway
- // TODO: For `Unbound`, it could be valid, if the target is a generic.
- if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) {
- return false;
- }
- return matches_type_int(m_params, m_type, type, ty_res, true);
-}
-bool ::HIR::TypeImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const
-{
- if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) {
- return false;
- }
- return matches_type_int(m_params, m_type, type, ty_res, true);
-}
-bool ::HIR::MarkerImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const
-{
- if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) {
- return false;
- }
- return matches_type_int(m_params, m_type, type, ty_res, true);
-}
-
-namespace {
-
- struct TypeOrdSpecific_MixedOrdering
- {
- };
-
- ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& left, const ::std::vector<::HIR::TypeRef>& right);
-
- ::Ordering type_ord_specific(const Span& sp, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right)
- {
- // TODO: What happens if you get `impl<T> Foo<T> for T` vs `impl<T,U> Foo<U> for T`
-
- // A generic can't be more specific than any other type we can see
- // - It's equally as specific as another Generic, so still false
- if( left.m_data.is_Generic() ) {
- return right.m_data.is_Generic() ? ::OrdEqual : ::OrdLess;
- }
- // - A generic is always less specific than anything but itself (handled above)
- if( right.m_data.is_Generic() ) {
- return ::OrdGreater;
- }
-
- TU_MATCH(::HIR::TypeRef::Data, (left.m_data), (le),
- (Generic,
- throw "";
- ),
- (Infer,
- BUG(sp, "Hit infer");
- ),
- (Diverge,
- BUG(sp, "Hit diverge");
- ),
- (Closure,
- BUG(sp, "Hit closure");
- ),
- (Primitive,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Primitive, re,
- if( le != re )
- BUG(sp, "Mismatched types - " << left << " and " << right);
- return ::OrdEqual;
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- ),
- (Path,
- if( !right.m_data.is_Path() || le.path.m_data.tag() != right.m_data.as_Path().path.m_data.tag() )
- BUG(sp, "Mismatched types - " << left << " and " << right);
- TU_MATCHA( (le.path.m_data, right.m_data.as_Path().path.m_data), (lpe, rpe),
- (Generic,
- if( lpe.m_path != rpe.m_path )
- BUG(sp, "Mismatched types - " << left << " and " << right);
- return typelist_ord_specific(sp, lpe.m_params.m_types, rpe.m_params.m_types);
- ),
- (UfcsUnknown,
- ),
- (UfcsKnown,
- ),
- (UfcsInherent,
- )
- )
- TODO(sp, "Path - " << le.path << " and " << right);
- ),
- (TraitObject,
- ASSERT_BUG(sp, right.m_data.is_TraitObject(), "Mismatched types - "<< left << " vs " << right);
- const auto& re = right.m_data.as_TraitObject();
- ASSERT_BUG(sp, le.m_trait.m_path.m_path == re.m_trait.m_path.m_path, "Mismatched types - "<< left << " vs " << right);
- ASSERT_BUG(sp, le.m_markers.size() == re.m_markers.size(), "Mismatched types - "<< left << " vs " << right);
-
- auto ord = typelist_ord_specific(sp, le.m_trait.m_path.m_params.m_types, re.m_trait.m_path.m_params.m_types);
- if( ord != ::OrdEqual )
- return ord;
- for(size_t i = 0; i < le.m_markers.size(); i ++)
- {
- ASSERT_BUG(sp, le.m_markers[i].m_path == re.m_markers[i].m_path, "Mismatched types - " << left << " vs " << right);
- ord = typelist_ord_specific(sp, le.m_markers[i].m_params.m_types, re.m_markers[i].m_params.m_types);
- if(ord != ::OrdEqual)
- return ord;
- }
- return ::OrdEqual;
- ),
- (ErasedType,
- TODO(sp, "ErasedType - " << left);
- ),
- (Function,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Function, re,
- if( left == right )
- return ::OrdEqual;
- TODO(sp, "Function - " << left << " and " << right);
- //return typelist_ord_specific(sp, le.arg_types, re.arg_types);
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- ),
- (Tuple,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Tuple, re,
- return typelist_ord_specific(sp, le, re);
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- ),
- (Slice,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Slice, re,
- return type_ord_specific(sp, *le.inner, *re.inner);
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- ),
- (Array,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Array, re,
- if( le.size_val != re.size_val )
- BUG(sp, "Mismatched types - " << left << " and " << right);
- return type_ord_specific(sp, *le.inner, *re.inner);
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- ),
- (Pointer,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Pointer, re,
- if( le.type != re.type )
- BUG(sp, "Mismatched types - " << left << " and " << right);
- return type_ord_specific(sp, *le.inner, *re.inner);
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- ),
- (Borrow,
- TU_IFLET(::HIR::TypeRef::Data, right.m_data, Borrow, re,
- if( le.type != re.type )
- BUG(sp, "Mismatched types - " << left << " and " << right);
- return type_ord_specific(sp, *le.inner, *re.inner);
- )
- else {
- BUG(sp, "Mismatched types - " << left << " and " << right);
- }
- )
- )
- throw "Fell off end of type_ord_specific";
- }
-
- ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& le, const ::std::vector<::HIR::TypeRef>& re)
- {
- auto rv = ::OrdEqual;
- assert(le.size() == re.size());
- for(unsigned int i = 0; i < le.size(); i ++) {
- auto a = type_ord_specific(sp, le[i], re[i]);
- if( a != ::OrdEqual ) {
- if( rv != ::OrdEqual && a != rv )
- {
- DEBUG("Inconsistent ordering between type lists - i=" << i << " [" << le << "] vs [" << re << "]");
- throw TypeOrdSpecific_MixedOrdering {};
- }
- rv = a;
- }
- }
- return rv;
- }
-}
-
-namespace {
- void add_bound_from_trait(::std::vector< ::HIR::GenericBound>& rv, const ::HIR::TypeRef& type, const ::HIR::TraitPath& cur_trait)
- {
- static Span sp;
- assert( cur_trait.m_trait_ptr );
- const auto& tr = *cur_trait.m_trait_ptr;
- auto monomorph_cb = monomorphise_type_get_cb(sp, &type, &cur_trait.m_path.m_params, nullptr);
-
- for(const auto& trait_path_raw : tr.m_all_parent_traits)
- {
- // 1. Monomorph
- auto trait_path_mono = monomorphise_traitpath_with(sp, trait_path_raw, monomorph_cb, false);
- // 2. Add
- rv.push_back( ::HIR::GenericBound::make_TraitBound({ type.clone(), mv$(trait_path_mono) }) );
- }
-
- // TODO: Add traits from `Self: Foo` bounds?
- // TODO: Move associated types to the source trait.
- }
- ::std::vector< ::HIR::GenericBound> flatten_bounds(const ::std::vector<::HIR::GenericBound>& bounds)
- {
- ::std::vector< ::HIR::GenericBound > rv;
- for(const auto& b : bounds)
- {
- TU_MATCHA( (b), (be),
- (Lifetime,
- rv.push_back( ::HIR::GenericBound(be) );
- ),
- (TypeLifetime,
- rv.push_back( ::HIR::GenericBound::make_TypeLifetime({ be.type.clone(), be.valid_for }) );
- ),
- (TraitBound,
- rv.push_back( ::HIR::GenericBound::make_TraitBound({ be.type.clone(), be.trait.clone() }) );
- add_bound_from_trait(rv, be.type, be.trait);
- ),
- (TypeEquality,
- rv.push_back( ::HIR::GenericBound::make_TypeEquality({ be.type.clone(), be.other_type.clone() }) );
- )
- )
- }
- ::std::sort(rv.begin(), rv.end(), [](const auto& a, const auto& b){ return ::ord(a,b) == OrdLess; });
- return rv;
- }
-}
-
-bool ::HIR::TraitImpl::more_specific_than(const ::HIR::TraitImpl& other) const
-{
- static const Span _sp;
- const Span& sp = _sp;
- TRACE_FUNCTION;
- //DEBUG("this = " << *this);
- //DEBUG("other = " << other);
-
- // >> https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md#defining-the-precedence-rules
- // 1. If this->m_type is less specific than other.m_type: return false
- try
- {
- auto ord = type_ord_specific(sp, this->m_type, other.m_type);
- // If `*this` < `other` : false
- if( ord != ::OrdEqual ) {
- DEBUG("- Type " << this->m_type << " " << (ord == ::OrdLess ? "less" : "more") << " specific than " << other.m_type);
- return ord == ::OrdGreater;
- }
- // 2. If any in te.impl->m_params is less specific than oe.impl->m_params: return false
- ord = typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types);
- if( ord != ::OrdEqual ) {
- DEBUG("- Trait arguments " << (ord == ::OrdLess ? "less" : "more") << " specific");
- return ord == ::OrdGreater;
- }
- }
- catch(const TypeOrdSpecific_MixedOrdering& e)
- {
- BUG(sp, "Mixed ordering in more_specific_than");
- }
-
- //if( other.m_params.m_bounds.size() == 0 ) {
- // DEBUG("- Params (none in other, some in this)");
- // return m_params.m_bounds.size() > 0;
- //}
- // 3. Compare bound set, if there is a rule in oe that is missing from te; return false
- // TODO: Cache these lists (calculate after outer typecheck?)
- auto bounds_t = flatten_bounds(m_params.m_bounds);
- auto bounds_o = flatten_bounds(other.m_params.m_bounds);
-
- DEBUG("bounds_t = " << bounds_t);
- DEBUG("bounds_o = " << bounds_o);
-
- // If there are less bounds in this impl, it can't be more specific.
- if( bounds_t.size() < bounds_o.size() )
- {
- DEBUG("Bound count");
- return false;
- }
-
- auto it_t = bounds_t.begin();
- auto it_o = bounds_o.begin();
- while( it_t != bounds_t.end() && it_o != bounds_o.end() )
- {
- auto cmp = ::ord(*it_t, *it_o);
- if( cmp == OrdEqual )
- {
- ++it_t;
- ++it_o;
- continue ;
- }
-
- // If the two bounds are similar
- if( it_t->tag() == it_o->tag() && it_t->is_TraitBound() )
- {
- const auto& b_t = it_t->as_TraitBound();
- const auto& b_o = it_o->as_TraitBound();
- // Check if the type is equal
- if( b_t.type == b_o.type && b_t.trait.m_path.m_path == b_o.trait.m_path.m_path )
- {
- const auto& params_t = b_t.trait.m_path.m_params;
- const auto& params_o = b_o.trait.m_path.m_params;
- switch( typelist_ord_specific(sp, params_t.m_types, params_o.m_types) )
- {
- case ::OrdLess: return false;
- case ::OrdGreater: return true;
- case ::OrdEqual: break;
- }
- // TODO: Find cases where there's `T: Foo<T>` and `T: Foo<U>`
- for(unsigned int i = 0; i < params_t.m_types.size(); i ++ )
- {
- if( params_t.m_types[i] != params_o.m_types[i] && params_t.m_types[i] == b_t.type )
- {
- return true;
- }
- }
- TODO(sp, *it_t << " ?= " << *it_o);
- }
- }
-
- if( cmp == OrdLess )
- {
- ++ it_t;
- }
- else
- {
- //++ it_o;
- return false;
- }
- }
- if( it_t != bounds_t.end() )
- {
- return true;
- }
- else
- {
- return false;
- }
-}
-
-// Returns `true` if the two impls overlap in the types they will accept
-bool ::HIR::TraitImpl::overlaps_with(const Crate& crate, const ::HIR::TraitImpl& other) const
-{
- // TODO: Pre-calculate impl trees (with pointers to parent impls)
- struct H {
- static bool types_overlap(const ::HIR::PathParams& a, const ::HIR::PathParams& b)
- {
- for(unsigned int i = 0; i < ::std::min(a.m_types.size(), b.m_types.size()); i ++)
- {
- if( ! H::types_overlap(a.m_types[i], b.m_types[i]) )
- return false;
- }
- return true;
- }
- static bool types_overlap(const ::HIR::TypeRef& a, const ::HIR::TypeRef& b)
- {
- static Span sp;
- //DEBUG("(" << a << "," << b << ")");
- if( a.m_data.is_Generic() || b.m_data.is_Generic() )
- return true;
- // TODO: Unbound/Opaque paths?
- if( a.m_data.tag() != b.m_data.tag() )
- return false;
- TU_MATCHA( (a.m_data, b.m_data), (ae, be),
- (Generic,
- ),
- (Infer,
- ),
- (Diverge,
- ),
- (Closure,
- BUG(sp, "Hit closure");
- ),
- (Primitive,
- if( ae != be )
- return false;
- ),
- (Path,
- if( ae.path.m_data.tag() != be.path.m_data.tag() )
- return false;
- TU_MATCHA( (ae.path.m_data, be.path.m_data), (ape, bpe),
- (Generic,
- if( ape.m_path != bpe.m_path )
- return false;
- return H::types_overlap(ape.m_params, bpe.m_params);
- ),
- (UfcsUnknown,
- ),
- (UfcsKnown,
- ),
- (UfcsInherent,
- )
- )
- TODO(sp, "Path - " << ae.path << " and " << be.path);
- ),
- (TraitObject,
- if( ae.m_trait.m_path.m_path != be.m_trait.m_path.m_path )
- return false;
- if( !H::types_overlap(ae.m_trait.m_path.m_params, be.m_trait.m_path.m_params) )
- return false;
- // Marker traits only overlap if the lists are the same (with overlap)
- if( ae.m_markers.size() != be.m_markers.size() )
- return false;
- for(size_t i = 0; i < ae.m_markers.size(); i++)
- {
- if( ae.m_markers[i].m_path != be.m_markers[i].m_path )
- return false;
- if( !H::types_overlap(ae.m_markers[i].m_params, be.m_markers[i].m_params) )
- return false;
- }
- return true;
- ),
- (ErasedType,
- TODO(sp, "ErasedType - " << a);
- ),
- (Function,
- if( ae.is_unsafe != be.is_unsafe )
- return false;
- if( ae.m_abi != be.m_abi )
- return false;
- if( ae.m_arg_types.size() != be.m_arg_types.size() )
- return false;
- for(unsigned int i = 0; i < ae.m_arg_types.size(); i ++)
- {
- if( ! H::types_overlap(ae.m_arg_types[i], be.m_arg_types[i]) )
- return false;
- }
- ),
- (Tuple,
- if( ae.size() != be.size() )
- return false;
- for(unsigned int i = 0; i < ae.size(); i ++)
- {
- if( ! H::types_overlap(ae[i], be[i]) )
- return false;
- }
- ),
- (Slice,
- return H::types_overlap( *ae.inner, *be.inner );
- ),
- (Array,
- if( ae.size_val != be.size_val )
- return false;
- return H::types_overlap( *ae.inner, *be.inner );
- ),
- (Pointer,
- if( ae.type != be.type )
- return false;
- return H::types_overlap( *ae.inner, *be.inner );
- ),
- (Borrow,
- if( ae.type != be.type )
- return false;
- return H::types_overlap( *ae.inner, *be.inner );
- )
- )
- return true;
- }
- };
-
- // Quick Check: If the types are equal, they do overlap
- if(this->m_type == other.m_type && this->m_trait_args == other.m_trait_args)
- {
- return true;
- }
-
- // 1. Are the impl types of the same form (or is one generic)
- if( ! H::types_overlap(this->m_type, other.m_type) )
- return false;
- if( ! H::types_overlap(this->m_trait_args, other.m_trait_args) )
- return false;
-
- DEBUG("TODO: Handle potential overlap (when not exactly equal)");
- //return this->m_type == other.m_type && this->m_trait_args == other.m_trait_args;
- Span sp;
-
- // TODO: Use `type_ord_specific` but treat any case of mixed ordering as this returning `false`
- try
- {
- type_ord_specific(sp, this->m_type, other.m_type);
- typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types);
- }
- catch(const TypeOrdSpecific_MixedOrdering& /*e*/)
- {
- return false;
- }
-
- // TODO: Detect `impl<T> Foo<T> for Bar<T>` vs `impl<T> Foo<&T> for Bar<T>`
- // > Create values for impl params from the type, then check if the trait params are compatible
- // > Requires two lists, and telling which one to use by the end
- auto cb_ident = [](const ::HIR::TypeRef& x)->const ::HIR::TypeRef& { return x; };
- bool is_reversed = false;
- ::std::vector<const ::HIR::TypeRef*> impl_tys;
- auto cb_match = [&](unsigned int idx, const auto& /*name*/, const ::HIR::TypeRef& x)->::HIR::Compare {
- assert(idx < impl_tys.size());
- if( impl_tys.at(idx) )
- {
- DEBUG("Compare " << x << " and " << *impl_tys.at(idx));
- return (x == *impl_tys.at(idx) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal);
- }
- else
- {
- impl_tys.at(idx) = &x;
- return ::HIR::Compare::Equal;
- }
- };
- impl_tys.resize( this->m_params.m_types.size() );
- if( ! this->m_type.match_test_generics(sp, other.m_type, cb_ident, cb_match) )
- {
- DEBUG("- Type mismatch, try other ordering");
- is_reversed = true;
- impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() );
- if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) )
- {
- DEBUG("- Type mismatch in both orderings");
- return false;
- }
- if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal )
- {
- DEBUG("- Params mismatch");
- return false;
- }
- // Matched with second ording
- }
- else if( this->m_trait_args.match_test_generics_fuzz(sp, other.m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal )
- {
- DEBUG("- Param mismatch, try other ordering");
- is_reversed = true;
- impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() );
- if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) )
- {
- DEBUG("- Type mismatch in alt ordering");
- return false;
- }
- if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal )
- {
- DEBUG("- Params mismatch in alt ordering");
- return false;
- }
- // Matched with second ordering
- }
- else
- {
- // Matched with first ordering
- }
-
- struct H2 {
- static const ::HIR::TypeRef& monomorph(const Span& sp, const ::HIR::TypeRef& in_ty, const ::std::vector<const ::HIR::TypeRef*>& args, ::HIR::TypeRef& tmp)
- {
- if( ! monomorphise_type_needed(in_ty) ) {
- return in_ty;
- }
- else if( const auto* tep = in_ty.m_data.opt_Generic() ) {
- ASSERT_BUG(sp, tep->binding < args.size(), "");
- ASSERT_BUG(sp, args[tep->binding], "");
- return *args[tep->binding];
- }
- else {
- auto monomorph_cb = [&](const auto& t)->const auto& {
- const auto& te = t.m_data.as_Generic();
- assert(te.binding < args.size());
- ASSERT_BUG(sp, te.binding < args.size(), "");
- ASSERT_BUG(sp, args[te.binding], "");
- return *args[te.binding];
- };
- tmp = monomorphise_type_with(sp, in_ty, monomorph_cb);
- // TODO: EAT?
- return tmp;
- }
- }
- static const ::HIR::TraitPath& monomorph(const Span& sp, const ::HIR::TraitPath& in, const ::std::vector<const ::HIR::TypeRef*>& args, ::HIR::TraitPath& tmp)
- {
- if( ! monomorphise_traitpath_needed(in) ) {
- return in;
- }
- else {
- auto monomorph_cb = [&](const auto& t)->const auto& {
- const auto& te = t.m_data.as_Generic();
- assert(te.binding < args.size());
- ASSERT_BUG(sp, te.binding < args.size(), "");
- ASSERT_BUG(sp, args[te.binding], "");
- return *args[te.binding];
- };
- tmp = monomorphise_traitpath_with(sp, in, monomorph_cb, true);
- // TODO: EAT?
- return tmp;
- }
- }
- static bool check_bounds(const ::HIR::Crate& crate, const ::HIR::TraitImpl& id, const ::std::vector<const ::HIR::TypeRef*>& args, const ::HIR::TraitImpl& g_src)
- {
- TRACE_FUNCTION;
- static Span sp;
- for(const auto& tb : id.m_params.m_bounds)
- {
- if(tb.is_TraitBound())
- {
- ::HIR::TypeRef tmp_ty;
- ::HIR::TraitPath tmp_tp;
- const auto& ty = H2::monomorph(sp, tb.as_TraitBound().type, args, tmp_ty);
- const auto& trait = H2::monomorph(sp, tb.as_TraitBound().trait, args, tmp_tp);;
-
- // Determine if `ty` would be bounded (it's an ATY or generic)
- if( ty.m_data.is_Generic() ) {
- bool found = false;
- for(const auto& bound : g_src.m_params.m_bounds)
- {
- if(const auto* be = bound.opt_TraitBound())
- {
- if( be->type != ty ) continue;
- if( be->trait != trait ) continue;
- found = true;
- }
- }
- if( !found )
- {
- DEBUG("No matching bound for " << ty << " : " << trait << " in source bounds - " << g_src.m_params.fmt_bounds());
- return false;
- }
- }
- else if( TU_TEST1(ty.m_data, Path, .binding.is_Opaque()) ) {
- TODO(Span(), "Check bound " << ty << " : " << trait << " in source bounds or trait bounds");
- }
- else {
- // Search the crate for an impl
- bool rv = crate.find_trait_impls(trait.m_path.m_path, ty, [](const auto&t)->const auto&{ return t; }, [&](const ::HIR::TraitImpl& ti)->bool {
- DEBUG("impl" << ti.m_params.fmt_args() << " " << trait.m_path.m_path << ti.m_trait_args << " for " << ti.m_type << ti.m_params.fmt_bounds());
-
- ::std::vector<const ::HIR::TypeRef*> impl_tys { ti.m_params.m_types.size() };
- auto cb_ident = [](const ::HIR::TypeRef& x)->const ::HIR::TypeRef& { return x; };
- auto cb_match = [&](unsigned int idx, const auto& /*name*/, const ::HIR::TypeRef& x)->::HIR::Compare {
- assert(idx < impl_tys.size());
- if( impl_tys.at(idx) )
- {
- DEBUG("Compare " << x << " and " << *impl_tys.at(idx));
- return (x == *impl_tys.at(idx) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal);
- }
- else
- {
- impl_tys.at(idx) = &x;
- return ::HIR::Compare::Equal;
- }
- };
- // 1. Triple-check the type matches (and get generics)
- if( ! ti.m_type.match_test_generics(sp, ty, cb_ident, cb_match) )
- return false;
- // 2. Check trait params
- assert(trait.m_path.m_params.m_types.size() == ti.m_trait_args.m_types.size());
- for(size_t i = 0; i < trait.m_path.m_params.m_types.size(); i ++)
- {
- if( !ti.m_trait_args.m_types[i].match_test_generics(sp, trait.m_path.m_params.m_types[i], cb_ident, cb_match) )
- return false;
- }
- // 3. Check bounds on the impl
- if( !H2::check_bounds(crate, ti, impl_tys, g_src) )
- return false;
- // 4. Check ATY bounds on the trait path
- for(const auto& atyb : trait.m_type_bounds)
- {
- const auto& aty = ti.m_types.at(atyb.first);
- if( !aty.data.match_test_generics(sp, atyb.second, cb_ident, cb_match) )
- return false;
- }
- // All those pass? It's good.
- return true;
- });
- if( !rv )
- {
- return false;
- }
- }
- }
- else
- {
- // TODO: Other bound types?
- }
- }
- // No bounds failed, it's good
- return true;
- }
- };
-
- // The two impls could overlap, pending on trait bounds
- if(is_reversed)
- {
- DEBUG("(reversed) impl params " << FMT_CB(os,
- for(auto* p : impl_tys)
- {
- if(p)
- os << *p;
- else
- os << "?";
- os << ",";
- }
- ));
- // Check bounds on `other` using these params
- // TODO: Take a callback that does the checks. Or somehow return a "maybe overlaps" result?
- return H2::check_bounds(crate, other, impl_tys, *this);
- }
- else
- {
- DEBUG("impl params " << FMT_CB(os,
- for(auto* p : impl_tys)
- {
- if(p)
- os << *p;
- else
- os << "?";
- os << ",";
- }
- ));
- // Check bounds on `*this`
- return H2::check_bounds(crate, *this, impl_tys, other);
- }
-}
-
const ::HIR::SimplePath& ::HIR::Crate::get_lang_item_path(const Span& sp, const char* name) const
{
@@ -1229,122 +361,3 @@ const ::HIR::Function& ::HIR::Crate::get_function_by_path(const Span& sp, const
}
}
-bool ::HIR::Crate::find_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TraitImpl&)> callback) const
-{
- auto its = this->m_trait_impls.equal_range( trait );
- for( auto it = its.first; it != its.second; ++ it )
- {
- const auto& impl = it->second;
- if( impl.matches_type(type, ty_res) ) {
- if( callback(impl) ) {
- return true;
- }
- }
- }
- for( const auto& ec : this->m_ext_crates )
- {
- if( ec.second.m_data->find_trait_impls(trait, type, ty_res, callback) ) {
- return true;
- }
- }
- return false;
-}
-bool ::HIR::Crate::find_auto_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::MarkerImpl&)> callback) const
-{
- auto its = this->m_marker_impls.equal_range( trait );
- for( auto it = its.first; it != its.second; ++ it )
- {
- const auto& impl = it->second;
- if( impl.matches_type(type, ty_res) ) {
- if( callback(impl) ) {
- return true;
- }
- }
- }
- for( const auto& ec : this->m_ext_crates )
- {
- if( ec.second.m_data->find_auto_trait_impls(trait, type, ty_res, callback) ) {
- return true;
- }
- }
- return false;
-}
-bool ::HIR::Crate::find_type_impls(const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TypeImpl&)> callback) const
-{
- // TODO: Restrict which crate is searched based on the type.
- for( const auto& impl : this->m_type_impls )
- {
- if( impl.matches_type(type, ty_res) ) {
- if( callback(impl) ) {
- return true;
- }
- }
- }
- for( const auto& ec : this->m_ext_crates )
- {
- //DEBUG("- " << ec.first);
- if( ec.second.m_data->find_type_impls(type, ty_res, callback) ) {
- return true;
- }
- }
- return false;
-}
-
-const ::MIR::Function* HIR::Crate::get_or_gen_mir(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& ep, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_ty) const
-{
- if( !ep )
- {
- return &*ep.m_mir;
- }
- else
- {
- if( !ep.m_mir )
- {
- ASSERT_BUG(Span(), ep.m_state, "No ExprState for " << ip);
-
- auto& ep_mut = const_cast<::HIR::ExprPtr&>(ep);
-
- // Ensure typechecked
- if( ep.m_state->stage < ::HIR::ExprState::Stage::Typecheck )
- {
- if( ep.m_state->stage == ::HIR::ExprState::Stage::TypecheckRequest )
- ERROR(Span(), E0000, "Loop in constant evaluation");
- ep.m_state->stage = ::HIR::ExprState::Stage::TypecheckRequest;
-
- // TODO: Set debug/timing stage
- //Debug_SetStagePre("HIR Typecheck");
- // - Can store that on the Expr, OR get it from the item path
- typeck::ModuleState ms { const_cast<::HIR::Crate&>(*this) };
- ms.m_impl_generics = ep.m_state->m_impl_generics;
- ms.m_item_generics = ep.m_state->m_item_generics;
- ms.m_traits = ep.m_state->m_traits;
- Typecheck_Code(ms, const_cast<::HIR::Function::args_t&>(args), ret_ty, ep_mut);
- //Debug_SetStagePre("Expand HIR Annotate");
- HIR_Expand_AnnotateUsage_Expr(*this, ep_mut);
- //Debug_SetStagePre("Expand HIR Closures");
- HIR_Expand_Closures_Expr(*this, ep_mut);
- //Debug_SetStagePre("Expand HIR Calls");
- HIR_Expand_UfcsEverything_Expr(*this, ep_mut);
- //Debug_SetStagePre("Expand HIR Reborrows");
- HIR_Expand_Reborrows_Expr(*this, ep_mut);
- //Debug_SetStagePre("Expand HIR ErasedType");
- //HIR_Expand_ErasedType(*this, ep_mut); // - Maybe?
- //Typecheck_Expressions_Validate(*hir_crate);
-
- ep.m_state->stage = ::HIR::ExprState::Stage::Typecheck;
- }
- // Generate MIR
- if( ep.m_state->stage < ::HIR::ExprState::Stage::Mir )
- {
- if( ep.m_state->stage == ::HIR::ExprState::Stage::MirRequest )
- ERROR(Span(), E0000, "Loop in constant evaluation");
- ep.m_state->stage = ::HIR::ExprState::Stage::MirRequest;
- //Debug_SetStage("Lower MIR");
- HIR_GenerateMIR_Expr(*this, ip, ep_mut, args, ret_ty);
- ep.m_state->stage = ::HIR::ExprState::Stage::Mir;
- }
- assert(ep.m_mir);
- }
- return &*ep.m_mir;
- }
-}
diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp
index 8024e1c0..8b718b4f 100644
--- a/src/hir/hir.hpp
+++ b/src/hir/hir.hpp
@@ -8,6 +8,7 @@
* Contains the expanded and desugared AST
*/
#pragma once
+#include <target_version.hpp>
#include <cassert>
#include <unordered_map>
@@ -37,13 +38,50 @@ class Static;
class ValueItem;
class TypeItem;
+class MacroItem;
class ItemPath;
+class Publicity
+{
+ static ::std::shared_ptr<::HIR::SimplePath> none_path;
+ ::std::shared_ptr<::HIR::SimplePath> vis_path;
+
+ Publicity(::std::shared_ptr<::HIR::SimplePath> p)
+ :vis_path(p)
+ {
+ }
+public:
+
+ static Publicity new_global() {
+ return Publicity({});
+ }
+ static Publicity new_none() {
+ return Publicity(none_path);
+ }
+ static Publicity new_priv(::HIR::SimplePath p) {
+ return Publicity(::std::make_shared<HIR::SimplePath>(::std::move(p)));
+ }
+
+ bool is_global() const {
+ return !vis_path;
+ }
+ bool is_visible(const ::HIR::SimplePath& p) const;
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const Publicity& x);
+};
+
+enum class ConstEvalState
+{
+ None,
+ Active,
+ Complete,
+};
+
template<typename Ent>
struct VisEnt
{
- bool is_public;
+ Publicity publicity;
Ent ent;
};
@@ -51,6 +89,7 @@ struct VisEnt
/// NOTE: Intentionally minimal, just covers the values (not the types)
TAGGED_UNION(Literal, Invalid,
(Invalid, struct {}),
+ (Defer, struct {}),
// List = Array, Tuple, struct literal
(List, ::std::vector<Literal>), // TODO: Have a variant for repetition lists
// Variant = Enum variant
@@ -111,6 +150,9 @@ public:
TypeRef m_type;
ExprPtr m_value;
Literal m_value_res;
+
+ // A cache of monomorphised versions when the `const` depends on generics for its value
+ mutable ::std::map< ::HIR::Path, Literal> m_monomorph_cache;
};
class Function
{
@@ -124,6 +166,7 @@ public:
//PointerMut,
//PointerConst,
Box,
+ Custom,
};
typedef ::std::vector< ::std::pair< ::HIR::Pattern, ::HIR::TypeRef> > args_t;
@@ -157,7 +200,7 @@ struct TypeAlias
};
typedef ::std::vector< VisEnt<::HIR::TypeRef> > t_tuple_fields;
-typedef ::std::vector< ::std::pair< ::std::string, VisEnt<::HIR::TypeRef> > > t_struct_fields;
+typedef ::std::vector< ::std::pair< RcString, VisEnt<::HIR::TypeRef> > > t_struct_fields;
/// Cache of the state of various language traits on an enum/struct
struct TraitMarkings
@@ -212,11 +255,18 @@ struct StructMarkings
unsigned int coerce_param = ~0u;
};
+class ExternType
+{
+public:
+ // TODO: do extern types need any associated data?
+ TraitMarkings m_markings;
+};
+
class Enum
{
public:
struct DataVariant {
- ::std::string name;
+ RcString name;
bool is_struct; // Indicates that the variant does not show up in the value namespace
::HIR::TypeRef type;
};
@@ -227,7 +277,7 @@ public:
Usize, U8, U16, U32, U64,
};
struct ValueVariant {
- ::std::string name;
+ RcString name;
::HIR::ExprPtr expr;
// TODO: Signed.
uint64_t val;
@@ -248,7 +298,7 @@ public:
size_t num_variants() const {
return (m_data.is_Data() ? m_data.as_Data().size() : m_data.as_Value().variants.size());
}
- size_t find_variant(const ::std::string& ) const;
+ size_t find_variant(const RcString& ) const;
/// Returns true if this enum is a C-like enum (has values only)
bool is_value() const;
@@ -264,6 +314,8 @@ public:
C,
Packed,
Simd,
+ Aligned, // Alignment stored elsewhere
+ Transparent,
};
TAGGED_UNION(Data, Unit,
(Unit, struct {}),
@@ -271,13 +323,33 @@ public:
(Named, t_struct_fields)
);
+ Struct(GenericParams params, Repr repr, Data data)
+ :m_params(mv$(params))
+ ,m_repr(mv$(repr))
+ ,m_data(mv$(data))
+ {
+ }
+ Struct(GenericParams params, Repr repr, Data data, unsigned align, TraitMarkings tm, StructMarkings sm)
+ :m_params(mv$(params))
+ ,m_repr(mv$(repr))
+ ,m_data(mv$(data))
+ ,m_forced_alignment(align)
+ ,m_markings(mv$(tm))
+ ,m_struct_markings(mv$(sm))
+ {
+ }
+
GenericParams m_params;
Repr m_repr;
Data m_data;
+ unsigned m_forced_alignment = 0;
TraitMarkings m_markings;
StructMarkings m_struct_markings;
+
+ ConstEvalState const_eval_state = ConstEvalState::None;
};
+extern ::std::ostream& operator<<(::std::ostream& os, const Struct::Repr& x);
class Union
{
public:
@@ -297,7 +369,7 @@ public:
struct AssociatedType
{
bool is_sized;
- ::std::string m_lifetime_bound;
+ LifetimeRef m_lifetime_bound;
::std::vector< ::HIR::TraitPath> m_trait_bounds;
::HIR::TypeRef m_default;
};
@@ -310,23 +382,25 @@ class Trait
{
public:
GenericParams m_params;
- ::std::string m_lifetime;
+ LifetimeRef m_lifetime;
::std::vector< ::HIR::TraitPath > m_parent_traits;
bool m_is_marker; // aka OIBIT
- ::std::unordered_map< ::std::string, AssociatedType > m_types;
- ::std::unordered_map< ::std::string, TraitValueItem > m_values;
+ ::std::unordered_map< RcString, AssociatedType > m_types;
+ ::std::unordered_map< RcString, TraitValueItem > m_values;
// Indexes into the vtable for each present method and value
- ::std::unordered_multimap< ::std::string, ::std::pair<unsigned int,::HIR::GenericPath> > m_value_indexes;
+ ::std::unordered_multimap< RcString, ::std::pair<unsigned int,::HIR::GenericPath> > m_value_indexes;
// Indexes in the vtable parameter list for each associated type
- ::std::unordered_map< ::std::string, unsigned int > m_type_indexes;
+ ::std::unordered_map< RcString, unsigned int > m_type_indexes;
// Flattend set of parent traits (monomorphised and associated types fixed)
::std::vector< ::HIR::TraitPath > m_all_parent_traits;
+ // VTable path
+ ::HIR::SimplePath m_vtable_path;
- Trait( GenericParams gps, ::std::string lifetime, ::std::vector< ::HIR::TraitPath> parents):
+ Trait( GenericParams gps, LifetimeRef lifetime, ::std::vector< ::HIR::TraitPath> parents):
m_params( mv$(gps) ),
m_lifetime( mv$(lifetime) ),
m_parent_traits( mv$(parents) ),
@@ -334,6 +408,17 @@ public:
{}
};
+class ProcMacro
+{
+public:
+ // Name of the macro
+ RcString name;
+ // Path to the handler
+ ::HIR::SimplePath path;
+ // A list of attributes to hand to the handler
+ ::std::vector<::std::string> attributes;
+};
+
class Module
{
public:
@@ -341,11 +426,13 @@ public:
::std::vector< ::HIR::SimplePath> m_traits;
// Contains all values and functions (including type constructors)
- ::std::unordered_map< ::std::string, ::std::unique_ptr<VisEnt<ValueItem>> > m_value_items;
+ ::std::unordered_map< RcString, ::std::unique_ptr<VisEnt<ValueItem>> > m_value_items;
// Contains types, traits, and modules
- ::std::unordered_map< ::std::string, ::std::unique_ptr<VisEnt<TypeItem>> > m_mod_items;
+ ::std::unordered_map< RcString, ::std::unique_ptr<VisEnt<TypeItem>> > m_mod_items;
+ // Macros!
+ ::std::unordered_map< RcString, ::std::unique_ptr<VisEnt<MacroItem>> > m_macro_items;
- ::std::vector< ::std::pair<::std::string, Static> > m_inline_statics;
+ ::std::vector< ::std::pair<RcString, Static> > m_inline_statics;
Module() {}
Module(const Module&) = delete;
@@ -360,6 +447,7 @@ TAGGED_UNION(TypeItem, Import,
(Import, struct { ::HIR::SimplePath path; bool is_variant; unsigned int idx; }),
(Module, Module),
(TypeAlias, TypeAlias), // NOTE: These don't introduce new values
+ (ExternType, ExternType),
(Enum, Enum),
(Struct, Struct),
(Union, Union),
@@ -373,6 +461,11 @@ TAGGED_UNION(ValueItem, Import,
(Function, Function),
(StructConstructor, struct { ::HIR::SimplePath ty; })
);
+TAGGED_UNION(MacroItem, Import,
+ (Import, struct { ::HIR::SimplePath path; }),
+ (MacroRules, MacroRulesPtr),
+ (ProcMacro, ProcMacro)
+ );
// --------------------------------------------------------------------
@@ -381,7 +474,7 @@ class TypeImpl
public:
template<typename T>
struct VisImplEnt {
- bool is_pub;
+ Publicity publicity;
bool is_specialisable;
T data;
};
@@ -389,8 +482,8 @@ public:
::HIR::GenericParams m_params;
::HIR::TypeRef m_type;
- ::std::map< ::std::string, VisImplEnt< ::HIR::Function> > m_methods;
- ::std::map< ::std::string, VisImplEnt< ::HIR::Constant> > m_constants;
+ ::std::map< RcString, VisImplEnt< ::HIR::Function> > m_methods;
+ ::std::map< RcString, VisImplEnt< ::HIR::Constant> > m_constants;
::HIR::SimplePath m_src_module;
@@ -413,11 +506,11 @@ public:
::HIR::PathParams m_trait_args;
::HIR::TypeRef m_type;
- ::std::map< ::std::string, ImplEnt< ::HIR::Function> > m_methods;
- ::std::map< ::std::string, ImplEnt< ::HIR::Constant> > m_constants;
- ::std::map< ::std::string, ImplEnt< ::HIR::Static> > m_statics;
+ ::std::map< RcString, ImplEnt< ::HIR::Function> > m_methods;
+ ::std::map< RcString, ImplEnt< ::HIR::Constant> > m_constants;
+ ::std::map< RcString, ImplEnt< ::HIR::Static> > m_statics;
- ::std::map< ::std::string, ImplEnt< ::HIR::TypeRef> > m_types;
+ ::std::map< RcString, ImplEnt< ::HIR::TypeRef> > m_types;
::HIR::SimplePath m_src_module;
@@ -461,31 +554,63 @@ class ExternLibrary
public:
::std::string name;
};
-class ProcMacro
-{
-public:
- // Name of the macro
- ::std::string name;
- // Path to the handler
- ::HIR::SimplePath path;
- // A list of attributes to hand to the handler
- ::std::vector<::std::string> attributes;
-};
class Crate
{
public:
- ::std::string m_crate_name;
+ RcString m_crate_name;
Module m_root_module;
- /// Impl blocks on just a type
- ::std::vector< ::HIR::TypeImpl > m_type_impls;
+ template<typename T>
+ struct ImplGroup
+ {
+ typedef ::std::vector<::std::unique_ptr<T>> list_t;
+ ::std::map<::HIR::SimplePath, list_t> named;
+ list_t non_named; // TODO: use a map of HIR::TypeRef::Data::Tag
+ list_t generic;
+
+ const list_t* get_list_for_type(const ::HIR::TypeRef& ty) const {
+ static list_t empty;
+ if( const auto* p = ty.get_sort_path() ) {
+ auto it = named.find(*p);
+ if( it != named.end() )
+ return &it->second;
+ else
+ return nullptr;
+ }
+ else {
+ // TODO: Sort these by type tag, use the `Primitive` group if `ty` is Infer
+ return &non_named;
+ }
+ }
+ list_t& get_list_for_type_mut(const ::HIR::TypeRef& ty) {
+ if( const auto* p = ty.get_sort_path() ) {
+ return named[*p];
+ }
+ else {
+ // TODO: Ivars match with core types
+ return non_named;
+ }
+ }
+ };
+ /// Impl blocks on just a type, split into three groups
+ // - Named type (sorted on the path)
+ // - Primitive types
+ // - Unsorted (generics, and everything before outer type resolution)
+ ImplGroup<::HIR::TypeImpl> m_type_impls;
+
/// Impl blocks
- ::std::multimap< ::HIR::SimplePath, ::HIR::TraitImpl > m_trait_impls;
- ::std::multimap< ::HIR::SimplePath, ::HIR::MarkerImpl > m_marker_impls;
+ ::std::map< ::HIR::SimplePath, ImplGroup<::HIR::TraitImpl> > m_trait_impls;
+ ::std::map< ::HIR::SimplePath, ImplGroup<::HIR::MarkerImpl> > m_marker_impls;
/// Macros exported by this crate
- ::std::unordered_map< ::std::string, ::MacroRulesPtr > m_exported_macros;
+ ::std::unordered_map< RcString, ::MacroRulesPtr > m_exported_macros;
+ /// Macros re-exported by this crate
+ struct MacroImport {
+ ::HIR::SimplePath path;
+ //bool is_proc_macro;
+ };
+ ::std::unordered_map< RcString, MacroImport > m_proc_macro_reexports;
/// Procedural macros presented
::std::vector< ::HIR::ProcMacro> m_proc_macros;
@@ -493,7 +618,7 @@ public:
::std::unordered_map< ::std::string, ::HIR::SimplePath> m_lang_items;
/// Referenced crates
- ::std::unordered_map< ::std::string, ExternCrate> m_ext_crates;
+ ::std::unordered_map< RcString, ExternCrate> m_ext_crates;
/// Referenced system libraries
::std::vector<ExternLibrary> m_ext_libs;
/// Extra paths for the linker
@@ -501,7 +626,7 @@ public:
/// Method called to populate runtime state after deserialisation
/// See hir/crate_post_load.cpp
- void post_load_update(const ::std::string& loaded_name);
+ void post_load_update(const RcString& loaded_name);
const ::HIR::SimplePath& get_lang_item_path(const Span& sp, const char* name) const;
const ::HIR::SimplePath& get_lang_item_path_opt(const char* name) const;
diff --git a/src/hir/hir_ops.cpp b/src/hir/hir_ops.cpp
new file mode 100644
index 00000000..3a33d5cb
--- /dev/null
+++ b/src/hir/hir_ops.cpp
@@ -0,0 +1,1148 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * hir/hir_ops.cpp
+ * - Complex operations on the HIR
+ */
+#include "hir.hpp"
+#include <algorithm>
+#include <hir_typeck/common.hpp>
+#include <hir_typeck/expr_visit.hpp> // for invoking typecheck
+#include "item_path.hpp"
+#include "expr_state.hpp"
+#include <hir_conv/main_bindings.hpp>
+#include <hir_expand/main_bindings.hpp>
+#include <mir/main_bindings.hpp>
+
+namespace {
+ bool matches_genericpath(const ::HIR::GenericPath& left, const ::HIR::GenericPath& right, ::HIR::t_cb_resolve_type ty_res, bool expand_generic);
+
+ bool matches_type_int(const ::HIR::TypeRef& left, const ::HIR::TypeRef& right_in, ::HIR::t_cb_resolve_type ty_res, bool expand_generic)
+ {
+ assert(! left.m_data.is_Infer() );
+ const auto& right = (right_in.m_data.is_Infer() ? ty_res(right_in) : right_in);
+ if( right_in.m_data.is_Generic() )
+ expand_generic = false;
+
+ //DEBUG("left = " << left << ", right = " << right);
+
+ // TODO: What indicates what out of ty_res?
+
+ if( const auto* re = right.m_data.opt_Infer() )
+ {
+ //DEBUG("left = " << left << ", right = " << right);
+ switch(re->ty_class)
+ {
+ case ::HIR::InferClass::None:
+ case ::HIR::InferClass::Diverge:
+ //return left.m_data.is_Generic();
+ return true;
+ case ::HIR::InferClass::Integer:
+ TU_IFLET(::HIR::TypeRef::Data, left.m_data, Primitive, le,
+ return is_integer(le);
+ )
+ else {
+ return left.m_data.is_Generic();
+ }
+ break;
+ case ::HIR::InferClass::Float:
+ TU_IFLET(::HIR::TypeRef::Data, left.m_data, Primitive, le,
+ return is_float(le);
+ )
+ else {
+ return left.m_data.is_Generic();
+ }
+ break;
+ }
+ throw "";
+ }
+
+ // A local generic could match anything, leave that up to the caller
+ if( left.m_data.is_Generic() ) {
+ DEBUG("> Generic left, success");
+ return true;
+ }
+ // A local UfcsKnown can only be becuase it couldn't be expanded earlier, assume it could match
+ if( left.m_data.is_Path() && left.m_data.as_Path().path.m_data.is_UfcsKnown() ) {
+ // True?
+ //DEBUG("> UFCS Unknown left, success");
+ return true;
+ }
+
+ // If the RHS (provided) is generic, it can only match if it binds to a local type parameter
+ if( right.m_data.is_Generic() ) {
+ // TODO: This is handled above?
+ //DEBUG("> Generic right, only if left generic");
+ return left.m_data.is_Generic();
+ }
+ // If the RHS (provided) is generic, it can only match if it binds to a local type parameter
+ if( TU_TEST1(right.m_data, Path, .binding.is_Unbound()) ) {
+ //DEBUG("> UFCS Unknown right, fuzzy");
+ return true;
+ }
+
+ if( left.m_data.tag() != right.m_data.tag() ) {
+ //DEBUG("> Tag mismatch, failure");
+ return false;
+ }
+ TU_MATCH(::HIR::TypeRef::Data, (left.m_data, right.m_data), (le, re),
+ (Infer, assert(!"infer");),
+ (Diverge, return true; ),
+ (Primitive, return le == re;),
+ (Path,
+ if( le.path.m_data.tag() != re.path.m_data.tag() )
+ return false;
+ TU_MATCH_DEF(::HIR::Path::Data, (le.path.m_data, re.path.m_data), (ple, pre),
+ (
+ return false;
+ ),
+ (Generic,
+ return matches_genericpath( ple, pre, ty_res, expand_generic);
+ )
+ )
+ ),
+ (Generic,
+ throw "";
+ ),
+ (TraitObject,
+ if( !matches_genericpath(le.m_trait.m_path, re.m_trait.m_path, ty_res, expand_generic) )
+ return false;
+ if( le.m_markers.size() != re.m_markers.size() )
+ return false;
+ for(unsigned int i = 0; i < le.m_markers.size(); i ++)
+ {
+ const auto& lm = le.m_markers[i];
+ const auto& rm = re.m_markers[i];
+ if( !matches_genericpath(lm, rm, ty_res, expand_generic) )
+ return false;
+ }
+ return true;
+ ),
+ (ErasedType,
+ throw "Unexpected ErasedType in matches_type_int";
+ ),
+ (Array,
+ if( ! matches_type_int(*le.inner, *re.inner, ty_res, expand_generic) )
+ return false;
+ if( le.size_val != re.size_val )
+ return false;
+ return true;
+ ),
+ (Slice,
+ return matches_type_int(*le.inner, *re.inner, ty_res, expand_generic);
+ ),
+ (Tuple,
+ if( le.size() != re.size() )
+ return false;
+ for( unsigned int i = 0; i < le.size(); i ++ )
+ if( !matches_type_int(le[i], re[i], ty_res, expand_generic) )
+ return false;
+ return true;
+ ),
+ (Borrow,
+ if( le.type != re.type )
+ return false;
+ return matches_type_int(*le.inner, *re.inner, ty_res, expand_generic);
+ ),
+ (Pointer,
+ if( le.type != re.type )
+ return false;
+ return matches_type_int(*le.inner, *re.inner, ty_res, expand_generic);
+ ),
+ (Function,
+ if( le.is_unsafe != re.is_unsafe )
+ return false;
+ if( le.m_abi != re.m_abi )
+ return false;
+ if( le.m_arg_types.size() != re.m_arg_types.size() )
+ return false;
+ for( unsigned int i = 0; i < le.m_arg_types.size(); i ++ )
+ if( !matches_type_int(le.m_arg_types[i], re.m_arg_types[i], ty_res, expand_generic) )
+ return false;
+ return matches_type_int(*le.m_rettype, *re.m_rettype, ty_res, expand_generic);
+ ),
+ (Closure,
+ return le.node == re.node;
+ )
+ )
+ return false;
+ }
+ bool matches_genericpath(const ::HIR::GenericPath& left, const ::HIR::GenericPath& right, ::HIR::t_cb_resolve_type ty_res, bool expand_generic)
+ {
+ if( left.m_path.m_crate_name != right.m_path.m_crate_name )
+ return false;
+ if( left.m_path.m_components.size() != right.m_path.m_components.size() )
+ return false;
+ for(unsigned int i = 0; i < left.m_path.m_components.size(); i ++ )
+ {
+ if( left.m_path.m_components[i] != right.m_path.m_components[i] )
+ return false;
+ }
+
+ if( left.m_params.m_types.size() > 0 || right.m_params.m_types.size() > 0 )
+ {
+ // Count mismatch. Allow due to defaults.
+ if( left.m_params.m_types.size() != right.m_params.m_types.size() ) {
+ return true;
+ //TODO(Span(), "Match generic paths " << left << " and " << right << " - count mismatch");
+ }
+ for( unsigned int i = 0; i < right.m_params.m_types.size(); i ++ )
+ {
+ if( ! matches_type_int(left.m_params.m_types[i], right.m_params.m_types[i], ty_res, expand_generic) )
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+namespace {
+ bool is_unbounded_infer(const ::HIR::TypeRef& type) {
+ if( const auto* e = type.m_data.opt_Infer() ) {
+ return e->ty_class == ::HIR::InferClass::None || e->ty_class == ::HIR::InferClass::Diverge;
+ }
+ else {
+ return false;
+ }
+ }
+}
+
+bool ::HIR::TraitImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const
+{
+ // NOTE: Don't return any impls when the type is an unbouned ivar. Wouldn't be able to pick anything anyway
+ // TODO: For `Unbound`, it could be valid, if the target is a generic.
+ // - Pure infer could also be useful (for knowing if there's any other potential impls)
+
+ // TODO: Allow unbounded types iff there's some non-unbounded parameters?
+ if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) {
+ return false;
+ }
+ return matches_type_int(m_type, type, ty_res, true);
+}
+bool ::HIR::TypeImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const
+{
+ if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) {
+ return false;
+ }
+ return matches_type_int(m_type, type, ty_res, true);
+}
+bool ::HIR::MarkerImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const
+{
+ if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) {
+ return false;
+ }
+ return matches_type_int(m_type, type, ty_res, true);
+}
+
+namespace {
+
+ struct TypeOrdSpecific_MixedOrdering
+ {
+ };
+
+ ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& left, const ::std::vector<::HIR::TypeRef>& right);
+
+ ::Ordering type_ord_specific(const Span& sp, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right)
+ {
+ // TODO: What happens if you get `impl<T> Foo<T> for T` vs `impl<T,U> Foo<U> for T`
+
+ // A generic can't be more specific than any other type we can see
+ // - It's equally as specific as another Generic, so still false
+ if( left.m_data.is_Generic() ) {
+ return right.m_data.is_Generic() ? ::OrdEqual : ::OrdLess;
+ }
+ // - A generic is always less specific than anything but itself (handled above)
+ if( right.m_data.is_Generic() ) {
+ return ::OrdGreater;
+ }
+
+ if( left == right ) {
+ return ::OrdEqual;
+ }
+
+ TU_MATCH(::HIR::TypeRef::Data, (left.m_data), (le),
+ (Generic,
+ throw "";
+ ),
+ (Infer,
+ BUG(sp, "Hit infer");
+ ),
+ (Diverge,
+ BUG(sp, "Hit diverge");
+ ),
+ (Closure,
+ BUG(sp, "Hit closure");
+ ),
+ (Primitive,
+ TU_IFLET(::HIR::TypeRef::Data, right.m_data, Primitive, re,
+ if( le != re )
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ return ::OrdEqual;
+ )
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ ),
+ (Path,
+ if( !right.m_data.is_Path() || le.path.m_data.tag() != right.m_data.as_Path().path.m_data.tag() )
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ TU_MATCHA( (le.path.m_data, right.m_data.as_Path().path.m_data), (lpe, rpe),
+ (Generic,
+ if( lpe.m_path != rpe.m_path )
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ return typelist_ord_specific(sp, lpe.m_params.m_types, rpe.m_params.m_types);
+ ),
+ (UfcsUnknown,
+ ),
+ (UfcsKnown,
+ ),
+ (UfcsInherent,
+ )
+ )
+ TODO(sp, "Path - " << le.path << " and " << right);
+ ),
+ (TraitObject,
+ ASSERT_BUG(sp, right.m_data.is_TraitObject(), "Mismatched types - "<< left << " vs " << right);
+ const auto& re = right.m_data.as_TraitObject();
+ ASSERT_BUG(sp, le.m_trait.m_path.m_path == re.m_trait.m_path.m_path, "Mismatched types - "<< left << " vs " << right);
+ ASSERT_BUG(sp, le.m_markers.size() == re.m_markers.size(), "Mismatched types - "<< left << " vs " << right);
+
+ auto ord = typelist_ord_specific(sp, le.m_trait.m_path.m_params.m_types, re.m_trait.m_path.m_params.m_types);
+ if( ord != ::OrdEqual )
+ return ord;
+ for(size_t i = 0; i < le.m_markers.size(); i ++)
+ {
+ ASSERT_BUG(sp, le.m_markers[i].m_path == re.m_markers[i].m_path, "Mismatched types - " << left << " vs " << right);
+ ord = typelist_ord_specific(sp, le.m_markers[i].m_params.m_types, re.m_markers[i].m_params.m_types);
+ if(ord != ::OrdEqual)
+ return ord;
+ }
+ return ::OrdEqual;
+ ),
+ (ErasedType,
+ TODO(sp, "ErasedType - " << left);
+ ),
+ (Function,
+ if(/*const auto* re =*/ right.m_data.opt_Function() ) {
+ if( left == right )
+ return ::OrdEqual;
+ TODO(sp, "Function - " << left << " vs " << right);
+ //return typelist_ord_specific(sp, le.arg_types, re->arg_types);
+ }
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ ),
+ (Tuple,
+ TU_IFLET(::HIR::TypeRef::Data, right.m_data, Tuple, re,
+ return typelist_ord_specific(sp, le, re);
+ )
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ ),
+ (Slice,
+ TU_IFLET(::HIR::TypeRef::Data, right.m_data, Slice, re,
+ return type_ord_specific(sp, *le.inner, *re.inner);
+ )
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ ),
+ (Array,
+ TU_IFLET(::HIR::TypeRef::Data, right.m_data, Array, re,
+ if( le.size_val != re.size_val )
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ return type_ord_specific(sp, *le.inner, *re.inner);
+ )
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ ),
+ (Pointer,
+ TU_IFLET(::HIR::TypeRef::Data, right.m_data, Pointer, re,
+ if( le.type != re.type )
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ return type_ord_specific(sp, *le.inner, *re.inner);
+ )
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ ),
+ (Borrow,
+ TU_IFLET(::HIR::TypeRef::Data, right.m_data, Borrow, re,
+ if( le.type != re.type )
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ return type_ord_specific(sp, *le.inner, *re.inner);
+ )
+ else {
+ BUG(sp, "Mismatched types - " << left << " and " << right);
+ }
+ )
+ )
+ throw "Fell off end of type_ord_specific";
+ }
+
+ ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& le, const ::std::vector<::HIR::TypeRef>& re)
+ {
+ auto rv = ::OrdEqual;
+ assert(le.size() == re.size());
+ for(unsigned int i = 0; i < le.size(); i ++) {
+ auto a = type_ord_specific(sp, le[i], re[i]);
+ if( a != ::OrdEqual ) {
+ if( rv != ::OrdEqual && a != rv )
+ {
+ DEBUG("Inconsistent ordering between type lists - i=" << i << " [" << le << "] vs [" << re << "]");
+ throw TypeOrdSpecific_MixedOrdering {};
+ }
+ rv = a;
+ }
+ }
+ return rv;
+ }
+}
+
+namespace {
+ void add_bound_from_trait(::std::vector< ::HIR::GenericBound>& rv, const ::HIR::TypeRef& type, const ::HIR::TraitPath& cur_trait)
+ {
+ static Span sp;
+ assert( cur_trait.m_trait_ptr );
+ const auto& tr = *cur_trait.m_trait_ptr;
+ auto monomorph_cb = monomorphise_type_get_cb(sp, &type, &cur_trait.m_path.m_params, nullptr);
+
+ for(const auto& trait_path_raw : tr.m_all_parent_traits)
+ {
+ // 1. Monomorph
+ auto trait_path_mono = monomorphise_traitpath_with(sp, trait_path_raw, monomorph_cb, false);
+ // 2. Add
+ rv.push_back( ::HIR::GenericBound::make_TraitBound({ type.clone(), mv$(trait_path_mono) }) );
+ }
+
+ // TODO: Add traits from `Self: Foo` bounds?
+ // TODO: Move associated types to the source trait.
+ }
+ ::std::vector< ::HIR::GenericBound> flatten_bounds(const ::std::vector<::HIR::GenericBound>& bounds)
+ {
+ ::std::vector< ::HIR::GenericBound > rv;
+ for(const auto& b : bounds)
+ {
+ TU_MATCHA( (b), (be),
+ (Lifetime,
+ rv.push_back( ::HIR::GenericBound(be) );
+ ),
+ (TypeLifetime,
+ rv.push_back( ::HIR::GenericBound::make_TypeLifetime({ be.type.clone(), be.valid_for }) );
+ ),
+ (TraitBound,
+ rv.push_back( ::HIR::GenericBound::make_TraitBound({ be.type.clone(), be.trait.clone() }) );
+ add_bound_from_trait(rv, be.type, be.trait);
+ ),
+ (TypeEquality,
+ rv.push_back( ::HIR::GenericBound::make_TypeEquality({ be.type.clone(), be.other_type.clone() }) );
+ )
+ )
+ }
+ ::std::sort(rv.begin(), rv.end(), [](const auto& a, const auto& b){ return ::ord(a,b) == OrdLess; });
+ return rv;
+ }
+}
+
+bool ::HIR::TraitImpl::more_specific_than(const ::HIR::TraitImpl& other) const
+{
+ static const Span _sp;
+ const Span& sp = _sp;
+ TRACE_FUNCTION;
+ //DEBUG("this = " << *this);
+ //DEBUG("other = " << other);
+
+ // >> https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md#defining-the-precedence-rules
+ // 1. If this->m_type is less specific than other.m_type: return false
+ try
+ {
+ auto ord = type_ord_specific(sp, this->m_type, other.m_type);
+ // If `*this` < `other` : false
+ if( ord != ::OrdEqual ) {
+ DEBUG("- Type " << this->m_type << " " << (ord == ::OrdLess ? "less" : "more") << " specific than " << other.m_type);
+ return ord == ::OrdGreater;
+ }
+ // 2. If any in te.impl->m_params is less specific than oe.impl->m_params: return false
+ ord = typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types);
+ if( ord != ::OrdEqual ) {
+ DEBUG("- Trait arguments " << (ord == ::OrdLess ? "less" : "more") << " specific");
+ return ord == ::OrdGreater;
+ }
+ }
+ catch(const TypeOrdSpecific_MixedOrdering& e)
+ {
+ BUG(sp, "Mixed ordering in more_specific_than");
+ }
+
+ //if( other.m_params.m_bounds.size() == 0 ) {
+ // DEBUG("- Params (none in other, some in this)");
+ // return m_params.m_bounds.size() > 0;
+ //}
+ // 3. Compare bound set, if there is a rule in oe that is missing from te; return false
+ // TODO: Cache these lists (calculate after outer typecheck?)
+ auto bounds_t = flatten_bounds(m_params.m_bounds);
+ auto bounds_o = flatten_bounds(other.m_params.m_bounds);
+
+ DEBUG("bounds_t = " << bounds_t);
+ DEBUG("bounds_o = " << bounds_o);
+
+ // If there are less bounds in this impl, it can't be more specific.
+ if( bounds_t.size() < bounds_o.size() )
+ {
+ DEBUG("Bound count");
+ return false;
+ }
+
+ auto it_t = bounds_t.begin();
+ auto it_o = bounds_o.begin();
+ while( it_t != bounds_t.end() && it_o != bounds_o.end() )
+ {
+ auto cmp = ::ord(*it_t, *it_o);
+ if( cmp == OrdEqual )
+ {
+ ++it_t;
+ ++it_o;
+ continue ;
+ }
+
+ // If the two bounds are similar
+ if( it_t->tag() == it_o->tag() && it_t->is_TraitBound() )
+ {
+ const auto& b_t = it_t->as_TraitBound();
+ const auto& b_o = it_o->as_TraitBound();
+ // Check if the type is equal
+ if( b_t.type == b_o.type && b_t.trait.m_path.m_path == b_o.trait.m_path.m_path )
+ {
+ const auto& params_t = b_t.trait.m_path.m_params;
+ const auto& params_o = b_o.trait.m_path.m_params;
+ switch( typelist_ord_specific(sp, params_t.m_types, params_o.m_types) )
+ {
+ case ::OrdLess: return false;
+ case ::OrdGreater: return true;
+ case ::OrdEqual: break;
+ }
+ // TODO: Find cases where there's `T: Foo<T>` and `T: Foo<U>`
+ for(unsigned int i = 0; i < params_t.m_types.size(); i ++ )
+ {
+ if( params_t.m_types[i] != params_o.m_types[i] && params_t.m_types[i] == b_t.type )
+ {
+ return true;
+ }
+ }
+ TODO(sp, *it_t << " ?= " << *it_o);
+ }
+ }
+
+ if( cmp == OrdLess )
+ {
+ ++ it_t;
+ }
+ else
+ {
+ //++ it_o;
+ return false;
+ }
+ }
+ if( it_t != bounds_t.end() )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Returns `true` if the two impls overlap in the types they will accept
+bool ::HIR::TraitImpl::overlaps_with(const Crate& crate, const ::HIR::TraitImpl& other) const
+{
+ // TODO: Pre-calculate impl trees (with pointers to parent impls)
+ struct H {
+ static bool types_overlap(const ::HIR::PathParams& a, const ::HIR::PathParams& b)
+ {
+ for(unsigned int i = 0; i < ::std::min(a.m_types.size(), b.m_types.size()); i ++)
+ {
+ if( ! H::types_overlap(a.m_types[i], b.m_types[i]) )
+ return false;
+ }
+ return true;
+ }
+ static bool types_overlap(const ::HIR::TypeRef& a, const ::HIR::TypeRef& b)
+ {
+ static Span sp;
+ //DEBUG("(" << a << "," << b << ")");
+ if( a.m_data.is_Generic() || b.m_data.is_Generic() )
+ return true;
+ // TODO: Unbound/Opaque paths?
+ if( a.m_data.tag() != b.m_data.tag() )
+ return false;
+ TU_MATCHA( (a.m_data, b.m_data), (ae, be),
+ (Generic,
+ ),
+ (Infer,
+ ),
+ (Diverge,
+ ),
+ (Closure,
+ BUG(sp, "Hit closure");
+ ),
+ (Primitive,
+ if( ae != be )
+ return false;
+ ),
+ (Path,
+ if( ae.path.m_data.tag() != be.path.m_data.tag() )
+ return false;
+ TU_MATCHA( (ae.path.m_data, be.path.m_data), (ape, bpe),
+ (Generic,
+ if( ape.m_path != bpe.m_path )
+ return false;
+ return H::types_overlap(ape.m_params, bpe.m_params);
+ ),
+ (UfcsUnknown,
+ ),
+ (UfcsKnown,
+ ),
+ (UfcsInherent,
+ )
+ )
+ TODO(sp, "Path - " << ae.path << " and " << be.path);
+ ),
+ (TraitObject,
+ if( ae.m_trait.m_path.m_path != be.m_trait.m_path.m_path )
+ return false;
+ if( !H::types_overlap(ae.m_trait.m_path.m_params, be.m_trait.m_path.m_params) )
+ return false;
+ // Marker traits only overlap if the lists are the same (with overlap)
+ if( ae.m_markers.size() != be.m_markers.size() )
+ return false;
+ for(size_t i = 0; i < ae.m_markers.size(); i++)
+ {
+ if( ae.m_markers[i].m_path != be.m_markers[i].m_path )
+ return false;
+ if( !H::types_overlap(ae.m_markers[i].m_params, be.m_markers[i].m_params) )
+ return false;
+ }
+ return true;
+ ),
+ (ErasedType,
+ TODO(sp, "ErasedType - " << a);
+ ),
+ (Function,
+ if( ae.is_unsafe != be.is_unsafe )
+ return false;
+ if( ae.m_abi != be.m_abi )
+ return false;
+ if( ae.m_arg_types.size() != be.m_arg_types.size() )
+ return false;
+ for(unsigned int i = 0; i < ae.m_arg_types.size(); i ++)
+ {
+ if( ! H::types_overlap(ae.m_arg_types[i], be.m_arg_types[i]) )
+ return false;
+ }
+ ),
+ (Tuple,
+ if( ae.size() != be.size() )
+ return false;
+ for(unsigned int i = 0; i < ae.size(); i ++)
+ {
+ if( ! H::types_overlap(ae[i], be[i]) )
+ return false;
+ }
+ ),
+ (Slice,
+ return H::types_overlap( *ae.inner, *be.inner );
+ ),
+ (Array,
+ if( ae.size_val != be.size_val )
+ return false;
+ return H::types_overlap( *ae.inner, *be.inner );
+ ),
+ (Pointer,
+ if( ae.type != be.type )
+ return false;
+ return H::types_overlap( *ae.inner, *be.inner );
+ ),
+ (Borrow,
+ if( ae.type != be.type )
+ return false;
+ return H::types_overlap( *ae.inner, *be.inner );
+ )
+ )
+ return true;
+ }
+ };
+
+ // Quick Check: If the types are equal, they do overlap
+ if(this->m_type == other.m_type && this->m_trait_args == other.m_trait_args)
+ {
+ return true;
+ }
+
+ // 1. Are the impl types of the same form (or is one generic)
+ if( ! H::types_overlap(this->m_type, other.m_type) )
+ return false;
+ if( ! H::types_overlap(this->m_trait_args, other.m_trait_args) )
+ return false;
+
+ DEBUG("TODO: Handle potential overlap (when not exactly equal)");
+ //return this->m_type == other.m_type && this->m_trait_args == other.m_trait_args;
+ Span sp;
+
+ // TODO: Use `type_ord_specific` but treat any case of mixed ordering as this returning `false`
+ try
+ {
+ type_ord_specific(sp, this->m_type, other.m_type);
+ typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types);
+ }
+ catch(const TypeOrdSpecific_MixedOrdering& /*e*/)
+ {
+ return false;
+ }
+
+ // TODO: Detect `impl<T> Foo<T> for Bar<T>` vs `impl<T> Foo<&T> for Bar<T>`
+ // > Create values for impl params from the type, then check if the trait params are compatible
+ // > Requires two lists, and telling which one to use by the end
+ auto cb_ident = [](const ::HIR::TypeRef& x)->const ::HIR::TypeRef& { return x; };
+ bool is_reversed = false;
+ ::std::vector<const ::HIR::TypeRef*> impl_tys;
+ auto cb_match = [&](unsigned int idx, const auto& /*name*/, const ::HIR::TypeRef& x)->::HIR::Compare {
+ assert(idx < impl_tys.size());
+ if( impl_tys.at(idx) )
+ {
+ DEBUG("Compare " << x << " and " << *impl_tys.at(idx));
+ return (x == *impl_tys.at(idx) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal);
+ }
+ else
+ {
+ impl_tys.at(idx) = &x;
+ return ::HIR::Compare::Equal;
+ }
+ };
+ impl_tys.resize( this->m_params.m_types.size() );
+ if( ! this->m_type.match_test_generics(sp, other.m_type, cb_ident, cb_match) )
+ {
+ DEBUG("- Type mismatch, try other ordering");
+ is_reversed = true;
+ impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() );
+ if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) )
+ {
+ DEBUG("- Type mismatch in both orderings");
+ return false;
+ }
+ if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal )
+ {
+ DEBUG("- Params mismatch");
+ return false;
+ }
+ // Matched with second ording
+ }
+ else if( this->m_trait_args.match_test_generics_fuzz(sp, other.m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal )
+ {
+ DEBUG("- Param mismatch, try other ordering");
+ is_reversed = true;
+ impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() );
+ if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) )
+ {
+ DEBUG("- Type mismatch in alt ordering");
+ return false;
+ }
+ if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal )
+ {
+ DEBUG("- Params mismatch in alt ordering");
+ return false;
+ }
+ // Matched with second ordering
+ }
+ else
+ {
+ // Matched with first ordering
+ }
+
+ struct H2 {
+ static const ::HIR::TypeRef& monomorph(const Span& sp, const ::HIR::TypeRef& in_ty, const ::std::vector<const ::HIR::TypeRef*>& args, ::HIR::TypeRef& tmp)
+ {
+ if( ! monomorphise_type_needed(in_ty) ) {
+ return in_ty;
+ }
+ else if( const auto* tep = in_ty.m_data.opt_Generic() ) {
+ ASSERT_BUG(sp, tep->binding < args.size(), "");
+ ASSERT_BUG(sp, args[tep->binding], "");
+ return *args[tep->binding];
+ }
+ else {
+ auto monomorph_cb = [&](const auto& t)->const auto& {
+ const auto& te = t.m_data.as_Generic();
+ assert(te.binding < args.size());
+ ASSERT_BUG(sp, te.binding < args.size(), "");
+ ASSERT_BUG(sp, args[te.binding], "");
+ return *args[te.binding];
+ };
+ tmp = monomorphise_type_with(sp, in_ty, monomorph_cb);
+ // TODO: EAT?
+ return tmp;
+ }
+ }
+ static const ::HIR::TraitPath& monomorph(const Span& sp, const ::HIR::TraitPath& in, const ::std::vector<const ::HIR::TypeRef*>& args, ::HIR::TraitPath& tmp)
+ {
+ if( ! monomorphise_traitpath_needed(in) ) {
+ return in;
+ }
+ else {
+ auto monomorph_cb = [&](const auto& t)->const auto& {
+ const auto& te = t.m_data.as_Generic();
+ assert(te.binding < args.size());
+ ASSERT_BUG(sp, te.binding < args.size(), "");
+ ASSERT_BUG(sp, args[te.binding], "");
+ return *args[te.binding];
+ };
+ tmp = monomorphise_traitpath_with(sp, in, monomorph_cb, true);
+ // TODO: EAT?
+ return tmp;
+ }
+ }
+ static bool check_bounds(const ::HIR::Crate& crate, const ::HIR::TraitImpl& id, const ::std::vector<const ::HIR::TypeRef*>& args, const ::HIR::TraitImpl& g_src)
+ {
+ TRACE_FUNCTION;
+ static Span sp;
+ for(const auto& tb : id.m_params.m_bounds)
+ {
+ DEBUG(tb);
+ if(tb.is_TraitBound())
+ {
+ ::HIR::TypeRef tmp_ty;
+ ::HIR::TraitPath tmp_tp;
+ const auto& ty = H2::monomorph(sp, tb.as_TraitBound().type, args, tmp_ty);
+ const auto& trait = H2::monomorph(sp, tb.as_TraitBound().trait, args, tmp_tp);;
+
+ // Determine if `ty` would be bounded (it's an ATY or generic)
+ if( ty.m_data.is_Generic() ) {
+ bool found = false;
+ for(const auto& bound : g_src.m_params.m_bounds)
+ {
+ if(const auto* be = bound.opt_TraitBound())
+ {
+ if( be->type != ty ) continue;
+ if( be->trait != trait ) continue;
+ found = true;
+ }
+ }
+ if( !found )
+ {
+ DEBUG("No matching bound for " << ty << " : " << trait << " in source bounds - " << g_src.m_params.fmt_bounds());
+ return false;
+ }
+ }
+ else if( TU_TEST1(ty.m_data, Path, .binding.is_Opaque()) ) {
+ TODO(sp, "Check bound " << ty << " : " << trait << " in source bounds or trait bounds");
+ }
+ else {
+ // Search the crate for an impl
+ bool rv = crate.find_trait_impls(trait.m_path.m_path, ty, [](const auto&t)->const auto&{ return t; }, [&](const ::HIR::TraitImpl& ti)->bool {
+ DEBUG("impl" << ti.m_params.fmt_args() << " " << trait.m_path.m_path << ti.m_trait_args << " for " << ti.m_type << ti.m_params.fmt_bounds());
+
+ ::std::vector<const ::HIR::TypeRef*> impl_tys { ti.m_params.m_types.size() };
+ auto cb_ident = [](const ::HIR::TypeRef& x)->const ::HIR::TypeRef& { return x; };
+ auto cb_match = [&](unsigned int idx, const auto& /*name*/, const ::HIR::TypeRef& x)->::HIR::Compare {
+ assert(idx < impl_tys.size());
+ if( impl_tys.at(idx) )
+ {
+ DEBUG("Compare " << x << " and " << *impl_tys.at(idx));
+ return (x == *impl_tys.at(idx) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal);
+ }
+ else
+ {
+ impl_tys.at(idx) = &x;
+ return ::HIR::Compare::Equal;
+ }
+ };
+ // 1. Triple-check the type matches (and get generics)
+ if( ! ti.m_type.match_test_generics(sp, ty, cb_ident, cb_match) )
+ return false;
+ // 2. Check trait params
+ assert(trait.m_path.m_params.m_types.size() == ti.m_trait_args.m_types.size());
+ for(size_t i = 0; i < trait.m_path.m_params.m_types.size(); i ++)
+ {
+ if( !ti.m_trait_args.m_types[i].match_test_generics(sp, trait.m_path.m_params.m_types[i], cb_ident, cb_match) )
+ return false;
+ }
+ // 3. Check bounds on the impl
+ if( !H2::check_bounds(crate, ti, impl_tys, g_src) )
+ return false;
+ // 4. Check ATY bounds on the trait path
+ for(const auto& atyb : trait.m_type_bounds)
+ {
+ if( ti.m_types.count(atyb.first) == 0 ) {
+ DEBUG("Associated type '" << atyb.first << "' not in trait impl, assuming good");
+ }
+ else {
+ const auto& aty = ti.m_types.at(atyb.first);
+ if( !aty.data.match_test_generics(sp, atyb.second, cb_ident, cb_match) )
+ return false;
+ }
+ }
+ // All those pass? It's good.
+ return true;
+ });
+ if( !rv )
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // TODO: Other bound types?
+ }
+ }
+ // No bounds failed, it's good
+ return true;
+ }
+ };
+
+ // The two impls could overlap, pending on trait bounds
+ if(is_reversed)
+ {
+ DEBUG("(reversed) impl params " << FMT_CB(os,
+ for(auto* p : impl_tys)
+ {
+ if(p)
+ os << *p;
+ else
+ os << "?";
+ os << ",";
+ }
+ ));
+ // Check bounds on `other` using these params
+ // TODO: Take a callback that does the checks. Or somehow return a "maybe overlaps" result?
+ return H2::check_bounds(crate, other, impl_tys, *this);
+ }
+ else
+ {
+ DEBUG("impl params " << FMT_CB(os,
+ for(auto* p : impl_tys)
+ {
+ if(p)
+ os << *p;
+ else
+ os << "?";
+ os << ",";
+ }
+ ));
+ // Check bounds on `*this`
+ return H2::check_bounds(crate, *this, impl_tys, other);
+ }
+}
+
+namespace
+{
+ template<typename ImplType>
+ bool find_impls_list(const typename ::HIR::Crate::ImplGroup<ImplType>::list_t& impl_list, const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res, ::std::function<bool(const ImplType&)> callback)
+ {
+ for(const auto& impl : impl_list)
+ {
+ if( impl->matches_type(type, ty_res) )
+ {
+ if( callback(*impl) )
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
+namespace
+{
+ bool find_trait_impls_int(
+ const ::HIR::Crate& crate, const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type,
+ ::HIR::t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TraitImpl&)> callback
+ )
+ {
+ auto it = crate.m_trait_impls.find( trait );
+ if( it != crate.m_trait_impls.end() )
+ {
+ // 1. Find named impls (associated with named types)
+ if( const auto* impl_list = it->second.get_list_for_type(type) )
+ {
+ if( find_impls_list(*impl_list, type, ty_res, callback) )
+ return true;
+ }
+
+ // 2. Search fully generic list.
+ if( find_impls_list(it->second.generic, type, ty_res, callback) )
+ return true;
+ }
+
+ return false;
+ }
+}
+
+bool ::HIR::Crate::find_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TraitImpl&)> callback) const
+{
+ if( find_trait_impls_int(*this, trait, type, ty_res, callback) )
+ {
+ return true;
+ }
+ for( const auto& ec : this->m_ext_crates )
+ {
+ if( find_trait_impls_int(*ec.second.m_data, trait, type, ty_res, callback) )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+namespace
+{
+ bool find_auto_trait_impls_int(
+ const ::HIR::Crate& crate, const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type,
+ ::HIR::t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::MarkerImpl&)> callback
+ )
+ {
+ auto it = crate.m_marker_impls.find( trait );
+ if( it != crate.m_marker_impls.end() )
+ {
+ // 1. Find named impls (associated with named types)
+ if( const auto* impl_list = it->second.get_list_for_type(type) )
+ {
+ if( find_impls_list(*impl_list, type, ty_res, callback) )
+ return true;
+ }
+
+ // 2. Search fully generic list.
+ if( find_impls_list(it->second.generic, type, ty_res, callback) )
+ return true;
+ }
+
+ return false;
+ }
+}
+bool ::HIR::Crate::find_auto_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::MarkerImpl&)> callback) const
+{
+ if( find_auto_trait_impls_int(*this, trait, type, ty_res, callback) )
+ {
+ return true;
+ }
+ for( const auto& ec : this->m_ext_crates )
+ {
+ if( find_auto_trait_impls_int(*ec.second.m_data, trait, type, ty_res, callback) )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+namespace
+{
+ bool find_type_impls_int(const ::HIR::Crate& crate, const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TypeImpl&)> callback)
+ {
+ // 1. Find named impls (associated with named types)
+ if( const auto* impl_list = crate.m_type_impls.get_list_for_type(type) )
+ {
+ if( find_impls_list(*impl_list, type, ty_res, callback) )
+ return true;
+ }
+
+ // 2. Search fully generic list?
+ if( find_impls_list(crate.m_type_impls.generic, type, ty_res, callback) )
+ return true;
+
+ return false;
+ }
+}
+bool ::HIR::Crate::find_type_impls(const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TypeImpl&)> callback) const
+{
+ // > Current crate
+ if( find_type_impls_int(*this, type, ty_res, callback) )
+ {
+ return true;
+ }
+ for( const auto& ec : this->m_ext_crates )
+ {
+ //DEBUG("- " << ec.first);
+ if( find_type_impls_int(*ec.second.m_data, type, ty_res, callback) )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+const ::MIR::Function* HIR::Crate::get_or_gen_mir(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& ep, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_ty) const
+{
+ if( !ep )
+ {
+ // No HIR, so has to just have MIR - from a extern crate most likely
+ assert(ep.m_mir);
+ return &*ep.m_mir;
+ }
+ else
+ {
+ if( !ep.m_mir )
+ {
+ TRACE_FUNCTION_F(ip);
+ ASSERT_BUG(Span(), ep.m_state, "No ExprState for " << ip);
+
+ auto& ep_mut = const_cast<::HIR::ExprPtr&>(ep);
+
+ // TODO: Ensure that all referenced items have constants evaluated
+ if( ep.m_state->stage < ::HIR::ExprState::Stage::ConstEval )
+ {
+ if( ep.m_state->stage == ::HIR::ExprState::Stage::ConstEvalRequest )
+ ERROR(Span(), E0000, "Loop in constant evaluation");
+ ep.m_state->stage = ::HIR::ExprState::Stage::ConstEvalRequest;
+ ConvertHIR_ConstantEvaluate_Expr(*this, ip, ep_mut);
+ ep.m_state->stage = ::HIR::ExprState::Stage::ConstEval;
+ }
+
+ // Ensure typechecked
+ if( ep.m_state->stage < ::HIR::ExprState::Stage::Typecheck )
+ {
+ if( ep.m_state->stage == ::HIR::ExprState::Stage::TypecheckRequest )
+ ERROR(Span(), E0000, "Loop in constant evaluation");
+ ep.m_state->stage = ::HIR::ExprState::Stage::TypecheckRequest;
+
+ // TODO: Set debug/timing stage
+ //Debug_SetStagePre("HIR Typecheck");
+ // - Can store that on the Expr, OR get it from the item path
+ typeck::ModuleState ms { const_cast<::HIR::Crate&>(*this) };
+ //ms.prepare_from_path( ip ); // <- Ideally would use this, but it's a lot of code for one usage
+ ms.m_impl_generics = ep.m_state->m_impl_generics;
+ ms.m_item_generics = ep.m_state->m_item_generics;
+ ms.m_traits = ep.m_state->m_traits;
+ ms.m_mod_paths.push_back(ep.m_state->m_mod_path);
+ Typecheck_Code(ms, const_cast<::HIR::Function::args_t&>(args), ret_ty, ep_mut);
+ //Debug_SetStagePre("Expand HIR Annotate");
+ HIR_Expand_AnnotateUsage_Expr(*this, ep_mut);
+ //Debug_SetStagePre("Expand HIR Closures");
+ HIR_Expand_Closures_Expr(*this, ep_mut);
+ //Debug_SetStagePre("Expand HIR Calls");
+ HIR_Expand_UfcsEverything_Expr(*this, ep_mut);
+ //Debug_SetStagePre("Expand HIR Reborrows");
+ HIR_Expand_Reborrows_Expr(*this, ep_mut);
+ //Debug_SetStagePre("Expand HIR ErasedType");
+ //HIR_Expand_ErasedType(*this, ep_mut); // - Maybe?
+ //Typecheck_Expressions_Validate(*hir_crate);
+
+ ep.m_state->stage = ::HIR::ExprState::Stage::Typecheck;
+ }
+ // Generate MIR
+ if( ep.m_state->stage < ::HIR::ExprState::Stage::Mir )
+ {
+ if( ep.m_state->stage == ::HIR::ExprState::Stage::MirRequest )
+ ERROR(Span(), E0000, "Loop in constant evaluation");
+ ep.m_state->stage = ::HIR::ExprState::Stage::MirRequest;
+ //Debug_SetStage("Lower MIR");
+ HIR_GenerateMIR_Expr(*this, ip, ep_mut, args, ret_ty);
+ ep.m_state->stage = ::HIR::ExprState::Stage::Mir;
+ }
+ assert(ep.m_mir);
+ }
+ return &*ep.m_mir;
+ }
+}
diff --git a/src/hir/item_path.hpp b/src/hir/item_path.hpp
index d19435eb..091a45c9 100644
--- a/src/hir/item_path.hpp
+++ b/src/hir/item_path.hpp
@@ -20,7 +20,9 @@ public:
const char* crate_name = nullptr;
const ::HIR::Path* wrapped = nullptr;
+ ItemPath(const char* crate): crate_name(crate) {}
ItemPath(const ::std::string& crate): crate_name(crate.c_str()) {}
+ ItemPath(const RcString& crate): crate_name(crate.c_str()) {}
ItemPath(const ItemPath& p, const char* n):
parent(&p),
name(n)
@@ -54,12 +56,12 @@ public:
}
else if( parent ) {
assert(name);
- return parent->get_simple_path() + name;
+ return parent->get_simple_path() + RcString::new_interned(name);
}
else {
assert(!name);
assert(crate_name);
- return ::HIR::SimplePath(crate_name);
+ return ::HIR::SimplePath(RcString::new_interned(crate_name));
}
}
::HIR::Path get_full_path() const {
@@ -76,20 +78,28 @@ public:
else if( parent->trait ) {
assert(parent->ty);
assert(parent->trait_params);
- return ::HIR::Path( parent->ty->clone(), ::HIR::GenericPath(parent->trait->clone(), parent->trait_params->clone()), ::std::string(name) );
+ return ::HIR::Path( parent->ty->clone(), ::HIR::GenericPath(parent->trait->clone(), parent->trait_params->clone()), RcString::new_interned(name) );
}
else {
assert(parent->ty);
- return ::HIR::Path( parent->ty->clone(), ::std::string(name) );
+ return ::HIR::Path( parent->ty->clone(), RcString::new_interned(name) );
}
}
const char* get_name() const {
return name ? name : "";
}
+ const ItemPath& get_top_ip() const {
+ if( this->parent )
+ return this->parent->get_top_ip();
+ return *this;
+ }
ItemPath operator+(const ::std::string& name) const {
return ItemPath(*this, name.c_str());
}
+ ItemPath operator+(const RcString& name) const {
+ return ItemPath(*this, name.c_str());
+ }
bool operator==(const ::HIR::SimplePath& sp) const {
if( sp.m_crate_name != "" ) return false;
@@ -133,7 +143,7 @@ public:
os << "<* as " << *x.trait << ">";
}
else if( x.crate_name ) {
- os << "\"" << x.crate_name << "\"";
+ os << "::\"" << x.crate_name << "\"";
}
return os;
}
diff --git a/src/hir/main_bindings.hpp b/src/hir/main_bindings.hpp
index 622d8e2e..89896df0 100644
--- a/src/hir/main_bindings.hpp
+++ b/src/hir/main_bindings.hpp
@@ -18,4 +18,4 @@ namespace AST {
extern void HIR_Dump(::std::ostream& sink, const ::HIR::Crate& crate);
extern ::HIR::CratePtr LowerHIR_FromAST(::AST::Crate crate);
extern void HIR_Serialise(const ::std::string& filename, const ::HIR::Crate& crate);
-extern ::HIR::CratePtr HIR_Deserialise(const ::std::string& filename, const ::std::string& loaded_name);
+extern ::HIR::CratePtr HIR_Deserialise(const ::std::string& filename);
diff --git a/src/hir/path.cpp b/src/hir/path.cpp
index e6dab41f..a867c245 100644
--- a/src/hir/path.cpp
+++ b/src/hir/path.cpp
@@ -8,7 +8,7 @@
#include <hir/path.hpp>
#include <hir/type.hpp>
-::HIR::SimplePath HIR::SimplePath::operator+(const ::std::string& s) const
+::HIR::SimplePath HIR::SimplePath::operator+(const RcString& s) const
{
::HIR::SimplePath ret(m_crate_name);
ret.m_components = m_components;
@@ -193,11 +193,11 @@ bool ::HIR::TraitPath::operator==(const ::HIR::TraitPath& x) const
m_data( ::HIR::Path::Data::make_Generic(::HIR::GenericPath(mv$(sp))) )
{
}
-::HIR::Path::Path(TypeRef ty, ::std::string item, PathParams item_params):
+::HIR::Path::Path(TypeRef ty, RcString item, PathParams item_params):
m_data(Data::make_UfcsInherent({ box$(ty), mv$(item), mv$(item_params) }))
{
}
-::HIR::Path::Path(TypeRef ty, GenericPath trait, ::std::string item, PathParams item_params):
+::HIR::Path::Path(TypeRef ty, GenericPath trait, RcString item, PathParams item_params):
m_data( Data::make_UfcsKnown({ box$(mv$(ty)), mv$(trait), mv$(item), mv$(item_params) }) )
{
}
diff --git a/src/hir/path.hpp b/src/hir/path.hpp
index f2bec6ee..86fe725e 100644
--- a/src/hir/path.hpp
+++ b/src/hir/path.hpp
@@ -25,7 +25,7 @@ enum Compare {
};
typedef ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> t_cb_resolve_type;
-typedef ::std::function< ::HIR::Compare(unsigned int, const ::std::string&, const ::HIR::TypeRef&) > t_cb_match_generics;
+typedef ::std::function< ::HIR::Compare(unsigned int, const RcString&, const ::HIR::TypeRef&) > t_cb_match_generics;
static inline ::std::ostream& operator<<(::std::ostream& os, const Compare& x) {
switch(x)
@@ -54,18 +54,18 @@ static inline Compare& operator &=(Compare& x, const Compare& y) {
/// Simple path - Absolute with no generic parameters
struct SimplePath
{
- ::std::string m_crate_name;
- ::std::vector< ::std::string> m_components;
+ RcString m_crate_name;
+ ::std::vector< RcString> m_components;
SimplePath():
m_crate_name("")
{
}
- SimplePath(::std::string crate):
+ SimplePath(RcString crate):
m_crate_name( mv$(crate) )
{
}
- SimplePath(::std::string crate, ::std::vector< ::std::string> components):
+ SimplePath(RcString crate, ::std::vector< RcString> components):
m_crate_name( mv$(crate) ),
m_components( mv$(components) )
{
@@ -73,7 +73,7 @@ struct SimplePath
SimplePath clone() const;
- SimplePath operator+(const ::std::string& s) const;
+ SimplePath operator+(const RcString& s) const;
bool operator==(const SimplePath& x) const {
return m_crate_name == x.m_crate_name && m_components == x.m_components;
}
@@ -158,9 +158,9 @@ class TraitPath
{
public:
GenericPath m_path;
- ::std::vector< ::std::string> m_hrls;
+ ::std::vector< RcString> m_hrls;
// TODO: Each bound should list its origin trait
- ::std::map< ::std::string, ::HIR::TypeRef> m_type_bounds;
+ ::std::map< RcString, ::HIR::TypeRef> m_type_bounds;
const ::HIR::Trait* m_trait_ptr;
@@ -190,20 +190,20 @@ public:
(Generic, GenericPath),
(UfcsInherent, struct {
::std::unique_ptr<TypeRef> type;
- ::std::string item;
+ RcString item;
PathParams params;
PathParams impl_params;
}),
(UfcsKnown, struct {
::std::unique_ptr<TypeRef> type;
GenericPath trait;
- ::std::string item;
+ RcString item;
PathParams params;
}),
(UfcsUnknown, struct {
::std::unique_ptr<TypeRef> type;
//GenericPath ??;
- ::std::string item;
+ RcString item;
PathParams params;
})
);
@@ -216,8 +216,8 @@ public:
Path(GenericPath _);
Path(SimplePath _);
- Path(TypeRef ty, ::std::string item, PathParams item_params=PathParams());
- Path(TypeRef ty, GenericPath trait, ::std::string item, PathParams item_params=PathParams());
+ Path(TypeRef ty, RcString item, PathParams item_params=PathParams());
+ Path(TypeRef ty, GenericPath trait, RcString item, PathParams item_params=PathParams());
Path clone() const;
Compare compare_with_placeholders(const Span& sp, const Path& x, t_cb_resolve_type resolve_placeholder) const;
diff --git a/src/hir/pattern.cpp b/src/hir/pattern.cpp
index da6446d7..063ed1b3 100644
--- a/src/hir/pattern.cpp
+++ b/src/hir/pattern.cpp
@@ -46,6 +46,9 @@ namespace HIR {
if( x.m_binding.is_valid() ) {
os << x.m_binding;
}
+ if( x.m_implicit_deref_count > 0 ) {
+ os << "&*" << x.m_implicit_deref_count;
+ }
TU_MATCH(Pattern::Data, (x.m_data), (e),
(Any,
os << "_";
@@ -151,8 +154,9 @@ namespace {
rv.push_back( pat.clone() );
return rv;
}
- ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> > clone_pat_fields(const ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> >& pats) {
- ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> > rv;
+ typedef ::std::vector< ::std::pair< RcString, ::HIR::Pattern> > pat_fields_t;
+ pat_fields_t clone_pat_fields(const pat_fields_t& pats) {
+ pat_fields_t rv;
rv.reserve( pats.size() );
for(const auto& field : pats)
rv.push_back( ::std::make_pair(field.first, field.second.clone()) );
@@ -181,102 +185,108 @@ namespace {
}
} // namespace
-::HIR::Pattern HIR::Pattern::clone() const
+namespace { ::HIR::Pattern::Data clone_pattern_data(const ::HIR::Pattern::Data& m_data)
{
TU_MATCH(::HIR::Pattern::Data, (m_data), (e),
(Any,
- return Pattern(m_binding, Data::make_Any({}));
+ return ::HIR::Pattern::Data::make_Any({});
),
(Box,
- return Pattern(m_binding, Data::make_Box({
+ return ::HIR::Pattern::Data::make_Box({
box$( e.sub->clone() )
- }));
+ });
),
(Ref,
- return Pattern(m_binding, Data::make_Ref({
+ return ::HIR::Pattern::Data::make_Ref({
e.type, box$(e.sub->clone())
- }));
+ });
),
(Tuple,
- return Pattern(m_binding, Data::make_Tuple({
+ return ::HIR::Pattern::Data::make_Tuple({
clone_pat_vec(e.sub_patterns)
- }));
+ });
),
(SplitTuple,
- return Pattern(m_binding, Data::make_SplitTuple({
+ return ::HIR::Pattern::Data::make_SplitTuple({
clone_pat_vec(e.leading),
clone_pat_vec(e.trailing),
e.total_size
- }));
+ });
),
(StructValue,
- return Pattern(m_binding, Data::make_StructValue({
+ return ::HIR::Pattern::Data::make_StructValue({
e.path.clone(), e.binding
- }));
+ });
),
(StructTuple,
- return Pattern(m_binding, Data::make_StructTuple({
+ return ::HIR::Pattern::Data::make_StructTuple({
e.path.clone(),
e.binding,
clone_pat_vec(e.sub_patterns)
- }));
+ });
),
(Struct,
- return Pattern(m_binding, Data::make_Struct({
+ return ::HIR::Pattern::Data::make_Struct({
e.path.clone(),
e.binding,
clone_pat_fields(e.sub_patterns),
e.is_exhaustive
- }));
+ });
),
(Value,
- return Pattern(m_binding, Data::make_Value({
+ return ::HIR::Pattern::Data::make_Value({
clone_patval(e.val)
- }));
+ });
),
(Range,
- return Pattern(m_binding, Data::make_Range({
+ return ::HIR::Pattern::Data::make_Range({
clone_patval(e.start),
clone_patval(e.end)
- }));
+ });
),
(EnumValue,
- return Pattern(m_binding, Data::make_EnumValue({ e.path.clone(), e.binding_ptr, e.binding_idx }));
+ return ::HIR::Pattern::Data::make_EnumValue({ e.path.clone(), e.binding_ptr, e.binding_idx });
),
(EnumTuple,
- return Pattern(m_binding, Data::make_EnumTuple({
+ return ::HIR::Pattern::Data::make_EnumTuple({
e.path.clone(),
e.binding_ptr,
e.binding_idx,
clone_pat_vec(e.sub_patterns)
- }));
+ });
),
(EnumStruct,
- return Pattern(m_binding, Data::make_EnumStruct({
+ return ::HIR::Pattern::Data::make_EnumStruct({
e.path.clone(),
e.binding_ptr,
e.binding_idx,
clone_pat_fields(e.sub_patterns),
e.is_exhaustive
- }));
+ });
),
(Slice,
- return Pattern(m_binding, Data::make_Slice({
+ return ::HIR::Pattern::Data::make_Slice({
clone_pat_vec(e.sub_patterns)
- }));
+ });
),
(SplitSlice,
- return Pattern(m_binding, Data::make_SplitSlice({
+ return ::HIR::Pattern::Data::make_SplitSlice({
clone_pat_vec(e.leading),
e.extra_bind,
clone_pat_vec(e.trailing)
- }));
+ });
)
)
throw "";
+} }
+::HIR::Pattern HIR::Pattern::clone() const
+{
+ auto rv = Pattern(m_binding, clone_pattern_data(m_data));
+ rv.m_implicit_deref_count = m_implicit_deref_count;
+ return rv;
}
diff --git a/src/hir/pattern.hpp b/src/hir/pattern.hpp
index df14de79..136bd587 100644
--- a/src/hir/pattern.hpp
+++ b/src/hir/pattern.hpp
@@ -29,22 +29,26 @@ struct PatternBinding
bool m_mutable;
Type m_type;
- ::std::string m_name;
+ RcString m_name;
unsigned int m_slot;
+ unsigned m_implicit_deref_count = 0;
+
bool is_valid() const { return m_name != ""; }
PatternBinding():
m_mutable(false),
m_type(Type::Move),
m_name(""),
- m_slot(0)
+ m_slot(0),
+ m_implicit_deref_count(0)
{}
- PatternBinding(bool mut, Type type, ::std::string name, unsigned int slot):
+ PatternBinding(bool mut, Type type, RcString name, unsigned int slot):
m_mutable(mut),
m_type(type),
m_name( mv$(name) ),
- m_slot( slot )
+ m_slot( slot ),
+ m_implicit_deref_count(0)
{}
};
@@ -100,8 +104,12 @@ struct Pattern
(Struct, struct {
GenericPath path;
const Struct* binding;
- ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns;
+ ::std::vector< ::std::pair<RcString, Pattern> > sub_patterns;
bool is_exhaustive;
+
+ bool is_wildcard() const {
+ return sub_patterns.empty() && !is_exhaustive;
+ }
} ),
// Refutable
(Value, struct { Value val; } ),
@@ -121,7 +129,7 @@ struct Pattern
GenericPath path;
const Enum* binding_ptr;
unsigned binding_idx;
- ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns;
+ ::std::vector< ::std::pair<RcString, Pattern> > sub_patterns;
bool is_exhaustive;
} ),
(Slice, struct {
@@ -136,6 +144,7 @@ struct Pattern
PatternBinding m_binding;
Data m_data;
+ unsigned m_implicit_deref_count = 0;
Pattern() {}
Pattern(PatternBinding pb, Data d):
diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp
index 50da4453..9acb6193 100644
--- a/src/hir/serialise.cpp
+++ b/src/hir/serialise.cpp
@@ -21,6 +21,15 @@
{}
template<typename V>
+ void serialise_strmap(const ::std::map<RcString,V>& map)
+ {
+ m_out.write_count(map.size());
+ for(const auto& v : map) {
+ m_out.write_string(v.first);
+ serialise(v.second);
+ }
+ }
+ template<typename V>
void serialise_strmap(const ::std::map< ::std::string,V>& map)
{
m_out.write_count(map.size());
@@ -30,6 +39,26 @@
}
}
template<typename V>
+ void serialise_pathmap(const ::std::map< ::HIR::SimplePath,V>& map)
+ {
+ m_out.write_count(map.size());
+ for(const auto& v : map) {
+ DEBUG("- " << v.first);
+ serialise(v.first);
+ serialise(v.second);
+ }
+ }
+ template<typename V>
+ void serialise_strmap(const ::std::unordered_map<RcString,V>& map)
+ {
+ m_out.write_count(map.size());
+ for(const auto& v : map) {
+ DEBUG("- " << v.first);
+ m_out.write_string(v.first);
+ serialise(v.second);
+ }
+ }
+ template<typename V>
void serialise_strmap(const ::std::unordered_map< ::std::string,V>& map)
{
m_out.write_count(map.size());
@@ -40,6 +69,16 @@
}
}
template<typename V>
+ void serialise_strmap(const ::std::unordered_multimap<RcString,V>& map)
+ {
+ m_out.write_count(map.size());
+ for(const auto& v : map) {
+ DEBUG("- " << v.first);
+ m_out.write_string(v.first);
+ serialise(v.second);
+ }
+ }
+ template<typename V>
void serialise_strmap(const ::std::unordered_multimap< ::std::string,V>& map)
{
m_out.write_count(map.size());
@@ -58,9 +97,14 @@
serialise(i);
}
template<typename T>
+ void serialise(const ::std::vector<T>& vec)
+ {
+ serialise_vec(vec);
+ }
+ template<typename T>
void serialise(const ::HIR::VisEnt<T>& e)
{
- m_out.write_bool(e.is_public);
+ m_out.write_bool(e.publicity.is_global()); // At this stage, we only care if the item is visible outside the crate or not
serialise(e.ent);
}
template<typename T>
@@ -73,6 +117,11 @@
serialise(e.second);
}
template<typename T>
+ void serialise(const ::std::pair< RcString, T>& e) {
+ m_out.write_string(e.first);
+ serialise(e.second);
+ }
+ template<typename T>
void serialise(const ::std::pair<unsigned int, T>& e) {
m_out.write_count(e.first);
serialise(e.second);
@@ -86,6 +135,10 @@
void serialise(uint64_t v) { m_out.write_u64c(v); };
void serialise(int64_t v) { m_out.write_i64c(v); };
+ void serialise(const ::HIR::LifetimeDef& ld)
+ {
+ m_out.write_string(ld.m_name);
+ }
void serialise(const ::HIR::LifetimeRef& lr)
{
m_out.write_count(lr.binding);
@@ -255,28 +308,29 @@
serialise(pm.path);
serialise_vec(pm.attributes);
}
+ template<typename T>
+ void serialise(const ::HIR::Crate::ImplGroup<T>& ig)
+ {
+ serialise_pathmap(ig.named);
+ serialise_vec(ig.non_named);
+ serialise_vec(ig.generic);
+ }
+ void serialise(const ::HIR::Crate::MacroImport& e)
+ {
+ serialise(e.path);
+ }
void serialise_crate(const ::HIR::Crate& crate)
{
m_out.write_string(crate.m_crate_name);
serialise_module(crate.m_root_module);
- m_out.write_count(crate.m_type_impls.size());
- for(const auto& impl : crate.m_type_impls) {
- serialise_typeimpl(impl);
- }
- m_out.write_count(crate.m_trait_impls.size());
- for(const auto& tr_impl : crate.m_trait_impls) {
- serialise_simplepath(tr_impl.first);
- serialise_traitimpl(tr_impl.second);
- }
- m_out.write_count(crate.m_marker_impls.size());
- for(const auto& tr_impl : crate.m_marker_impls) {
- serialise_simplepath(tr_impl.first);
- serialise_markerimpl(tr_impl.second);
- }
+ serialise(crate.m_type_impls);
+ serialise_pathmap(crate.m_trait_impls);
+ serialise_pathmap(crate.m_marker_impls);
serialise_strmap(crate.m_exported_macros);
+ serialise_strmap(crate.m_proc_macro_reexports);
{
decltype(crate.m_lang_items) lang_items_filtered;
for(const auto& ent : crate.m_lang_items)
@@ -293,7 +347,8 @@
for(const auto& ext : crate.m_ext_crates)
{
m_out.write_string(ext.first);
- m_out.write_string(ext.second.m_basename);
+ //m_out.write_string(ext.second.m_basename);
+ m_out.write_string(ext.second.m_path);
}
serialise_vec(crate.m_ext_libs);
serialise_vec(crate.m_link_paths);
@@ -322,19 +377,23 @@
m_out.write_count(impl.m_methods.size());
for(const auto& v : impl.m_methods) {
m_out.write_string(v.first);
- m_out.write_bool(v.second.is_pub);
+ m_out.write_bool(v.second.publicity.is_global());
m_out.write_bool(v.second.is_specialisable);
serialise(v.second.data);
}
m_out.write_count(impl.m_constants.size());
for(const auto& v : impl.m_constants) {
m_out.write_string(v.first);
- m_out.write_bool(v.second.is_pub);
+ m_out.write_bool(v.second.publicity.is_global());
m_out.write_bool(v.second.is_specialisable);
serialise(v.second.data);
}
// m_src_module doesn't matter after typeck
}
+ void serialise(const ::HIR::TypeImpl& impl)
+ {
+ serialise_typeimpl(impl);
+ }
void serialise_traitimpl(const ::HIR::TraitImpl& impl)
{
TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " ?" << impl.m_trait_args << " for " << impl.m_type);
@@ -372,6 +431,10 @@
}
// m_src_module doesn't matter after typeck
}
+ void serialise(const ::HIR::TraitImpl& impl)
+ {
+ serialise_traitimpl(impl);
+ }
void serialise_markerimpl(const ::HIR::MarkerImpl& impl)
{
serialise_generics(impl.m_params);
@@ -379,6 +442,10 @@
m_out.write_bool(impl.is_positive);
serialise_type(impl.m_type);
}
+ void serialise(const ::HIR::MarkerImpl& impl)
+ {
+ serialise_markerimpl(impl);
+ }
void serialise(const ::HIR::TypeRef& ty) {
serialise_type(ty);
@@ -392,6 +459,9 @@
void serialise(const ::std::string& v) {
m_out.write_string(v);
}
+ void serialise(const RcString& v) {
+ m_out.write_string(v);
+ }
void serialise(const ::MacroRulesPtr& mac)
{
@@ -400,6 +470,7 @@
void serialise(const ::MacroRules& mac)
{
//m_exported: IGNORE, should be set
+ assert(mac.m_rules.size() > 0);
serialise_vec(mac.m_rules);
m_out.write_string(mac.m_source_crate);
}
@@ -415,6 +486,34 @@
serialise_vec(pe.subpats);
}
}
+ void serialise(const ::SimplePatIfCheck& e) {
+ m_out.write_tag( static_cast<int>(e.ty) );
+ serialise(e.tok);
+ }
+ void serialise(const ::SimplePatEnt& pe) {
+ m_out.write_tag( pe.tag() );
+ TU_MATCH_HDRA( (pe), { )
+ TU_ARMA(End, _e) {}
+ TU_ARMA(LoopStart, _e) {}
+ TU_ARMA(LoopNext, _e) {}
+ TU_ARMA(LoopEnd, _e) {}
+ TU_ARMA(Jump, e) {
+ m_out.write_count(e.jump_target);
+ }
+ TU_ARMA(ExpectTok, e) {
+ serialise(e);
+ }
+ TU_ARMA(ExpectPat, e) {
+ m_out.write_tag( static_cast<int>(e.type) );
+ m_out.write_count(e.idx);
+ }
+ TU_ARMA(If, e) {
+ m_out.write_bool(e.is_equal);
+ m_out.write_count(e.jump_target);
+ serialise_vec(e.ents);
+ }
+ }
+ }
void serialise(const ::MacroRulesArm& arm) {
serialise_vec(arm.m_param_names);
serialise_vec(arm.m_pattern);
@@ -459,6 +558,9 @@
TU_ARM(td, String, e) {
m_out.write_string(e);
} break;
+ TU_ARM(td, IString, e) {
+ m_out.write_string(e);
+ } break;
TU_ARM(td, Integer, e) {
m_out.write_tag(e.m_datatype);
m_out.write_u64c(e.m_intval);
@@ -479,6 +581,8 @@
(Invalid,
//BUG(Span(), "Literal::Invalid encountered in HIR");
),
+ (Defer,
+ ),
(List,
serialise_vec(e);
),
@@ -647,35 +751,18 @@
void serialise(const ::MIR::LValue& lv)
{
TRACE_FUNCTION_F("LValue = "<<lv);
- m_out.write_tag( static_cast<int>(lv.tag()) );
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Argument,
- m_out.write_count(e.idx);
- ),
- (Local,
- m_out.write_count(e);
- ),
- (Static,
- serialise_path(e);
- ),
- (Field,
- serialise(e.val);
- m_out.write_count(e.field_index);
- ),
- (Deref,
- serialise(e.val);
- ),
- (Index,
- serialise(e.val);
- serialise(e.idx);
- ),
- (Downcast,
- serialise(e.val);
- m_out.write_count(e.variant_index);
- )
- )
+ if( lv.m_root.is_Static() ) {
+ m_out.write_count(3);
+ serialise_path(lv.m_root.as_Static());
+ }
+ else {
+ m_out.write_count( lv.m_root.get_inner() );
+ }
+ serialise_vec(lv.m_wrappers);
+ }
+ void serialise(const ::MIR::LValue::Wrapper& w)
+ {
+ m_out.write_count(w.get_inner());
}
void serialise(const ::MIR::RValue& val)
{
@@ -764,10 +851,10 @@
m_out.write_string(e);
),
(Const,
- serialise_path(e.p);
+ serialise_path(*e.p);
),
(ItemAddr,
- serialise_path(e);
+ serialise_path(*e);
)
)
}
@@ -804,6 +891,10 @@
(Union,
m_out.write_tag(6);
serialise(e);
+ ),
+ (ExternType,
+ m_out.write_tag(7);
+ serialise(e);
)
)
}
@@ -975,6 +1066,7 @@
)
)
+ m_out.write_u64c(item.m_forced_alignment);
serialise(item.m_markings);
serialise(item.m_struct_markings);
}
@@ -989,6 +1081,11 @@
serialise(item.m_markings);
}
+ void serialise(const ::HIR::ExternType& item)
+ {
+ TRACE_FUNCTION_F("ExternType");
+ serialise(item.m_markings);
+ }
void serialise(const ::HIR::Trait& item)
{
TRACE_FUNCTION_F("_trait:");
@@ -1000,6 +1097,7 @@
serialise_strmap( item.m_value_indexes );
serialise_strmap( item.m_type_indexes );
serialise_vec( item.m_all_parent_traits );
+ serialise( item.m_vtable_path );
}
void serialise(const ::HIR::TraitValueItem& tvi)
{
@@ -1022,7 +1120,7 @@
void serialise(const ::HIR::AssociatedType& at)
{
m_out.write_bool(at.is_sized);
- //m_out.write_string(at.m_lifetime_bound); // TODO: better type for lifetime
+ serialise(at.m_lifetime_bound);
serialise_vec(at.m_trait_bounds);
serialise_type(at.m_default);
}
@@ -1031,8 +1129,10 @@
void HIR_Serialise(const ::std::string& filename, const ::HIR::Crate& crate)
{
- ::HIR::serialise::Writer out { filename };
+ ::HIR::serialise::Writer out;
HirSerialiser s { out };
s.serialise_crate(crate);
+ out.open(filename);
+ s.serialise_crate(crate);
}
diff --git a/src/hir/serialise_lowlevel.cpp b/src/hir/serialise_lowlevel.cpp
index cf8f5506..5c4b0df2 100644
--- a/src/hir/serialise_lowlevel.cpp
+++ b/src/hir/serialise_lowlevel.cpp
@@ -11,6 +11,7 @@
#include <fstream>
#include <string.h> // memcpy
#include <common.hpp>
+#include <algorithm>
namespace HIR {
namespace serialise {
@@ -29,17 +30,58 @@ public:
void write(const void* buf, size_t len);
};
-Writer::Writer(const ::std::string& filename):
- m_inner( new WriterInner(filename) )
+Writer::Writer():
+ m_inner(nullptr)
{
}
Writer::~Writer()
{
delete m_inner, m_inner = nullptr;
}
+void Writer::open(const ::std::string& filename)
+{
+ // 1. Sort strings by frequency
+ ::std::vector<::std::pair<RcString, unsigned>> sorted;
+ sorted.reserve(m_istring_cache.size());
+ for(const auto& e : m_istring_cache)
+ sorted.push_back( e );
+ // 2. Write out string table
+ ::std::sort(sorted.begin(), sorted.end(), [](const auto& a, const auto& b){ return a.second > b.second; });
+
+ m_inner = new WriterInner(filename);
+ // 3. Reset m_istring_cache to use the same value
+ this->write_count(sorted.size());
+ for(size_t i = 0; i < sorted.size(); i ++)
+ {
+ const auto& s = sorted[i].first;
+ this->write_string(s.size(), s.c_str());
+ DEBUG(i << " = " << m_istring_cache[s] << " '" << s << "'");
+ m_istring_cache[s] = i;
+ }
+ for(const auto& e : m_istring_cache)
+ {
+ assert(e.second < sorted.size());
+ }
+}
void Writer::write(const void* buf, size_t len)
{
- m_inner->write(buf, len);
+ if( m_inner ) {
+ m_inner->write(buf, len);
+ }
+ else {
+ // No-op, pre caching
+ }
+}
+void Writer::write_string(const RcString& v)
+{
+ if( m_inner ) {
+ // Emit ID from the cache
+ this->write_count( m_istring_cache.at(v) );
+ }
+ else {
+ // Find/add in cache
+ m_istring_cache.insert(::std::make_pair(v, 0)).first->second += 1;
+ }
}
@@ -186,8 +228,17 @@ void ReadBuffer::populate(ReaderInner& is)
Reader::Reader(const ::std::string& filename):
m_inner( new ReaderInner(filename) ),
- m_buffer(1024)
+ m_buffer(1024),
+ m_pos(0)
{
+ size_t n_strings = read_count();
+ m_strings.reserve(n_strings);
+ DEBUG("n_strings = " << n_strings);
+ for(size_t i = 0; i < n_strings; i ++)
+ {
+ auto s = read_string();
+ m_strings.push_back( RcString::new_interned(s) );
+ }
}
Reader::~Reader()
{
@@ -198,6 +249,7 @@ void Reader::read(void* buf, size_t len)
{
auto used = m_buffer.read(buf, len);
if( used == len ) {
+ m_pos += len;
return ;
}
buf = reinterpret_cast<uint8_t*>(buf) + used;
@@ -214,6 +266,8 @@ void Reader::read(void* buf, size_t len)
if( used != len )
throw ::std::runtime_error( FMT("Reader::read - Requested " << len << " bytes from buffer, got " << used) );
}
+
+ m_pos += len;
}
diff --git a/src/hir/serialise_lowlevel.hpp b/src/hir/serialise_lowlevel.hpp
index 6be8ff8c..b3633d54 100644
--- a/src/hir/serialise_lowlevel.hpp
+++ b/src/hir/serialise_lowlevel.hpp
@@ -9,8 +9,10 @@
#include <vector>
#include <string>
+#include <map>
#include <stddef.h>
#include <assert.h>
+#include <rc_string.hpp>
namespace HIR {
namespace serialise {
@@ -21,12 +23,14 @@ class ReaderInner;
class Writer
{
WriterInner* m_inner;
+ ::std::map<RcString, unsigned> m_istring_cache;
public:
- Writer(const ::std::string& path);
+ Writer();
Writer(const Writer&) = delete;
Writer(Writer&&) = delete;
~Writer();
+ void open(const ::std::string& filename);
void write(const void* data, size_t count);
void write_u8(uint8_t v) {
@@ -114,16 +118,20 @@ public:
write_u16( static_cast<uint16_t>(c) );
}
}
- void write_string(const ::std::string& v) {
- if(v.size() < 128) {
- write_u8( static_cast<uint8_t>(v.size()) );
+ void write_string(const RcString& v);
+ void write_string(size_t len, const char* s) {
+ if(len < 128) {
+ write_u8( static_cast<uint8_t>(len) );
}
else {
- assert(v.size() < (1u<<(16+7)));
- write_u8( static_cast<uint8_t>(128 + (v.size() >> 16)) );
- write_u16( static_cast<uint16_t>(v.size() & 0xFFFF) );
+ assert(len < (1u<<(16+7)));
+ write_u8( static_cast<uint8_t>(128 + (len >> 16)) );
+ write_u16( static_cast<uint16_t>(len & 0xFFFF) );
}
- this->write(v.data(), v.size());
+ this->write(s, len);
+ }
+ void write_string(const ::std::string& v) {
+ write_string(v.size(), v.c_str());
}
void write_bool(bool v) {
write_u8(v ? 0xFF : 0x00);
@@ -147,12 +155,15 @@ class Reader
{
ReaderInner* m_inner;
ReadBuffer m_buffer;
+ size_t m_pos;
+ ::std::vector<RcString> m_strings;
public:
Reader(const ::std::string& path);
Reader(const Writer&) = delete;
Reader(Writer&&) = delete;
~Reader();
+ size_t get_pos() const { return m_pos; }
void read(void* dst, size_t count);
uint8_t read_u8() {
@@ -249,6 +260,10 @@ public:
return ~0u;
}
}
+ RcString read_istring() {
+ size_t idx = read_count();
+ return m_strings.at(idx);
+ }
::std::string read_string() {
size_t len = read_u8();
if( len < 128 ) {
diff --git a/src/hir/type.cpp b/src/hir/type.cpp
index 6f826111..6e8eaaa9 100644
--- a/src/hir/type.cpp
+++ b/src/hir/type.cpp
@@ -58,8 +58,8 @@ namespace HIR {
void ::HIR::TypeRef::fmt(::std::ostream& os) const
{
- TU_MATCH(::HIR::TypeRef::Data, (m_data), (e),
- (Infer,
+ TU_MATCH_HDR( (m_data), { )
+ TU_ARM(m_data, Infer, e) {
os << "_";
if( e.index != ~0u || e.ty_class != ::HIR::InferClass::None ) {
os << "/*";
@@ -73,24 +73,25 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
}
os << "*/";
}
- ),
- (Diverge,
+ }
+ TU_ARM(m_data, Diverge, e) {
os << "!";
- ),
- (Primitive,
+ }
+ TU_ARM(m_data, Primitive, e) {
os << e;
- ),
- (Path,
+ }
+ TU_ARM(m_data, Path, e) {
os << e.path;
TU_MATCH(::HIR::TypeRef::TypePathBinding, (e.binding), (be),
(Unbound, os << "/*?*/";),
(Opaque, os << "/*O*/";),
+ (ExternType, os << "/*X*/";),
(Struct, os << "/*S*/";),
(Union, os << "/*U*/";),
(Enum, os << "/*E*/";)
)
- ),
- (Generic,
+ }
+ TU_ARM(m_data, Generic, e) {
os << e.name << "/*";
if( e.binding == 0xFFFF )
os << "";
@@ -103,8 +104,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
else
os << e.binding;
os << "*/";
- ),
- (TraitObject,
+ }
+ TU_ARM(m_data, TraitObject, e) {
os << "dyn (";
if( e.m_trait.m_path != ::HIR::GenericPath() )
{
@@ -115,8 +116,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
if( e.m_lifetime != LifetimeRef::new_static() )
os << "+" << e.m_lifetime;
os << ")";
- ),
- (ErasedType,
+ }
+ TU_ARM(m_data, ErasedType, e) {
os << "impl ";
for(const auto& tr : e.m_traits) {
if( &tr != &e.m_traits[0] )
@@ -126,25 +127,25 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
if( e.m_lifetime != LifetimeRef::new_static() )
os << "+ '" << e.m_lifetime;
os << "/*" << e.m_origin << "#" << e.m_index << "*/";
- ),
- (Array,
+ }
+ TU_ARM(m_data, Array, e) {
os << "[" << *e.inner << "; ";
if( e.size_val != ~0u )
os << e.size_val;
else
os << "/*sz*/";
os << "]";
- ),
- (Slice,
+ }
+ TU_ARM(m_data, Slice, e) {
os << "[" << *e.inner << "]";
- ),
- (Tuple,
+ }
+ TU_ARM(m_data, Tuple, e) {
os << "(";
for(const auto& t : e)
os << t << ", ";
os << ")";
- ),
- (Borrow,
+ }
+ TU_ARM(m_data, Borrow, e) {
switch(e.type)
{
case ::HIR::BorrowType::Shared: os << "&"; break;
@@ -152,8 +153,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
case ::HIR::BorrowType::Owned: os << "&move "; break;
}
os << *e.inner;
- ),
- (Pointer,
+ }
+ TU_ARM(m_data, Pointer, e) {
switch(e.type)
{
case ::HIR::BorrowType::Shared: os << "*const "; break;
@@ -161,8 +162,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
case ::HIR::BorrowType::Owned: os << "*move "; break;
}
os << *e.inner;
- ),
- (Function,
+ }
+ TU_ARM(m_data, Function, e) {
if( e.is_unsafe ) {
os << "unsafe ";
}
@@ -173,17 +174,15 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const
for(const auto& t : e.m_arg_types)
os << t << ", ";
os << ") -> " << *e.m_rettype;
- ),
- (Closure,
+ }
+ TU_ARM(m_data, Closure, e) {
os << "closure["<<e.node<<"]";
- /*
os << "(";
for(const auto& t : e.m_arg_types)
os << t << ", ";
os << ") -> " << *e.m_rettype;
- */
- )
- )
+ }
+ }
}
bool ::HIR::TypeRef::operator==(const ::HIR::TypeRef& x) const
@@ -782,6 +781,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x
TU_MATCH(::HIR::TypeRef::TypePathBinding, (*this), (e),
(Unbound, return ::HIR::TypeRef::TypePathBinding::make_Unbound({}); ),
(Opaque , return ::HIR::TypeRef::TypePathBinding::make_Opaque({}); ),
+ (ExternType, return ::HIR::TypeRef::TypePathBinding(e); ),
(Struct, return ::HIR::TypeRef::TypePathBinding(e); ),
(Union , return ::HIR::TypeRef::TypePathBinding(e); ),
(Enum , return ::HIR::TypeRef::TypePathBinding(e); )
@@ -789,7 +789,34 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x
assert(!"Fell off end of clone_binding");
throw "";
}
+bool HIR::TypeRef::TypePathBinding::operator==(const HIR::TypeRef::TypePathBinding& x) const
+{
+ if( this->tag() != x.tag() )
+ return false;
+ TU_MATCH(::HIR::TypeRef::TypePathBinding, (*this, x), (te, xe),
+ (Unbound, return true;),
+ (Opaque, return true;),
+ (ExternType, return te == xe;),
+ (Struct, return te == xe;),
+ (Union , return te == xe;),
+ (Enum , return te == xe;)
+ )
+ throw "";
+}
+const ::HIR::TraitMarkings* HIR::TypeRef::TypePathBinding::get_trait_markings() const
+{
+ const ::HIR::TraitMarkings* markings_ptr = nullptr;
+ TU_MATCHA( (*this), (tpb),
+ (Unbound, ),
+ (Opaque, ),
+ (ExternType, markings_ptr = &tpb->m_markings; ),
+ (Struct, markings_ptr = &tpb->m_markings; ),
+ (Union, markings_ptr = &tpb->m_markings; ),
+ (Enum, markings_ptr = &tpb->m_markings; )
+ )
+ return markings_ptr;
+}
::HIR::TypeRef HIR::TypeRef::clone() const
{
@@ -889,7 +916,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x
}
::HIR::Compare HIR::TypeRef::compare_with_placeholders(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder) const
{
- TRACE_FUNCTION_F(*this << " ?= " << x);
+ //TRACE_FUNCTION_F(*this << " ?= " << x);
const auto& left = (m_data.is_Infer() || m_data.is_Generic() ? resolve_placeholder(*this) : *this);
//const auto& left = *this;
const auto& right = (x.m_data.is_Infer() ? resolve_placeholder(x) : (x.m_data.is_Generic() ? resolve_placeholder(x) : x));
@@ -899,6 +926,22 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x
return Compare::Equal;
}
+ // Unbound paths and placeholder generics
+ if( left.m_data.tag() != right.m_data.tag() ) {
+ if( left.m_data.is_Path() && left.m_data.as_Path().binding.is_Unbound() ) {
+ return Compare::Fuzzy;
+ }
+ if( right.m_data.is_Path() && right.m_data.as_Path().binding.is_Unbound() ) {
+ return Compare::Fuzzy;
+ }
+ if( left.m_data.is_Generic() && (left.m_data.as_Generic().binding >> 8) == 2 ) {
+ return Compare::Fuzzy;
+ }
+ if( right.m_data.is_Generic() && (right.m_data.as_Generic().binding >> 8) == 2 ) {
+ return Compare::Fuzzy;
+ }
+ }
+
// If left is infer
TU_IFLET(::HIR::TypeRef::Data, left.m_data, Infer, e,
switch(e.ty_class)
@@ -1023,18 +1066,6 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x
// - See `(Generic,` below
if( left.m_data.tag() != right.m_data.tag() ) {
- if( left.m_data.is_Path() && left.m_data.as_Path().binding.is_Unbound() ) {
- return Compare::Fuzzy;
- }
- if( right.m_data.is_Path() && right.m_data.as_Path().binding.is_Unbound() ) {
- return Compare::Fuzzy;
- }
- if( left.m_data.is_Generic() && (left.m_data.as_Generic().binding >> 8) == 2 ) {
- return Compare::Fuzzy;
- }
- if( right.m_data.is_Generic() && (right.m_data.as_Generic().binding >> 8) == 2 ) {
- return Compare::Fuzzy;
- }
return Compare::Unequal;
}
TU_MATCH(::HIR::TypeRef::Data, (left.m_data, right.m_data), (le, re),
diff --git a/src/hir/type.hpp b/src/hir/type.hpp
index 480b32c4..cbc2e94a 100644
--- a/src/hir/type.hpp
+++ b/src/hir/type.hpp
@@ -19,6 +19,8 @@
namespace HIR {
+class TraitMarkings;
+class ExternType;
class Struct;
class Union;
class Enum;
@@ -87,15 +89,28 @@ struct LifetimeRef
static const uint32_t UNKNOWN = 0;
static const uint32_t STATIC = 0xFFFF;
+ //RcString name;
// Values below 2^16 are parameters/static, values above are per-function region IDs allocated during region inferrence.
uint32_t binding = UNKNOWN;
+ LifetimeRef()
+ :binding(UNKNOWN)
+ {
+ }
+ LifetimeRef(uint32_t binding)
+ :binding(binding)
+ {
+ }
+
static LifetimeRef new_static() {
LifetimeRef rv;
rv.binding = STATIC;
return rv;
}
+ Ordering ord(const LifetimeRef& x) const {
+ return ::ord(binding, x.binding);
+ }
bool operator==(const LifetimeRef& x) const {
return binding == x.binding;
}
@@ -152,11 +167,17 @@ public:
TAGGED_UNION_EX(TypePathBinding, (), Unbound, (
(Unbound, struct {}), // Not yet bound, either during lowering OR during resolution (when associated and still being resolved)
(Opaque, struct {}), // Opaque, i.e. An associated type of a generic (or Self in a trait)
+ (ExternType, const ::HIR::ExternType*),
(Struct, const ::HIR::Struct*),
(Union, const ::HIR::Union*),
(Enum, const ::HIR::Enum*)
), (), (), (
TypePathBinding clone() const;
+
+ const TraitMarkings* get_trait_markings() const;
+
+ bool operator==(const TypePathBinding& x) const;
+ bool operator!=(const TypePathBinding& x) const { return !(*this == x); }
)
);
@@ -184,9 +205,16 @@ public:
(Path, struct {
::HIR::Path path;
TypePathBinding binding;
+
+ bool is_closure() const {
+ return path.m_data.is_Generic()
+ && path.m_data.as_Generic().m_path.m_components.back().size() > 8
+ && path.m_data.as_Generic().m_path.m_components.back().compare(0,8, "closure#") == 0
+ ;
+ }
}),
(Generic, struct {
- ::std::string name;
+ RcString name;
// 0xFFFF = Self, 0-255 = Type/Trait, 256-511 = Method, 512-767 = Placeholder
unsigned int binding;
@@ -208,7 +236,7 @@ public:
(Array, struct {
::std::unique_ptr<TypeRef> inner;
::std::shared_ptr<::HIR::ExprPtr> size;
- size_t size_val;
+ uint64_t size_val;
}),
(Slice, struct {
::std::unique_ptr<TypeRef> inner;
@@ -249,7 +277,7 @@ public:
TypeRef(::std::vector< ::HIR::TypeRef> sts):
m_data( Data::make_Tuple(mv$(sts)) )
{}
- TypeRef(::std::string name, unsigned int slot):
+ TypeRef(RcString name, unsigned int slot):
m_data( Data::make_Generic({ mv$(name), slot }) )
{}
TypeRef(::HIR::TypeRef::Data x):
@@ -316,6 +344,24 @@ public:
// Compares this type with another, using `resolve_placeholder` to get replacements for generics/infers in `x`
Compare compare_with_placeholders(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder) const;
+
+ const ::HIR::SimplePath* get_sort_path() const {
+ // - Generic paths get sorted
+ if( TU_TEST1(this->m_data, Path, .path.m_data.is_Generic()) )
+ {
+ return &this->m_data.as_Path().path.m_data.as_Generic().m_path;
+ }
+ // - So do trait objects
+ else if( this->m_data.is_TraitObject() )
+ {
+ return &this->m_data.as_TraitObject().m_trait.m_path.m_path;
+ }
+ else
+ {
+ // Keep as nullptr, will search primitive list
+ return nullptr;
+ }
+ }
};
extern ::std::ostream& operator<<(::std::ostream& os, const ::HIR::TypeRef& ty);
diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp
index 2e03990a..664d34ad 100644
--- a/src/hir/visitor.cpp
+++ b/src/hir/visitor.cpp
@@ -12,21 +12,39 @@
{
}
+namespace {
+ template<typename T>
+ void visit_impls(::HIR::Crate::ImplGroup<T>& g, ::std::function<void(T&)> cb) {
+ for( auto& impl_group : g.named )
+ {
+ for( auto& impl : impl_group.second )
+ {
+ cb(*impl);
+ }
+ }
+ for( auto& impl : g.non_named )
+ {
+ cb(*impl);
+ }
+ for( auto& impl : g.generic )
+ {
+ cb(*impl);
+ }
+ }
+}
+
void ::HIR::Visitor::visit_crate(::HIR::Crate& crate)
{
this->visit_module(::HIR::ItemPath(crate.m_crate_name), crate.m_root_module );
- for( auto& ty_impl : crate.m_type_impls )
- {
- this->visit_type_impl(ty_impl);
- }
- for( auto& impl : crate.m_trait_impls )
+ visit_impls<::HIR::TypeImpl>(crate.m_type_impls, [&](::HIR::TypeImpl& ty_impl){ this->visit_type_impl(ty_impl); });
+ for( auto& impl_group : crate.m_trait_impls )
{
- this->visit_trait_impl(impl.first, impl.second);
+ visit_impls<::HIR::TraitImpl>(impl_group.second, [&](::HIR::TraitImpl& ty_impl){ this->visit_trait_impl(impl_group.first, ty_impl); });
}
- for( auto& impl : crate.m_marker_impls )
+ for( auto& impl_group : crate.m_marker_impls )
{
- this->visit_marker_impl(impl.first, impl.second);
+ visit_impls<::HIR::MarkerImpl>(impl_group.second, [&](::HIR::MarkerImpl& ty_impl){ this->visit_marker_impl(impl_group.first, ty_impl); });
}
}
@@ -47,6 +65,9 @@ void ::HIR::Visitor::visit_module(::HIR::ItemPath p, ::HIR::Module& mod)
DEBUG("type " << name);
this->visit_type_alias(p + name, e);
),
+ (ExternType,
+ DEBUG("extern type " << name);
+ ),
(Enum,
DEBUG("enum " << name);
this->visit_enum(p + name, e);
@@ -168,10 +189,9 @@ void ::HIR::Visitor::visit_trait(::HIR::ItemPath p, ::HIR::Trait& item)
this->visit_trait_path(par);
}
for(auto& i : item.m_types) {
+ auto item_path = ::HIR::ItemPath(trait_ip, i.first.c_str());
DEBUG("type " << i.first);
- for(auto& bound : i.second.m_trait_bounds)
- this->visit_trait_path(bound);
- this->visit_type(i.second.m_default);
+ this->visit_associatedtype(item_path, i.second);
}
for(auto& i : item.m_values) {
auto item_path = ::HIR::ItemPath(trait_ip, i.first.c_str());
@@ -230,12 +250,21 @@ void ::HIR::Visitor::visit_enum(::HIR::ItemPath p, ::HIR::Enum& item)
}
void ::HIR::Visitor::visit_union(::HIR::ItemPath p, ::HIR::Union& item)
{
+ TRACE_FUNCTION_F(p);
this->visit_params(item.m_params);
for(auto& var : item.m_variants)
this->visit_type(var.second.ent);
}
+void ::HIR::Visitor::visit_associatedtype(ItemPath p, ::HIR::AssociatedType& item)
+{
+ TRACE_FUNCTION_F(p);
+ for(auto& bound : item.m_trait_bounds)
+ this->visit_trait_path(bound);
+ this->visit_type(item.m_default);
+}
void ::HIR::Visitor::visit_function(::HIR::ItemPath p, ::HIR::Function& item)
{
+ TRACE_FUNCTION_F(p);
this->visit_params(item.m_params);
for(auto& arg : item.m_args)
{
@@ -247,11 +276,13 @@ void ::HIR::Visitor::visit_function(::HIR::ItemPath p, ::HIR::Function& item)
}
void ::HIR::Visitor::visit_static(::HIR::ItemPath p, ::HIR::Static& item)
{
+ TRACE_FUNCTION_F(p);
this->visit_type(item.m_type);
this->visit_expr(item.m_value);
}
void ::HIR::Visitor::visit_constant(::HIR::ItemPath p, ::HIR::Constant& item)
{
+ TRACE_FUNCTION_F(p);
this->visit_params(item.m_params);
this->visit_type(item.m_type);
this->visit_expr(item.m_value);
@@ -259,6 +290,7 @@ void ::HIR::Visitor::visit_constant(::HIR::ItemPath p, ::HIR::Constant& item)
void ::HIR::Visitor::visit_params(::HIR::GenericParams& params)
{
+ TRACE_FUNCTION_F(params.fmt_args() << params.fmt_bounds());
for(auto& tps : params.m_types)
this->visit_type( tps.m_default );
for(auto& bound : params.m_bounds )
diff --git a/src/hir/visitor.hpp b/src/hir/visitor.hpp
index dbf759a4..d432b29d 100644
--- a/src/hir/visitor.hpp
+++ b/src/hir/visitor.hpp
@@ -33,8 +33,9 @@ public:
virtual void visit_type_alias(ItemPath p, ::HIR::TypeAlias& item);
virtual void visit_trait(ItemPath p, ::HIR::Trait& item);
virtual void visit_struct(ItemPath p, ::HIR::Struct& item);
- virtual void visit_union(ItemPath p, ::HIR::Union& item);
virtual void visit_enum(ItemPath p, ::HIR::Enum& item);
+ virtual void visit_union(ItemPath p, ::HIR::Union& item);
+ virtual void visit_associatedtype(ItemPath p, ::HIR::AssociatedType& item);
// - Value Items
virtual void visit_function(ItemPath p, ::HIR::Function& item);
virtual void visit_static(ItemPath p, ::HIR::Static& item);
diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp
index 227ccd9f..e3441157 100644
--- a/src/hir_conv/bind.cpp
+++ b/src/hir_conv/bind.cpp
@@ -120,7 +120,7 @@ namespace {
m_cur_module.ptr = &mod;
m_cur_module.path = &p;
- m_ms.push_traits(mod);
+ m_ms.push_traits(p, mod);
::HIR::Visitor::visit_module(p, mod);
m_ms.pop_traits(mod);
@@ -140,6 +140,9 @@ namespace {
TU_MATCH(::HIR::Literal, (lit), (e),
(Invalid,
),
+ (Defer,
+ // Shouldn't happen here, but ...
+ ),
(List,
for(auto& val : e) {
visit_literal(sp, val);
@@ -253,17 +256,26 @@ namespace {
::HIR::Visitor::visit_pattern(pat);
- TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (e),
- (
- ),
- (Value,
+ TU_MATCH_HDRA( (pat.m_data), {)
+ default:
+ // Nothing
+ TU_ARMA(Value, e) {
this->visit_pattern_Value(sp, pat, e.val);
- ),
- (Range,
+ }
+ TU_ARMA(Range, e) {
this->visit_pattern_Value(sp, pat, e.start);
this->visit_pattern_Value(sp, pat, e.end);
- ),
- (StructTuple,
+ }
+ TU_ARMA(StructValue, e) {
+ const auto& str = get_struct_ptr(sp, m_crate, e.path);
+ TU_IFLET(::HIR::Struct::Data, str.m_data, Unit, _,
+ e.binding = &str;
+ )
+ else {
+ ERROR(sp, E0000, "Struct value pattern on non-unit struct " << e.path);
+ }
+ }
+ TU_ARMA(StructTuple, e) {
const auto& str = get_struct_ptr(sp, m_crate, e.path);
TU_IFLET(::HIR::Struct::Data, str.m_data, Tuple, _,
e.binding = &str;
@@ -271,8 +283,8 @@ namespace {
else {
ERROR(sp, E0000, "Struct tuple pattern on non-tuple struct " << e.path);
}
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, e) {
const auto& str = get_struct_ptr(sp, m_crate, e.path);
if(str.m_data.is_Named() ) {
}
@@ -284,8 +296,19 @@ namespace {
ERROR(sp, E0000, "Struct pattern `" << pat << "` on field-less struct " << e.path);
}
e.binding = &str;
- ),
- (EnumTuple,
+ }
+ TU_ARMA(EnumValue, e) {
+ auto p = get_enum_ptr(sp, m_crate, e.path);
+ if( p.first->m_data.is_Data() )
+ {
+ const auto& var = p.first->m_data.as_Data()[p.second];
+ if( var.is_struct || var.type != ::HIR::TypeRef::new_unit() )
+ ERROR(sp, E0000, "Enum value pattern on non-unit variant " << e.path);
+ }
+ e.binding_ptr = p.first;
+ e.binding_idx = p.second;
+ }
+ TU_ARMA(EnumTuple, e) {
auto p = get_enum_ptr(sp, m_crate, e.path);
if( !p.first->m_data.is_Data() )
ERROR(sp, E0000, "Enum tuple pattern on non-tuple variant " << e.path);
@@ -294,18 +317,61 @@ namespace {
ERROR(sp, E0000, "Enum tuple pattern on non-tuple variant " << e.path);
e.binding_ptr = p.first;
e.binding_idx = p.second;
- ),
- (EnumStruct,
+ }
+ TU_ARMA(EnumStruct, e) {
auto p = get_enum_ptr(sp, m_crate, e.path);
- if( !p.first->m_data.is_Data() )
- ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path);
- const auto& var = p.first->m_data.as_Data()[p.second];
- if( !var.is_struct )
- ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path);
+ if( !e.is_exhaustive && e.sub_patterns.empty() )
+ {
+ if( !p.first->m_data.is_Data() ) {
+ pat.m_data = ::HIR::Pattern::Data::make_EnumValue({
+ ::std::move(e.path), p.first, p.second
+ });
+ }
+ else {
+ const auto& var = p.first->m_data.as_Data()[p.second];
+ if( var.type == ::HIR::TypeRef::new_unit() )
+ {
+ pat.m_data = ::HIR::Pattern::Data::make_EnumValue({
+ ::std::move(e.path), p.first, p.second
+ });
+ }
+ else if( !var.is_struct )
+ {
+ ASSERT_BUG(sp, var.type.m_data.is_Path(), "");
+ ASSERT_BUG(sp, var.type.m_data.as_Path().binding.is_Struct(), "EnumStruct pattern on unexpected variant " << e.path << " with " << var.type.m_data.as_Path().binding.tag_str());
+ const auto& str = *var.type.m_data.as_Path().binding.as_Struct();
+ ASSERT_BUG(sp, str.m_data.is_Tuple(), "");
+ const auto& flds = str.m_data.as_Tuple();
+ ::std::vector<HIR::Pattern> subpats;
+ for(size_t i = 0; i < flds.size(); i ++)
+ subpats.push_back(::HIR::Pattern { });
+ pat.m_data = ::HIR::Pattern::Data::make_EnumTuple({
+ ::std::move(e.path), p.first, p.second, mv$(subpats)
+ });
+ }
+ else
+ {
+ // Keep as a struct pattern
+ }
+ }
+ }
+ else
+ {
+ if( !p.first->m_data.is_Data() )
+ {
+ ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path);
+ }
+ else
+ {
+ const auto& var = p.first->m_data.as_Data()[p.second];
+ if( !var.is_struct )
+ ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path);
+ }
+ }
e.binding_ptr = p.first;
e.binding_idx = p.second;
- )
- )
+ }
+ }
}
static void fix_param_count(const Span& sp, const ::HIR::GenericPath& path, const ::HIR::GenericParams& param_defs, ::HIR::PathParams& params, bool fill_infer=true, const ::HIR::TypeRef* self_ty=nullptr)
{
@@ -314,6 +380,8 @@ namespace {
return ;
}
+ TRACE_FUNCTION_F(path);
+
if( params.m_types.size() == 0 && fill_infer ) {
for(const auto& typ : param_defs.m_types) {
(void)typ;
@@ -334,9 +402,20 @@ namespace {
auto ty = clone_ty_with(sp, typ.m_default, [&](const auto& ty, auto& out){
if(const auto* te = ty.m_data.opt_Generic() )
{
- if( te->binding != GENERIC_Self || !self_ty )
+ if( te->binding == GENERIC_Self ) {
+ if( !self_ty )
+ TODO(sp, "Self enountered in default params, but no Self available - " << ty << " in " << typ.m_default << " for " << path);
+ out = self_ty->clone();
+ }
+ // NOTE: Should only be seeing impl-level params here. Method-level ones are only seen in expression context.
+ else if( (te->binding >> 8) == 0 ) {
+ auto idx = te->binding & 0xFF;
+ ASSERT_BUG(sp, idx < params.m_types.size(), "TODO: Handle use of latter types in defaults");
+ out = params.m_types[idx].clone();
+ }
+ else {
TODO(sp, "Monomorphise in fix_param_count - encountered " << ty << " in " << typ.m_default);
- out = self_ty->clone();
+ }
return true;
}
return false;
@@ -377,6 +456,10 @@ namespace {
(TypeAlias,
BUG(sp, "TypeAlias encountered after `Resolve Type Aliases` - " << ty);
),
+ (ExternType,
+ e.binding = ::HIR::TypeRef::TypePathBinding::make_ExternType(&e3);
+ DEBUG("- " << ty);
+ ),
(Struct,
fix_param_count(sp, pe, e3.m_params, pe.m_params);
e.binding = ::HIR::TypeRef::TypePathBinding::make_Struct(&e3);
@@ -429,12 +512,16 @@ namespace {
void visit_type_impl(::HIR::TypeImpl& impl) override
{
- TRACE_FUNCTION_F("impl " << impl.m_type);
+ TRACE_FUNCTION_F("impl " << impl.m_type << " - from " << impl.m_src_module);
auto _ = this->m_ms.set_impl_generics(impl.m_params);
+ auto mod_ip = ::HIR::ItemPath(impl.m_src_module);
const auto* mod = (impl.m_src_module != ::HIR::SimplePath() ? &this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module) : nullptr);
- if(mod)
- m_ms.push_traits(*mod);
+ if(mod) {
+ m_ms.push_traits(impl.m_src_module, *mod);
+ m_cur_module.ptr = mod;
+ m_cur_module.path = &mod_ip;
+ }
::HIR::Visitor::visit_type_impl(impl);
if(mod)
m_ms.pop_traits(*mod);
@@ -444,9 +531,13 @@ namespace {
TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type);
auto _ = this->m_ms.set_impl_generics(impl.m_params);
+ auto mod_ip = ::HIR::ItemPath(impl.m_src_module);
const auto* mod = (impl.m_src_module != ::HIR::SimplePath() ? &this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module) : nullptr);
- if(mod)
- m_ms.push_traits(*mod);
+ if(mod) {
+ m_ms.push_traits(impl.m_src_module, *mod);
+ m_cur_module.ptr = mod;
+ m_cur_module.path = &mod_ip;
+ }
m_ms.m_traits.push_back( ::std::make_pair( &trait_path, &this->m_ms.m_crate.get_trait_by_path(Span(), trait_path) ) );
::HIR::Visitor::visit_trait_impl(trait_path, impl);
m_ms.m_traits.pop_back( );
@@ -458,9 +549,13 @@ namespace {
TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type << " { }");
auto _ = this->m_ms.set_impl_generics(impl.m_params);
+ auto mod_ip = ::HIR::ItemPath(impl.m_src_module);
const auto* mod = (impl.m_src_module != ::HIR::SimplePath() ? &this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module) : nullptr);
- if(mod)
- m_ms.push_traits(*mod);
+ if(mod) {
+ m_ms.push_traits(impl.m_src_module, *mod);
+ m_cur_module.ptr = mod;
+ m_cur_module.path = &mod_ip;
+ }
::HIR::Visitor::visit_marker_impl(trait_path, impl);
if(mod)
m_ms.pop_traits(*mod);
@@ -566,7 +661,7 @@ namespace {
void visit(::HIR::ExprNode_StructLiteral& node) override
{
- upper_visitor.visit_generic_path(node.m_path, ::HIR::Visitor::PathContext::TYPE);
+ upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::TYPE);
::HIR::ExprVisitorDef::visit(node);
}
void visit(::HIR::ExprNode_ArraySized& node) override
@@ -609,28 +704,24 @@ namespace {
struct H {
static void visit_lvalue(Visitor& upper_visitor, ::MIR::LValue& lv)
{
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Local,
- ),
- (Argument,
- ),
- (Static,
- upper_visitor.visit_path(e, ::HIR::Visitor::PathContext::VALUE);
- ),
- (Field,
- H::visit_lvalue(upper_visitor, *e.val);
- ),
- (Deref,
- H::visit_lvalue(upper_visitor, *e.val);
- ),
- (Index,
- H::visit_lvalue(upper_visitor, *e.val);
- H::visit_lvalue(upper_visitor, *e.idx);
+ if( lv.m_root.is_Static() ) {
+ upper_visitor.visit_path(lv.m_root.as_Static(), ::HIR::Visitor::PathContext::VALUE);
+ }
+ }
+ static void visit_constant(Visitor& upper_visitor, ::MIR::Constant& e)
+ {
+ TU_MATCHA( (e), (ce),
+ (Int, ),
+ (Uint,),
+ (Float, ),
+ (Bool, ),
+ (Bytes, ),
+ (StaticString, ), // String
+ (Const,
+ upper_visitor.visit_path(*ce.p, ::HIR::Visitor::PathContext::VALUE);
),
- (Downcast,
- H::visit_lvalue(upper_visitor, *e.val);
+ (ItemAddr,
+ upper_visitor.visit_path(*ce, ::HIR::Visitor::PathContext::VALUE);
)
)
}
@@ -639,20 +730,7 @@ namespace {
TU_MATCHA( (p), (e),
(LValue, H::visit_lvalue(upper_visitor, e);),
(Constant,
- TU_MATCHA( (e), (ce),
- (Int, ),
- (Uint,),
- (Float, ),
- (Bool, ),
- (Bytes, ),
- (StaticString, ), // String
- (Const,
- upper_visitor.visit_path(ce.p, ::HIR::Visitor::PathContext::VALUE);
- ),
- (ItemAddr,
- upper_visitor.visit_path(ce, ::HIR::Visitor::PathContext::VALUE);
- )
- )
+ H::visit_constant(upper_visitor, e);
)
)
}
@@ -670,20 +748,7 @@ namespace {
H::visit_lvalue(*this, e);
),
(Constant,
- TU_MATCHA( (e), (ce),
- (Int, ),
- (Uint,),
- (Float, ),
- (Bool, ),
- (Bytes, ),
- (StaticString, ), // String
- (Const,
- this->visit_path(ce.p, ::HIR::Visitor::PathContext::VALUE);
- ),
- (ItemAddr,
- this->visit_path(ce, ::HIR::Visitor::PathContext::VALUE);
- )
- )
+ H::visit_constant(*this, e);
),
(SizedArray,
H::visit_param(*this, e.val);
@@ -779,11 +844,12 @@ namespace {
void ConvertHIR_Bind(::HIR::Crate& crate)
{
Visitor exp { crate };
- exp.visit_crate( crate );
// Also visit extern crates to update their pointers
for(auto& ec : crate.m_ext_crates)
{
exp.visit_crate( *ec.second.m_data );
}
+
+ exp.visit_crate( crate );
}
diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp
index ec313e4a..35669dd9 100644
--- a/src/hir_conv/constant_evaluation.cpp
+++ b/src/hir_conv/constant_evaluation.cpp
@@ -16,8 +16,15 @@
#include <trans/target.hpp>
#include <hir/expr_state.hpp>
+#include "constant_evaluation.hpp"
+#include <trans/monomorphise.hpp> // For handling monomorph of MIR in provided associated constants
+
+#define CHECK_DEFER(var) do { if( var.is_Defer() ) { m_rv = ::HIR::Literal::make_Defer({}); return ; } } while(0)
+
namespace {
- struct NewvalState {
+ struct NewvalState
+ : public HIR::Evaluator::Newval
+ {
const ::HIR::Module& mod;
const ::HIR::ItemPath& mod_path;
::std::string name_prefix;
@@ -31,9 +38,9 @@ namespace {
{
}
- ::HIR::SimplePath new_static(::HIR::TypeRef type, ::HIR::Literal value)
+ virtual ::HIR::Path new_static(::HIR::TypeRef type, ::HIR::Literal value) override
{
- auto name = FMT(name_prefix << next_item_idx);
+ auto name = RcString::new_interned(FMT(name_prefix << next_item_idx));
next_item_idx ++;
DEBUG("mod_path = " << mod_path);
auto rv = mod_path.get_simple_path() + name.c_str();
@@ -47,23 +54,6 @@ namespace {
return rv;
}
};
- struct Evaluator
- {
- const Span& root_span;
- StaticTraitResolve resolve;
- NewvalState nvs;
-
- Evaluator(const Span& sp, const ::HIR::Crate& crate, NewvalState nvs):
- root_span(sp),
- resolve(crate),
- nvs( ::std::move(nvs) )
- {
- }
-
- ::HIR::Literal evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp);
-
- ::HIR::Literal evaluate_constant_mir(const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args);
- };
::HIR::Literal clone_literal(const ::HIR::Literal& v)
{
@@ -71,6 +61,9 @@ namespace {
(Invalid,
return ::HIR::Literal();
),
+ (Defer,
+ return ::HIR::Literal::make_Defer({});
+ ),
(List,
::std::vector< ::HIR::Literal> vals;
for(const auto& val : e) {
@@ -162,6 +155,8 @@ namespace {
),
(Enum,
),
+ (ExternType,
+ ),
(TypeAlias,
)
)
@@ -267,13 +262,16 @@ namespace {
TODO(sp, "Could not find function for " << path << " - " << rv.tag_str());
}
}
+} // namespace <anon>
+
+namespace HIR {
- ::HIR::Literal Evaluator::evaluate_constant_mir(const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args)
+ ::HIR::Literal Evaluator::evaluate_constant_mir(const ::HIR::ItemPath& ip, const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args)
{
// TODO: Full-blown miri
TRACE_FUNCTION_F("exp=" << exp << ", args=" << args);
- ::MIR::TypeResolve state { this->root_span, this->resolve, FMT_CB(,), exp, {}, fcn };
+ ::MIR::TypeResolve state { this->root_span, this->resolve, FMT_CB(ss, ss<<ip), exp, {}, fcn };
::HIR::Literal retval;
::std::vector< ::HIR::Literal> locals( fcn.locals.size() );
@@ -295,61 +293,66 @@ namespace {
::HIR::Literal& get_lval(const ::MIR::LValue& lv)
{
- TU_MATCHA( (lv), (e),
+ ::HIR::Literal* lit_ptr;
+ TRACE_FUNCTION_FR(lv, *lit_ptr);
+ TU_MATCHA( (lv.m_root), (e),
(Return,
- return retval;
+ lit_ptr = &retval;
),
(Local,
- if( e >= locals.size() )
- MIR_BUG(state, "Local index out of range - " << e << " >= " << locals.size());
- return locals[e];
+ MIR_ASSERT(state, e < locals.size(), "Local index out of range - " << e << " >= " << locals.size());
+ lit_ptr = &locals[e];
),
(Argument,
- if( e.idx >= args.size() )
- MIR_BUG(state, "Local index out of range - " << e.idx << " >= " << args.size());
- return args[e.idx];
+ MIR_ASSERT(state, e < args.size(), "Argument index out of range - " << e << " >= " << args.size());
+ lit_ptr = &args[e];
),
(Static,
MIR_TODO(state, "LValue::Static - " << e);
- ),
- (Field,
- auto& val = get_lval(*e.val);
- MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv);
- auto& vals = val.as_List();
- MIR_ASSERT(state, e.field_index < vals.size(), "LValue::Field index out of range");
- return vals[ e.field_index ];
- ),
- (Deref,
- auto& val = get_lval(*e.val);
- TU_MATCH_DEF( ::HIR::Literal, (val), (ve),
- (
- MIR_TODO(state, "LValue::Deref - " << lv << " { " << val << " }");
- ),
- (BorrowData,
- return *ve;
- ),
- (String,
- // Just clone the string (hack)
- // - TODO: Create a list?
- return val;
- )
- )
- ),
- (Index,
- auto& val = get_lval(*e.val);
- MIR_ASSERT(state, val.is_List(), "LValue::Index on non-list literal - " << val.tag_str() << " - " << lv);
- auto& idx = get_lval(*e.idx);
- MIR_ASSERT(state, idx.is_Integer(), "LValue::Index with non-integer index literal - " << idx.tag_str() << " - " << lv);
- auto& vals = val.as_List();
- auto idx_v = static_cast<size_t>( idx.as_Integer() );
- MIR_ASSERT(state, idx_v < vals.size(), "LValue::Index index out of range");
- return vals[ idx_v ];
- ),
- (Downcast,
- MIR_TODO(state, "LValue::Downcast - " << lv);
)
)
- throw "";
+
+ for(const auto& w : lv.m_wrappers)
+ {
+ auto& val = *lit_ptr;
+ TU_MATCH_HDRA( (w), {)
+ TU_ARMA(Field, e) {
+ MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv);
+ auto& vals = val.as_List();
+ MIR_ASSERT(state, e < vals.size(), "LValue::Field index out of range");
+ lit_ptr = &vals[ e ];
+ }
+ TU_ARMA(Deref, e) {
+ TU_MATCH_DEF( ::HIR::Literal, (val), (ve),
+ (
+ MIR_TODO(state, "LValue::Deref - " << lv << " { " << val << " }");
+ ),
+ (BorrowData,
+ lit_ptr = &*ve;
+ ),
+ (String,
+ // Just clone the string (hack)
+ // - TODO: Create a list?
+ lit_ptr = &val;
+ )
+ )
+ }
+ TU_ARMA(Index, e) {
+ MIR_ASSERT(state, val.is_List(), "LValue::Index on non-list literal - " << val.tag_str() << " - " << lv);
+ MIR_ASSERT(state, e < locals.size(), "LValue::Index index local out of range");
+ auto& idx = locals[e];
+ MIR_ASSERT(state, idx.is_Integer(), "LValue::Index with non-integer index literal - " << idx.tag_str() << " - " << lv);
+ auto& vals = val.as_List();
+ auto idx_v = static_cast<size_t>( idx.as_Integer() );
+ MIR_ASSERT(state, idx_v < vals.size(), "LValue::Index index out of range");
+ lit_ptr = &vals[ idx_v ];
+ }
+ TU_ARMA(Downcast, e) {
+ MIR_TODO(state, "LValue::Downcast - " << lv);
+ }
+ }
+ }
+ return *lit_ptr;
}
::HIR::Literal read_lval(const ::MIR::LValue& lv)
{
@@ -377,27 +380,28 @@ namespace {
LocalState local_state( state, retval, args, locals );
auto const_to_lit = [&](const ::MIR::Constant& c)->::HIR::Literal {
- TU_MATCH(::MIR::Constant, (c), (e2),
- (Int,
+ TU_MATCH_HDR( (c), {)
+ TU_ARM(c, Int, e2) {
return ::HIR::Literal(static_cast<uint64_t>(e2.v));
- ),
- (Uint,
+ }
+ TU_ARM(c, Uint, e2)
return ::HIR::Literal(e2.v);
- ),
- (Float,
+ TU_ARM(c, Float, e2)
return ::HIR::Literal(e2.v);
- ),
- (Bool,
+ TU_ARM(c, Bool, e2)
return ::HIR::Literal(static_cast<uint64_t>(e2.v));
- ),
- (Bytes,
+ TU_ARM(c, Bytes, e2)
return ::HIR::Literal::make_String({e2.begin(), e2.end()});
- ),
- (StaticString,
+ TU_ARM(c, StaticString, e2)
return ::HIR::Literal(e2);
- ),
- (Const,
- auto p = ms.monomorph(state.sp, e2.p);
+ TU_ARM(c, Const, e2) {
+ auto p = ms.monomorph(state.sp, *e2.p);
+ // If there's any mention of generics in this path, then return Literal::Defer
+ if( visit_path_tys_with(p, [&](const auto& ty)->bool { return ty.m_data.is_Generic(); }) )
+ {
+ DEBUG("Return Literal::Defer for constant " << *e2.p << " which references a generic parameter");
+ return ::HIR::Literal::make_Defer({});
+ }
MonomorphState const_ms;
auto ent = get_ent_fullpath(state.sp, this->resolve.m_crate, p, EntNS::Value, const_ms);
MIR_ASSERT(state, ent.is_Constant(), "MIR Constant::Const(" << p << ") didn't point to a Constant - " << ent.tag_str());
@@ -407,19 +411,25 @@ namespace {
auto& item = const_cast<::HIR::Constant&>(c);
// Challenge: Adding items to the module might invalidate an iterator.
::HIR::ItemPath mod_ip { item.m_value.m_state->m_mod_path };
- auto eval = Evaluator { item.m_value->span(), resolve.m_crate, NewvalState { item.m_value.m_state->m_module, mod_ip, FMT(&c << "$") } };
+ auto nvs = NewvalState { item.m_value.m_state->m_module, mod_ip, FMT("const" << &c << "#") };
+ auto eval = ::HIR::Evaluator { item.m_value.span(), resolve.m_crate, nvs };
DEBUG("- Evaluate " << p);
DEBUG("- " << ::HIR::ItemPath(p));
item.m_value_res = eval.evaluate_constant(::HIR::ItemPath(p), item.m_value, item.m_type.clone());
//check_lit_type(item.m_value->span(), item.m_type, item.m_value_res);
}
+ auto it = c.m_monomorph_cache.find(*e2.p);
+ if( it != c.m_monomorph_cache.end() )
+ {
+ MIR_ASSERT(state, !it->second.is_Defer(), "Cached literal for " << *e2.p << " is Defer");
+ return clone_literal( it->second );
+ }
return clone_literal( c.m_value_res );
- ),
- (ItemAddr,
- return ::HIR::Literal::make_BorrowPath( ms.monomorph(state.sp, e2) );
- )
- )
+ }
+ TU_ARM(c, ItemAddr, e2)
+ return ::HIR::Literal::make_BorrowPath( ms.monomorph(state.sp, *e2) );
+ }
throw "";
};
auto read_param = [&](const ::MIR::Param& p) -> ::HIR::Literal
@@ -476,17 +486,14 @@ namespace {
MIR_BUG(state, "Only shared borrows are allowed in constants");
}
- if( e.type != ::HIR::BorrowType::Shared ) {
- MIR_BUG(state, "Only shared borrows are allowed in constants");
+ if( !e.val.m_wrappers.empty() && e.val.m_wrappers.back().is_Deref() ) {
+ //if( p->val->is_Deref() )
+ // MIR_TODO(state, "Undo nested deref coercion - " << *p->val);
+ val = local_state.read_lval(e.val.clone_unwrapped());
}
- if( const auto* p = e.val.opt_Deref() ) {
- if( p->val->is_Deref() )
- MIR_TODO(state, "Undo nested deref coercion - " << *p->val);
- val = local_state.read_lval(*p->val);
- }
- else if( const auto* p = e.val.opt_Static() ) {
+ else if( e.val.m_wrappers.empty() && e.val.m_root.is_Static() ){
// Borrow of a static, emit BorrowPath with the same path
- val = ::HIR::Literal::make_BorrowPath( p->clone() );
+ val = ::HIR::Literal::make_BorrowPath( e.val.m_root.as_Static().clone() );
}
else {
auto inner_val = local_state.read_lval(e.val);
@@ -504,6 +511,10 @@ namespace {
),
(Cast,
auto inval = local_state.read_lval(e.val);
+ if( inval.is_Defer() ) {
+ val = ::HIR::Literal::make_Defer({});
+ }
+ else
TU_MATCH_DEF(::HIR::TypeRef::Data, (e.type.m_data), (te),
(
// NOTE: Can be an unsizing!
@@ -585,6 +596,8 @@ namespace {
(BinOp,
auto inval_l = read_param(e.val_l);
auto inval_r = read_param(e.val_r);
+ if( inval_l.is_Defer() || inval_r.is_Defer() )
+ return ::HIR::Literal::make_Defer({});
MIR_ASSERT(state, inval_l.tag() == inval_r.tag(), "Mismatched literal types in binop - " << inval_l << " and " << inval_r);
TU_MATCH_DEF( ::HIR::Literal, (inval_l, inval_r), (l, r),
(
@@ -651,6 +664,8 @@ namespace {
),
(UniOp,
auto inval = local_state.read_lval(e.val);
+ if( inval.is_Defer() )
+ return ::HIR::Literal::make_Defer({});
TU_IFLET( ::HIR::Literal, inval, Integer, i,
switch( e.op )
{
@@ -685,7 +700,9 @@ namespace {
),
(MakeDst,
auto ptr = read_param(e.ptr_val);
+ if(ptr.is_Defer()) return ::HIR::Literal::make_Defer({});
auto meta = read_param(e.meta_val);
+ if(meta.is_Defer()) return ::HIR::Literal::make_Defer({});
if( ! meta.is_Integer() ) {
MIR_TODO(state, "RValue::MakeDst - (non-integral meta) " << ptr << " , " << meta);
}
@@ -696,26 +713,39 @@ namespace {
(Tuple,
::std::vector< ::HIR::Literal> vals;
vals.reserve( e.vals.size() );
- for(const auto& v : e.vals)
+ for(const auto& v : e.vals) {
vals.push_back( read_param(v) );
+ if( vals.back().is_Defer() ) {
+ return ::HIR::Literal::make_Defer({});
+ }
+ }
val = ::HIR::Literal::make_List( mv$(vals) );
),
(Array,
::std::vector< ::HIR::Literal> vals;
vals.reserve( e.vals.size() );
- for(const auto& v : e.vals)
+ for(const auto& v : e.vals) {
vals.push_back( read_param(v) );
+ if( vals.back().is_Defer() ) {
+ return ::HIR::Literal::make_Defer({});
+ }
+ }
val = ::HIR::Literal::make_List( mv$(vals) );
),
(Variant,
auto ival = read_param(e.val);
+ if(ival.is_Defer()) return ::HIR::Literal::make_Defer({});
val = ::HIR::Literal::make_Variant({ e.index, box$(ival) });
),
(Struct,
::std::vector< ::HIR::Literal> vals;
vals.reserve( e.vals.size() );
- for(const auto& v : e.vals)
+ for(const auto& v : e.vals) {
vals.push_back( read_param(v) );
+ if( vals.back().is_Defer() ) {
+ return ::HIR::Literal::make_Defer({});
+ }
+ }
val = ::HIR::Literal::make_List( mv$(vals) );
)
)
@@ -724,15 +754,18 @@ namespace {
dst = mv$(val);
}
state.set_cur_stmt_term(cur_block);
- TU_MATCH_DEF( ::MIR::Terminator, (block.terminator), (e),
- (
+ TU_MATCH_HDRA( (block.terminator), {)
+ default:
MIR_BUG(state, "Unexpected terminator - " << block.terminator);
- ),
- (Goto,
+ TU_ARMA(Goto, e) {
cur_block = e;
- ),
- (Return,
- if( exp.m_data.is_Primitive() )
+ }
+ TU_ARMA(Return, e) {
+ if( retval.is_Defer() )
+ {
+ //
+ }
+ else if( exp.m_data.is_Primitive() )
{
switch( exp.m_data.as_Primitive() )
{
@@ -773,52 +806,81 @@ namespace {
}
}
return retval;
- ),
- (Call,
- if( !e.fcn.is_Path() )
- MIR_BUG(state, "Unexpected terminator - " << block.terminator);
- const auto& fcnp_raw = e.fcn.as_Path();
- auto fcnp = ms.monomorph(state.sp, fcnp_raw);
-
+ }
+ TU_ARMA(Call, e) {
auto& dst = local_state.get_lval(e.ret_val);
- MonomorphState fcn_ms;
- auto& fcn = get_function(this->root_span, this->resolve.m_crate, fcnp, fcn_ms);
+ if( const auto* te = e.fcn.opt_Intrinsic() )
+ {
+ if( te->name == "size_of" ) {
+ auto ty = ms.monomorph(state.sp, te->params.m_types.at(0));
+ size_t size_val;
+ Target_GetSizeOf(state.sp, this->resolve, ty, size_val);
+ dst = ::HIR::Literal::make_Integer( size_val );
+ }
+ else {
+ MIR_TODO(state, "Call intrinsic \"" << te->name << "\" - " << block.terminator);
+ }
+ }
+ else if( const auto* te = e.fcn.opt_Path() )
+ {
+ const auto& fcnp_raw = *te;
+ auto fcnp = ms.monomorph(state.sp, fcnp_raw);
- ::std::vector< ::HIR::Literal> call_args;
- call_args.reserve( e.args.size() );
- for(const auto& a : e.args)
- call_args.push_back( read_param(a) );
- // TODO: Set m_const during parse and check here
+ MonomorphState fcn_ms;
+ auto& fcn = get_function(this->root_span, this->resolve.m_crate, fcnp, fcn_ms);
- // Call by invoking evaluate_constant on the function
+ ::std::vector< ::HIR::Literal> call_args;
+ call_args.reserve( e.args.size() );
+ for(const auto& a : e.args)
+ call_args.push_back( read_param(a) );
+ // TODO: Set m_const during parse and check here
+
+ // Call by invoking evaluate_constant on the function
+ {
+ TRACE_FUNCTION_F("Call const fn " << fcnp << " args={ " << call_args << " }");
+ auto fcn_ip = ::HIR::ItemPath(fcnp);
+ const auto* mir = this->resolve.m_crate.get_or_gen_mir( fcn_ip, fcn );
+ MIR_ASSERT(state, mir, "No MIR for function " << fcnp);
+ dst = evaluate_constant_mir(fcn_ip, *mir, mv$(fcn_ms), fcn.m_return.clone(), mv$(call_args));
+ }
+ }
+ else
{
- TRACE_FUNCTION_F("Call const fn " << fcnp << " args={ " << call_args << " }");
- const auto* mir = this->resolve.m_crate.get_or_gen_mir( ::HIR::ItemPath(fcnp.clone()), fcn );
- MIR_ASSERT(state, mir, "No MIR for function " << fcnp);
- dst = evaluate_constant_mir(*mir, mv$(fcn_ms), fcn.m_return.clone(), mv$(call_args));
+ MIR_BUG(state, "Unexpected terminator - " << block.terminator);
}
-
cur_block = e.ret_block;
- )
- )
+ }
+ }
}
}
- ::HIR::Literal Evaluator::evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp)
+ ::HIR::Literal Evaluator::evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp, MonomorphState ms/*={}*/)
{
TRACE_FUNCTION_F(ip);
const auto* mir = this->resolve.m_crate.get_or_gen_mir(ip, expr, exp);
if( mir ) {
- return evaluate_constant_mir(*mir, {}, mv$(exp), {});
+ ::HIR::TypeRef ty_self { "Self", GENERIC_Self };
+ // Might want to have a fully-populated MonomorphState for expanding inside impl blocks
+ // HACK: Generate a roughly-correct one
+ const auto& top_ip = ip.get_top_ip();
+ if( top_ip.trait && !top_ip.ty ) {
+ ms.self_ty = &ty_self;
+ }
+ return evaluate_constant_mir(ip, *mir, mv$(ms), mv$(exp), {});
}
else {
BUG(this->root_span, "Attempting to evaluate constant expression with no associated code");
}
}
+} // namespace HIR
+
+namespace {
void check_lit_type(const Span& sp, const ::HIR::TypeRef& type, ::HIR::Literal& lit)
{
+ if( lit.is_Defer() )
+ return ;
// TODO: Mask down limited size integers
TU_MATCHA( (type.m_data), (te),
(Infer,
@@ -898,12 +960,15 @@ namespace {
const ::HIR::Crate& m_crate;
const ::HIR::Module* m_mod;
const ::HIR::ItemPath* m_mod_path;
+ MonomorphState m_monomorph_state;
+ bool m_recurse_types;
public:
Expander(const ::HIR::Crate& crate):
m_crate(crate),
m_mod(nullptr),
m_mod_path(nullptr)
+ ,m_recurse_types(false)
{}
void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override
@@ -918,20 +983,123 @@ namespace {
m_mod = saved_m;
m_mod_path = saved_mp;
}
+ void visit_function(::HIR::ItemPath p, ::HIR::Function& f) override
+ {
+ TRACE_FUNCTION_F(p);
+ ::HIR::Visitor::visit_function(p, f);
+ }
+
+ void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override
+ {
+ static Span sp;
+ TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type);
+ const auto& trait = m_crate.get_trait_by_path(sp, trait_path);
+
+ StaticTraitResolve resolve( m_crate );
+ // - TODO: Defer this call until first missing item?
+ resolve.set_impl_generics(impl.m_params);
+
+ auto mp = ::HIR::ItemPath(impl.m_src_module);
+ m_mod_path = &mp;
+ m_mod = &m_crate.get_mod_by_path(sp, impl.m_src_module);
+
+ for(const auto& vi : trait.m_values)
+ {
+ // Search for any constants that are in the trait itself, but NOT in this impl
+ // - For each of these, find the lowest parent specialisation with the constant set
+ // - Ensure that the MIR has been generated for the constant (TODO: This only needs to be done for
+ // specialisations, not trait-provided)
+ // - Monomorphise the MIR for this impl, and let expansion happen as usual
+ if( vi.second.is_Constant() )
+ {
+ if( impl.m_constants.count(vi.first) > 0 )
+ continue;
+ DEBUG("- Constant " << vi.first << " missing, looking for a source");
+ // This trait impl doesn't have this constant, need to find the provided version that applies
+
+ MonomorphState ms;
+ ms.self_ty = &impl.m_type;
+ ms.pp_impl = &impl.m_trait_args;
+
+ resolve.find_impl(sp, trait_path, impl.m_trait_args, impl.m_type, [&](ImplRef found_impl, bool is_fuzzed)->bool {
+ ASSERT_BUG(sp, found_impl.m_data.is_TraitImpl(), "");
+ // If this found impl is the current one, keep searching
+ if( found_impl.m_data.as_TraitImpl().impl == &impl )
+ return false;
+ TODO(sp, "Found a possible parent specialisation of " << trait_path << impl.m_trait_args << " for " << impl.m_type << " - " << found_impl);
+ return false;
+ });
+ const auto& template_const = vi.second.as_Constant();
+ if( template_const.m_value_res.is_Defer() ) {
+ auto nvs = NewvalState { *m_mod, *m_mod_path, FMT("impl" << &impl << "_" << vi.first << "#") };
+ auto eval = ::HIR::Evaluator { sp, m_crate, nvs };
+ ::HIR::ExprPtr ep;
+ Trans_Params tp(sp);
+ tp.self_type = ms.self_ty->clone();
+ tp.pp_impl = ms.pp_impl->clone();
+ ep.m_mir = Trans_Monomorphise(resolve, mv$(tp), template_const.m_value.m_mir);
+ ep.m_state = ::HIR::ExprStatePtr( ::HIR::ExprState(*m_mod, m_mod_path->get_simple_path()) );
+ DEBUG("TMP TMP " << trait_path << " - " << ep.m_state->m_mod_path);
+ ep.m_state->stage = ::HIR::ExprState::Stage::Mir;
+ impl.m_constants.insert(::std::make_pair(
+ vi.first,
+ ::HIR::TraitImpl::ImplEnt<::HIR::Constant> {
+ /*is_specialisable=*/false,
+ ::HIR::Constant {
+ template_const.m_params.clone(),
+ /*m_type=*/ms.monomorph(sp, template_const.m_type),
+ /*m_value=*/mv$(ep),
+ ::HIR::Literal()
+ }
+ }
+ ));
+ }
+ else {
+ //TODO(sp, "Assign associated type " << vi.first << " in impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type);
+ impl.m_constants.insert(::std::make_pair(
+ vi.first,
+ ::HIR::TraitImpl::ImplEnt<::HIR::Constant> {
+ /*is_specialisable=*/false,
+ ::HIR::Constant {
+ template_const.m_params.clone(),
+ /*m_type=*/ms.monomorph(sp, template_const.m_type),
+ /*m_value=*/::HIR::ExprPtr(),
+ clone_literal(template_const.m_value_res)
+ }
+ }
+ ));
+ }
+ }
+ }
+
+ ::HIR::PathParams pp_impl;
+ for(const auto& tp : impl.m_params.m_types)
+ pp_impl.m_types.push_back( ::HIR::TypeRef(tp.m_name, pp_impl.m_types.size() | 256) );
+ m_monomorph_state.pp_impl = &pp_impl;
+
+ ::HIR::Visitor::visit_trait_impl(trait_path, impl);
+
+ m_monomorph_state.pp_impl = nullptr;
+
+ m_mod = nullptr;
+ m_mod_path = nullptr;
+ }
void visit_type(::HIR::TypeRef& ty) override
{
::HIR::Visitor::visit_type(ty);
TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e,
+ TRACE_FUNCTION_FR(ty, ty);
if( e.size_val == ~0u )
{
assert(e.size);
assert(*e.size);
const auto& expr_ptr = *e.size;
- auto ty_name = FMT("ty_" << &ty << "$");
+ auto ty_name = FMT("ty_" << &ty << "#");
- auto eval = Evaluator { expr_ptr->span(), m_crate, NewvalState { *m_mod, *m_mod_path, ty_name } };
+ auto nvs = NewvalState { *m_mod, *m_mod_path, ty_name };
+ auto eval = ::HIR::Evaluator { expr_ptr->span(), m_crate, nvs };
auto val = eval.evaluate_constant(::HIR::ItemPath(*m_mod_path, ty_name.c_str()), expr_ptr, ::HIR::CoreType::Usize);
if( !val.is_Integer() )
ERROR(expr_ptr->span(), E0000, "Array size isn't an integer");
@@ -939,29 +1107,60 @@ namespace {
}
DEBUG("Array " << ty << " - size = " << e.size_val);
)
+
+ if( m_recurse_types )
+ {
+ m_recurse_types = false;
+ if( const auto* te = ty.m_data.opt_Path() )
+ {
+ TU_MATCH_HDRA( (te->binding), {)
+ TU_ARMA(Unbound, _) {
+ }
+ TU_ARMA(Opaque, _) {
+ }
+ TU_ARMA(Struct, pbe) {
+ // If this struct hasn't been visited already, visit it
+ this->visit_struct(te->path.m_data.as_Generic().m_path, const_cast<::HIR::Struct&>(*pbe));
+ }
+ TU_ARMA(Union, pbe) {
+ }
+ TU_ARMA(Enum, pbe) {
+ }
+ TU_ARMA(ExternType, pbe) {
+ }
+ }
+ }
+ m_recurse_types = true;
+ }
}
void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override
{
+ m_recurse_types = true;
::HIR::Visitor::visit_constant(p, item);
+ m_recurse_types = false;
// NOTE: Consteval needed here for MIR match generation to work
- if( item.m_value )
+ if( item.m_value || item.m_value.m_mir )
{
- auto eval = Evaluator { item.m_value->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") } };
- item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone());
+ auto nvs = NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "#") };
+ auto eval = ::HIR::Evaluator { item.m_value.span(), m_crate, nvs };
+ item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone(), m_monomorph_state.clone());
- check_lit_type(item.m_value->span(), item.m_type, item.m_value_res);
+ check_lit_type(item.m_value.span(), item.m_type, item.m_value_res);
DEBUG("constant: " << item.m_type << " = " << item.m_value_res);
}
}
void visit_static(::HIR::ItemPath p, ::HIR::Static& item) override
{
+ m_recurse_types = true;
::HIR::Visitor::visit_static(p, item);
+ m_recurse_types = false;
if( item.m_value )
{
- auto eval = Evaluator { item.m_value->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") } };
+ auto nvs = NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "#") };
+ auto eval = ::HIR::Evaluator { item.m_value->span(), m_crate, nvs };
item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone());
check_lit_type(item.m_value->span(), item.m_type, item.m_value_res);
@@ -970,6 +1169,7 @@ namespace {
}
}
void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override {
+ static Span sp;
if( auto* e = item.m_data.opt_Value() )
{
::HIR::TypeRef ty = ::HIR::CoreType::Isize;
@@ -978,7 +1178,8 @@ namespace {
{
if( var.expr )
{
- auto eval = Evaluator { var.expr->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$" << var.name << "$") } };
+ auto nvs = NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "_" << var.name << "#") };
+ auto eval = ::HIR::Evaluator { var.expr->span(), m_crate, nvs };
auto val = eval.evaluate_constant(p, var.expr, ty.clone());
DEBUG("enum variant: " << p << "::" << var.name << " = " << val);
i = val.as_Integer();
@@ -989,6 +1190,15 @@ namespace {
}
::HIR::Visitor::visit_enum(p, item);
}
+ void visit_struct(::HIR::ItemPath p, ::HIR::Struct& item) override {
+ if( item.const_eval_state != HIR::ConstEvalState::Complete )
+ {
+ ASSERT_BUG(Span(), item.const_eval_state == HIR::ConstEvalState::None, "Constant evaluation loop involving " << p);
+ item.const_eval_state = HIR::ConstEvalState::Active;
+ ::HIR::Visitor::visit_struct(p, item);
+ item.const_eval_state = HIR::ConstEvalState::Complete;
+ }
+ }
void visit_expr(::HIR::ExprPtr& expr) override
{
@@ -1003,6 +1213,7 @@ namespace {
void visit_type(::HIR::TypeRef& ty) override {
// Need to evaluate array sizes
+ DEBUG("expr type " << ty);
m_exp.visit_type(ty);
}
void visit_path_params(::HIR::PathParams& pp) override {
@@ -1012,8 +1223,9 @@ namespace {
void visit(::HIR::ExprNode_ArraySized& node) override {
assert( node.m_size );
- auto name = FMT("array_" << &node << "$");
- auto eval = Evaluator { node.span(), m_exp.m_crate, NewvalState { *m_exp.m_mod, *m_exp.m_mod_path, name } };
+ auto name = FMT("array_" << &node << "#");
+ auto nvs = NewvalState { *m_exp.m_mod, *m_exp.m_mod_path, name };
+ auto eval = ::HIR::Evaluator { node.span(), m_exp.m_crate, nvs };
auto val = eval.evaluate_constant( ::HIR::ItemPath(*m_exp.m_mod_path, name.c_str()), node.m_size, ::HIR::CoreType::Usize );
if( !val.is_Integer() )
ERROR(node.span(), E0000, "Array size isn't an integer");
@@ -1025,7 +1237,9 @@ namespace {
if( expr.get() != nullptr )
{
Visitor v { *this };
+ //m_recurse_types = true;
(*expr).visit(v);
+ //m_recurse_types = false;
}
}
};
@@ -1047,7 +1261,7 @@ namespace {
{
// ::std::unique_ptr<VisEnt<ValueItem>>
::std::unique_ptr<::HIR::VisEnt<::HIR::ValueItem>> iv;
- iv.reset( new ::HIR::VisEnt<::HIR::ValueItem> { false, ::HIR::ValueItem::make_Static(mv$(v.second)) } );
+ iv.reset( new ::HIR::VisEnt<::HIR::ValueItem> { ::HIR::Publicity::new_none(), ::HIR::ValueItem::make_Static(mv$(v.second)) } );
mod.m_value_items.insert(::std::make_pair( v.first, mv$(iv) ));
}
mod.m_inline_statics.clear();
@@ -1066,3 +1280,10 @@ void ConvertHIR_ConstantEvaluate(::HIR::Crate& crate)
ExpanderApply().visit_crate(crate);
}
+void ConvertHIR_ConstantEvaluate_Expr(const ::HIR::Crate& crate, const ::HIR::ItemPath& ip, ::HIR::ExprPtr& expr_ptr)
+{
+ TRACE_FUNCTION_F(ip);
+ // Check innards but NOT the value
+ Expander exp { crate };
+ exp.visit_expr( expr_ptr );
+}
diff --git a/src/hir_conv/constant_evaluation.hpp b/src/hir_conv/constant_evaluation.hpp
new file mode 100644
index 00000000..a5fd7050
--- /dev/null
+++ b/src/hir_conv/constant_evaluation.hpp
@@ -0,0 +1,33 @@
+/*
+ */
+#include <hir/hir.hpp>
+
+namespace HIR {
+
+
+struct Evaluator
+{
+ class Newval
+ {
+ public:
+ virtual ::HIR::Path new_static(::HIR::TypeRef type, ::HIR::Literal value) = 0;
+ };
+
+ Span root_span;
+ StaticTraitResolve resolve;
+ Newval& nvs;
+
+ Evaluator(const Span& sp, const ::HIR::Crate& crate, Newval& nvs):
+ root_span(sp),
+ resolve(crate),
+ nvs( nvs )
+ {
+ }
+
+ ::HIR::Literal evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp, MonomorphState ms={});
+
+ ::HIR::Literal evaluate_constant_mir(const ::HIR::ItemPath& ip, const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args);
+};
+
+} // namespace HIR
+
diff --git a/src/hir_conv/expand_type.cpp b/src/hir_conv/expand_type.cpp
index dcdf79bd..2dfffb73 100644
--- a/src/hir_conv/expand_type.cpp
+++ b/src/hir_conv/expand_type.cpp
@@ -21,8 +21,14 @@
// Anything else - leave it be
),
(TypeAlias,
- if( !is_expr && path.m_params.m_types.size() != e2.m_params.m_types.size() ) {
- ERROR(sp, E0000, "Mismatched parameter count in " << path << ", expected " << e2.m_params.m_types.size() << " got " << path.m_params.m_types.size());
+ auto pp = path.m_params.clone();
+ if( !is_expr ) {
+ while( pp.m_types.size() < e2.m_params.m_types.size() && e2.m_params.m_types[pp.m_types.size()].m_default != ::HIR::TypeRef() ) {
+ pp.m_types.push_back( e2.m_params.m_types[pp.m_types.size()].m_default.clone() );
+ }
+ if( pp.m_types.size() != e2.m_params.m_types.size() ) {
+ ERROR(sp, E0000, "Mismatched parameter count in " << path << ", expected " << e2.m_params.m_types.size() << " got " << pp.m_types.size());
+ }
}
if( e2.m_params.m_types.size() > 0 ) {
// TODO: Better `monomorphise_type`
@@ -33,8 +39,8 @@
}
else if( (ge.binding >> 8) == 0 ) {
auto idx = ge.binding & 0xFF;
- if( idx < path.m_params.m_types.size() )
- return path.m_params.m_types[idx];
+ if( idx < pp.m_types.size() )
+ return pp.m_types[idx];
else if( is_expr )
return empty_type;
else
@@ -255,9 +261,10 @@ public:
{
if( node.m_is_struct )
{
- auto new_path = upper_visitor.expand_alias_gp(node.span(), node.m_path);
- if( new_path.m_path.m_components.size() != 0 )
+ auto new_type = ConvertHIR_ExpandAliases_GetExpansion(upper_visitor.m_crate, node.m_path, /*in_expr=*/true);
+ if( new_type != ::HIR::TypeRef() )
{
+ auto new_path = mv$(new_type.m_data.as_Path().path);
DEBUG("Replacing " << node.m_path << " with " << new_path);
node.m_path = mv$(new_path);
}
diff --git a/src/hir_conv/main_bindings.hpp b/src/hir_conv/main_bindings.hpp
index 37488dae..a7bc9de6 100644
--- a/src/hir_conv/main_bindings.hpp
+++ b/src/hir_conv/main_bindings.hpp
@@ -9,10 +9,16 @@
namespace HIR {
class Crate;
+ class ItemPath;
+ class ExprPtr;
};
extern void ConvertHIR_ExpandAliases(::HIR::Crate& crate);
extern void ConvertHIR_Bind(::HIR::Crate& crate);
+extern void ConvertHIR_ResolveUFCS_Outer(::HIR::Crate& crate);
extern void ConvertHIR_ResolveUFCS(::HIR::Crate& crate);
extern void ConvertHIR_Markings(::HIR::Crate& crate);
extern void ConvertHIR_ConstantEvaluate(::HIR::Crate& hir_crate);
+
+extern void ConvertHIR_ConstantEvaluate_Expr(const ::HIR::Crate& crate, const ::HIR::ItemPath& ip, ::HIR::ExprPtr& exp);
+
diff --git a/src/hir_conv/markings.cpp b/src/hir_conv/markings.cpp
index df7fbd36..01eb0952 100644
--- a/src/hir_conv/markings.cpp
+++ b/src/hir_conv/markings.cpp
@@ -20,6 +20,7 @@ class Visitor:
const ::HIR::Crate& m_crate;
const ::HIR::SimplePath& m_lang_Unsize;
const ::HIR::SimplePath& m_lang_CoerceUnsized;
+ const ::HIR::SimplePath& m_lang_Copy;
const ::HIR::SimplePath& m_lang_Deref;
const ::HIR::SimplePath& m_lang_Drop;
const ::HIR::SimplePath& m_lang_PhantomData;
@@ -28,6 +29,7 @@ public:
m_crate(crate),
m_lang_Unsize( crate.get_lang_item_path_opt("unsize") ),
m_lang_CoerceUnsized( crate.get_lang_item_path_opt("coerce_unsized") ),
+ m_lang_Copy( crate.get_lang_item_path_opt("copy") ),
m_lang_Deref( crate.get_lang_item_path_opt("deref") ),
m_lang_Drop( crate.get_lang_item_path_opt("drop") ),
m_lang_PhantomData( crate.get_lang_item_path_opt("phantom_data") )
@@ -329,14 +331,7 @@ public:
if( impl.m_type.m_data.is_Path() )
{
const auto& te = impl.m_type.m_data.as_Path();
- const ::HIR::TraitMarkings* markings_ptr = nullptr;
- TU_MATCHA( (te.binding), (tpb),
- (Unbound, ),
- (Opaque, ),
- (Struct, markings_ptr = &tpb->m_markings; ),
- (Union , markings_ptr = &tpb->m_markings; ),
- (Enum , markings_ptr = &tpb->m_markings; )
- )
+ const ::HIR::TraitMarkings* markings_ptr = te.binding.get_trait_markings();
if( markings_ptr )
{
::HIR::TraitMarkings& markings = *const_cast<::HIR::TraitMarkings*>(markings_ptr);
@@ -434,6 +429,10 @@ public:
DEBUG("Type " << impl.m_type << " can Deref");
markings.has_a_deref = true;
}
+ else if( trait_path == m_lang_Copy ) {
+ DEBUG("Type " << impl.m_type << " has a Copy impl");
+ markings.is_copy = true;
+ }
// TODO: Marker traits (with conditions)
else {
}
diff --git a/src/hir_conv/resolve_ufcs.cpp b/src/hir_conv/resolve_ufcs.cpp
index 55fbf593..90b3868d 100644
--- a/src/hir_conv/resolve_ufcs.cpp
+++ b/src/hir_conv/resolve_ufcs.cpp
@@ -5,6 +5,10 @@
* hir_conv/resolve_ufcs.cpp
* - Resolve unkown UFCS traits into inherent or trait
* - HACK: Will likely be replaced with a proper typeck pass (no it won't)
+ *
+ * TODO: Remove this pass, except maybe for running EAT on outer types
+ * - Expression code can handle picking UFCS functions better than this code can
+ * - Outer EAT is nice, but StaticTraitResolve will need to handle non-EAT-ed types when doing lookups
*/
#include "main_bindings.hpp"
#include <hir/hir.hpp>
@@ -91,11 +95,37 @@ namespace {
auto _g = m_resolve.set_impl_generics(impl.m_params);
::HIR::Visitor::visit_type_impl(impl);
}
+ void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl) override {
+ ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args );
+ TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")");
+ auto _t = this->push_mod_traits( this->m_crate.get_mod_by_path(Span(), impl.m_src_module) );
+ auto _g = m_resolve.set_impl_generics(impl.m_params);
+
+ // TODO: Push a bound that `Self: ThisTrait`
+ m_current_type = &impl.m_type;
+ m_current_trait = &m_crate.get_trait_by_path(Span(), trait_path);
+ m_current_trait_path = &p;
+
+ // The implemented trait is always in scope
+ m_traits.push_back( ::std::make_pair( &trait_path, m_current_trait) );
+ ::HIR::Visitor::visit_marker_impl(trait_path, impl);
+ m_traits.pop_back( );
+
+ m_current_trait = nullptr;
+ m_current_type = nullptr;
+ }
void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override {
::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args );
TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")");
auto _t = this->push_mod_traits( this->m_crate.get_mod_by_path(Span(), impl.m_src_module) );
auto _g = m_resolve.set_impl_generics(impl.m_params);
+ // TODO: Handle resolution of all items in m_resolve.m_type_equalities
+ // - params might reference each other, so `set_item_generics` has to have been called
+ // - But `m_type_equalities` can end up with non-resolved UFCS paths
+ for(auto& e : m_resolve.m_type_equalities)
+ {
+ visit_type(e.second);
+ }
// TODO: Push a bound that `Self: ThisTrait`
m_current_type = &impl.m_type;
@@ -157,6 +187,11 @@ namespace {
upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::VALUE);
::HIR::ExprVisitorDef::visit(node);
}
+ void visit(::HIR::ExprNode_StructLiteral& node) override
+ {
+ upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::TYPE);
+ ::HIR::ExprVisitorDef::visit(node);
+ }
void visit(::HIR::ExprNode_Match& node) override
{
diff --git a/src/hir_conv/resolve_ufcs_outer.cpp b/src/hir_conv/resolve_ufcs_outer.cpp
new file mode 100644
index 00000000..4e90f4f2
--- /dev/null
+++ b/src/hir_conv/resolve_ufcs_outer.cpp
@@ -0,0 +1,384 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * hir_conv/resolve_ufcs_outer.cpp
+ * - Resolve UfcsUnknown paths in outer scope (signatures/types)
+ *
+ * RULES:
+ * - Only generics are allowed to be UfcsKnown in signatures/types (within bodies anything goes?)
+ */
+#include "main_bindings.hpp"
+#include <hir/hir.hpp>
+#include <hir/expr.hpp>
+#include <hir/visitor.hpp>
+#include <hir_typeck/common.hpp> // monomorphise_genericpath_needed
+#include <algorithm>
+
+namespace {
+ class Visitor:
+ public ::HIR::Visitor
+ {
+ const ::HIR::Crate& m_crate;
+
+ const ::HIR::GenericParams* m_params_impl = nullptr;
+ const ::HIR::GenericParams* m_params_method = nullptr;
+
+ const ::HIR::TypeRef* m_current_type = nullptr; // used because sometimes `Self` is already replaced
+ const ::HIR::Trait* m_current_trait = nullptr;
+ const ::HIR::ItemPath* m_current_trait_path = nullptr;
+
+ public:
+ Visitor(const ::HIR::Crate& crate):
+ m_crate(crate)
+ {}
+
+ void visit_struct(::HIR::ItemPath p, ::HIR::Struct& item) override {
+ m_params_method = &item.m_params;
+ ::HIR::Visitor::visit_struct(p, item);
+ m_params_method = nullptr;
+ }
+ void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override {
+ m_params_method = &item.m_params;
+ ::HIR::Visitor::visit_enum(p, item);
+ m_params_method = nullptr;
+ }
+ void visit_function(::HIR::ItemPath p, ::HIR::Function& item) override {
+ m_params_method = &item.m_params;
+ ::HIR::Visitor::visit_function(p, item);
+ m_params_method = nullptr;
+ }
+ void visit_type_alias(::HIR::ItemPath p, ::HIR::TypeAlias& item) override {
+ // NOTE: Disabled, becuase generics in type aliases are never checked
+#if 0
+ auto _ = m_resolve.set_item_generics(item.m_params);
+ ::HIR::Visitor::visit_function(p, item);
+#endif
+ }
+ void visit_trait(::HIR::ItemPath p, ::HIR::Trait& trait) override {
+ m_params_impl = &trait.m_params;
+ m_current_trait = &trait;
+ m_current_trait_path = &p;
+ ::HIR::Visitor::visit_trait(p, trait);
+ m_current_trait = nullptr;
+ m_params_impl = nullptr;
+ }
+ void visit_type_impl(::HIR::TypeImpl& impl) override {
+ TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << impl.m_type << " (mod=" << impl.m_src_module << ")");
+ m_params_impl = &impl.m_params;
+ m_current_type = &impl.m_type;
+ ::HIR::Visitor::visit_type_impl(impl);
+ m_current_type = nullptr;
+ m_params_impl = nullptr;
+ }
+ void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl) override {
+ ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args );
+ TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")");
+
+ m_params_impl = &impl.m_params;
+ m_current_type = &impl.m_type;
+ m_current_trait = &m_crate.get_trait_by_path(Span(), trait_path);
+ m_current_trait_path = &p;
+
+ ::HIR::Visitor::visit_marker_impl(trait_path, impl);
+
+ m_current_trait = nullptr;
+ m_current_type = nullptr;
+ m_params_impl = nullptr;
+ }
+ void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override {
+ ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args );
+ TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")");
+
+ m_params_impl = &impl.m_params;
+ m_current_type = &impl.m_type;
+ m_current_trait = &m_crate.get_trait_by_path(Span(), trait_path);
+ m_current_trait_path = &p;
+
+ ::HIR::Visitor::visit_trait_impl(trait_path, impl);
+
+ m_current_trait = nullptr;
+ m_current_type = nullptr;
+ m_params_impl = nullptr;
+ }
+
+ void visit_expr(::HIR::ExprPtr& expr) override
+ {
+ // No inner visiting for expressions
+ }
+
+ bool locate_trait_item_in_bounds(::HIR::Visitor::PathContext pc, const ::HIR::TypeRef& tr, const ::HIR::GenericParams& params, ::HIR::Path::Data& pd) {
+ static Span sp;
+ //const auto& name = pd.as_UfcsUnknown().item;
+ for(const auto& b : params.m_bounds)
+ {
+ TU_IFLET(::HIR::GenericBound, b, TraitBound, e,
+ DEBUG("- " << e.type << " : " << e.trait.m_path);
+ if( e.type == tr ) {
+ DEBUG(" - Match");
+ if( locate_in_trait_and_set(pc, e.trait.m_path, m_crate.get_trait_by_path(sp, e.trait.m_path.m_path), pd) ) {
+ return true;
+ }
+ }
+ );
+ // -
+ }
+ return false;
+ }
+ static ::HIR::Path::Data get_ufcs_known(::HIR::Path::Data::Data_UfcsUnknown e, ::HIR::GenericPath trait_path, const ::HIR::Trait& trait)
+ {
+ return ::HIR::Path::Data::make_UfcsKnown({ mv$(e.type), mv$(trait_path), mv$(e.item), mv$(e.params)} );
+ }
+ static bool locate_item_in_trait(::HIR::Visitor::PathContext pc, const ::HIR::Trait& trait, ::HIR::Path::Data& pd)
+ {
+ const auto& e = pd.as_UfcsUnknown();
+
+ switch(pc)
+ {
+ case ::HIR::Visitor::PathContext::VALUE:
+ if( trait.m_values.find( e.item ) != trait.m_values.end() ) {
+ return true;
+ }
+ break;
+ case ::HIR::Visitor::PathContext::TRAIT:
+ break;
+ case ::HIR::Visitor::PathContext::TYPE:
+ if( trait.m_types.find( e.item ) != trait.m_types.end() ) {
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+ static ::HIR::GenericPath make_generic_path(::HIR::SimplePath sp, const ::HIR::Trait& trait)
+ {
+ auto trait_path_g = ::HIR::GenericPath( mv$(sp) );
+ for(unsigned int i = 0; i < trait.m_params.m_types.size(); i ++ ) {
+ //trait_path_g.m_params.m_types.push_back( ::HIR::TypeRef(trait.m_params.m_types[i].m_name, i) );
+ //trait_path_g.m_params.m_types.push_back( ::HIR::TypeRef() );
+ trait_path_g.m_params.m_types.push_back( trait.m_params.m_types[i].m_default.clone() );
+ }
+ return trait_path_g;
+ }
+ // Locate the item in `pd` and set `pd` to UfcsResolved if found
+ // TODO: This code may end up generating paths without the type information they should contain
+ bool locate_in_trait_and_set(::HIR::Visitor::PathContext pc, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait, ::HIR::Path::Data& pd) {
+ // TODO: Get the span from caller
+ static Span _sp;
+ const auto& sp = _sp;
+ if( locate_item_in_trait(pc, trait, pd) ) {
+ pd = get_ufcs_known(mv$(pd.as_UfcsUnknown()), trait_path.clone() /*make_generic_path(trait_path.m_path, trait)*/, trait);
+ return true;
+ }
+
+ auto monomorph_cb = [&](const auto& ty)->const ::HIR::TypeRef& {
+ const auto& ge = ty.m_data.as_Generic();
+ if( ge.binding == 0xFFFF ) {
+ // TODO: This has to be the _exact_ same type, including future ivars.
+ return *pd.as_UfcsUnknown().type;
+ }
+ else if( (ge.binding >> 8) == 0 ) {
+ auto idx = ge.binding & 0xFF;
+ ASSERT_BUG(sp, idx < trait.m_params.m_types.size(), "");
+ if( idx < trait_path.m_params.m_types.size() )
+ return trait_path.m_params.m_types[idx];
+ // If the param is omitted, but has a default, use the default.
+ else if( trait.m_params.m_types[idx].m_default != ::HIR::TypeRef() ) {
+ const auto& def = trait.m_params.m_types[idx].m_default;
+ if( ! monomorphise_type_needed(def) )
+ return def;
+ if( def == ::HIR::TypeRef("Self", 0xFFFF) )
+ // TODO: This has to be the _exact_ same type, including future ivars.
+ return *pd.as_UfcsUnknown().type;
+ TODO(sp, "Monomorphise default arg " << def << " for trait path " << trait_path);
+ }
+ else
+ BUG(sp, "Binding out of range in " << ty << " for trait path " << trait_path);
+ }
+ else {
+ ERROR(sp, E0000, "Unexpected generic binding " << ty);
+ }
+ };
+ ::HIR::GenericPath par_trait_path_tmp;
+ auto monomorph_gp_if_needed = [&](const ::HIR::GenericPath& tpl)->const ::HIR::GenericPath& {
+ // NOTE: This doesn't monomorph if the parameter set is the same
+ if( monomorphise_genericpath_needed(tpl) && tpl.m_params != trait_path.m_params ) {
+ DEBUG("- Monomorph " << tpl);
+ return par_trait_path_tmp = monomorphise_genericpath_with(sp, tpl, monomorph_cb, false /*no infer*/);
+ }
+ else {
+ return tpl;
+ }
+ };
+
+ // Search supertraits (recursively)
+ for(const auto& pt : trait.m_parent_traits)
+ {
+ const auto& par_trait_path = monomorph_gp_if_needed(pt.m_path);
+ DEBUG("- Check " << par_trait_path);
+ if( locate_in_trait_and_set(pc, par_trait_path, *pt.m_trait_ptr, pd) ) {
+ return true;
+ }
+ }
+ for(const auto& pt : trait.m_all_parent_traits)
+ {
+ const auto& par_trait_path = monomorph_gp_if_needed(pt.m_path);
+ DEBUG("- Check (all) " << par_trait_path);
+ if( locate_item_in_trait(pc, *pt.m_trait_ptr, pd) ) {
+ // TODO: Don't clone if this is from the temp.
+ pd = get_ufcs_known(mv$(pd.as_UfcsUnknown()), par_trait_path.clone(), *pt.m_trait_ptr);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool resolve_UfcsUnknown_inherent(const ::HIR::Path& p, ::HIR::Visitor::PathContext pc, ::HIR::Path::Data& pd)
+ {
+ auto& e = pd.as_UfcsUnknown();
+ return m_crate.find_type_impls(*e.type, [&](const auto& t)->const auto& { return t; }, [&](const auto& impl) {
+ DEBUG("- matched inherent impl" << impl.m_params.fmt_args() << " " << impl.m_type);
+ // Search for item in this block
+ switch( pc )
+ {
+ case ::HIR::Visitor::PathContext::VALUE:
+ if( impl.m_methods.find(e.item) != impl.m_methods.end() ) {
+ }
+ else if( impl.m_constants.find(e.item) != impl.m_constants.end() ) {
+ }
+ else {
+ return false;
+ }
+ // Found it, just keep going (don't care about details here)
+ break;
+ case ::HIR::Visitor::PathContext::TRAIT:
+ case ::HIR::Visitor::PathContext::TYPE:
+ return false;
+ }
+
+ auto new_data = ::HIR::Path::Data::make_UfcsInherent({ mv$(e.type), mv$(e.item), mv$(e.params)} );
+ pd = mv$(new_data);
+ DEBUG("- Resolved, replace with " << p);
+ return true;
+ });
+ }
+
+ void visit_path(::HIR::Path& p, ::HIR::Visitor::PathContext pc) override
+ {
+ static Span sp;
+
+ // Explicitly handle UfcsUnknown (doesn't call default)
+ if(auto* pe = p.m_data.opt_UfcsUnknown())
+ {
+ auto& e = *pe;
+ TRACE_FUNCTION_FR("UfcsUnknown - p=" << p, p);
+
+ this->visit_type( *e.type );
+ this->visit_path_params( e.params );
+
+ // Search for matching impls in current generic blocks
+ if( m_params_method != nullptr && locate_trait_item_in_bounds(pc, *e.type, *m_params_method, p.m_data) ) {
+ DEBUG("Found in item params, p = " << p);
+ return ;
+ }
+ if( m_params_impl != nullptr && locate_trait_item_in_bounds(pc, *e.type, *m_params_impl, p.m_data) ) {
+ DEBUG("Found in impl params, p = " << p);
+ return ;
+ }
+
+ // If processing a trait, and the type is 'Self', search for the type/method on the trait
+ // - TODO: This could be encoded by a `Self: Trait` bound in the generics, but that may have knock-on issues?
+ // NOTE: `Self` can already be replaced by the self type (AST resolve does this)
+ if( *e.type == ::HIR::TypeRef("Self", 0xFFFF) || (m_current_type && *e.type == *m_current_type) )
+ {
+ ::HIR::GenericPath trait_path;
+ if( m_current_trait_path->trait_path() )
+ {
+ trait_path = ::HIR::GenericPath( *m_current_trait_path->trait_path() );
+ trait_path.m_params = m_current_trait_path->trait_args()->clone();
+ }
+ else
+ {
+ trait_path = ::HIR::GenericPath( m_current_trait_path->get_simple_path() );
+ for(unsigned int i = 0; i < m_current_trait->m_params.m_types.size(); i ++ ) {
+ trait_path.m_params.m_types.push_back( ::HIR::TypeRef(m_current_trait->m_params.m_types[i].m_name, i) );
+ }
+ }
+ if( locate_in_trait_and_set(pc, trait_path, *m_current_trait, p.m_data) ) {
+ DEBUG("Found in Self, p = " << p);
+ return ;
+ }
+ DEBUG("- Item " << e.item << " not found in Self - ty=" << *e.type);
+ }
+
+ // Cases for the type:
+ // - Path:UfcsKnown - Search trait impl's ATY bounds (and our own bound set?)
+ // - Generic - Search local bound set for a suitable implemented trait
+ // - Anything else - ERROR
+ if( e.type->m_data.is_Path() && e.type->m_data.as_Path().path.m_data.is_UfcsKnown() )
+ {
+ // TODO: Search bounds on this ATY (in the trait defintiion)
+ TODO(sp, "Get " << e.item << " for " << *e.type);
+ }
+ else if( e.type->m_data.is_Generic())
+ {
+ // Local bounds have already been searched, error now?
+ TODO(sp, "Get " << e.item << " for " << *e.type);
+ }
+ else
+ {
+ ERROR(sp, E0000, "Ambigious associated type " << p); // rustc E0223
+ }
+ }
+ else
+ {
+ ::HIR::Visitor::visit_path(p, pc);
+ }
+ }
+ };
+
+}
+
+namespace {
+ template<typename T>
+ void sort_impl_group(::HIR::Crate::ImplGroup<T>& ig)
+ {
+ auto new_end = ::std::remove_if(ig.generic.begin(), ig.generic.end(), [&ig](::std::unique_ptr<T>& ty_impl) {
+ const auto& type = ty_impl->m_type; // Using field accesses in templates feels so dirty
+ const ::HIR::SimplePath* path = type.get_sort_path();
+
+ if( path )
+ {
+ ig.named[*path].push_back(mv$(ty_impl));
+ }
+ else if( type.m_data.is_Path() || type.m_data.is_Generic() )
+ {
+ return false;
+ }
+ else
+ {
+ ig.non_named.push_back(mv$(ty_impl));
+ }
+ return true;
+ });
+ ig.generic.erase(new_end, ig.generic.end());
+ }
+}
+
+void ConvertHIR_ResolveUFCS_Outer(::HIR::Crate& crate)
+{
+ Visitor exp { crate };
+ exp.visit_crate( crate );
+
+ // Sort impls!
+ sort_impl_group(crate.m_type_impls);
+ DEBUG("Type impl counts: " << crate.m_type_impls.named.size() << " path groups, " << crate.m_type_impls.non_named.size() << " primitive, " << crate.m_type_impls.generic.size() << " ungrouped");
+ for(auto& impl_group : crate.m_trait_impls)
+ {
+ sort_impl_group(impl_group.second);
+ }
+ for(auto& impl_group : crate.m_marker_impls)
+ {
+ sort_impl_group(impl_group.second);
+ }
+}
diff --git a/src/hir_expand/annotate_value_usage.cpp b/src/hir_expand/annotate_value_usage.cpp
index 693c7745..5ce270bc 100644
--- a/src/hir_expand/annotate_value_usage.cpp
+++ b/src/hir_expand/annotate_value_usage.cpp
@@ -122,6 +122,10 @@ namespace {
void visit(::HIR::ExprNode_LoopControl& node) override
{
// NOTE: Leaf
+ if( node.m_value )
+ {
+ this->visit_node_ptr(node.m_value);
+ }
}
void visit(::HIR::ExprNode_Match& node) override
{
@@ -333,9 +337,32 @@ namespace {
}
void visit(::HIR::ExprNode_CallMethod& node) override
{
+ {
+ assert(node.m_cache.m_fcn);
+ ::HIR::ValueUsage vu = ::HIR::ValueUsage::Borrow;
+ switch(node.m_cache.m_fcn->m_receiver)
+ {
+ case ::HIR::Function::Receiver::Free:
+ BUG(node.span(), "_CallMethod resolved to free function");
+ case ::HIR::Function::Receiver::Value:
+ case ::HIR::Function::Receiver::Box:
+ case ::HIR::Function::Receiver::Custom:
+ case ::HIR::Function::Receiver::BorrowOwned:
+ vu = ::HIR::ValueUsage::Move;
+ break;
+ case ::HIR::Function::Receiver::BorrowUnique:
+ vu = ::HIR::ValueUsage::Mutate;
+ break;
+ case ::HIR::Function::Receiver::BorrowShared:
+ vu = ::HIR::ValueUsage::Borrow;
+ break;
+ //case ::HIR::Function::Receiver::PointerMut:
+ //case ::HIR::Function::Receiver::PointerConst:
+ }
+ auto _ = push_usage( vu );
+ this->visit_node_ptr(node.m_value);
+ }
auto _ = push_usage( ::HIR::ValueUsage::Move );
-
- this->visit_node_ptr(node.m_value);
for( auto& val : node.m_args )
this->visit_node_ptr(val);
}
@@ -356,13 +383,15 @@ namespace {
void visit(::HIR::ExprNode_StructLiteral& node) override
{
const auto& sp = node.span();
+ ASSERT_BUG(sp, node.m_path.m_data.is_Generic(), "Struct literal with non-Generic path - " << node.m_path);
+ auto& ty_path = node.m_path.m_data.as_Generic();
if( node.m_base_value ) {
bool is_moved = false;
const auto& tpb = node.m_base_value->m_res_type.m_data.as_Path().binding;
const ::HIR::Struct* str;
if( tpb.is_Enum() ) {
const auto& enm = *tpb.as_Enum();
- auto idx = enm.find_variant(node.m_path.m_path.m_components.back());
+ auto idx = enm.find_variant(ty_path.m_path.m_components.back());
ASSERT_BUG(sp, idx != SIZE_MAX, "");
const auto& var_ty = enm.m_data.as_Data()[idx].type;
str = var_ty.m_data.as_Path().binding.as_Struct();
@@ -379,7 +408,7 @@ namespace {
provided_mask[idx] = true;
}
- const auto monomorph_cb = monomorphise_type_get_cb(node.span(), nullptr, &node.m_path.m_params, nullptr);
+ const auto monomorph_cb = monomorphise_type_get_cb(node.span(), nullptr, &ty_path.m_params, nullptr);
for( unsigned int i = 0; i < fields.size(); i ++ ) {
if( ! provided_mask[i] ) {
const auto& ty_o = fields[i].second.ent;
@@ -452,11 +481,19 @@ namespace {
throw "";
}
- ::HIR::ValueUsage get_usage_for_pattern(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty) const
+ ::HIR::ValueUsage get_usage_for_pattern(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& outer_ty) const
{
if( pat.m_binding.is_valid() ) {
- return get_usage_for_pattern_binding(sp, pat.m_binding, ty);
+ return get_usage_for_pattern_binding(sp, pat.m_binding, outer_ty);
+ }
+
+ // Implicit derefs
+ const ::HIR::TypeRef* typ = &outer_ty;
+ for(size_t i = 0; i < pat.m_implicit_deref_count; i ++)
+ {
+ typ = &*typ->m_data.as_Borrow().inner;
}
+ const ::HIR::TypeRef& ty = *typ;
TU_MATCHA( (pat.m_data), (pe),
(Any,
@@ -510,6 +547,12 @@ namespace {
),
(Struct,
const auto& str = *pe.binding;
+ if( pe.is_wildcard() )
+ return ::HIR::ValueUsage::Borrow;
+ if( pe.sub_patterns.empty() && (TU_TEST1(str.m_data, Tuple, .empty()) || str.m_data.is_Unit()) ) {
+ return ::HIR::ValueUsage::Borrow;
+ }
+ ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-brace struct");
const auto& flds = str.m_data.as_Named();
auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &pe.path.m_params, nullptr);
@@ -552,10 +595,10 @@ namespace {
),
(EnumStruct,
const auto& enm = *pe.binding_ptr;
- ASSERT_BUG(sp, enm.m_data.is_Data(), "");
+ ASSERT_BUG(sp, enm.m_data.is_Data(), "EnumStruct pattern on non-data enum");
const auto& var = enm.m_data.as_Data().at(pe.binding_idx);
const auto& str = *var.type.m_data.as_Path().binding.as_Struct();
- ASSERT_BUG(sp, str.m_data.is_Named(), "");
+ ASSERT_BUG(sp, str.m_data.is_Named(), "EnumStruct pattern on non-struct variant - " << pe.path);
const auto& flds = str.m_data.as_Named();
auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &pe.path.m_params, nullptr);
diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp
index 51b2c638..c53396a0 100644
--- a/src/hir_expand/closures.cpp
+++ b/src/hir_expand/closures.cpp
@@ -9,6 +9,7 @@
#include <hir/expr.hpp>
#include <hir_typeck/static.hpp>
#include <algorithm>
+#include <hir/expr_state.hpp>
#include "main_bindings.hpp"
namespace {
@@ -18,7 +19,7 @@ namespace {
namespace {
- typedef ::std::function< ::HIR::SimplePath(::HIR::Struct )> new_type_cb_t;
+ typedef ::std::function< ::std::pair<::HIR::SimplePath, const ::HIR::Struct*>(const char* suffix, ::HIR::Struct )> new_type_cb_t;
typedef ::std::vector< ::std::pair< ::HIR::ExprNode_Closure::Class, ::HIR::TraitImpl> > out_impls_t;
template<typename K, typename V>
@@ -45,6 +46,50 @@ namespace {
return rv;
}
+ void push_new_impls(const Span& sp, ::HIR::Crate& crate, out_impls_t new_trait_impls)
+ {
+ for(auto& impl : new_trait_impls)
+ {
+ ::HIR::Crate::ImplGroup<::HIR::TraitImpl>::list_t* trait_impl_list;
+ switch(impl.first)
+ {
+ case ::HIR::ExprNode_Closure::Class::Once:
+ trait_impl_list = &crate.m_trait_impls[crate.get_lang_item_path(sp, "fn_once")].get_list_for_type_mut(impl.second.m_type);
+ if(0)
+ case ::HIR::ExprNode_Closure::Class::Mut:
+ trait_impl_list = &crate.m_trait_impls[crate.get_lang_item_path(sp, "fn_mut" )].get_list_for_type_mut(impl.second.m_type);
+ if(0)
+ case ::HIR::ExprNode_Closure::Class::Shared:
+ trait_impl_list = &crate.m_trait_impls[crate.get_lang_item_path(sp, "fn" )].get_list_for_type_mut(impl.second.m_type);
+ trait_impl_list->push_back( box$(impl.second) );
+ break;
+ case ::HIR::ExprNode_Closure::Class::NoCapture: {
+ assert(impl.second.m_methods.size() == 1);
+ assert(impl.second.m_types.empty());
+ assert(impl.second.m_constants.empty());
+ // NOTE: This should always have a name
+ const auto& path = impl.second.m_type.m_data.as_Path().path.m_data.as_Generic().m_path;
+ DEBUG("Adding type impl " << path);
+ auto* list_it = &crate.m_type_impls.named[path];
+ list_it->push_back(box$(::HIR::TypeImpl {
+ mv$(impl.second.m_params),
+ mv$(impl.second.m_type),
+ make_map1(
+ impl.second.m_methods.begin()->first,
+ ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> { ::HIR::Publicity::new_global(), false, mv$(impl.second.m_methods.begin()->second.data) }
+ ),
+ {},
+ mv$(impl.second.m_src_module)
+ }));
+ } break;
+ case ::HIR::ExprNode_Closure::Class::Unknown:
+ BUG(Span(), "Encountered Unkown closure type in new impls");
+ break;
+ }
+ }
+ new_trait_impls.resize(0);
+ }
+
/// Mutate the contents of a closure to update captures, variables, and types
class ExprVisitor_Mutate:
public ::HIR::ExprVisitorDef
@@ -106,7 +151,7 @@ namespace {
assert( node_ptr );
auto& node = *node_ptr;
const char* node_ty = typeid(node).name();
- TRACE_FUNCTION_FR(&node << " " << node_ty << " : " << node.m_res_type, node_ty);
+ TRACE_FUNCTION_FR("[_Mutate] " << &node << " " << node_ty << " : " << node.m_res_type, node_ty);
node.visit(*this);
if( m_replacement ) {
@@ -134,7 +179,9 @@ namespace {
auto binding_it = ::std::find(m_local_vars.begin(), m_local_vars.end(), node.m_slot);
if( binding_it != m_local_vars.end() ) {
// NOTE: Offset of 1 is for `self` (`args` is destructured)
- node.m_slot = 1 + binding_it - m_local_vars.begin();
+ auto new_slot = 1 + binding_it - m_local_vars.begin();
+ DEBUG("_Variable: #" << node.m_slot << " -> #" << new_slot);
+ node.m_slot = new_slot;
return ;
}
}
@@ -146,7 +193,7 @@ namespace {
{
m_replacement = NEWNODE(node.m_res_type.clone(), Field, node.span(),
get_self(node.span()),
- FMT(binding_it - m_captures.begin())
+ RcString::new_interned(FMT(binding_it - m_captures.begin()))
);
if( binding_it->second != ::HIR::ValueUsage::Move ) {
auto bt = (binding_it->second == ::HIR::ValueUsage::Mutate ? ::HIR::BorrowType::Unique : ::HIR::BorrowType::Shared);
@@ -156,6 +203,7 @@ namespace {
m_replacement = NEWNODE(node.m_res_type.clone(), Deref, node.span(), mv$(m_replacement));
}
m_replacement->m_usage = node.m_usage;
+ DEBUG("_Variable: #" << node.m_slot << " -> capture");
return ;
}
}
@@ -194,22 +242,38 @@ namespace {
public ::HIR::ExprVisitorDef
{
const ::HIR::Crate& m_crate;
+ StaticTraitResolve m_resolve;
t_cb_generic m_monomorph_cb;
+ bool m_run_eat;
public:
- ExprVisitor_Fixup(const ::HIR::Crate& crate, t_cb_generic monomorph_cb):
+ ExprVisitor_Fixup(const ::HIR::Crate& crate, const ::HIR::GenericParams* params, t_cb_generic monomorph_cb):
m_crate(crate),
- m_monomorph_cb( mv$(monomorph_cb) )
+ m_resolve(crate),
+ m_monomorph_cb( mv$(monomorph_cb) ),
+ m_run_eat(false)
{
+ if( params ) {
+ m_resolve.set_impl_generics_raw(*params);
+ m_run_eat = true;
+ }
}
- static void fix_type(const ::HIR::Crate& crate, t_cb_generic monomorph_cb, ::HIR::TypeRef& ty) {
+ static void fix_type(const ::HIR::Crate& crate, const Span& sp, t_cb_generic monomorph_cb, ::HIR::TypeRef& ty) {
TU_IFLET( ::HIR::TypeRef::Data, ty.m_data, Closure, e,
DEBUG("Closure: " << e.node->m_obj_path_base);
- auto path = monomorphise_genericpath_with(Span(), e.node->m_obj_path_base, monomorph_cb, false);
- const auto& str = crate.get_struct_by_path( Span(), path.m_path );
+ auto path = monomorphise_genericpath_with(sp, e.node->m_obj_path_base, monomorph_cb, false);
+ const auto& str = *e.node->m_obj_ptr;
DEBUG(ty << " -> " << path);
ty = ::HIR::TypeRef::new_path( mv$(path), ::HIR::TypeRef::TypePathBinding::make_Struct(&str) );
)
+
+ if( auto* e = ty.m_data.opt_Path() )
+ {
+ if( e->binding.is_Unbound() && e->path.m_data.is_UfcsKnown() )
+ {
+ e->binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({});
+ }
+ }
}
void visit_root(::HIR::ExprPtr& root)
@@ -233,6 +297,42 @@ namespace {
visit_type(node->m_res_type);
}
+ void visit(::HIR::ExprNode_Cast& node) override
+ {
+ const Span& sp = node.span();
+ // Handle casts from closures to function pointers
+ if( node.m_value->m_res_type.m_data.is_Closure() )
+ {
+ const auto& src_te = node.m_value->m_res_type.m_data.as_Closure();
+ ASSERT_BUG(sp, node.m_res_type.m_data.is_Function(), "Cannot convert closure to non-fn type");
+ //const auto& dte = node.m_res_type.m_data.as_Function();
+ if( src_te.node->m_class != ::HIR::ExprNode_Closure::Class::NoCapture )
+ {
+ ERROR(sp, E0000, "Cannot cast a closure with captures to a fn() type");
+ }
+
+ ::HIR::FunctionType fcn_ty_inner { /*is_unsafe=*/false, ABI_RUST, box$(src_te.node->m_return.clone()), {} };
+ ::std::vector<::HIR::TypeRef> arg_types;
+ fcn_ty_inner.m_arg_types.reserve(src_te.node->m_args.size());
+ arg_types.reserve(src_te.node->m_args.size());
+ for(const auto& arg : src_te.node->m_args)
+ {
+ fcn_ty_inner.m_arg_types.push_back( arg.second.clone() );
+ arg_types.push_back(arg.second.clone());
+ }
+ auto trait_params = ::HIR::PathParams( ::HIR::TypeRef(mv$(arg_types)) );
+ auto res_ty = ::HIR::TypeRef(mv$(fcn_ty_inner));
+
+ const auto& str = *src_te.node->m_obj_ptr;
+ auto closure_type = ::HIR::TypeRef::new_path( src_te.node->m_obj_path.clone(), &str );
+ auto fn_path = ::HIR::Path(mv$(closure_type), "call_free");
+ fn_path.m_data.as_UfcsInherent().impl_params = src_te.node->m_obj_path.m_params.clone();
+
+ node.m_value = NEWNODE(mv$(res_ty), PathValue, sp, mv$(fn_path), ::HIR::ExprNode_PathValue::FUNCTION);
+ }
+ ::HIR::ExprVisitorDef::visit(node);
+ }
+
void visit(::HIR::ExprNode_CallValue& node) override
{
TU_IFLET( ::HIR::TypeRef::Data, node.m_value->m_res_type.m_data, Closure, e,
@@ -258,8 +358,15 @@ namespace {
void visit_type(::HIR::TypeRef& ty) override
{
- fix_type(m_crate, m_monomorph_cb, ty);
+ bool run_eat = m_run_eat;
+ m_run_eat = false;
+ fix_type(m_crate, Span(), m_monomorph_cb, ty);
::HIR::ExprVisitorDef::visit_type(ty);
+ if( run_eat ) {
+ // TODO: Instead of running EAT, just mark any Unbound UfcsKnown types as Opaque
+ //m_resolve.expand_associated_types(Span(), ty);
+ m_run_eat = true;
+ }
}
};
@@ -280,6 +387,37 @@ namespace {
code.m_bindings[0] = self_ty.clone();
}
}
+ static ::HIR::TraitImpl make_fnfree(
+ ::HIR::GenericParams params,
+ ::HIR::TypeRef closure_type,
+ ::std::vector<::std::pair< ::HIR::Pattern, ::HIR::TypeRef>> args,
+ ::HIR::TypeRef ret_ty,
+ ::HIR::ExprPtr code
+ )
+ {
+ // NOTE: Fixup isn't needed, there's no self
+ //fix_fn_params(code, closure_type, args_argent.second);
+ assert(code.m_bindings.size() > 0);
+ code.m_bindings[0] = ::HIR::TypeRef::new_unit();
+ return ::HIR::TraitImpl {
+ mv$(params), {}, mv$(closure_type),
+ make_map1(
+ RcString::new_interned("call_free"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
+ false, ::HIR::Linkage {},
+ ::HIR::Function::Receiver::Free,
+ ABI_RUST, false, false,
+ {},
+ mv$(args), false,
+ ret_ty.clone(),
+ mv$(code)
+ } }
+ ),
+ {},
+ {},
+ {},
+ ::HIR::SimplePath()
+ };
+ }
static ::HIR::TraitImpl make_fnonce(
::HIR::GenericParams params,
::HIR::PathParams trait_params,
@@ -294,7 +432,7 @@ namespace {
return ::HIR::TraitImpl {
mv$(params), mv$(trait_params), mv$(closure_type),
make_map1(
- ::std::string("call_once"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
+ RcString::new_interned("call_once"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
false, ::HIR::Linkage {},
::HIR::Function::Receiver::Value,
ABI_RUST, false, false,
@@ -313,7 +451,7 @@ namespace {
{},
{},
make_map1(
- ::std::string("Output"), ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> { false, mv$(ret_ty) }
+ RcString::new_interned("Output"), ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> { false, mv$(ret_ty) }
),
::HIR::SimplePath()
};
@@ -332,7 +470,7 @@ namespace {
return ::HIR::TraitImpl {
mv$(params), mv$(trait_params), mv$(closure_type),
make_map1(
- ::std::string("call_mut"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
+ RcString::new_interned("call_mut"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
false, ::HIR::Linkage {},
::HIR::Function::Receiver::BorrowUnique,
ABI_RUST, false, false,
@@ -368,7 +506,7 @@ namespace {
return ::HIR::TraitImpl {
mv$(params), mv$(trait_params), mv$(closure_type),
make_map1(
- ::std::string("call"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
+ RcString::new_interned("call"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function {
false, ::HIR::Linkage {},
::HIR::Function::Receiver::BorrowShared,
ABI_RUST, false, false,
@@ -419,17 +557,19 @@ namespace {
// Outputs
out_impls_t& m_out_impls;
+ const char* m_new_type_suffix;
const new_type_cb_t& m_new_type;
/// Stack of active closures
::std::vector<ClosureScope> m_closure_stack;
public:
- ExprVisitor_Extract(const StaticTraitResolve& resolve, const ::HIR::TypeRef* self_type, ::std::vector< ::HIR::TypeRef>& var_types, out_impls_t& out_impls, const new_type_cb_t& new_type):
+ ExprVisitor_Extract(const StaticTraitResolve& resolve, const ::HIR::TypeRef* self_type, ::std::vector< ::HIR::TypeRef>& var_types, out_impls_t& out_impls, const char* nt_suffix, const new_type_cb_t& new_type):
m_resolve(resolve),
m_self_type(self_type),
m_variable_types(var_types),
m_out_impls( out_impls ),
+ m_new_type_suffix(nt_suffix),
m_new_type( new_type )
{
}
@@ -445,6 +585,8 @@ namespace {
TRACE_FUNCTION_F("Extract closure - " << node.m_res_type);
+ ASSERT_BUG(sp, node.m_obj_path == ::HIR::GenericPath(), "Closure path already set? " << node.m_obj_path);
+
// --- Determine borrow set ---
m_closure_stack.push_back( ClosureScope(node) );
@@ -507,6 +649,7 @@ namespace {
params_placeholders.push_back( ::HIR::TypeRef(params.m_types[i].m_name, i) );
impl_path_params.m_types.push_back( ::HIR::TypeRef(params.m_types[i].m_name, i) );
}
+ DEBUG("params_placeholders = " << params_placeholders << ", ofs_item = " << ofs_item << ", ofs_impl = " << ofs_impl);
auto monomorph_cb = [&](const auto& ty)->const ::HIR::TypeRef& {
const auto& ge = ty.m_data.as_Generic();
@@ -593,6 +736,7 @@ namespace {
::std::vector< ::HIR::ExprNodeP> capture_nodes;
capture_types.reserve( ent.captured_vars.size() );
capture_nodes.reserve( ent.captured_vars.size() );
+ node.m_is_copy = true;
for(const auto binding : ent.captured_vars)
{
const auto binding_idx = binding.first;
@@ -627,20 +771,34 @@ namespace {
}
// - Fix type to replace closure types with known paths
- ExprVisitor_Fixup fixup { m_resolve.m_crate, monomorph_cb };
+ ExprVisitor_Fixup fixup { m_resolve.m_crate, &params, monomorph_cb };
fixup.visit_type(ty_mono);
- capture_types.push_back( ::HIR::VisEnt< ::HIR::TypeRef> { false, mv$(ty_mono) } );
+ if( !m_resolve.type_is_copy(sp, ty_mono) )
+ {
+ node.m_is_copy = false;
+ }
+ capture_types.push_back( ::HIR::VisEnt< ::HIR::TypeRef> { ::HIR::Publicity::new_none(), mv$(ty_mono) } );
}
- auto closure_struct_path = m_new_type(
- ::HIR::Struct {
- params.clone(),
- ::HIR::Struct::Repr::Rust,
- ::HIR::Struct::Data::make_Tuple(mv$(capture_types))
- }
- );
- const auto& closure_struct_ref = m_resolve.m_crate.get_struct_by_path(sp, closure_struct_path);
+
+ // --- ---
+ if( node.m_is_copy )
+ {
+ DEBUG("Copy closure");
+ }
+
+ auto str = ::HIR::Struct {
+ params.clone(),
+ ::HIR::Struct::Repr::Rust,
+ ::HIR::Struct::Data::make_Tuple(mv$(capture_types))
+ };
+ str.m_markings.is_copy = node.m_is_copy;
+ ::HIR::SimplePath closure_struct_path;
+ const ::HIR::Struct* closure_struct_ptr;
+ ::std::tie(closure_struct_path, closure_struct_ptr) = m_new_type(m_new_type_suffix, mv$(str));
+ const auto& closure_struct_ref = *closure_struct_ptr;
// Mark the object pathname in the closure.
+ node.m_obj_ptr = &closure_struct_ref;
node.m_obj_path = ::HIR::GenericPath( closure_struct_path, mv$(constructor_path_params) );
node.m_obj_path_base = node.m_obj_path.clone();
node.m_captures = mv$(capture_nodes);
@@ -669,7 +827,7 @@ namespace {
{
DEBUG("-- Fixing types in body code");
- ExprVisitor_Fixup fixup { m_resolve.m_crate, monomorph_cb };
+ ExprVisitor_Fixup fixup { m_resolve.m_crate, &params, monomorph_cb };
fixup.visit_root( body_code );
DEBUG("-- Fixing types in signature");
@@ -678,6 +836,19 @@ namespace {
// TODO: Replace erased types too
}
+ if( node.m_is_copy )
+ {
+ auto& v = const_cast<::HIR::Crate&>(m_resolve.m_crate).m_trait_impls[m_resolve.m_crate.get_lang_item_path(sp, "copy")].get_list_for_type_mut(closure_type);
+ v.push_back(box$(::HIR::TraitImpl {
+ params.clone(), {}, closure_type.clone(),
+ {},
+ {},
+ {},
+ {},
+ /*source module*/::HIR::SimplePath(m_resolve.m_crate.m_crate_name, {})
+ }));
+ }
+
// ---
// 3. Create trait impls
// ---
@@ -687,7 +858,83 @@ namespace {
{
case ::HIR::ExprNode_Closure::Class::Unknown:
node.m_class = ::HIR::ExprNode_Closure::Class::NoCapture;
- case ::HIR::ExprNode_Closure::Class::NoCapture:
+ case ::HIR::ExprNode_Closure::Class::NoCapture: {
+
+ struct H2 {
+ static ::std::pair<::HIR::ExprNode_Closure::Class, HIR::TraitImpl> make_dispatch(
+ const Span& sp,
+ ::HIR::ExprNode_Closure::Class c,
+ ::HIR::GenericParams params,
+ ::HIR::PathParams trait_params,
+ const ::HIR::TypeRef& closure_type,
+ const ::HIR::TypeRef& args_ty,
+ const ::HIR::TypeRef& ret_type
+ )
+ {
+ const auto& args_tup_inner = args_ty.m_data.as_Tuple();
+ // 1. Create a list of `arg.0, arg.1, arg.2, ...` for the dispatch methods
+ ::std::vector<HIR::ExprNodeP> dispatch_args;
+ ::std::vector<HIR::TypeRef> dispatch_node_args_cache;
+ dispatch_args.reserve( args_tup_inner.size() );
+ dispatch_node_args_cache.reserve( args_tup_inner.size()+1 );
+ for(size_t i = 0; i < args_tup_inner.size(); i ++)
+ {
+ const auto& ty = args_tup_inner[i];
+ dispatch_args.push_back( NEWNODE(ty.clone(), Field, sp, NEWNODE(args_ty.clone(), Variable, sp, RcString::new_interned("arg"), 1), RcString::new_interned(FMT(i))) );
+ dispatch_node_args_cache.push_back( ty.clone() );
+ }
+ dispatch_node_args_cache.push_back( ret_type.clone() );
+ auto path = ::HIR::Path(closure_type.clone(), RcString::new_interned("call_free"));
+ path.m_data.as_UfcsInherent().impl_params = closure_type.m_data.as_Path().path.m_data.as_Generic().m_params.clone();
+ HIR::ExprNodeP dispatch_node = NEWNODE(ret_type.clone(), CallPath, sp,
+ mv$(path),
+ mv$(dispatch_args)
+ );
+ dynamic_cast<::HIR::ExprNode_CallPath&>(*dispatch_node).m_cache.m_arg_types = mv$(dispatch_node_args_cache);
+
+ auto args_arg = ::std::make_pair(
+ ::HIR::Pattern { {false, ::HIR::PatternBinding::Type::Move, RcString::new_interned("args"), 1}, {} },
+ args_ty.clone()
+ );
+ HIR::TraitImpl fcn;
+ switch(c)
+ {
+ case ::HIR::ExprNode_Closure::Class::Once:
+ fcn = H::make_fnonce( mv$(params), mv$(trait_params), closure_type.clone(), mv$(args_arg), ret_type.clone(), mv$(dispatch_node) );
+ break;
+ case ::HIR::ExprNode_Closure::Class::Mut:
+ fcn = H::make_fnmut( mv$(params), mv$(trait_params), closure_type.clone(), mv$(args_arg), ret_type.clone(), mv$(dispatch_node) );
+ break;
+ case ::HIR::ExprNode_Closure::Class::Shared:
+ fcn = H::make_fn( mv$(params), mv$(trait_params), closure_type.clone(), mv$(args_arg), ret_type.clone(), mv$(dispatch_node) );
+ break;
+ default:
+ throw "";
+ }
+ return ::std::make_pair(c, mv$(fcn));
+ }
+ };
+ m_out_impls.push_back( H2::make_dispatch(sp, ::HIR::ExprNode_Closure::Class::Once , params.clone(), trait_params.clone(), closure_type, args_ty, ret_type) );
+ m_out_impls.push_back( H2::make_dispatch(sp, ::HIR::ExprNode_Closure::Class::Mut , params.clone(), trait_params.clone(), closure_type, args_ty, ret_type) );
+ m_out_impls.push_back( H2::make_dispatch(sp, ::HIR::ExprNode_Closure::Class::Shared, params.clone(), mv$(trait_params) , closure_type, args_ty, ret_type) );
+
+ // 2. Split args_pat/args_ty into separate arguments
+ ::std::vector<::std::pair< ::HIR::Pattern, ::HIR::TypeRef>> args_split;
+ args_split.reserve( node.m_args.size() );
+ for(size_t i = 0; i < node.m_args.size(); i ++)
+ {
+ args_split.push_back(::std::make_pair(
+ mv$( args_pat.m_data.as_Tuple().sub_patterns[i] ),
+ mv$( args_ty.m_data.as_Tuple()[i] )
+ ));
+ }
+ // - Create fn_free free method
+ m_out_impls.push_back(::std::make_pair(
+ ::HIR::ExprNode_Closure::Class::NoCapture,
+ H::make_fnfree( mv$(params), mv$(closure_type), mv$(args_split), mv$(ret_type), mv$(body_code) )
+ ));
+
+ } break;
case ::HIR::ExprNode_Closure::Class::Shared: {
const auto& lang_Fn = m_resolve.m_crate.get_lang_item_path(node.span(), "fn");
const auto method_self_ty = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, closure_type.clone() );
@@ -695,9 +942,9 @@ namespace {
// - FnOnce
{
auto dispatch_node = NEWNODE(ret_type.clone(), CallPath, sp,
- ::HIR::Path(closure_type.clone(), ::HIR::GenericPath(lang_Fn, trait_params.clone()), "call"),
+ ::HIR::Path(closure_type.clone(), ::HIR::GenericPath(lang_Fn, trait_params.clone()), RcString::new_interned("call")),
make_vec2(
- NEWNODE(method_self_ty.clone(), Borrow, sp, ::HIR::BorrowType::Shared, NEWNODE(closure_type.clone(), Variable, sp, "self", 0)),
+ NEWNODE(method_self_ty.clone(), Borrow, sp, ::HIR::BorrowType::Shared, NEWNODE(closure_type.clone(), Variable, sp, RcString::new_interned("self"), 0)),
NEWNODE(args_ty.clone(), Variable, sp, "arg", 1)
)
);
@@ -787,6 +1034,7 @@ namespace {
}
void visit(::HIR::ExprNode_Variable& node) override
{
+ DEBUG("_Variable: #" << node.m_slot << " '" << node.m_name << "' " << node.m_usage);
if( !m_closure_stack.empty() )
{
mark_used_variable(node.span(), node.m_slot, node.m_usage);
@@ -1012,26 +1260,19 @@ namespace {
unsigned int closure_count = 0;
::HIR::SimplePath root_mod_path(crate.m_crate_name,{});
m_cur_mod_path = &root_mod_path;
- m_new_type = [&](auto s)->auto {
- auto name = FMT("closure_I_" << closure_count);
+ m_new_type = [&](const char* suffix, auto s)->auto {
+ auto name = RcString::new_interned(FMT("closure#I_" << closure_count));
closure_count += 1;
- auto boxed = box$(( ::HIR::VisEnt< ::HIR::TypeItem> { false, ::HIR::TypeItem( mv$(s) ) } ));
+ auto boxed = box$(( ::HIR::VisEnt< ::HIR::TypeItem> { ::HIR::Publicity::new_none(), ::HIR::TypeItem( mv$(s) ) } ));
+ auto* ret_ptr = &boxed->ent.as_Struct();
crate.m_root_module.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) );
- return ::HIR::SimplePath(crate.m_crate_name, {}) + name;
+ return ::std::make_pair( ::HIR::SimplePath(crate.m_crate_name, {}) + name, ret_ptr );
};
::HIR::Visitor::visit_crate(crate);
- for(auto& impl : m_new_trait_impls)
- {
- const auto& trait =
- impl.first == ::HIR::ExprNode_Closure::Class::Once ? crate.get_lang_item_path(sp, "fn_once")
- : impl.first == ::HIR::ExprNode_Closure::Class::Mut ? crate.get_lang_item_path(sp, "fn_mut")
- : /*impl.first == ::HIR::ExprNode_Closure::Class::Shared ?*/ crate.get_lang_item_path(sp, "fn")
- ;
- crate.m_trait_impls.insert( ::std::make_pair(trait.clone(), mv$(impl.second)) );
- }
- m_new_trait_impls.resize(0);
+ push_new_impls(sp, crate, mv$(m_new_trait_impls));
+ m_new_trait_impls.clear();
}
void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override
@@ -1040,20 +1281,29 @@ namespace {
auto path = p.get_simple_path();
m_cur_mod_path = &path;
+ ::std::vector< ::std::pair<RcString, std::unique_ptr< ::HIR::VisEnt< ::HIR::TypeItem> > >> new_types;
+
unsigned int closure_count = 0;
auto saved_nt = mv$(m_new_type);
- m_new_type = [&](auto s)->auto {
- auto name = FMT("closure_" << closure_count);
+ m_new_type = [&](const char* suffix, auto s)->auto {
+ // TODO: Use a function on `mod` that adds a closure and makes the indexes be per suffix
+ auto name = RcString( FMT("closure#" << suffix << (suffix[0] ? "_" : "") << closure_count) );
closure_count += 1;
- auto boxed = box$( (::HIR::VisEnt< ::HIR::TypeItem> { false, ::HIR::TypeItem( mv$(s) ) }) );
- mod.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) );
- return (p + name).get_simple_path();
+ auto boxed = box$( (::HIR::VisEnt< ::HIR::TypeItem> { ::HIR::Publicity::new_none(), ::HIR::TypeItem( mv$(s) ) }) );
+ auto* ret_ptr = &boxed->ent.as_Struct();
+ new_types.push_back( ::std::make_pair(name, mv$(boxed)) );
+ return ::std::make_pair( (p + name).get_simple_path(), ret_ptr );
};
::HIR::Visitor::visit_module(p, mod);
m_cur_mod_path = saved;
m_new_type = mv$(saved_nt);
+
+ for(auto& e : new_types)
+ {
+ mod.m_mod_items.insert( mv$(e) );
+ }
}
// NOTE: This is left here to ensure that any expressions that aren't handled by higher code cause a failure
@@ -1088,12 +1338,12 @@ namespace {
DEBUG("Function code " << p);
{
- ExprVisitor_Extract ev(m_resolve, m_self_type, item.m_code.m_bindings, m_new_trait_impls, m_new_type);
+ ExprVisitor_Extract ev(m_resolve, m_self_type, item.m_code.m_bindings, m_new_trait_impls, p.name, m_new_type);
ev.visit_root( *item.m_code );
}
{
- ExprVisitor_Fixup fixup(m_resolve.m_crate, [](const auto& x)->const auto&{ return x; });
+ ExprVisitor_Fixup fixup(m_resolve.m_crate, nullptr, [](const auto& x)->const auto&{ return x; });
fixup.visit_root( item.m_code );
}
}
@@ -1152,6 +1402,8 @@ namespace {
m_self_type = &impl.m_type;
auto _ = this->m_resolve.set_impl_generics(impl.m_params);
+ // TODO: Re-create m_new_type to store in the source module
+
::HIR::Visitor::visit_type_impl(impl);
m_self_type = nullptr;
@@ -1169,9 +1421,50 @@ namespace {
};
}
-void HIR_Expand_Closures_Expr(const ::HIR::Crate& crate, ::HIR::ExprPtr& exp)
+void HIR_Expand_Closures_Expr(const ::HIR::Crate& crate_ro, ::HIR::ExprPtr& exp)
{
- // TODO:
+ Span sp;
+ auto& crate = const_cast<::HIR::Crate&>(crate_ro);
+ TRACE_FUNCTION;
+
+ StaticTraitResolve resolve { crate };
+ assert(exp);
+ if(exp.m_state->m_impl_generics) resolve.set_impl_generics(*exp.m_state->m_impl_generics);
+ if(exp.m_state->m_item_generics) resolve.set_item_generics(*exp.m_state->m_item_generics);
+
+ const ::HIR::TypeRef* self_type = nullptr; // TODO: Need to be able to get this?
+
+ static int closure_count = 0;
+ out_impls_t new_trait_impls;
+ new_type_cb_t new_type_cb = [&](const char* suffix, auto s)->auto {
+ auto name = RcString::new_interned(FMT("closure#C_" << closure_count));
+ closure_count += 1;
+ auto boxed = box$(( ::HIR::VisEnt< ::HIR::TypeItem> { ::HIR::Publicity::new_none(), ::HIR::TypeItem( mv$(s) ) } ));
+ auto* ret_ptr = &boxed->ent.as_Struct();
+ crate.m_root_module.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) );
+ return ::std::make_pair( ::HIR::SimplePath(crate.m_crate_name, {}) + name, ret_ptr );
+ };
+
+ {
+ ExprVisitor_Extract ev(resolve, self_type, exp.m_bindings, new_trait_impls, "", new_type_cb);
+ ev.visit_root( *exp );
+ }
+
+ {
+ ExprVisitor_Fixup fixup(crate, nullptr, [](const auto& x)->const auto&{ return x; });
+ fixup.visit_root( exp );
+ }
+
+ for(auto& impl : new_trait_impls)
+ {
+ for( auto& m : impl.second.m_methods )
+ {
+ m.second.data.m_code.m_state = ::HIR::ExprStatePtr(*exp.m_state);
+ m.second.data.m_code.m_state->stage = ::HIR::ExprState::Stage::Typecheck;
+ }
+ impl.second.m_src_module = exp.m_state->m_mod_path;
+ }
+ push_new_impls(sp, crate, mv$(new_trait_impls));
}
void HIR_Expand_Closures(::HIR::Crate& crate)
diff --git a/src/hir_expand/reborrow.cpp b/src/hir_expand/reborrow.cpp
index cb466f6f..ecf37c64 100644
--- a/src/hir_expand/reborrow.cpp
+++ b/src/hir_expand/reborrow.cpp
@@ -87,6 +87,10 @@ namespace {
return node_ptr;
}
+ void visit(::HIR::ExprNode_Cast& node) override {
+ ::HIR::ExprVisitorDef::visit(node);
+ node.m_value = do_reborrow(mv$(node.m_value));
+ }
void visit(::HIR::ExprNode_Emplace& node) override {
::HIR::ExprVisitorDef::visit(node);
node.m_value = do_reborrow(mv$(node.m_value));
diff --git a/src/hir_expand/ufcs_everything.cpp b/src/hir_expand/ufcs_everything.cpp
index ffdc0a77..79feea32 100644
--- a/src/hir_expand/ufcs_everything.cpp
+++ b/src/hir_expand/ufcs_everything.cpp
@@ -353,10 +353,10 @@ namespace {
{
case ::HIR::ExprNode_BinOp::Op::CmpEqu: { langitem = "eq"; method = "eq"; } if(0)
case ::HIR::ExprNode_BinOp::Op::CmpNEqu:{ langitem = "eq"; method = "ne"; } if(0)
- case ::HIR::ExprNode_BinOp::Op::CmpLt: { langitem = "ord"; method = "lt"; } if(0)
- case ::HIR::ExprNode_BinOp::Op::CmpLtE: { langitem = "ord"; method = "le"; } if(0)
- case ::HIR::ExprNode_BinOp::Op::CmpGt: { langitem = "ord"; method = "gt"; } if(0)
- case ::HIR::ExprNode_BinOp::Op::CmpGtE: { langitem = "ord"; method = "ge"; }
+ case ::HIR::ExprNode_BinOp::Op::CmpLt: { langitem = TARGETVER_1_29 ? "partial_ord" : "ord"; method = "lt"; } if(0)
+ case ::HIR::ExprNode_BinOp::Op::CmpLtE: { langitem = TARGETVER_1_29 ? "partial_ord" : "ord"; method = "le"; } if(0)
+ case ::HIR::ExprNode_BinOp::Op::CmpGt: { langitem = TARGETVER_1_29 ? "partial_ord" : "ord"; method = "gt"; } if(0)
+ case ::HIR::ExprNode_BinOp::Op::CmpGtE: { langitem = TARGETVER_1_29 ? "partial_ord" : "ord"; method = "ge"; }
{
// 1. Check if the types are valid for primitive comparison
if( ty_l == ty_r ) {
diff --git a/src/hir_expand/vtable.cpp b/src/hir_expand/vtable.cpp
index 79e163ac..d2afff5d 100644
--- a/src/hir_expand/vtable.cpp
+++ b/src/hir_expand/vtable.cpp
@@ -17,7 +17,7 @@ namespace {
{
const ::HIR::Crate& m_crate;
//StaticTraitResolve m_resolve;
- ::std::function<::HIR::SimplePath(bool, ::std::string, ::HIR::Struct)> m_new_type;
+ ::std::function<::HIR::SimplePath(bool, RcString, ::HIR::Struct)> m_new_type;
::HIR::SimplePath m_lang_Sized;
public:
OuterVisitor(const ::HIR::Crate& crate):
@@ -32,7 +32,7 @@ namespace {
::std::vector< decltype(mod.m_mod_items)::value_type> new_types;
m_new_type = [&](bool pub, auto name, auto s)->auto {
- auto boxed = box$( (::HIR::VisEnt< ::HIR::TypeItem> { pub, ::HIR::TypeItem( mv$(s) ) }) );
+ auto boxed = box$( (::HIR::VisEnt< ::HIR::TypeItem> { (pub ? ::HIR::Publicity::new_global() : ::HIR::Publicity::new_none()), ::HIR::TypeItem( mv$(s) ) }) );
auto ret = (p + name).get_simple_path();
new_types.push_back( ::std::make_pair( mv$(name), mv$(boxed)) );
return ret;
@@ -72,7 +72,7 @@ namespace {
//TODO(Span(), "Handle conflicting associated types - '" << ty.first << "'");
}
else {
- params.m_types.push_back( ::HIR::TypeParamDef { "a#"+ty.first, {}, ty.second.is_sized } );
+ params.m_types.push_back( ::HIR::TypeParamDef { RcString::new_interned(FMT("a#" << ty.first)), {}, ty.second.is_sized } );
}
i ++;
}
@@ -98,14 +98,14 @@ namespace {
auto clone_cb = [&](const auto& t, auto& o) {
if(t.m_data.is_Path() && t.m_data.as_Path().path.m_data.is_UfcsKnown()) {
const auto& pe = t.m_data.as_Path().path.m_data.as_UfcsKnown();
- bool is_self = (*pe.type == ::HIR::TypeRef("Self", 0xFFFF));
+ bool is_self = (*pe.type == ::HIR::TypeRef(RcString::new_interned("Self"), 0xFFFF));
auto it = trait_ptr->m_type_indexes.find(pe.item);
bool has_item = (it != trait_ptr->m_type_indexes.end());
// TODO: Check the trait against m_type_indexes
if( is_self /*&& pe.trait == trait_path*/ && has_item ) {
DEBUG("[clone_cb] t=" << t << " -> " << it->second);
// Replace with a new type param, need to know the index of it
- o = ::HIR::TypeRef("a#"+pe.item, it->second);
+ o = ::HIR::TypeRef( RcString::new_interned(FMT("a#" << pe.item)), it->second);
return true;
}
else {
@@ -173,7 +173,7 @@ namespace {
DEBUG("- '" << vi.first << "' is @" << fields.size());
fields.push_back( ::std::make_pair(
vi.first,
- ::HIR::VisEnt< ::HIR::TypeRef> { true, mv$(fcn_type) }
+ ::HIR::VisEnt< ::HIR::TypeRef> { ::HIR::Publicity::new_global(), mv$(fcn_type) }
) );
),
(Static,
@@ -204,11 +204,11 @@ namespace {
ft.m_abi = ABI_RUST;
ft.m_rettype.reset( new ::HIR::TypeRef(::HIR::TypeRef::new_unit()) );
ft.m_arg_types.push_back( ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Owned, ::HIR::TypeRef::new_unit()) );
- vtc.fields.push_back(::std::make_pair( "#drop_glue", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::TypeRef(mv$(ft)) } ));
+ vtc.fields.push_back(::std::make_pair( "#drop_glue", ::HIR::VisEnt<::HIR::TypeRef> { ::HIR::Publicity::new_none(), ::HIR::TypeRef(mv$(ft)) } ));
// - Size of data
- vtc.fields.push_back(::std::make_pair( "#size", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::CoreType::Usize } ));
+ vtc.fields.push_back(::std::make_pair( "#size", ::HIR::VisEnt<::HIR::TypeRef> { ::HIR::Publicity::new_none(), ::HIR::CoreType::Usize } ));
// - Alignment of data
- vtc.fields.push_back(::std::make_pair( "#align", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::CoreType::Usize } ));
+ vtc.fields.push_back(::std::make_pair( "#align", ::HIR::VisEnt<::HIR::TypeRef> { ::HIR::Publicity::new_none(), ::HIR::CoreType::Usize } ));
// - Add methods
if( ! vtc.add_ents_from_trait(tr, trait_path) )
{
@@ -231,12 +231,12 @@ namespace {
}
}
// TODO: Would like to have access to the publicity marker
- auto item_path = m_new_type(true, FMT(p.get_name() << "#vtable"), ::HIR::Struct {
- mv$(args),
- ::HIR::Struct::Repr::Rust,
- ::HIR::Struct::Data(mv$(fields)),
- {}
- });
+ auto item_path = m_new_type(
+ true,
+ RcString::new_interned(FMT(p.get_name() << "#vtable")),
+ ::HIR::Struct(mv$(args), ::HIR::Struct::Repr::Rust, ::HIR::Struct::Data(mv$(fields)))
+ );
+ tr.m_vtable_path = item_path;
DEBUG("Vtable structure created - " << item_path);
::HIR::GenericPath path( mv$(item_path), mv$(params) );
diff --git a/src/hir_typeck/common.cpp b/src/hir_typeck/common.cpp
index e78ed21b..1bb21f99 100644
--- a/src/hir_typeck/common.cpp
+++ b/src/hir_typeck/common.cpp
@@ -113,6 +113,10 @@ bool visit_ty_with(const ::HIR::TypeRef& ty, t_cb_visit_ty callback)
)
return false;
}
+bool visit_path_tys_with(const ::HIR::Path& path, t_cb_visit_ty callback)
+{
+ return visit_ty_with__path(path, callback);
+}
bool monomorphise_pathparams_needed(const ::HIR::PathParams& tpl)
{
@@ -140,7 +144,7 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl)
}
-::HIR::PathParams clone_ty_with__path_params(const Span& sp, const ::HIR::PathParams& tpl, t_cb_clone_ty callback) {
+::HIR::PathParams clone_path_params_with(const Span& sp, const ::HIR::PathParams& tpl, t_cb_clone_ty callback) {
::HIR::PathParams rv;
rv.m_types.reserve( tpl.m_types.size() );
for( const auto& ty : tpl.m_types)
@@ -148,7 +152,7 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl)
return rv;
}
::HIR::GenericPath clone_ty_with__generic_path(const Span& sp, const ::HIR::GenericPath& tpl, t_cb_clone_ty callback) {
- return ::HIR::GenericPath( tpl.m_path, clone_ty_with__path_params(sp, tpl.m_params, callback) );
+ return ::HIR::GenericPath( tpl.m_path, clone_path_params_with(sp, tpl.m_params, callback) );
}
::HIR::TraitPath clone_ty_with__trait_path(const Span& sp, const ::HIR::TraitPath& tpl, t_cb_clone_ty callback) {
::HIR::TraitPath rv {
@@ -177,22 +181,22 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl)
box$( clone_ty_with(sp, *e2.type, callback) ),
clone_ty_with__generic_path(sp, e2.trait, callback),
e2.item,
- clone_ty_with__path_params(sp, e2.params, callback)
+ clone_path_params_with(sp, e2.params, callback)
});
),
(UfcsUnknown,
return ::HIR::Path::Data::make_UfcsUnknown({
box$( clone_ty_with(sp, *e2.type, callback) ),
e2.item,
- clone_ty_with__path_params(sp, e2.params, callback)
+ clone_path_params_with(sp, e2.params, callback)
});
),
(UfcsInherent,
return ::HIR::Path::Data::make_UfcsInherent({
box$( clone_ty_with(sp, *e2.type, callback) ),
e2.item,
- clone_ty_with__path_params(sp, e2.params, callback),
- clone_ty_with__path_params(sp, e2.impl_params, callback)
+ clone_path_params_with(sp, e2.params, callback),
+ clone_path_params_with(sp, e2.impl_params, callback)
});
)
)
@@ -203,7 +207,7 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl)
::HIR::TypeRef rv;
if( callback(tpl, rv) ) {
- DEBUG(tpl << " => " << rv);
+ //DEBUG(tpl << " => " << rv);
return rv;
}
@@ -222,8 +226,9 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl)
clone_ty_with__path(sp, e.path, callback),
e.binding.clone()
} );
- // If the input binding was Opaque, clear it back to Unbound
- if( e.binding.is_Opaque() ) {
+ // If the input binding was Opaque, AND the type changed, clear it back to Unbound
+ if( e.binding.is_Opaque() /*&& rv != tpl*/ ) {
+ // NOTE: The replacement can be Self=Self, which should trigger a binding clear.
rv.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding();
}
),
@@ -319,7 +324,7 @@ namespace {
::HIR::PathParams monomorphise_path_params_with(const Span& sp, const ::HIR::PathParams& tpl, t_cb_generic callback, bool allow_infer)
{
- return clone_ty_with__path_params(sp, tpl, monomorphise_type_with__closure(sp, tpl, callback, allow_infer));
+ return clone_path_params_with(sp, tpl, monomorphise_type_with__closure(sp, tpl, callback, allow_infer));
}
::HIR::GenericPath monomorphise_genericpath_with(const Span& sp, const ::HIR::GenericPath& tpl, t_cb_generic callback, bool allow_infer)
{
diff --git a/src/hir_typeck/common.hpp b/src/hir_typeck/common.hpp
index 09a5d9b2..9d662100 100644
--- a/src/hir_typeck/common.hpp
+++ b/src/hir_typeck/common.hpp
@@ -29,14 +29,33 @@ extern ::HIR::Path monomorphise_path_with(const Span& sp, const ::HIR::Path& tpl
extern ::HIR::TypeRef monomorphise_type_with(const Span& sp, const ::HIR::TypeRef& tpl, t_cb_generic callback, bool allow_infer=true);
extern ::HIR::TypeRef monomorphise_type(const Span& sp, const ::HIR::GenericParams& params_def, const ::HIR::PathParams& params, const ::HIR::TypeRef& tpl);
+// Wrappers to only monomorphise if required
+static inline const ::HIR::TypeRef& monomorphise_type_with_opt(const Span& sp, ::HIR::TypeRef& tmp, const ::HIR::TypeRef& tpl, t_cb_generic callback, bool allow_infer=true) {
+ return (monomorphise_type_needed(tpl) ? tmp = monomorphise_type_with(sp, tpl, callback, allow_infer) : tpl);
+}
+static inline const ::HIR::Path& monomorphise_path_with_opt(const Span& sp, ::HIR::Path& tmp, const ::HIR::Path& tpl, t_cb_generic callback, bool allow_infer=true) {
+ return (monomorphise_path_needed(tpl) ? tmp = monomorphise_path_with(sp, tpl, callback, allow_infer) : tpl);
+}
+static inline const ::HIR::GenericPath& monomorphise_genericpath_with_opt(const Span& sp, ::HIR::GenericPath& tmp, const ::HIR::GenericPath& tpl, t_cb_generic callback, bool allow_infer=true) {
+ return (monomorphise_genericpath_needed(tpl) ? tmp = monomorphise_genericpath_with(sp, tpl, callback, allow_infer) : tpl);
+}
+static inline const ::HIR::TraitPath& monomorphise_traitpath_with_opt(const Span& sp, ::HIR::TraitPath& tmp, const ::HIR::TraitPath& tpl, t_cb_generic callback, bool allow_infer=true) {
+ return (monomorphise_traitpath_needed(tpl) ? tmp = monomorphise_traitpath_with(sp, tpl, callback, allow_infer) : tpl);
+}
+static inline const ::HIR::PathParams& monomorphise_pathparams_with_opt(const Span& sp, ::HIR::PathParams& tmp, const ::HIR::PathParams& tpl, t_cb_generic callback, bool allow_infer=true) {
+ return (monomorphise_pathparams_needed(tpl) ? tmp = monomorphise_path_params_with(sp, tpl, callback, allow_infer) : tpl);
+}
+
typedef ::std::function<bool(const ::HIR::TypeRef&)> t_cb_visit_ty;
/// Calls the provided callback on every type seen when recursing the type.
/// If the callback returns `true`, no further types are visited and the function returns `true`.
extern bool visit_ty_with(const ::HIR::TypeRef& ty, t_cb_visit_ty callback);
+extern bool visit_path_tys_with(const ::HIR::Path& ty, t_cb_visit_ty callback);
typedef ::std::function<bool(const ::HIR::TypeRef&, ::HIR::TypeRef&)> t_cb_clone_ty;
/// Clones a type, calling the provided callback on every type (optionally providing a replacement)
extern ::HIR::TypeRef clone_ty_with(const Span& sp, const ::HIR::TypeRef& tpl, t_cb_clone_ty callback);
+extern ::HIR::PathParams clone_path_params_with(const Span& sp, const ::HIR::PathParams& tpl, t_cb_clone_ty callback);
// Helper for passing a group of params around
struct MonomorphState
@@ -119,3 +138,6 @@ static inline t_cb_generic monomorphise_type_get_cb(const Span& sp, const ::HIR:
}
extern void check_type_class_primitive(const Span& sp, const ::HIR::TypeRef& type, ::HIR::InferClass ic, ::HIR::CoreType ct);
+
+class StaticTraitResolve;
+extern void Typecheck_Expressions_ValidateOne(const StaticTraitResolve& resolve, const ::std::vector<::std::pair< ::HIR::Pattern, ::HIR::TypeRef>>& args, const ::HIR::TypeRef& ret_ty, const ::HIR::ExprPtr& code);
diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp
index 319124ad..7abe5532 100644
--- a/src/hir_typeck/expr_check.cpp
+++ b/src/hir_typeck/expr_check.cpp
@@ -22,14 +22,18 @@ namespace {
const ::HIR::TypeRef& ret_type;
::std::vector< const ::HIR::TypeRef*> closure_ret_types;
::std::vector<const ::HIR::ExprNode_Loop*> m_loops;
+ //const ::HIR::ExprPtr* m_cur_expr;
::HIR::SimplePath m_lang_Index;
public:
+ bool expand_erased_types;
+
ExprVisitor_Validate(const StaticTraitResolve& res, const t_args& args, const ::HIR::TypeRef& ret_type):
m_resolve(res),
//m_args(args),
ret_type(ret_type)
+ ,expand_erased_types(true)
{
m_lang_Index = m_resolve.m_crate.get_lang_item_path_opt("index");
}
@@ -131,6 +135,7 @@ namespace {
TRACE_FUNCTION_F(&node << " let " << node.m_pattern << ": " << node.m_type);
if(node.m_value)
{
+ check_pattern(node.m_pattern, node.m_value->m_res_type);
check_types_equal(node.span(), node.m_type, node.m_value->m_res_type);
node.m_value->visit(*this);
}
@@ -141,6 +146,10 @@ namespace {
node.m_value->visit(*this);
for(auto& arm : node.m_arms)
{
+ for(const auto& pat : arm.m_patterns)
+ {
+ check_pattern(pat, node.m_value->m_res_type);
+ }
check_types_equal(node.span(), node.m_res_type, arm.m_code->m_res_type);
arm.m_code->visit( *this );
}
@@ -149,9 +158,11 @@ namespace {
{
TRACE_FUNCTION_F(&node << " if ... { ... } else { ... }");
node.m_cond->visit( *this );
+ node.m_true->visit( *this );
check_types_equal(node.span(), node.m_res_type, node.m_true->m_res_type);
if( node.m_false )
{
+ node.m_false->visit( *this );
check_types_equal(node.span(), node.m_res_type, node.m_false->m_res_type);
}
}
@@ -208,10 +219,10 @@ namespace {
{
case ::HIR::ExprNode_BinOp::Op::CmpEqu: item_name = "eq"; break;
case ::HIR::ExprNode_BinOp::Op::CmpNEqu: item_name = "eq"; break;
- case ::HIR::ExprNode_BinOp::Op::CmpLt: item_name = "ord"; break;
- case ::HIR::ExprNode_BinOp::Op::CmpLtE: item_name = "ord"; break;
- case ::HIR::ExprNode_BinOp::Op::CmpGt: item_name = "ord"; break;
- case ::HIR::ExprNode_BinOp::Op::CmpGtE: item_name = "ord"; break;
+ case ::HIR::ExprNode_BinOp::Op::CmpLt: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break;
+ case ::HIR::ExprNode_BinOp::Op::CmpLtE: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break;
+ case ::HIR::ExprNode_BinOp::Op::CmpGt: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break;
+ case ::HIR::ExprNode_BinOp::Op::CmpGtE: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break;
default: break;
}
assert(item_name);
@@ -306,11 +317,10 @@ namespace {
}
// Check castability
- TU_MATCH_DEF(::HIR::TypeRef::Data, (dst_ty.m_data), (de),
- (
- ERROR(sp, E0000, "Invalid cast to " << dst_ty);
- ),
- (Pointer,
+ TU_MATCH_HDRA( (dst_ty.m_data), {)
+ default:
+ ERROR(sp, E0000, "Invalid cast to\n " << dst_ty << "\n from\n " << src_ty);
+ TU_ARMA(Pointer, de) {
TU_MATCH_DEF(::HIR::TypeRef::Data, (src_ty.m_data), (se),
(
ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty);
@@ -346,11 +356,40 @@ namespace {
this->check_types_equal(sp, *de.inner, *se.inner);
)
)
- ),
- (Primitive,
+ }
+ TU_ARMA(Function, de) {
+ // NOTE: cast fn() only valid from:
+ // - the same function pointer (already checked, but eventually could be a stripping of the path tag)
+ // - A capture-less closure
+ TU_MATCH_HDRA( (src_ty.m_data), {)
+ default:
+ ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty);
+ break;
+ TU_ARMA(Function, se) {
+ if( se.is_unsafe != de.is_unsafe && se.is_unsafe )
+ ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - removing unsafe");
+ if( se.m_abi != de.m_abi )
+ ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - different ABI");
+ if( *se.m_rettype != *de.m_rettype )
+ ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - return type different");
+ if( se.m_arg_types.size() != de.m_arg_types.size() )
+ ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - argument count different");
+ for( size_t i = 0; i < se.m_arg_types.size(); i ++)
+ {
+ if( se.m_arg_types[i] != de.m_arg_types[i] )
+ ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty << " - argument " << i << " different");
+ }
+ }
+ TU_ARMA(Closure, se) {
+ // Allowed, but won't exist after expansion
+ // TODO: Check argument types
+ }
+ }
+ }
+ TU_ARMA(Primitive, de) {
// TODO: Check cast to primitive
- )
- )
+ }
+ }
node.m_value->visit( *this );
}
@@ -362,7 +401,12 @@ namespace {
const auto& src_ty = node.m_value->m_res_type;
const auto& dst_ty = node.m_res_type;
- if( src_ty == dst_ty )
+ if( src_ty.m_data.is_Array() )
+ {
+ ASSERT_BUG(sp, dst_ty.m_data.is_Slice(), "");
+ ASSERT_BUG(sp, node.m_usage == ::HIR::ValueUsage::Unknown, "");
+ }
+ else if( src_ty == dst_ty )
{
}
else if( src_ty.m_data.is_Borrow() && dst_ty.m_data.is_Borrow() )
@@ -462,6 +506,9 @@ namespace {
(Union,
BUG(sp, "Union in TupleVariant");
),
+ (ExternType,
+ BUG(sp, "ExternType in TupleVariant");
+ ),
(Struct,
ASSERT_BUG(sp, e->m_data.is_Tuple(), "Pointed struct in TupleVariant (" << node.m_path << ") isn't a Tuple");
fields_ptr = &e->m_data.as_Tuple();
@@ -496,6 +543,8 @@ namespace {
if( node.m_base_value) {
check_types_equal( node.m_base_value->span(), node.m_res_type, node.m_base_value->m_res_type );
}
+ ASSERT_BUG(sp, node.m_path.m_data.is_Generic(), "_StructLiteral with non-Generic path - " << node.m_path);
+ auto& ty_path = node.m_path.m_data.as_Generic();
// - Create ivars in path, and set result type
const auto& ty = node.m_res_type;
@@ -506,7 +555,7 @@ namespace {
(Unbound, ),
(Opaque, ),
(Enum,
- const auto& var_name = node.m_path.m_path.m_components.back();
+ const auto& var_name = ty_path.m_path.m_components.back();
const auto& enm = *e;
auto idx = enm.find_variant(var_name);
ASSERT_BUG(sp, idx != SIZE_MAX, "");
@@ -520,6 +569,9 @@ namespace {
(Union,
TODO(sp, "Union in StructLiteral");
),
+ (ExternType,
+ BUG(sp, "ExternType in StructLiteral");
+ ),
(Struct,
if( e->m_data.is_Unit() )
{
@@ -536,7 +588,7 @@ namespace {
const ::HIR::t_struct_fields& fields = *fields_ptr;
#if 1
- const auto& ty_params = node.m_path.m_params.m_types;
+ const auto& ty_params = ty_path.m_params.m_types;
auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& {
const auto& ge = gt.m_data.as_Generic();
if( ge.binding == 0xFFFF ) {
@@ -609,6 +661,9 @@ namespace {
(Union,
BUG(sp, "Union with _UnitVariant");
),
+ (ExternType,
+ BUG(sp, "ExternType with _UnitVariant");
+ ),
(Struct,
assert( e->m_data.is_Unit() );
)
@@ -631,8 +686,8 @@ namespace {
const ::HIR::Function* fcn_ptr = nullptr;
::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> monomorph_cb;
- TU_MATCH(::HIR::Path::Data, (path.m_data), (e),
- (Generic,
+ TU_MATCH_HDRA( (path.m_data), {)
+ TU_ARMA(Generic, e) {
const auto& path_params = e.m_params;
const auto& fcn = m_resolve.m_crate.get_function_by_path(sp, e.m_path);
@@ -657,8 +712,8 @@ namespace {
BUG(sp, "Generic bounding out of total range");
}
};
- ),
- (UfcsKnown,
+ }
+ TU_ARMA(UfcsKnown, e) {
const auto& trait_params = e.trait.m_params;
const auto& path_params = e.params;
@@ -677,11 +732,11 @@ namespace {
fcn_ptr = &fcn;
monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &trait_params, &path_params);
- ),
- (UfcsUnknown,
+ }
+ TU_ARMA(UfcsUnknown, e) {
TODO(sp, "Hit a UfcsUnknown (" << path << ") - Is this an error?");
- ),
- (UfcsInherent,
+ }
+ TU_ARMA(UfcsInherent, e) {
// - Locate function (and impl block)
const ::HIR::TypeImpl* impl_ptr = nullptr;
m_resolve.m_crate.find_type_impls(*e.type, [&](const auto& ty)->const ::HIR::TypeRef& { return ty; },
@@ -703,14 +758,15 @@ namespace {
// NOTE: Trusts the existing cache.
- ASSERT_BUG(sp, e.impl_params.m_types.size() == impl_ptr->m_params.m_types.size(), "");
+ ASSERT_BUG(sp, e.impl_params.m_types.size() == impl_ptr->m_params.m_types.size(),
+ "Path impl_params cache is missized - " << e.impl_params.m_types.size() << " != " << impl_ptr->m_params.m_types.size());
auto& impl_params = e.impl_params;
// Create monomorphise callback
const auto& fcn_params = e.params;
monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &impl_params, &fcn_params);
- )
- )
+ }
+ }
assert( fcn_ptr );
const auto& fcn = *fcn_ptr;
@@ -733,7 +789,7 @@ namespace {
rv = monomorph_cb(tpl).clone();
return true;
}
- else if( tpl.m_data.is_ErasedType() ) {
+ else if( this->expand_erased_types && tpl.m_data.is_ErasedType() ) {
const auto& e = tpl.m_data.as_ErasedType();
ASSERT_BUG(sp, e.m_index < fcn_ptr->m_code.m_erased_types.size(), "");
@@ -789,7 +845,7 @@ namespace {
// TODO: Either - Don't include the above impl bound, or change the below trait to the one that has that type
for( const auto& assoc : be.trait.m_type_bounds ) {
::HIR::GenericPath type_trait_path;
- bool has_ty = m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first, type_trait_path);
+ bool has_ty = m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first.c_str(), type_trait_path);
ASSERT_BUG(sp, has_ty, "Type " << assoc.first << " not found in chain of " << real_trait);
auto other_ty = monomorphise_type_with(sp, assoc.second, cache.m_monomorph_cb, true);
@@ -825,6 +881,9 @@ namespace {
}
check_types_equal(node.span(), node.m_res_type, *e.m_rettype);
)
+ else if( node.m_trait_used == ::HIR::ExprNode_CallValue::TraitUsed::Unknown )
+ {
+ }
else
{
// 1. Look up the encoded trait
@@ -888,7 +947,7 @@ namespace {
const auto& sp = node.span();
const auto& str_ty = node.m_value->m_res_type;
- bool is_index = ( '0' <= node.m_field[0] && node.m_field[0] <= '9' );
+ bool is_index = ( '0' <= node.m_field.c_str()[0] && node.m_field.c_str()[0] <= '9' );
if( str_ty.m_data.is_Tuple() )
{
ASSERT_BUG(sp, is_index, "Non-index _Field on tuple");
@@ -1050,6 +1109,16 @@ namespace {
}
void check_types_equal(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) const
{
+ // TODO: Recurse when an erased type is encountered
+ //if( const auto* e = l.m_data.opt_ErasedType() )
+ //{
+ // return check_types_equal(sp, m_cur_expr->m_erased_types.at(e->m_index), r);
+ //}
+ //if( const auto* e = r.m_data.opt_ErasedType() )
+ //{
+ // return check_types_equal(sp, l, m_cur_expr->m_erased_types.at(e->m_index));
+ //}
+ //DEBUG(sp << " - " << l << " == " << r);
if( /*l.m_data.is_Diverge() ||*/ r.m_data.is_Diverge() ) {
// Diverge, matches everything.
// TODO: Is this always true?
@@ -1097,6 +1166,89 @@ namespace {
ERROR(sp, E0000, "Cannot find an impl of " << trait << params << " for " << ity);
}
}
+ void check_pattern(const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty) const
+ {
+ Span sp;
+ TU_MATCH_HDRA( (pat.m_data), { )
+ TU_ARMA(Any, pe) {
+ // Don't care
+ }
+ TU_ARMA(Box, pe) {
+ // TODO: Assert that `ty` is an owned_box
+ }
+ TU_ARMA(Ref, pe) {
+ // TODO: Assert that `ty` is a &-ptr
+ }
+ TU_ARMA(Tuple, pe) {
+ // TODO: Check for a matching tuple size
+ }
+ TU_ARMA(SplitTuple, pe) {
+ // TODO: Check for a matching tuple size
+ }
+ TU_ARMA(StructValue, pe) {
+ // TODO: Check that the type matches the struct
+ }
+ TU_ARMA(StructTuple, pe) {
+ // TODO: Destructure
+ }
+ TU_ARMA(Struct, pe) {
+ // TODO: Destructure
+ }
+
+ TU_ARMA(Value, pe) {
+ this->check_pattern_value(sp, pe.val, ty);
+ }
+ TU_ARMA(Range, pe) {
+ this->check_pattern_value(sp, pe.start, ty);
+ this->check_pattern_value(sp, pe.end, ty);
+ }
+ TU_ARMA(EnumValue, e) {
+ // TODO: Check type
+ }
+ TU_ARMA(EnumTuple, e) {
+ // TODO: Destructure
+ }
+ TU_ARMA(EnumStruct, e) {
+ // TODO: Destructure
+ }
+ TU_ARMA(Slice, e) {
+ // TODO: Check that the type is a Slice or Array
+ // - Array must match size
+ }
+ TU_ARMA(SplitSlice, e) {
+ // TODO: Check that the type is a Slice or Array
+ // - Array must have compatible size
+ }
+ }
+ }
+ void check_pattern_value(const Span& sp, const ::HIR::Pattern::Value& pv, const ::HIR::TypeRef& ty) const
+ {
+ TU_MATCH_HDRA( (pv), { )
+ TU_ARMA(Integer, e) {
+ if( e.type == ::HIR::CoreType::Str ) {
+ }
+ else {
+ check_types_equal(sp, ty, e.type);
+ }
+ }
+ TU_ARMA(Float, e) {
+ if( e.type == ::HIR::CoreType::Str ) {
+ }
+ else {
+ check_types_equal(sp, ty, e.type);
+ }
+ }
+ TU_ARMA(String, e) {
+ check_types_equal(sp, ty, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::CoreType::Str));
+ }
+ TU_ARMA(ByteString, e) {
+ check_types_equal(sp, ty, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_slice(::HIR::CoreType::U8)));
+ }
+ TU_ARMA(Named, e) {
+ // TODO: Get type of the value and check equality
+ }
+ }
+ }
const ::HIR::SimplePath& get_lang_item_path(const Span& sp, const char* name) const
{
@@ -1166,6 +1318,7 @@ namespace {
ExprVisitor_Validate ev(m_resolve, tmp, item.m_type);
ev.visit_root(item.m_value);
}
+ m_resolve.expand_associated_types(Span(), item.m_type);
}
void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override {
//auto _ = this->m_ms.set_item_generics(item.m_params);
@@ -1210,6 +1363,13 @@ namespace {
};
}
+void Typecheck_Expressions_ValidateOne(const StaticTraitResolve& resolve, const ::std::vector<::std::pair< ::HIR::Pattern, ::HIR::TypeRef>>& args, const ::HIR::TypeRef& ret_ty, const ::HIR::ExprPtr& code)
+{
+ ExprVisitor_Validate ev(resolve, args, ret_ty);
+ ev.expand_erased_types = false; // TODO: Make this an argument, we don't want to do this too early
+ ev.visit_root( const_cast<::HIR::ExprPtr&>(code) );
+}
+
void Typecheck_Expressions_Validate(::HIR::Crate& crate)
{
OuterVisitor ov(crate);
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index 363dfeeb..8a374946 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -11,11 +11,32 @@
#include <hir/visitor.hpp>
#include <algorithm> // std::find_if
+#include <hir_typeck/static.hpp>
#include "helpers.hpp"
#include "expr_visit.hpp"
namespace {
inline HIR::ExprNodeP mk_exprnodep(HIR::ExprNode* en, ::HIR::TypeRef ty){ en->m_res_type = mv$(ty); return HIR::ExprNodeP(en); }
+
+ inline ::HIR::SimplePath get_parent_path(const ::HIR::SimplePath& sp) {
+ auto rv = sp;
+ rv.m_components.pop_back();
+ return rv;
+ }
+ inline ::HIR::GenericPath get_parent_path(const ::HIR::GenericPath& gp) {
+ auto rv = gp.clone();
+ rv.m_path.m_components.pop_back();
+ return rv;
+ }
+
+ bool type_contains_impl_placeholder(const ::HIR::TypeRef& t) {
+ return visit_ty_with(t, [&](const auto& ty)->bool {
+ if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding >> 8 == 2 ) {
+ return true;
+ }
+ return false;
+ });
+ }
}
#define NEWNODE(TY, SP, CLASS, ...) mk_exprnodep(new HIR::ExprNode##CLASS(SP ,## __VA_ARGS__), TY)
@@ -26,13 +47,14 @@ struct Context
{
public:
virtual ~Revisitor() = default;
+ virtual const Span& span() const = 0;
virtual void fmt(::std::ostream& os) const = 0;
- virtual bool revisit(Context& context) = 0;
+ virtual bool revisit(Context& context, bool is_fallback) = 0;
};
struct Binding
{
- ::std::string name;
+ RcString name;
::HIR::TypeRef ty;
//unsigned int ivar;
};
@@ -40,47 +62,58 @@ struct Context
/// Inferrence variable equalities
struct Coercion
{
+ unsigned rule_idx;
::HIR::TypeRef left_ty;
::HIR::ExprNodeP* right_node_ptr;
friend ::std::ostream& operator<<(::std::ostream& os, const Coercion& v) {
- os << v.left_ty << " := " << v.right_node_ptr << " " << &**v.right_node_ptr << " (" << (*v.right_node_ptr)->m_res_type << ")";
+ os << "R" << v.rule_idx << " " << v.left_ty << " := " << v.right_node_ptr << " " << &**v.right_node_ptr << " (" << (*v.right_node_ptr)->m_res_type << ")";
return os;
}
};
struct Associated
{
+ unsigned rule_idx;
Span span;
::HIR::TypeRef left_ty;
::HIR::SimplePath trait;
::HIR::PathParams params;
::HIR::TypeRef impl_ty;
- ::std::string name; // if "", no type is used (and left is ignored) - Just does trait selection
+ RcString name; // if "", no type is used (and left is ignored) - Just does trait selection
// HACK: operators are special - the result when both types are primitives is ALWAYS the lefthand side
bool is_operator;
friend ::std::ostream& operator<<(::std::ostream& os, const Associated& v) {
+ os << "R" << v.rule_idx << " ";
if( v.name == "" ) {
os << "req ty " << v.impl_ty << " impl " << v.trait << v.params;
}
else {
os << v.left_ty << " = " << "< `" << v.impl_ty << "` as `" << v.trait << v.params << "` >::" << v.name;
}
+ if( v.is_operator )
+ os << " - op";
return os;
}
};
struct IVarPossible
{
+ bool force_disable = false;
bool force_no_to = false;
bool force_no_from = false;
+ // Target types for coercion/unsizing (these types are known to exist in the function)
::std::vector<::HIR::TypeRef> types_coerce_to;
::std::vector<::HIR::TypeRef> types_unsize_to;
+ // Source types for coercion/unsizing (these types are known to exist in the function)
::std::vector<::HIR::TypeRef> types_coerce_from;
::std::vector<::HIR::TypeRef> types_unsize_from;
+ // Possible default types (from generic defaults)
//::std::vector<::HIR::TypeRef> types_default;
+ // Possible types from trait impls (may introduce new types)
+ ::std::vector<::HIR::TypeRef> bounded;
void reset() {
//auto tmp = mv$(this->types_default);
@@ -88,7 +121,19 @@ struct Context
//this->types_default = mv$(tmp);
}
bool has_rules() const {
- return !types_unsize_to.empty() || !types_coerce_to.empty() || !types_unsize_from.empty() || !types_coerce_from.empty() /* || !types_default.empty()*/;
+ if( !types_coerce_to.empty() )
+ return true;
+ if( !types_unsize_to.empty() )
+ return true;
+ if( !types_coerce_from.empty() )
+ return true;
+ if( !types_unsize_from.empty() )
+ return true;
+ //if( !types_default.empty() )
+ // return true;
+ if( !bounded.empty() )
+ return true;
+ return false;
}
};
@@ -98,6 +143,7 @@ struct Context
HMTypeInferrence m_ivars;
TraitResolution m_resolve;
+ unsigned next_rule_idx;
::std::vector<Coercion> link_coerce;
::std::vector<Associated> link_assoc;
/// Nodes that need revisiting (e.g. method calls when the receiver isn't known)
@@ -105,15 +151,18 @@ struct Context
/// Callback-based revisits (e.g. for slice patterns handling slices/arrays)
::std::vector< ::std::unique_ptr<Revisitor> > adv_revisits;
+ // Keep track of if an ivar is used in a context where it has to be Sized
+ // - If it is, then we can discount any unsized possibilities
::std::vector<bool> m_ivars_sized;
::std::vector< IVarPossible> possible_ivar_vals;
const ::HIR::SimplePath m_lang_Box;
- Context(const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params):
+ Context(const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params, const ::HIR::SimplePath& mod_path):
m_crate(crate),
- m_resolve(m_ivars, crate, impl_params, item_params),
- m_lang_Box( crate.get_lang_item_path_opt("owned_box") )
+ m_resolve(m_ivars, crate, impl_params, item_params, mod_path)
+ ,next_rule_idx( 0 )
+ ,m_lang_Box( crate.get_lang_item_path_opt("owned_box") )
{
}
@@ -164,6 +213,7 @@ struct Context
equate_types_shadow(sp, l, false);
}
void equate_types_shadow(const Span& sp, const ::HIR::TypeRef& ty, bool is_to);
+ void equate_types_shadow_strong(const Span& sp, const ::HIR::TypeRef& ty);
/// Possible type that this ivar can coerce to
void possible_equate_type_coerce_to(unsigned int ivar_index, const ::HIR::TypeRef& t) {
@@ -191,15 +241,19 @@ struct Context
}
/// Default type
//void possible_equate_type_def(unsigned int ivar_index, const ::HIR::TypeRef& t);
+ /// Add a possible type for an ivar (which is used if only one possibility meets available bounds)
+ void possible_equate_type_bound(const Span& sp, unsigned int ivar_index, const ::HIR::TypeRef& t);
void possible_equate_type(unsigned int ivar_index, const ::HIR::TypeRef& t, bool is_to, bool is_borrow);
void possible_equate_type_disable(unsigned int ivar_index, bool is_to);
+ void possible_equate_type_disable_strong(const Span& sp, unsigned int ivar_index);
// - Add a pattern binding (forcing the type to match)
- void add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type);
+ void handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type);
+ void handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type);
void add_binding_inner(const Span& sp, const ::HIR::PatternBinding& pb, ::HIR::TypeRef type);
- void add_var(const Span& sp, unsigned int index, const ::std::string& name, ::HIR::TypeRef type);
+ void add_var(const Span& sp, unsigned int index, const RcString& name, ::HIR::TypeRef type);
const ::HIR::TypeRef& get_var(const Span& sp, unsigned int idx) const;
// - Add a revisit entry
@@ -224,6 +278,7 @@ namespace {
void apply_bounds_as_rules(Context& context, const Span& sp, const ::HIR::GenericParams& params_def, t_cb_generic monomorph_cb, bool is_impl_level)
{
+ TRACE_FUNCTION;
for(const auto& bound : params_def.m_bounds)
{
TU_MATCH(::HIR::GenericBound, (bound), (be),
@@ -250,7 +305,7 @@ namespace {
::HIR::GenericPath type_trait_path;
ASSERT_BUG(sp, be.trait.m_trait_ptr, "Trait pointer not set in " << be.trait.m_path);
// TODO: Store the source trait for this bound in the the bound list?
- if( !context.m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first, type_trait_path) )
+ if( !context.m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first.c_str(), type_trait_path) )
BUG(sp, "Couldn't find associated type " << assoc.first << " in trait " << real_trait);
auto other_ty = monomorphise_type_with(sp, assoc.second, monomorph_cb, true);
@@ -377,11 +432,13 @@ namespace {
// --- Monomorphise the argument/return types (into current context)
for(const auto& arg : fcn.m_args) {
- DEBUG("Arg " << arg.first << ": " << arg.second);
+ TRACE_FUNCTION_FR(path << " - Arg " << arg.first << ": " << arg.second, "Arg " << arg.first << " : " << cache.m_arg_types.back());
cache.m_arg_types.push_back( monomorphise_type_with(sp, arg.second, monomorph_cb, false) );
}
- DEBUG("Ret " << fcn.m_return);
- cache.m_arg_types.push_back( monomorphise_type_with(sp, fcn.m_return, monomorph_cb, false) );
+ {
+ TRACE_FUNCTION_FR(path << " - Ret " << fcn.m_return, "Ret " << cache.m_arg_types.back());
+ cache.m_arg_types.push_back( monomorphise_type_with(sp, fcn.m_return, monomorph_cb, false) );
+ }
// --- Apply bounds by adding them to the associated type ruleset
apply_bounds_as_rules(context, sp, *cache.m_fcn_params, cache.m_monomorph_cb, /*is_impl_level=*/false);
@@ -520,6 +577,22 @@ namespace {
return true;
}
+ class ExprVisitor_AddIvars:
+ public HIR::ExprVisitorDef
+ {
+ Context& context;
+ public:
+ ExprVisitor_AddIvars(Context& context):
+ context(context)
+ {
+ }
+
+ void visit_type(::HIR::TypeRef& ty)
+ {
+ this->context.add_ivars(ty);
+ }
+ };
+
// -----------------------------------------------------------------------
// Enumeration visitor
//
@@ -731,7 +804,7 @@ namespace {
TRACE_FUNCTION_F(&node << " let " << node.m_pattern << ": " << node.m_type);
this->context.add_ivars( node.m_type );
- this->context.add_binding(node.span(), node.m_pattern, node.m_type);
+ this->context.handle_pattern(node.span(), node.m_pattern, node.m_type);
if( node.m_value )
{
@@ -756,14 +829,17 @@ namespace {
{
TRACE_FUNCTION_F(&node << " match ...");
- const auto& val_type = node.m_value->m_res_type;
+ auto val_type = this->context.m_ivars.new_ivar_tr();
{
auto _ = this->push_inner_coerce_scoped(true);
this->context.add_ivars(node.m_value->m_res_type);
- // TODO: If a coercion point (and ivar for the value) is placed here, it will allow `match &string { "..." ... }`
node.m_value->visit( *this );
+ // TODO: If a coercion point (and ivar for the value) is placed here, it will allow `match &string { "..." ... }`
+ // - But, this can break some parts of inferrence
+ this->context.equate_types( node.span(), val_type, node.m_value->m_res_type );
+ //this->context.equate_types_coerce( node.span(), val_type, node.m_value );
}
for(auto& arm : node.m_arms)
@@ -771,7 +847,7 @@ namespace {
TRACE_FUNCTION_F("ARM " << arm.m_patterns);
for(auto& pat : arm.m_patterns)
{
- this->context.add_binding(node.span(), pat, val_type);
+ this->context.handle_pattern(node.span(), pat, val_type);
}
if( arm.m_cond )
@@ -786,6 +862,11 @@ namespace {
this->equate_types_inner_coerce(node.span(), node.m_res_type, arm.m_code);
arm.m_code->visit( *this );
}
+
+ if( node.m_arms.empty() ) {
+ DEBUG("Empty match");
+ this->context.equate_types(node.span(), node.m_res_type, ::HIR::TypeRef::new_diverge());
+ }
}
void visit(::HIR::ExprNode_If& node) override
@@ -891,10 +972,10 @@ namespace {
{
case ::HIR::ExprNode_BinOp::Op::CmpEqu: item_name = "eq"; break;
case ::HIR::ExprNode_BinOp::Op::CmpNEqu: item_name = "eq"; break;
- case ::HIR::ExprNode_BinOp::Op::CmpLt: item_name = "ord"; break;
- case ::HIR::ExprNode_BinOp::Op::CmpLtE: item_name = "ord"; break;
- case ::HIR::ExprNode_BinOp::Op::CmpGt: item_name = "ord"; break;
- case ::HIR::ExprNode_BinOp::Op::CmpGtE: item_name = "ord"; break;
+ case ::HIR::ExprNode_BinOp::Op::CmpLt: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break;
+ case ::HIR::ExprNode_BinOp::Op::CmpLtE: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break;
+ case ::HIR::ExprNode_BinOp::Op::CmpGt: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break;
+ case ::HIR::ExprNode_BinOp::Op::CmpGtE: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break;
default: break;
}
assert(item_name);
@@ -999,10 +1080,12 @@ namespace {
TRACE_FUNCTION_F(&node << " ... [ ... ]");
this->context.add_ivars( node.m_value->m_res_type );
+ node.m_cache.index_ty = this->context.m_ivars.new_ivar_tr();
this->context.add_ivars( node.m_index->m_res_type );
node.m_value->visit( *this );
node.m_index->visit( *this );
+ this->context.equate_types_coerce(node.m_index->span(), node.m_cache.index_ty, node.m_index);
this->context.add_revisit(node);
}
@@ -1068,8 +1151,7 @@ namespace {
}
else
{
- auto s_path = gp.m_path;
- s_path.m_components.pop_back();
+ auto s_path = get_parent_path(gp.m_path);
const auto& enm = this->context.m_crate.get_enum_by_path(sp, s_path);
fix_param_count(sp, this->context, ::HIR::TypeRef(), false, gp, enm.m_params, gp.m_params);
@@ -1110,6 +1192,9 @@ namespace {
),
(Union,
BUG(sp, "TupleVariant pointing to a union");
+ ),
+ (ExternType,
+ BUG(sp, "TupleVariant pointing to a extern type");
)
)
assert(fields_ptr);
@@ -1159,7 +1244,9 @@ namespace {
{
const auto& sp = node.span();
TRACE_FUNCTION_F(&node << " " << node.m_path << "{...} [" << (node.m_is_struct ? "struct" : "enum") << "]");
- this->add_ivars_generic_path(node.span(), node.m_path);
+
+ this->add_ivars_path(node.span(), node.m_path);
+
for( auto& val : node.m_values ) {
this->context.add_ivars( val.second->m_res_type );
}
@@ -1167,8 +1254,17 @@ namespace {
this->context.add_ivars( node.m_base_value->m_res_type );
}
+ // TODO: The path can be a Ufcs (any type)
+ if( !node.m_path.m_data.is_Generic() )
+ {
+ auto t = this->context.m_resolve.expand_associated_types(sp, ::HIR::TypeRef::new_path( mv$(node.m_path), {} ));
+ node.m_path = mv$(t.m_data.as_Path().path);
+ }
+ ASSERT_BUG(sp, node.m_path.m_data.is_Generic(), "Struct literal with non-Generic path - " << node.m_path);
+ auto& ty_path = node.m_path.m_data.as_Generic();
+
// - Create ivars in path, and set result type
- const auto ty = this->get_structenum_ty(node.span(), node.m_is_struct, node.m_path);
+ const auto ty = this->get_structenum_ty(node.span(), node.m_is_struct, ty_path);
this->context.equate_types(node.span(), node.m_res_type, ty);
if( node.m_base_value ) {
this->context.equate_types(node.span(), node.m_base_value->m_res_type, ty);
@@ -1179,8 +1275,9 @@ namespace {
TU_MATCH(::HIR::TypeRef::TypePathBinding, (ty.m_data.as_Path().binding), (e),
(Unbound, ),
(Opaque, ),
+ (ExternType, ), // Error?
(Enum,
- const auto& var_name = node.m_path.m_path.m_components.back();
+ const auto& var_name = ty_path.m_path.m_components.back();
const auto& enm = *e;
auto idx = enm.find_variant(var_name);
ASSERT_BUG(sp, idx != SIZE_MAX, "");
@@ -1223,7 +1320,7 @@ namespace {
ASSERT_BUG(node.span(), fields_ptr, "");
const ::HIR::t_struct_fields& fields = *fields_ptr;
- const auto& ty_params = node.m_path.m_params.m_types;
+ const auto& ty_params = ty_path.m_params.m_types;
auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& {
const auto& ge = gt.m_data.as_Generic();
if( ge.binding == 0xFFFF ) {
@@ -1247,7 +1344,7 @@ namespace {
{
const auto& name = val.first;
auto it = ::std::find_if(fields.begin(), fields.end(), [&](const auto& v)->bool{ return v.first == name; });
- ASSERT_BUG(node.span(), it != fields.end(), "Field '" << name << "' not found in struct " << node.m_path);
+ ASSERT_BUG(node.span(), it != fields.end(), "Field '" << name << "' not found in struct " << ty_path);
const auto& des_ty_r = it->second.ent;
auto& des_ty_cache = node.m_value_types[it - fields.begin()];
const auto* des_ty = &des_ty_r;
@@ -1407,7 +1504,7 @@ namespace {
}
// - Search in-scope trait list for traits that provide a method of this name
- const ::std::string& method_name = node.m_method;
+ const RcString& method_name = node.m_method;
::HIR::t_trait_list possible_traits;
unsigned int max_num_params = 0;
for(const auto& trait_ref : ::reverse(m_traits))
@@ -1628,8 +1725,7 @@ namespace {
} break;
case ::HIR::ExprNode_PathValue::ENUM_VAR_CONSTR: {
const auto& var_name = e.m_path.m_components.back();
- auto enum_path = e.m_path;
- enum_path.m_components.pop_back();
+ auto enum_path = get_parent_path(e.m_path);
const auto& enm = this->context.m_crate.get_enum_by_path(sp, enum_path);
fix_param_count(sp, this->context, ::HIR::TypeRef(), false, e, enm.m_params, e.m_params);
size_t idx = enm.find_variant(var_name);
@@ -1855,7 +1951,7 @@ namespace {
TRACE_FUNCTION_F(&node << " |...| ...");
for(auto& arg : node.m_args) {
this->context.add_ivars( arg.second );
- this->context.add_binding( node.span(), arg.first, arg.second );
+ this->context.handle_pattern( node.span(), arg.first, arg.second );
}
this->context.add_ivars( node.m_return );
this->context.add_ivars( node.m_code->m_res_type );
@@ -1981,7 +2077,7 @@ namespace {
const auto& ty = this->context.get_type(rty);
// TODO: Search the entire type for `!`? (What about pointers to it? or Option/Result?)
// - A correct search will search for unconditional (ignoring enums with a non-! variant) non-rawptr instances of ! in the type
- return ty.m_data.is_Diverge();// || (ty.m_data.is_Infer() && ty.m_data.as_Infer().ty_class == ::HIR::InferClass::Diverge);
+ return ty.m_data.is_Diverge();
};
assert( !node.m_nodes.empty() );
@@ -1998,6 +2094,7 @@ namespace {
diverges = false;
break;
default:
+ this->context.equate_types_from_shadow(node.span(), node.m_res_type);
return ;
}
)
@@ -2075,7 +2172,24 @@ namespace {
),
(Primitive,
// Don't have anything to contribute
- this->m_completed = true;
+ // EXCEPT: `char` can only be casted from `u8` (but what about no-op casts?)
+ // - Hint the input (default) to be `u8`
+ if( e == ::HIR::CoreType::Char )
+ {
+ if(this->m_is_fallback)
+ {
+ this->context.equate_types(sp, src_ty, ::HIR::CoreType::U8);
+ }
+
+ if( !this->context.get_type(src_ty).m_data.is_Infer() )
+ {
+ this->m_completed = true;
+ }
+ }
+ else
+ {
+ this->m_completed = true;
+ }
),
(Path,
this->context.equate_types_coerce(sp, tgt_ty, node.m_value);
@@ -2154,8 +2268,8 @@ namespace {
}
),
(Borrow,
- // Check class (must be equal) and type
- if( s_e.type != e.type ) {
+ // Check class (destination must be weaker) and type
+ if( !(s_e.type >= e.type) ) {
ERROR(sp, E0000, "Invalid cast from " << src_ty << " to " << tgt_ty);
}
const auto& src_inner = this->context.get_type(*s_e.inner);
@@ -2194,16 +2308,17 @@ namespace {
// TODO: In some rare cases, this ivar could be completely
// unrestricted. If in fallback mode
const auto& dst_inner = this->context.get_type(*e.inner);
- if(this->m_is_fallback)
+ if( dst_inner.m_data.is_Infer() )
{
- if( dst_inner.m_data.is_Infer() )
+ if(this->m_is_fallback)
{
+ DEBUG("- Fallback mode, assume inner types are equal");
this->context.equate_types(sp, *e.inner, *s_e.inner);
}
- }
- else if( dst_inner.m_data.is_Infer() )
- {
- return ;
+ else
+ {
+ return ;
+ }
}
else
{
@@ -2238,7 +2353,8 @@ namespace {
void visit(::HIR::ExprNode_Index& node) override {
const auto& lang_Index = this->context.m_crate.get_lang_item_path(node.span(), "index");
const auto& val_ty = this->context.get_type(node.m_value->m_res_type);
- const auto& idx_ty = this->context.get_type(node.m_index->m_res_type);
+ //const auto& idx_ty = this->context.get_type(node.m_index->m_res_type);
+ const auto& idx_ty = this->context.get_type(node.m_cache.index_ty);
TRACE_FUNCTION_F("Index: val=" << val_ty << ", idx=" << idx_ty << "");
this->context.equate_types_from_shadow(node.span(), node.m_res_type);
@@ -2255,6 +2371,9 @@ namespace {
do {
const auto& ty = this->context.get_type(*current_ty);
DEBUG("(Index): (: " << ty << ")[: " << trait_pp.m_types[0] << "]");
+ if( ty.m_data.is_Infer() ) {
+ return ;
+ }
::HIR::TypeRef possible_index_type;
::HIR::TypeRef possible_res_type;
@@ -2334,7 +2453,29 @@ namespace {
)
this->m_completed = true;
}
- void visit(::HIR::ExprNode_Emplace& node) override {
+ void visit_emplace_129(::HIR::ExprNode_Emplace& node) {
+ const auto& sp = node.span();
+ const auto& exp_ty = this->context.get_type(node.m_res_type);
+ const auto& data_ty = this->context.get_type(node.m_value->m_res_type);
+ const auto& placer_ty = this->context.get_type(node.m_place->m_res_type);
+ const auto& lang_Boxed = this->context.m_lang_Box;
+ TRACE_FUNCTION_F("exp_ty=" << exp_ty << ", data_ty=" << data_ty << ", placer_ty" << placer_ty);
+ ASSERT_BUG(sp, node.m_type == ::HIR::ExprNode_Emplace::Type::Boxer, "1.29 mode with non-box _Emplace node");
+ ASSERT_BUG(sp, placer_ty == ::HIR::TypeRef::new_unit(), "1.29 mode with box in syntax - placer type is " << placer_ty);
+
+ ASSERT_BUG(sp, !lang_Boxed.m_components.empty(), "`owbed_box` not present when `box` operator used");
+
+ // NOTE: `owned_box` shouldn't point to anything but a struct
+ const auto& str = this->context.m_crate.get_struct_by_path(sp, lang_Boxed);
+ // TODO: Store this type to avoid having to construct it every pass
+ auto boxed_ty = ::HIR::TypeRef::new_path( ::HIR::GenericPath(lang_Boxed, {data_ty.clone()}), &str );
+
+ // TODO: is there anyting special about this node that might need revisits?
+
+ context.equate_types(sp, exp_ty, boxed_ty);
+ this->m_completed = true;
+ }
+ void visit_emplace_119(::HIR::ExprNode_Emplace& node) {
const auto& sp = node.span();
const auto& exp_ty = this->context.get_type(node.m_res_type);
const auto& data_ty = this->context.get_type(node.m_value->m_res_type);
@@ -2352,6 +2493,8 @@ namespace {
{
// Can't do anything, the place is still unknown
DEBUG("Place unknown, wait");
+ //this->context.equate_types_to_shadow(sp, placer_ty);
+ this->context.equate_types_to_shadow(sp, data_ty);
return ;
}
@@ -2381,6 +2524,7 @@ namespace {
auto boxed_ty = ::HIR::TypeRef::new_path( ::HIR::GenericPath(lang_Boxed, {data_ty.clone()}), &str );
this->context.possible_equate_type_coerce_from( exp_ty.m_data.as_Infer().index, boxed_ty );
}
+ this->context.equate_types_to_shadow(sp, data_ty);
return ;
}
// Assert that the expected result is a Path::Generic type.
@@ -2429,6 +2573,16 @@ namespace {
this->m_completed = true;
}
+ void visit(::HIR::ExprNode_Emplace& node) override {
+ switch(gTargetVersion)
+ {
+ case TargetVersion::Rustc1_19:
+ return visit_emplace_119(node);
+ case TargetVersion::Rustc1_29:
+ return visit_emplace_129(node);
+ }
+ throw "BUG: Unhandled target version";
+ }
void visit(::HIR::ExprNode_TupleVariant& node) override {
no_revisit(node);
@@ -2441,8 +2595,9 @@ namespace {
const auto& ty_o = this->context.get_type(node.m_value->m_res_type);
TRACE_FUNCTION_F("CallValue: ty=" << ty_o);
+ //this->context.equate_types_from_shadow(node.span(), node.m_res_type);
+ this->context.equate_types_shadow_strong(node.span(), node.m_res_type);
// - Shadow (prevent ivar guessing) every parameter
- this->context.equate_types_from_shadow(node.span(), node.m_res_type);
for( const auto& arg_ty : node.m_arg_ivars ) {
this->context.equate_types_to_shadow(node.span(), arg_ty);
}
@@ -2498,6 +2653,15 @@ namespace {
// No idea yet
return ;
}
+ else if( const auto* e = ty.m_data.opt_Borrow() )
+ {
+ deref_count++;
+ ty_p = &this->context.get_type(*e->inner);
+ DEBUG("Deref " << ty << " -> " << *ty_p);
+ keep_looping = true;
+ continue;
+ }
+ // TODO: If autoderef is possible, do it and continue. Only look for impls once autoderef fails
else
{
::HIR::TypeRef fcn_args_tup;
@@ -2507,8 +2671,12 @@ namespace {
// - This will get the TraitObject impl search too
// Locate an impl of FnOnce (exists for all other Fn* traits)
+ // TODO: Sometimes there's impls that just forward for wrappers, which can lead to incorrect rules
+ // e.g. `&mut _` (where `_ = Box<...>`) later will pick the FnMut impl for `&mut T: FnMut` - but Box doesn't have those forwarding impls
+ // - Maybe just keep applying auto-deref until it's no longer possible?
unsigned int count = 0;
this->context.m_resolve.find_trait_impls(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp)->bool {
+ // TODO: Don't accept if too fuzzy
count++;
auto tup = impl.get_trait_ty_param(0);
@@ -2524,7 +2692,7 @@ namespace {
if(count > 1) {
return;
}
- if(count == 1)
+ if( count == 1 )
{
// 3. Locate the most permissive implemented Fn* trait (Fn first, then FnMut, then assume just FnOnce)
@@ -2646,7 +2814,10 @@ namespace {
const auto& sp = node.span();
const auto& ty = this->context.get_type(node.m_value->m_res_type);
- TRACE_FUNCTION_F("(CallMethod) {" << this->context.m_ivars.fmt_type(ty) << "}." << node.m_method << node.m_params);
+ TRACE_FUNCTION_F("(CallMethod) {" << this->context.m_ivars.fmt_type(ty) << "}." << node.m_method << node.m_params
+ << "(" << FMT_CB(os, for( const auto& arg_node : node.m_args ) os << this->context.m_ivars.fmt_type(arg_node->m_res_type) << ", ";) << ")"
+ << " -> " << this->context.m_ivars.fmt_type(node.m_res_type)
+ );
// Make sure that no mentioned types are inferred until this method is known
this->context.equate_types_from_shadow(node.span(), node.m_res_type);
@@ -2659,14 +2830,103 @@ namespace {
// - If running in a mode after stablise (before defaults), fall
// back to trait if the inherent is still ambigious.
::std::vector<::std::pair<TraitResolution::AutoderefBorrow, ::HIR::Path>> possible_methods;
- unsigned int deref_count = this->context.m_resolve.autoderef_find_method(node.span(), node.m_traits, node.m_trait_param_ivars, ty, node.m_method, possible_methods);
+ unsigned int deref_count = this->context.m_resolve.autoderef_find_method(node.span(), node.m_traits, node.m_trait_param_ivars, ty, node.m_method.c_str(), possible_methods);
try_again:
if( deref_count != ~0u )
{
DEBUG("possible_methods = " << possible_methods);
if( possible_methods.empty() )
{
- ERROR(sp, E0000, "No applicable methods for {" << ty << "}." << node.m_method);
+ //ERROR(sp, E0000, "Could not find method `" << method_name << "` on type `" << top_ty << "`");
+ ERROR(sp, E0000, "No applicable methods for {" << this->context.m_ivars.fmt_type(ty) << "}." << node.m_method);
+ }
+ if( possible_methods.size() > 1 )
+ {
+ // TODO: What do do when there's multiple possibilities?
+ // - Should use available information to strike them down
+ // > Try and equate the return type and the arguments, if any fail then move on to the next possibility?
+ // > ONLY if those arguments/return are generic
+ //
+ // Possible causes of multiple entries
+ // - Multiple distinct traits with the same method
+ // > If `self` is concretely known, this is an error (and shouldn't happen in well-formed code).
+ // - Multiple inherent methods on a type
+ // > These would have to have different type parmeters
+ // - Multiple trait bounds (same trait, different type params)
+ // > Guess at the type params, then discard if there's a conflict?
+ // > De-duplicate same traits?
+ //
+ //
+ // So: To be able to prune the list, we need to check the type parameters for the trait/type/impl
+
+ // De-duplcate traits in this list.
+ // - If the self type and the trait name are the same, replace with an entry using placeholder
+ // ivars (node.m_trait_param_ivars)
+ for(auto it_1 = possible_methods.begin(); it_1 != possible_methods.end(); ++ it_1)
+ {
+ if( it_1->first != possible_methods.front().first )
+ {
+ it_1 = possible_methods.erase(it_1) - 1;
+ }
+ }
+ for(auto it_1 = possible_methods.begin(); it_1 != possible_methods.end(); ++ it_1)
+ {
+ if( !it_1->second.m_data.is_UfcsKnown() )
+ continue;
+ bool was_found = false;
+ auto& e1 = it_1->second.m_data.as_UfcsKnown();
+ for(auto it_2 = it_1 + 1; it_2 != possible_methods.end(); ++ it_2)
+ {
+ if( !it_2->second.m_data.is_UfcsKnown() )
+ continue;
+ if( it_2->second == it_1->second ) {
+ it_2 = possible_methods.erase(it_2) - 1;
+ continue ;
+ }
+ const auto& e2 = it_2->second.m_data.as_UfcsKnown();
+
+ // TODO: If the trait is the same, but the type differs, pick the first?
+ if( e1.trait == e2.trait ) {
+ DEBUG("Duplicate trait, different type - " << e1.trait << " for " << *e1.type << " or " << *e2.type << ", picking the first");
+ it_2 = possible_methods.erase(it_2) - 1;
+ continue ;
+ }
+ if( *e1.type != *e2.type )
+ continue;
+ if( e1.trait.m_path != e2.trait.m_path )
+ continue;
+ assert( !(e1.trait.m_params == e2.trait.m_params) );
+
+ DEBUG("Duplicate trait in possible_methods - " << it_1->second << " and " << it_2->second);
+ if( !was_found )
+ {
+ was_found = true;
+ const auto& ivars = node.m_trait_param_ivars;
+ unsigned int n_params = e1.trait.m_params.m_types.size();
+ assert(n_params <= ivars.size());
+ ::HIR::PathParams trait_params;
+ trait_params.m_types.reserve( n_params );
+ for(unsigned int i = 0; i < n_params; i++) {
+ trait_params.m_types.push_back( ::HIR::TypeRef::new_infer(ivars[i], ::HIR::InferClass::None) );
+ //ASSERT_BUG(sp, m_ivars.get_type( trait_params.m_types.back() ).m_data.as_Infer().index == ivars[i], "A method selection ivar was bound");
+ }
+ // If one of these was already using the placeholder ivars, then maintain the one with the palceholders
+ if( e1.trait.m_params != trait_params )
+ {
+ e1.trait.m_params = mv$(trait_params);
+ }
+
+ it_2 = possible_methods.erase(it_2) - 1;
+ }
+ }
+ }
+ }
+ assert( !possible_methods.empty() );
+ if( possible_methods.size() != 1 && possible_methods.front().second.m_data.is_UfcsKnown() )
+ {
+ DEBUG("- Multiple options, deferring");
+ // TODO: If the type is fully known, then this is an error.
+ return;
}
auto& ad_borrow = possible_methods.front().first;
auto& fcn_path = possible_methods.front().second;
@@ -2705,6 +2965,7 @@ namespace {
)
if( this->m_is_fallback && fcn_path.m_data.is_UfcsInherent() )
{
+ //possible_methods.erase(possible_methods.begin());
while( !possible_methods.empty() && possible_methods.front().second.m_data.is_UfcsInherent() )
{
possible_methods.erase(possible_methods.begin());
@@ -2790,7 +3051,8 @@ namespace {
const auto& field_name = node.m_field;
TRACE_FUNCTION_F("(Field) name=" << field_name << ", ty = " << this->context.m_ivars.fmt_type(node.m_value->m_res_type));
- this->context.equate_types_from_shadow(node.span(), node.m_res_type);
+ //this->context.equate_types_from_shadow(node.span(), node.m_res_type);
+ this->context.equate_types_shadow_strong(node.span(), node.m_res_type);
::HIR::TypeRef out_type;
@@ -2800,6 +3062,7 @@ namespace {
const auto* current_ty = &node.m_value->m_res_type;
::std::vector< ::HIR::TypeRef> deref_res_types;
+ // TODO: autoderef_find_field?
do {
const auto& ty = this->context.m_ivars.get_type(*current_ty);
if( ty.m_data.is_Infer() ) {
@@ -2810,7 +3073,7 @@ namespace {
DEBUG("Hit unbound path, returning early");
return ;
}
- if( this->context.m_resolve.find_field(node.span(), ty, field_name, out_type) ) {
+ if( this->context.m_resolve.find_field(node.span(), ty, field_name.c_str(), out_type) ) {
this->context.equate_types(node.span(), node.m_res_type, out_type);
break;
}
@@ -2877,7 +3140,7 @@ namespace {
void no_revisit(::HIR::ExprNode& node) {
BUG(node.span(), "Node revisit unexpected - " << typeid(node).name());
}
- };
+ }; // class ExprVisitor_Revisit
// -----------------------------------------------------------------------
// Post-inferrence visitor
@@ -2916,7 +3179,7 @@ namespace {
void visit_node_ptr(::HIR::ExprNodeP& node_ptr) override {
auto& node = *node_ptr;
const char* node_ty = typeid(node).name();
- TRACE_FUNCTION_FR(&node << " " << &node << " " << node_ty << " : " << node.m_res_type, node_ty);
+ TRACE_FUNCTION_FR(&node_ptr << " " << &node << " " << node_ty << " : " << node.m_res_type, &node << " " << node_ty);
this->check_type_resolved_top(node.span(), node.m_res_type);
DEBUG(node_ty << " : = " << node.m_res_type);
::HIR::ExprVisitorDef::visit_node_ptr(node_ptr);
@@ -2961,6 +3224,23 @@ namespace {
::HIR::ExprVisitorDef::visit_pattern(sp, pat);
}
+ void visit(::HIR::ExprNode_Block& node) override {
+ ::HIR::ExprVisitorDef::visit(node);
+ if( node.m_value_node )
+ {
+ check_types_equal(node.span(), node.m_res_type, node.m_value_node->m_res_type);
+ }
+ // If the last node diverges (yields `!`) then this block can yield `!` (or anything)
+ else if( ! node.m_nodes.empty() && node.m_nodes.back()->m_res_type == ::HIR::TypeRef::new_diverge() )
+ {
+ }
+ else
+ {
+ // Non-diverging (empty, or with a non-diverging last node) blocks must yield `()`
+ check_types_equal(node.span(), node.m_res_type, ::HIR::TypeRef::new_unit());
+ }
+ }
+
void visit(::HIR::ExprNode_Let& node) override {
this->check_type_resolved_top(node.span(), node.m_type);
::HIR::ExprVisitorDef::visit(node);
@@ -3002,7 +3282,7 @@ namespace {
this->check_type_resolved_genericpath(node.span(), node.m_path);
}
void visit(::HIR::ExprNode_StructLiteral& node) override {
- this->check_type_resolved_pp(node.span(), node.m_path.m_params, ::HIR::TypeRef());
+ this->check_type_resolved_path(node.span(), node.m_path);
for(auto& ty : node.m_value_types) {
if( ty != ::HIR::TypeRef() ) {
this->check_type_resolved_top(node.span(), ty);
@@ -3169,7 +3449,148 @@ namespace {
)
)
}
- };
+
+ void check_types_equal(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) const
+ {
+ DEBUG(sp << " - " << l << " == " << r);
+ if( r.m_data.is_Diverge() ) {
+ // Diverge on the right is always valid
+ // - NOT on the left, because `!` can become everything, but nothing can become `!`
+ }
+ else if( l != r ) {
+ ERROR(sp, E0000, "Type mismatch - " << l << " != " << r);
+ }
+ else {
+ // All good
+ }
+ }
+ }; // class ExprVisitor_Apply
+
+ class ExprVisitor_Print:
+ public ::HIR::ExprVisitor
+ {
+ const Context& context;
+ ::std::ostream& m_os;
+ public:
+ ExprVisitor_Print(const Context& context, ::std::ostream& os):
+ context(context),
+ m_os(os)
+ {}
+
+ void visit(::HIR::ExprNode_Block& node) override {
+ m_os << "_Block {" << context.m_ivars.fmt_type(node.m_nodes.back()->m_res_type) << "}";
+ }
+ void visit(::HIR::ExprNode_Asm& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Return& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Let& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Loop& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_LoopControl& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Match& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_If& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Assign& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_BinOp& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_UniOp& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Borrow& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Cast& node) override {
+ m_os << "_Cast {" << context.m_ivars.fmt_type(node.m_value->m_res_type) << "}";
+ }
+ void visit(::HIR::ExprNode_Unsize& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Index& node) override {
+ m_os << "_Index {" << fmt_res_ty(*node.m_value) << "}[{" << fmt_res_ty(*node.m_index) << "}]";
+ }
+ void visit(::HIR::ExprNode_Deref& node) override {
+ m_os << "_Deref {" << fmt_res_ty(*node.m_value) << "}";
+ }
+ void visit(::HIR::ExprNode_Emplace& node) override {
+ m_os << "_Emplace(" << fmt_res_ty(*node.m_value) << " in " << fmt_res_ty(*node.m_place) << ")";
+ }
+
+ void visit(::HIR::ExprNode_TupleVariant& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_CallPath& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_CallValue& node) override {
+ m_os << "_CallValue {" << fmt_res_ty(*node.m_value) << "}(";
+ for(const auto& arg : node.m_args)
+ m_os << "{" << fmt_res_ty(*arg) << "}, ";
+ m_os << ")";
+ }
+ void visit(::HIR::ExprNode_CallMethod& node) override {
+ m_os << "_CallMethod {" << fmt_res_ty(*node.m_value) << "}." << node.m_method << "(";
+ for(const auto& arg : node.m_args)
+ m_os << "{" << fmt_res_ty(*arg) << "}, ";
+ m_os << ")";
+ }
+ void visit(::HIR::ExprNode_Field& node) override {
+ m_os << "_Field {" << fmt_res_ty(*node.m_value) << "}." << node.m_field;
+ }
+
+ void visit(::HIR::ExprNode_Literal& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_UnitVariant& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_PathValue& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Variable& node) override {
+ no_revisit(node);
+ }
+
+ void visit(::HIR::ExprNode_StructLiteral& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_UnionLiteral& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_Tuple& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_ArrayList& node) override {
+ no_revisit(node);
+ }
+ void visit(::HIR::ExprNode_ArraySized& node) override {
+ no_revisit(node);
+ }
+
+ void visit(::HIR::ExprNode_Closure& node) override {
+ no_revisit(node);
+ }
+ private:
+ HMTypeInferrence::FmtType fmt_res_ty(const ::HIR::ExprNode& n) {
+ return context.m_ivars.fmt_type(n.m_res_type);
+ }
+ void no_revisit(::HIR::ExprNode& n) {
+ throw "";
+ }
+ }; // class ExprVisitor_Print
}
@@ -3183,13 +3604,14 @@ void Context::dump() const {
m_ivars.dump();
DEBUG("--- CS Context - " << link_coerce.size() << " Coercions, " << link_assoc.size() << " associated, " << to_visit.size() << " nodes, " << adv_revisits.size() << " callbacks");
for(const auto& v : link_coerce) {
- DEBUG(v);
+ //DEBUG(v);
+ DEBUG("R" << v.rule_idx << " " << this->m_ivars.fmt_type(v.left_ty) << " := " << v.right_node_ptr << " " << &**v.right_node_ptr << " (" << this->m_ivars.fmt_type((*v.right_node_ptr)->m_res_type) << ")");
}
for(const auto& v : link_assoc) {
DEBUG(v);
}
for(const auto& v : to_visit) {
- DEBUG(&*v << " " << typeid(*v).name() << " -> " << this->m_ivars.fmt_type(v->m_res_type));
+ DEBUG(&*v << " " << FMT_CB(os, { ExprVisitor_Print ev(*this, os); v->visit(ev); }) << " -> " << this->m_ivars.fmt_type(v->m_res_type));
}
for(const auto& v : adv_revisits) {
DEBUG(FMT_CB(ss, v->fmt(ss);));
@@ -3207,24 +3629,21 @@ void Context::equate_types(const Span& sp, const ::HIR::TypeRef& li, const ::HIR
// Instantly apply equality
TRACE_FUNCTION_F(li << " == " << ri);
- visit_ty_with(ri, [&](const auto& ty)->bool {
- if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding >> 8 == 2 ) {
- BUG(sp, "Type contained an impl placeholder parameter - " << ri);
- }
- return false;
- });
- visit_ty_with(li, [&](const auto& ty)->bool {
- if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding >> 8 == 2 ) {
- BUG(sp, "Type contained an impl placeholder parameter - " << li);
- }
- return false;
- });
+ ASSERT_BUG(sp, !type_contains_impl_placeholder(ri), "Type contained an impl placeholder parameter - " << ri);
+ ASSERT_BUG(sp, !type_contains_impl_placeholder(li), "Type contained an impl placeholder parameter - " << li);
::HIR::TypeRef l_tmp;
::HIR::TypeRef r_tmp;
const auto& l_t = this->m_resolve.expand_associated_types(sp, this->m_ivars.get_type(li), l_tmp);
const auto& r_t = this->m_resolve.expand_associated_types(sp, this->m_ivars.get_type(ri), r_tmp);
+ if( l_t.m_data.is_Diverge() && !r_t.m_data.is_Infer() ) {
+ return ;
+ }
+ if( r_t.m_data.is_Diverge() && !l_t.m_data.is_Infer() ) {
+ return;
+ }
+
equate_types_inner(sp, l_t, r_t);
}
@@ -3494,7 +3913,809 @@ void Context::add_binding_inner(const Span& sp, const ::HIR::PatternBinding& pb,
}
// NOTE: Mutates the pattern to add ivars to contained paths
-void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type)
+void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type)
+{
+ TRACE_FUNCTION_F("pat = " << pat << ", type = " << type);
+
+ // TODO: 1.29 includes "match ergonomics" which allows automatic insertion of borrow/deref when matching
+ // - Handling this will make pattern matching slightly harder (all patterns needing revisist)
+ // - BUT: New bindings will still be added as usualin this pass.
+ // - Any use of `&` (or `ref`?) in the pattern disables match ergonomics for the entire pattern.
+ // - Does `box` also do this disable?
+ //
+ //
+ // - Add a counter to each pattern indicting how many implicit borrows/derefs are applied.
+ // - When this function is called, check if the pattern is eligable for pattern auto-ref/deref
+ // - Detect if the pattern uses & or ref. If it does, then invoke the existing code
+ // - Otherwise, register a revisit for the pattern
+
+
+ struct H2 {
+ static bool has_ref_or_borrow(const Span& sp, const ::HIR::Pattern& pat) {
+ // TODO: Turns out that this isn't valid. See libsyntax 1.29
+ // - ref `rustc-1.29.0-src/src/libsyntax/print/pprust.rs` 2911, `&Option` matched with `Some(ref foo)`
+ //if( pat.m_binding.is_valid() && pat.m_binding.m_type != ::HIR::PatternBinding::Type::Move ) {
+ // return true;
+ //}
+ if( pat.m_data.is_Ref() ) {
+ return true;
+ }
+ bool rv = false;
+ TU_MATCHA( (pat.m_data), (e),
+ (Any,
+ ),
+ (Value,
+ ),
+ (Range,
+ ),
+ (Box,
+ rv |= H2::has_ref_or_borrow(sp, *e.sub);
+ ),
+ (Ref,
+ rv |= H2::has_ref_or_borrow(sp, *e.sub);
+ ),
+ (Tuple,
+ for(const auto& subpat : e.sub_patterns)
+ rv |= H2::has_ref_or_borrow(sp, subpat);
+ ),
+ (SplitTuple,
+ for(auto& subpat : e.leading) {
+ rv |= H2::has_ref_or_borrow(sp, subpat);
+ }
+ for(auto& subpat : e.trailing) {
+ rv |= H2::has_ref_or_borrow(sp, subpat);
+ }
+ ),
+ (Slice,
+ for(auto& sub : e.sub_patterns)
+ rv |= H2::has_ref_or_borrow(sp, sub);
+ ),
+ (SplitSlice,
+ for(auto& sub : e.leading)
+ rv |= H2::has_ref_or_borrow(sp, sub);
+ for(auto& sub : e.trailing)
+ rv |= H2::has_ref_or_borrow(sp, sub);
+ ),
+
+ // - Enums/Structs
+ (StructValue,
+ ),
+ (StructTuple,
+ for(const auto& subpat : e.sub_patterns)
+ rv |= H2::has_ref_or_borrow(sp, subpat);
+ ),
+ (Struct,
+ for( auto& field_pat : e.sub_patterns )
+ rv |= H2::has_ref_or_borrow(sp, field_pat.second);
+ ),
+ (EnumValue,
+ ),
+ (EnumTuple,
+ for(const auto& subpat : e.sub_patterns)
+ rv |= H2::has_ref_or_borrow(sp, subpat);
+ ),
+ (EnumStruct,
+ for( auto& field_pat : e.sub_patterns )
+ rv |= H2::has_ref_or_borrow(sp, field_pat.second);
+ )
+ )
+ return rv;
+ }
+ };
+
+ // 1. Determine if this pattern can apply auto-ref/deref
+ if( pat.m_data.is_Any() ) {
+ // `_` pattern, no destructure/match, so no auto-ref/deref
+ // - TODO: Does this do auto-borrow too?
+ if( pat.m_binding.is_valid() ) {
+ this->add_binding_inner(sp, pat.m_binding, type.clone());
+ }
+ return ;
+ }
+
+ // NOTE: Even if the top-level is a binding, and even if the top-level type is fully known, match ergonomics
+ // still applies.
+ if( TARGETVER_1_29 ) { //&& ! H2::has_ref_or_borrow(sp, pat) ) {
+ // There's not a `&` or `ref` in the pattern, and we're targeting 1.29
+ // - Run the match ergonomics handler
+ // TODO: Default binding mode can be overridden back to "move" with `mut`
+
+ struct MatchErgonomicsRevisit:
+ public Revisitor
+ {
+ Span sp;
+ ::HIR::TypeRef m_outer_ty;
+ ::HIR::Pattern& m_pattern;
+ ::HIR::PatternBinding::Type m_outer_mode;
+
+ mutable ::std::vector<::HIR::TypeRef> m_temp_ivars;
+ mutable ::HIR::TypeRef m_possible_type;
+
+ MatchErgonomicsRevisit(Span sp, ::HIR::TypeRef outer, ::HIR::Pattern& pat, ::HIR::PatternBinding::Type binding_mode=::HIR::PatternBinding::Type::Move):
+ sp(mv$(sp)), m_outer_ty(mv$(outer)),
+ m_pattern(pat),
+ m_outer_mode(binding_mode)
+ {}
+
+ const Span& span() const override {
+ return sp;
+ }
+ void fmt(::std::ostream& os) const override {
+ os << "MatchErgonomicsRevisit { " << m_pattern << " : " << m_outer_ty << " }";
+ }
+ bool revisit(Context& context, bool is_fallback_mode) override {
+ TRACE_FUNCTION_F("Match ergonomics - " << m_pattern << " : " << m_outer_ty << (is_fallback_mode ? " (fallback)": ""));
+ m_outer_ty = context.m_resolve.expand_associated_types(sp, mv$(m_outer_ty));
+ return this->revisit_inner_real(context, m_pattern, m_outer_ty, m_outer_mode, is_fallback_mode);
+ }
+ // TODO: Recurse into inner patterns, creating new revisitors?
+ // - OR, could just recurse on it.
+ //
+ // Recusring incurs costs on every iteration, but is less expensive the first time around
+ // New revisitors are cheaper when inferrence takes multiple iterations, but takes longer first time.
+ bool revisit_inner(Context& context, ::HIR::Pattern& pattern, const ::HIR::TypeRef& type, ::HIR::PatternBinding::Type binding_mode) const
+ {
+ if( !revisit_inner_real(context, pattern, type, binding_mode, false) )
+ {
+ DEBUG("Add revisit for " << pattern << " : " << type << "(mode = " << (int)binding_mode << ")");
+ context.add_revisit_adv( box$(( MatchErgonomicsRevisit { sp, type.clone(), pattern, binding_mode } )) );
+ }
+ return true;
+ }
+ ::HIR::TypeRef get_possible_type_val(Context& context, ::HIR::Pattern::Value& pv) const
+ {
+ TU_MATCH_HDR( (pv), {)
+ TU_ARM(pv, Integer, ve) {
+ if( ve.type == ::HIR::CoreType::Str ) {
+ return ::HIR::TypeRef::new_infer(context.m_ivars.new_ivar(), ::HIR::InferClass::Integer);
+ }
+ return ve.type;
+ }
+ TU_ARM(pv, Float, ve) {
+ if( ve.type == ::HIR::CoreType::Str ) {
+ return ::HIR::TypeRef::new_infer(context.m_ivars.new_ivar(), ::HIR::InferClass::Float);
+ }
+ return ve.type;
+ }
+ TU_ARM(pv, String, ve) {
+ return ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::CoreType::Str);
+ }
+ TU_ARM(pv, ByteString, ve) {
+ // TODO: ByteString patterns can match either &[u8] or &[u8; N]
+ //return ::HIR::TypeRef::new_borrow(
+ // ::HIR::BorrowType::Shared,
+ // ::HIR::TypeRef::new_slice(::HIR::CoreType::U8)
+ // );
+ return ::HIR::TypeRef();
+ }
+ TU_ARM(pv, Named, ve) {
+ // TODO: Look up the path and get the type
+ return ::HIR::TypeRef();
+ }
+ }
+ throw "";
+ }
+ const ::HIR::TypeRef& get_possible_type(Context& context, ::HIR::Pattern& pattern) const
+ {
+ if( m_possible_type == ::HIR::TypeRef() )
+ {
+ ::HIR::TypeRef possible_type;
+ // Get a potential type from the pattern, and set as a possibility.
+ // - Note, this is only if no derefs were applied
+ TU_MATCH_HDR( (pattern.m_data), { )
+ TU_ARM(pattern.m_data, Any, pe) {
+ // No type information.
+ }
+ TU_ARM(pattern.m_data, Value, pe) {
+ possible_type = get_possible_type_val(context, pe.val);
+ }
+ TU_ARM(pattern.m_data, Range, pe) {
+ possible_type = get_possible_type_val(context, pe.start);
+ if( possible_type == ::HIR::TypeRef() ) {
+ possible_type = get_possible_type_val(context, pe.end);
+ }
+ else {
+ // TODO: Check that the type from .end matches .start
+ }
+ }
+ TU_ARM(pattern.m_data, Box, pe) {
+ // TODO: Get type info (Box<_>) ?
+ // - Is this possible? Shouldn't a box pattern disable ergonomics?
+ }
+ TU_ARM(pattern.m_data, Ref, pe) {
+ BUG(sp, "Match ergonomics - & pattern");
+ }
+ TU_ARM(pattern.m_data, Tuple, e) {
+ // Get type info `(T, U, ...)`
+ if( m_temp_ivars.size() != e.sub_patterns.size() ) {
+ for(size_t i = 0; i < e.sub_patterns.size(); i ++)
+ m_temp_ivars.push_back( context.m_ivars.new_ivar_tr() );
+ }
+ decltype(m_temp_ivars) tuple;
+ for(const auto& ty : m_temp_ivars)
+ tuple.push_back(ty.clone());
+ possible_type = ::HIR::TypeRef( ::std::move(tuple) );
+ }
+ TU_ARM(pattern.m_data, SplitTuple, pe) {
+ // Can't get type information, tuple size is unkown
+ }
+ TU_ARM(pattern.m_data, Slice, e) {
+ // Can be either a [T] or [T; n]. Can't provide a hint
+ }
+ TU_ARM(pattern.m_data, SplitSlice, pe) {
+ // Can be either a [T] or [T; n]. Can't provide a hint
+ }
+ TU_ARM(pattern.m_data, StructValue, e) {
+ context.add_ivars_params( e.path.m_params );
+ possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding));
+ }
+ TU_ARM(pattern.m_data, StructTuple, e) {
+ context.add_ivars_params( e.path.m_params );
+ possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding));
+ }
+ TU_ARM(pattern.m_data, Struct, e) {
+ context.add_ivars_params( e.path.m_params );
+ possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding));
+ }
+ TU_ARM(pattern.m_data, EnumValue, e) {
+ context.add_ivars_params( e.path.m_params );
+ possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr));
+ }
+ TU_ARM(pattern.m_data, EnumTuple, e) {
+ context.add_ivars_params( e.path.m_params );
+ possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr));
+ }
+ TU_ARM(pattern.m_data, EnumStruct, e) {
+ context.add_ivars_params( e.path.m_params );
+ possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr));
+ }
+ }
+ m_possible_type = ::std::move(possible_type);
+ }
+ return m_possible_type;
+ }
+ bool revisit_inner_real(Context& context, ::HIR::Pattern& pattern, const ::HIR::TypeRef& type, ::HIR::PatternBinding::Type binding_mode, bool is_fallback) const
+ {
+ TRACE_FUNCTION_F(pattern << " : " << type);
+
+ // Binding applies to the raw input type (not after dereferencing)
+ if( pattern.m_binding.is_valid() )
+ {
+ // - Binding present, use the current binding mode
+ if( pattern.m_binding.m_type == ::HIR::PatternBinding::Type::Move )
+ {
+ pattern.m_binding.m_type = binding_mode;
+ }
+ ::HIR::TypeRef tmp;
+ const ::HIR::TypeRef* binding_type = nullptr;
+ switch(pattern.m_binding.m_type)
+ {
+ case ::HIR::PatternBinding::Type::Move:
+ binding_type = &type;
+ break;
+ case ::HIR::PatternBinding::Type::MutRef:
+ // NOTE: Needs to deref and borrow to get just `&mut T` (where T isn't a &mut T)
+ binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Unique, type.clone()));
+ break;
+ case ::HIR::PatternBinding::Type::Ref:
+ // NOTE: Needs to deref and borrow to get just `&mut T` (where T isn't a &mut T)
+ binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, type.clone()));
+ break;
+ default:
+ TODO(sp, "Assign variable type using mode " << (int)binding_mode << " and " << type);
+ }
+ assert(binding_type);
+ context.equate_types(sp, context.get_var(sp, pattern.m_binding.m_slot), *binding_type);
+ }
+
+ // For `_` patterns, there's nothing to match, so they just succeed with no derefs
+ if( pattern.m_data.is_Any() )
+ {
+ return true;
+ }
+
+ if( auto* pe = pattern.m_data.opt_Ref() )
+ {
+ // Require a &-ptr (hard requirement), then visit sub-pattern
+ auto inner_ty = context.m_ivars.new_ivar_tr();
+ auto new_ty = ::HIR::TypeRef::new_borrow( pe->type, inner_ty.clone() );
+ context.equate_types(sp, type, new_ty);
+
+ return this->revisit_inner( context, *pe->sub, inner_ty, binding_mode );
+ }
+
+ // If the type is a borrow, then count derefs required for the borrow
+ // - If the first non-borrow inner is an ivar, return false
+ unsigned n_deref = 0;
+ ::HIR::BorrowType bt = ::HIR::BorrowType::Owned;
+ const auto* ty_p = &context.get_type(type);
+ while( ty_p->m_data.is_Borrow() ) {
+ DEBUG("bt " << bt << ", " << ty_p->m_data.as_Borrow().type);
+ bt = ::std::min(bt, ty_p->m_data.as_Borrow().type);
+ ty_p = &context.get_type( *ty_p->m_data.as_Borrow().inner );
+ n_deref ++;
+ }
+ DEBUG("- " << n_deref << " derefs of class " << bt << " to get " << *ty_p);
+ if( ty_p->m_data.is_Infer() || TU_TEST1(ty_p->m_data, Path, .binding.is_Unbound()) )
+ {
+ // Still pure infer, can't do anything
+ // - What if it's a literal?
+
+ // TODO: Don't do fallback if the ivar is marked as being hard blocked
+ if( const auto* te = ty_p->m_data.opt_Infer() )
+ {
+ if( te->index < context.possible_ivar_vals.size()
+ && context.possible_ivar_vals[te->index].force_disable
+ )
+ {
+ MatchErgonomicsRevisit::disable_possibilities_on_bindings(sp, context, pattern);
+ return false;
+ }
+ }
+
+ // If there's no dereferences done, then add a possible unsize type
+ const ::HIR::TypeRef& possible_type = get_possible_type(context, pattern);
+ if( possible_type != ::HIR::TypeRef() )
+ {
+ DEBUG("n_deref = " << n_deref << ", possible_type = " << possible_type);
+ const ::HIR::TypeRef* possible_type_p = &possible_type;
+ // Unwrap borrows as many times as we've already dereferenced
+ for(size_t i = 0; i < n_deref && possible_type_p; i ++) {
+ if( const auto* te = possible_type_p->m_data.opt_Borrow() ) {
+ possible_type_p = &*te->inner;
+ }
+ else {
+ possible_type_p = nullptr;
+ }
+ }
+ if( possible_type_p )
+ {
+ const auto& possible_type = *possible_type_p;
+ if( const auto* te = ty_p->m_data.opt_Infer() )
+ {
+ context.possible_equate_type_unsize_to(te->index, possible_type);
+ }
+ else if( is_fallback )
+ {
+ DEBUG("Fallback equate " << possible_type);
+ context.equate_types(sp, *ty_p, possible_type);
+ }
+ else
+ {
+ }
+
+ //if( is_fallback )
+ //{
+ // DEBUG("Possible equate " << possible_type);
+ // context.equate_types( sp, *ty_p, possible_type );
+ //}
+ }
+ }
+
+ // Visit all inner bindings and disable coercion fallbacks on them.
+ MatchErgonomicsRevisit::disable_possibilities_on_bindings(sp, context, pattern);
+ return false;
+ }
+ const auto& ty = *ty_p;
+
+ // Here we have a known type and binding mode for this pattern
+ // - Time to handle this pattern then recurse into sub-patterns
+
+ // Store the deref count in the pattern.
+ pattern.m_implicit_deref_count = n_deref;
+ // Determine the new binding mode from the borrow type
+ switch(bt)
+ {
+ case ::HIR::BorrowType::Owned:
+ // No change
+ break;
+ case ::HIR::BorrowType::Unique:
+ switch(binding_mode)
+ {
+ case ::HIR::PatternBinding::Type::Move:
+ case ::HIR::PatternBinding::Type::MutRef:
+ binding_mode = ::HIR::PatternBinding::Type::MutRef;
+ break;
+ case ::HIR::PatternBinding::Type::Ref:
+ // No change
+ break;
+ }
+ break;
+ case ::HIR::BorrowType::Shared:
+ binding_mode = ::HIR::PatternBinding::Type::Ref;
+ break;
+ }
+
+ bool rv = false;
+ TU_MATCH_HDR( (pattern.m_data), { )
+ TU_ARM(pattern.m_data, Any, pe) {
+ // no-op
+ rv = true;
+ }
+ TU_ARM(pattern.m_data, Value, pe) {
+ // no-op?
+ if( pe.val.is_String() || pe.val.is_ByteString() ) {
+ ASSERT_BUG(sp, pattern.m_implicit_deref_count >= 1, "");
+ pattern.m_implicit_deref_count -= 1;
+ }
+ rv = true;
+ }
+ TU_ARM(pattern.m_data, Range, pe) {
+ // no-op?
+ rv = true;
+ }
+ TU_ARM(pattern.m_data, Box, pe) {
+ // Box<T>
+ if( TU_TEST2(ty.m_data, Path, .path.m_data, Generic, .m_path == context.m_lang_Box) )
+ {
+ const auto& path = ty.m_data.as_Path().path.m_data.as_Generic();
+ const auto& inner = path.m_params.m_types.at(0);
+ rv = this->revisit_inner(context, *pe.sub, inner, binding_mode);
+ }
+ else
+ {
+ TODO(sp, "Match ergonomics - box pattern - Non Box<T> type: " << ty);
+ //auto inner = this->m_ivars.new_ivar_tr();
+ //this->handle_pattern_direct_inner(sp, *e.sub, inner);
+ //::HIR::GenericPath path { m_lang_Box, ::HIR::PathParams(mv$(inner)) };
+ //this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(&m_crate.get_struct_by_path(sp, m_lang_Box))) );
+ }
+ }
+ TU_ARM(pattern.m_data, Ref, pe) {
+ BUG(sp, "Match ergonomics - & pattern");
+ }
+ TU_ARM(pattern.m_data, Tuple, e) {
+ if( !ty.m_data.is_Tuple() ) {
+ ERROR(sp, E0000, "Matching a non-tuple with a tuple pattern - " << ty);
+ }
+ const auto& te = ty.m_data.as_Tuple();
+ if( e.sub_patterns.size() != te.size() ) {
+ ERROR(sp, E0000, "Tuple pattern with an incorrect number of fields, expected " << e.sub_patterns.size() << "-tuple, got " << ty);
+ }
+
+ rv = true;
+ for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
+ rv &= this->revisit_inner(context, e.sub_patterns[i], te[i], binding_mode);
+ }
+ TU_ARM(pattern.m_data, SplitTuple, pe) {
+ if( !ty.m_data.is_Tuple() ) {
+ ERROR(sp, E0000, "Matching a non-tuple with a tuple pattern - " << ty);
+ }
+ const auto& te = ty.m_data.as_Tuple();
+ if( pe.leading.size() + pe.trailing.size() > te.size() ) {
+ ERROR(sp, E0000, "Split-tuple pattern with an incorrect number of fields, expected at most " << (pe.leading.size() + pe.trailing.size()) << "-tuple, got " << te.size());
+ }
+ pe.total_size = te.size();
+ rv = true;
+ for(size_t i = 0; i < pe.leading.size(); i++)
+ rv &= this->revisit_inner(context, pe.leading[i], te[i], binding_mode);
+ for(size_t i = 0; i < pe.trailing.size(); i++)
+ rv &= this->revisit_inner(context, pe.trailing[i], te[te.size() - pe.trailing.size() + i], binding_mode);
+ }
+ TU_ARM(pattern.m_data, Slice, e) {
+ const ::HIR::TypeRef* slice_inner;
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te,
+ slice_inner = &*te.inner;
+ )
+ else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te,
+ slice_inner = &*te.inner;
+ )
+ else {
+ ERROR(sp, E0000, "Matching a non-array/slice with a slice pattern - " << ty);
+ }
+ rv = true;
+ for(auto& sub : e.sub_patterns)
+ rv |= this->revisit_inner(context, sub, *slice_inner, binding_mode);
+ }
+ TU_ARM(pattern.m_data, SplitSlice, pe) {
+ const ::HIR::TypeRef* slice_inner;
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te,
+ slice_inner = &*te.inner;
+ )
+ else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te,
+ slice_inner = &*te.inner;
+ )
+ else {
+ ERROR(sp, E0000, "Matching a non-array/slice with a slice pattern - " << ty);
+ }
+ rv = true;
+ for(auto& sub : pe.leading)
+ rv |= this->revisit_inner(context, sub, *slice_inner, binding_mode);
+ // TODO: Extra bind
+ for(auto& sub : pe.trailing)
+ rv |= this->revisit_inner(context, sub, *slice_inner, binding_mode);
+ }
+ TU_ARM(pattern.m_data, StructValue, e) {
+ context.add_ivars_params( e.path.m_params );
+ context.equate_types( sp, ty, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) );
+ rv = true;
+ }
+ TU_ARM(pattern.m_data, StructTuple, e) {
+ context.add_ivars_params( e.path.m_params );
+ context.equate_types( sp, ty, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) );
+
+ assert(e.binding);
+ const auto& str = *e.binding;
+
+ // - assert check from earlier pass
+ ASSERT_BUG(sp, str.m_data.is_Tuple(), "Struct-tuple pattern on non-Tuple struct");
+ const auto& sd = str.m_data.as_Tuple();
+ const auto& params = e.path.m_params;
+ ::HIR::TypeRef tmp;
+ auto maybe_monomorph = [&](const ::HIR::TypeRef& field_type)->const ::HIR::TypeRef& {
+ return (monomorphise_type_needed(field_type)
+ ? (tmp = context.m_resolve.expand_associated_types(sp, monomorphise_type(sp, str.m_params, params, field_type)))
+ : field_type
+ );
+ };
+
+ rv = true;
+ for( unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
+ {
+ /*const*/ auto& sub_pat = e.sub_patterns[i];
+ const auto& field_type = sd[i].ent;
+ const auto& var_ty = maybe_monomorph(field_type);
+ rv &= this->revisit_inner(context, sub_pat, var_ty, binding_mode);
+ }
+ }
+ TU_ARM(pattern.m_data, Struct, e) {
+ context.add_ivars_params( e.path.m_params );
+ context.equate_types( sp, ty, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) );
+ assert(e.binding);
+ const auto& str = *e.binding;
+
+ //if( ! e.is_wildcard() )
+ if( e.sub_patterns.empty() )
+ {
+ // TODO: Check the field count?
+ rv = true;
+ }
+ else
+ {
+ // - assert check from earlier pass
+ ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct");
+ const auto& sd = str.m_data.as_Named();
+ const auto& params = e.path.m_params;
+
+ ::HIR::TypeRef tmp;
+ auto maybe_monomorph = [&](const ::HIR::TypeRef& field_type)->const ::HIR::TypeRef& {
+ return (monomorphise_type_needed(field_type)
+ ? (tmp = context.m_resolve.expand_associated_types(sp, monomorphise_type(sp, str.m_params, params, field_type)))
+ : field_type
+ );
+ };
+
+ rv = true;
+ for( auto& field_pat : e.sub_patterns )
+ {
+ unsigned int f_idx = ::std::find_if( sd.begin(), sd.end(), [&](const auto& x){ return x.first == field_pat.first; } ) - sd.begin();
+ if( f_idx == sd.size() ) {
+ ERROR(sp, E0000, "Struct " << e.path << " doesn't have a field " << field_pat.first);
+ }
+ const ::HIR::TypeRef& field_type = maybe_monomorph(sd[f_idx].second.ent);
+ rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode);
+ }
+ }
+ }
+ TU_ARM(pattern.m_data, EnumValue, e) {
+ context.add_ivars_params( e.path.m_params );
+ context.equate_types( sp, ty, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
+ rv = true;
+ }
+ TU_ARM(pattern.m_data, EnumTuple, e) {
+ context.add_ivars_params( e.path.m_params );
+ context.equate_types( sp, ty, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
+ assert(e.binding_ptr);
+ const auto& enm = *e.binding_ptr;
+ const auto& str = *enm.m_data.as_Data()[e.binding_idx].type.m_data.as_Path().binding.as_Struct();
+ const auto& tup_var = str.m_data.as_Tuple();
+
+ const auto& params = e.path.m_params;
+
+ ::HIR::TypeRef tmp;
+ auto maybe_monomorph = [&](const ::HIR::TypeRef& field_type)->const ::HIR::TypeRef& {
+ return (monomorphise_type_needed(field_type)
+ ? (tmp = context.m_resolve.expand_associated_types(sp, monomorphise_type(sp, str.m_params, params, field_type)))
+ : field_type
+ );
+ };
+
+ if( e.sub_patterns.size() != tup_var.size() ) {
+ ERROR(sp, E0000, "Enum pattern with an incorrect number of fields - " << e.path << " - expected " << tup_var.size() << ", got " << e.sub_patterns.size() );
+ }
+
+ rv = true; // &= below ensures that all must be complete to return complete
+ for( unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
+ {
+ const auto& var_ty = maybe_monomorph(tup_var[i].ent);
+ rv &= this->revisit_inner(context, e.sub_patterns[i], var_ty, binding_mode);
+ }
+ }
+ TU_ARM(pattern.m_data, EnumStruct, e) {
+ context.add_ivars_params( e.path.m_params );
+ context.equate_types( sp, ty, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
+ assert(e.binding_ptr);
+
+ const auto& enm = *e.binding_ptr;
+ const auto& str = *enm.m_data.as_Data()[e.binding_idx].type.m_data.as_Path().binding.as_Struct();
+ const auto& tup_var = str.m_data.as_Named();
+ const auto& params = e.path.m_params;
+
+ ::HIR::TypeRef tmp;
+ auto maybe_monomorph = [&](const ::HIR::TypeRef& field_type)->const ::HIR::TypeRef& {
+ return (monomorphise_type_needed(field_type)
+ ? (tmp = context.m_resolve.expand_associated_types(sp, monomorphise_type(sp, str.m_params, params, field_type)))
+ : field_type
+ );
+ };
+
+ rv = true; // &= below ensures that all must be complete to return complete
+ for( auto& field_pat : e.sub_patterns )
+ {
+ unsigned int f_idx = ::std::find_if( tup_var.begin(), tup_var.end(), [&](const auto& x){ return x.first == field_pat.first; } ) - tup_var.begin();
+ if( f_idx == tup_var.size() ) {
+ ERROR(sp, E0000, "Enum variant " << e.path << " doesn't have a field " << field_pat.first);
+ }
+ const ::HIR::TypeRef& field_type = maybe_monomorph(tup_var[f_idx].second.ent);
+ rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode);
+ }
+ }
+ }
+ return rv;
+ }
+
+ static void disable_possibilities_on_bindings(const Span& sp, Context& context, const ::HIR::Pattern& pat)
+ {
+ if( pat.m_binding.is_valid() ) {
+ const auto& pb = pat.m_binding;
+ //context.equate_types_from_shadow(sp, context.get_var(sp, pb.m_slot));
+ context.equate_types_shadow_strong(sp, context.get_var(sp, pb.m_slot));
+ }
+ TU_MATCHA( (pat.m_data), (e),
+ (Any,
+ ),
+ (Value,
+ ),
+ (Range,
+ ),
+ (Box,
+ disable_possibilities_on_bindings(sp, context, *e.sub);
+ ),
+ (Ref,
+ disable_possibilities_on_bindings(sp, context, *e.sub);
+ ),
+ (Tuple,
+ for(auto& subpat : e.sub_patterns)
+ disable_possibilities_on_bindings(sp, context, subpat);
+ ),
+ (SplitTuple,
+ for(auto& subpat : e.leading) {
+ disable_possibilities_on_bindings(sp, context, subpat);
+ }
+ for(auto& subpat : e.trailing) {
+ disable_possibilities_on_bindings(sp, context, subpat);
+ }
+ ),
+ (Slice,
+ for(auto& sub : e.sub_patterns)
+ disable_possibilities_on_bindings(sp, context, sub);
+ ),
+ (SplitSlice,
+ for(auto& sub : e.leading)
+ disable_possibilities_on_bindings(sp, context, sub);
+ for(auto& sub : e.trailing)
+ disable_possibilities_on_bindings(sp, context, sub);
+ ),
+
+ // - Enums/Structs
+ (StructValue,
+ ),
+ (StructTuple,
+ for(auto& subpat : e.sub_patterns)
+ disable_possibilities_on_bindings(sp, context, subpat);
+ ),
+ (Struct,
+ for(auto& field_pat : e.sub_patterns)
+ disable_possibilities_on_bindings(sp, context, field_pat.second);
+ ),
+ (EnumValue,
+ ),
+ (EnumTuple,
+ for(auto& subpat : e.sub_patterns)
+ disable_possibilities_on_bindings(sp, context, subpat);
+ ),
+ (EnumStruct,
+ for(auto& field_pat : e.sub_patterns)
+ disable_possibilities_on_bindings(sp, context, field_pat.second);
+ )
+ )
+ }
+ static void create_bindings(const Span& sp, Context& context, ::HIR::Pattern& pat)
+ {
+ if( pat.m_binding.is_valid() ) {
+ const auto& pb = pat.m_binding;
+ context.add_var( sp, pb.m_slot, pb.m_name, context.m_ivars.new_ivar_tr() );
+ // TODO: Ensure that there's no more bindings below this?
+ // - I'll leave the option open, MIR generation should handle cases where there's multiple borrows
+ // or moves.
+ }
+ TU_MATCH_HDRA( (pat.m_data), { )
+ TU_ARMA(Any, e) {
+ }
+ TU_ARMA(Value, e) {
+ }
+ TU_ARMA(Range, e) {
+ }
+ TU_ARMA(Box, e) {
+ create_bindings(sp, context, *e.sub);
+ }
+ TU_ARMA(Ref, e) {
+ create_bindings(sp, context, *e.sub);
+ }
+ TU_ARMA(Tuple, e) {
+ for(auto& subpat : e.sub_patterns)
+ create_bindings(sp, context, subpat);
+ }
+ TU_ARMA(SplitTuple, e) {
+ for(auto& subpat : e.leading) {
+ create_bindings(sp, context, subpat);
+ }
+ for(auto& subpat : e.trailing) {
+ create_bindings(sp, context, subpat);
+ }
+ }
+ TU_ARMA(Slice, e) {
+ for(auto& sub : e.sub_patterns)
+ create_bindings(sp, context, sub);
+ }
+ TU_ARMA(SplitSlice, e) {
+ for(auto& sub : e.leading)
+ create_bindings(sp, context, sub);
+ if( e.extra_bind.is_valid() ) {
+ const auto& pb = e.extra_bind;
+ context.add_var( sp, pb.m_slot, pb.m_name, context.m_ivars.new_ivar_tr() );
+ }
+ for(auto& sub : e.trailing)
+ create_bindings(sp, context, sub);
+ }
+
+ // - Enums/Structs
+ TU_ARMA(StructValue, e) {
+ }
+ TU_ARMA(StructTuple, e) {
+ for(auto& subpat : e.sub_patterns)
+ create_bindings(sp, context, subpat);
+ }
+ TU_ARMA(Struct, e) {
+ for(auto& field_pat : e.sub_patterns)
+ create_bindings(sp, context, field_pat.second);
+ }
+ TU_ARMA(EnumValue, e) {
+ }
+ TU_ARMA(EnumTuple, e) {
+ for(auto& subpat : e.sub_patterns)
+ create_bindings(sp, context, subpat);
+ }
+ TU_ARMA(EnumStruct, e) {
+ for(auto& field_pat : e.sub_patterns)
+ create_bindings(sp, context, field_pat.second);
+ }
+ }
+ }
+ };
+ // - Create variables, assigning new ivars for all of them.
+ MatchErgonomicsRevisit::create_bindings(sp, *this, pat);
+ // - Add a revisit for the outer pattern (saving the current target type as well as the pattern)
+ DEBUG("Handle match ergonomics - " << pat << " with " << type);
+ this->add_revisit_adv( box$(( MatchErgonomicsRevisit { sp, type.clone(), pat } )) );
+ return ;
+ }
+
+ // ---
+ this->handle_pattern_direct_inner(sp, pat, type);
+}
+
+void Context::handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type)
{
TRACE_FUNCTION_F("pat = " << pat << ", type = " << type);
@@ -3504,7 +4725,6 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
// TODO: Bindings aren't allowed within another binding
}
-
struct H {
static void handle_value(Context& context, const Span& sp, const ::HIR::TypeRef& type, const ::HIR::Pattern::Value& val) {
TU_MATCH(::HIR::Pattern::Value, (val), (v),
@@ -3561,13 +4781,13 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
if( te.path.m_data.is_Generic() && te.path.m_data.as_Generic().m_path == m_lang_Box ) {
// Box<T>
const auto& inner = te.path.m_data.as_Generic().m_params.m_types.at(0);
- this->add_binding(sp, *e.sub, inner);
+ this->handle_pattern_direct_inner(sp, *e.sub, inner);
break ;
}
)
auto inner = this->m_ivars.new_ivar_tr();
- this->add_binding(sp, *e.sub, inner);
+ this->handle_pattern_direct_inner(sp, *e.sub, inner);
::HIR::GenericPath path { m_lang_Box, ::HIR::PathParams(mv$(inner)) };
this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(&m_crate.get_struct_by_path(sp, m_lang_Box))) );
),
@@ -3577,11 +4797,11 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
if( te.type != e.type ) {
ERROR(sp, E0000, "Pattern-type mismatch, &-ptr mutability mismatch");
}
- this->add_binding(sp, *e.sub, *te.inner);
+ this->handle_pattern_direct_inner(sp, *e.sub, *te.inner);
)
else {
auto inner = this->m_ivars.new_ivar_tr();
- this->add_binding(sp, *e.sub, inner);
+ this->handle_pattern_direct_inner(sp, *e.sub, inner);
this->equate_types(sp, type, ::HIR::TypeRef::new_borrow( e.type, mv$(inner) ));
}
),
@@ -3594,14 +4814,14 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
}
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
- this->add_binding(sp, e.sub_patterns[i], te[i] );
+ this->handle_pattern_direct_inner(sp, e.sub_patterns[i], te[i] );
)
else {
::std::vector< ::HIR::TypeRef> sub_types;
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) {
sub_types.push_back( this->m_ivars.new_ivar_tr() );
- this->add_binding(sp, e.sub_patterns[i], sub_types[i] );
+ this->handle_pattern_direct_inner(sp, e.sub_patterns[i], sub_types[i] );
}
this->equate_types(sp, ty, ::HIR::TypeRef( mv$(sub_types) ));
}
@@ -3614,11 +4834,11 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
unsigned int tup_idx = 0;
for(auto& subpat : e.leading) {
- this->add_binding(sp, subpat, te[tup_idx++]);
+ this->handle_pattern_direct_inner(sp, subpat, te[tup_idx++]);
}
tup_idx = te.size() - e.trailing.size();
for(auto& subpat : e.trailing) {
- this->add_binding(sp, subpat, te[tup_idx++]);
+ this->handle_pattern_direct_inner(sp, subpat, te[tup_idx++]);
}
// TODO: Should this replace the pattern with a non-split?
@@ -3634,12 +4854,12 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
leading_tys.reserve(e.leading.size());
for(auto& subpat : e.leading) {
leading_tys.push_back( this->m_ivars.new_ivar_tr() );
- this->add_binding(sp, subpat, leading_tys.back());
+ this->handle_pattern_direct_inner(sp, subpat, leading_tys.back());
}
::std::vector<::HIR::TypeRef> trailing_tys;
for(auto& subpat : e.trailing) {
trailing_tys.push_back( this->m_ivars.new_ivar_tr() );
- this->add_binding(sp, subpat, trailing_tys.back());
+ this->handle_pattern_direct_inner(sp, subpat, trailing_tys.back());
}
struct SplitTuplePatRevisit:
@@ -3657,10 +4877,13 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
m_pat_total_size(pat_total_size)
{}
+ const Span& span() const override {
+ return sp;
+ }
void fmt(::std::ostream& os) const override {
os << "SplitTuplePatRevisit { " << m_outer_ty << " = (" << m_leading_tys << ", ..., " << m_trailing_tys << ") }";
}
- bool revisit(Context& context) override {
+ bool revisit(Context& context, bool is_fallback) override {
const auto& ty = context.get_type(m_outer_ty);
TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Infer, te,
return false;
@@ -3690,16 +4913,16 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
const auto& ty = this->get_type(type);
TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te,
for(auto& sub : e.sub_patterns)
- this->add_binding(sp, sub, *te.inner );
+ this->handle_pattern_direct_inner(sp, sub, *te.inner );
)
else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te,
for(auto& sub : e.sub_patterns)
- this->add_binding(sp, sub, *te.inner );
+ this->handle_pattern_direct_inner(sp, sub, *te.inner );
)
else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Infer, te,
auto inner = this->m_ivars.new_ivar_tr();
for(auto& sub : e.sub_patterns)
- this->add_binding(sp, sub, inner);
+ this->handle_pattern_direct_inner(sp, sub, inner);
struct SlicePatRevisit:
public Revisitor
@@ -3713,8 +4936,11 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
sp(mv$(sp)), inner(mv$(inner)), type(mv$(type)), size(size)
{}
+ const Span& span() const override {
+ return sp;
+ }
void fmt(::std::ostream& os) const override { os << "SlicePatRevisit { " << inner << ", " << type << ", " << size; }
- bool revisit(Context& context) override {
+ bool revisit(Context& context, bool is_fallback) override {
const auto& ty = context.get_type(type);
TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te,
context.equate_types(sp, *te.inner, inner);
@@ -3788,8 +5014,11 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
sp(mv$(sp)), inner(mv$(inner)), type(mv$(type)), var_ty(mv$(var_ty)), min_size(size)
{}
+ const Span& span() const override {
+ return sp;
+ }
void fmt(::std::ostream& os) const override { os << "SplitSlice inner=" << inner << ", outer=" << type << ", binding="<<var_ty<<", " << min_size; }
- bool revisit(Context& context) override {
+ bool revisit(Context& context, bool is_fallback) override {
const auto& ty = context.get_type(this->type);
if( ty.m_data.is_Infer() )
return false;
@@ -3827,9 +5056,9 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
}
for(auto& sub : e.leading)
- this->add_binding( sp, sub, inner );
+ this->handle_pattern_direct_inner( sp, sub, inner );
for(auto& sub : e.trailing)
- this->add_binding( sp, sub, inner );
+ this->handle_pattern_direct_inner( sp, sub, inner );
),
// - Enums/Structs
@@ -3856,10 +5085,10 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
const auto& field_type = sd[i].ent;
if( monomorphise_type_needed(field_type) ) {
auto var_ty = monomorphise_type(sp, str.m_params, params, field_type);
- this->add_binding(sp, sub_pat, var_ty);
+ this->handle_pattern_direct_inner(sp, sub_pat, var_ty);
}
else {
- this->add_binding(sp, sub_pat, field_type);
+ this->handle_pattern_direct_inner(sp, sub_pat, field_type);
}
}
),
@@ -3867,7 +5096,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
this->add_ivars_params( e.path.m_params );
this->equate_types( sp, type, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) );
- if( e.sub_patterns.empty() )
+ if( e.is_wildcard() )
return ;
assert(e.binding);
@@ -3887,20 +5116,16 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
const ::HIR::TypeRef& field_type = sd[f_idx].second.ent;
if( monomorphise_type_needed(field_type) ) {
auto field_type_mono = monomorphise_type(sp, str.m_params, params, field_type);
- this->add_binding(sp, field_pat.second, field_type_mono);
+ this->handle_pattern_direct_inner(sp, field_pat.second, field_type_mono);
}
else {
- this->add_binding(sp, field_pat.second, field_type);
+ this->handle_pattern_direct_inner(sp, field_pat.second, field_type);
}
}
),
(EnumValue,
this->add_ivars_params( e.path.m_params );
- {
- auto path = e.path.clone();
- path.m_path.m_components.pop_back();
- this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
- }
+ this->equate_types( sp, type, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
assert(e.binding_ptr);
const auto& enm = *e.binding_ptr;
@@ -3912,12 +5137,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
),
(EnumTuple,
this->add_ivars_params( e.path.m_params );
- {
- auto path = e.path.clone();
- path.m_path.m_components.pop_back();
-
- this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
- }
+ this->equate_types( sp, type, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
assert(e.binding_ptr);
const auto& enm = *e.binding_ptr;
const auto& str = *enm.m_data.as_Data()[e.binding_idx].type.m_data.as_Path().binding.as_Struct();
@@ -3933,21 +5153,16 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
{
if( monomorphise_type_needed(tup_var[i].ent) ) {
auto var_ty = monomorphise_type(sp, enm.m_params, params, tup_var[i].ent);
- this->add_binding(sp, e.sub_patterns[i], var_ty);
+ this->handle_pattern_direct_inner(sp, e.sub_patterns[i], var_ty);
}
else {
- this->add_binding(sp, e.sub_patterns[i], tup_var[i].ent);
+ this->handle_pattern_direct_inner(sp, e.sub_patterns[i], tup_var[i].ent);
}
}
),
(EnumStruct,
this->add_ivars_params( e.path.m_params );
- {
- auto path = e.path.clone();
- path.m_path.m_components.pop_back();
-
- this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
- }
+ this->equate_types( sp, type, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) );
if( e.sub_patterns.empty() )
return ;
@@ -3967,10 +5182,10 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type
const ::HIR::TypeRef& field_type = tup_var[f_idx].second.ent;
if( monomorphise_type_needed(field_type) ) {
auto field_type_mono = monomorphise_type(sp, enm.m_params, params, field_type);
- this->add_binding(sp, field_pat.second, field_type_mono);
+ this->handle_pattern_direct_inner(sp, field_pat.second, field_type_mono);
}
else {
- this->add_binding(sp, field_pat.second, field_type);
+ this->handle_pattern_direct_inner(sp, field_pat.second, field_type);
}
}
)
@@ -3981,9 +5196,10 @@ void Context::equate_types_coerce(const Span& sp, const ::HIR::TypeRef& l, ::HIR
this->m_ivars.get_type(l);
// - Just record the equality
this->link_coerce.push_back(Coercion {
+ this->next_rule_idx ++,
l.clone(), &node_ptr
});
- DEBUG("equate_types_coerce(" << this->link_coerce.back() << ")");
+ DEBUG("++ " << this->link_coerce.back());
this->m_ivars.mark_change();
}
void Context::equate_types_shadow(const Span& sp, const ::HIR::TypeRef& l, bool is_to)
@@ -4025,6 +5241,46 @@ void Context::equate_types_shadow(const Span& sp, const ::HIR::TypeRef& l, bool
)
)
}
+void Context::equate_types_shadow_strong(const Span& sp, const ::HIR::TypeRef& ty)
+{
+ // TODO: Would like to use visit_ty_with in a way that can be told to not recurse (for non-Generic paths)
+ TU_MATCH_DEF(::HIR::TypeRef::Data, (this->get_type(ty).m_data), (e),
+ (
+ // TODO: Shadow sub-types too
+ ),
+ (Path,
+ TU_MATCH_DEF( ::HIR::Path::Data, (e.path.m_data), (pe),
+ (
+ ),
+ (Generic,
+ for(const auto& sty : pe.m_params.m_types)
+ this->equate_types_shadow_strong(sp, sty);
+ )
+ )
+ ),
+ (Tuple,
+ for(const auto& sty : e)
+ this->equate_types_shadow_strong(sp, sty);
+ ),
+ (Borrow,
+ this->equate_types_shadow_strong(sp, *e.inner);
+ ),
+ (Array,
+ this->equate_types_shadow_strong(sp, *e.inner);
+ ),
+ (Slice,
+ this->equate_types_shadow_strong(sp, *e.inner);
+ ),
+ (Closure,
+ for(const auto& aty : e.m_arg_types)
+ this->equate_types_shadow_strong(sp, aty);
+ this->equate_types_shadow_strong(sp, *e.m_rettype);
+ ),
+ (Infer,
+ this->possible_equate_type_disable_strong(sp, e.index);
+ )
+ )
+}
void Context::equate_types_assoc(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::SimplePath& trait, ::HIR::PathParams pp, const ::HIR::TypeRef& impl_ty, const char *name, bool is_op)
{
for(const auto& a : this->link_assoc)
@@ -4046,6 +5302,7 @@ void Context::equate_types_assoc(const Span& sp, const ::HIR::TypeRef& l, const
return ;
}
this->link_assoc.push_back(Associated {
+ this->next_rule_idx ++,
sp,
l.clone(),
@@ -4055,7 +5312,7 @@ void Context::equate_types_assoc(const Span& sp, const ::HIR::TypeRef& l, const
name,
is_op
});
- DEBUG("(" << this->link_assoc.back() << ")");
+ DEBUG("++ " << this->link_assoc.back());
this->m_ivars.mark_change();
}
void Context::add_revisit(::HIR::ExprNode& node) {
@@ -4101,6 +5358,10 @@ void Context::require_sized(const Span& sp, const ::HIR::TypeRef& ty_)
// Already checked by type_is_sized
params_def = nullptr;
),
+ (ExternType,
+ static ::HIR::GenericParams empty_params;
+ params_def = &empty_params;
+ ),
(Enum,
params_def = &pb->m_params;
),
@@ -4168,6 +5429,41 @@ void Context::possible_equate_type(unsigned int ivar_index, const ::HIR::TypeRef
);
list.push_back( t.clone() );
}
+void Context::possible_equate_type_bound(const Span& sp, unsigned int ivar_index, const ::HIR::TypeRef& t) {
+ {
+ ::HIR::TypeRef ty_l;
+ ty_l.m_data.as_Infer().index = ivar_index;
+ const auto& real_ty = m_ivars.get_type(ty_l);
+ if( real_ty != ty_l )
+ {
+ DEBUG("IVar " << ivar_index << " is actually " << real_ty);
+ return ;
+ }
+
+ ASSERT_BUG(sp, !type_contains_impl_placeholder(t), "Type contained an impl placeholder parameter - " << t);
+ }
+
+ if( ivar_index >= possible_ivar_vals.size() ) {
+ possible_ivar_vals.resize( ivar_index + 1 );
+ }
+ auto& ent = possible_ivar_vals[ivar_index];
+ for(const auto& e : ent.bounded)
+ {
+ if( e == t )
+ {
+ if( t.m_data.is_Infer() )
+ DEBUG(ivar_index << " duplicate bounded " << t << " " << this->m_ivars.get_type(t));
+ else
+ DEBUG(ivar_index << " duplicate bounded " << t);
+ return ;
+ }
+ }
+ ent.bounded.push_back( t.clone() );
+ if( t.m_data.is_Infer() )
+ DEBUG(ivar_index << " bounded as " << t << " " << this->m_ivars.get_type(t));
+ else
+ DEBUG(ivar_index << " bounded as " << t);
+}
void Context::possible_equate_type_disable(unsigned int ivar_index, bool is_to) {
DEBUG(ivar_index << " ?= ?? (" << (is_to ? "to" : "from") << ")");
{
@@ -4187,14 +5483,30 @@ void Context::possible_equate_type_disable(unsigned int ivar_index, bool is_to)
ent.force_no_from = true;
}
}
+void Context::possible_equate_type_disable_strong(const Span& sp, unsigned int ivar_index)
+{
+ DEBUG(ivar_index << " = ??");
+ {
+ ::HIR::TypeRef ty_l;
+ ty_l.m_data.as_Infer().index = ivar_index;
+ ASSERT_BUG(sp, m_ivars.get_type(ty_l).m_data.is_Infer(), "possible_equate_type_disable_strong on known ivar");
+ }
+
+ if( ivar_index >= possible_ivar_vals.size() ) {
+ possible_ivar_vals.resize( ivar_index + 1 );
+ }
+ auto& ent = possible_ivar_vals[ivar_index];
+ ent.force_disable = true;
+}
-void Context::add_var(const Span& sp, unsigned int index, const ::std::string& name, ::HIR::TypeRef type) {
+void Context::add_var(const Span& sp, unsigned int index, const RcString& name, ::HIR::TypeRef type) {
DEBUG("(" << index << " " << name << " : " << type << ")");
assert(index != ~0u);
if( m_bindings.size() <= index )
m_bindings.resize(index+1);
if( m_bindings[index].name == "" ) {
m_bindings[index] = Binding { name, mv$(type) };
+ this->require_sized(sp, m_bindings[index].ty);
}
else {
ASSERT_BUG(sp, m_bindings[index].name == name, "");
@@ -4299,6 +5611,7 @@ namespace {
{
DEBUG("- Moving into block");
assert( p->m_value_node );
+ // Block result and the inner node's result must be the same type
ASSERT_BUG( p->span(), context.m_ivars.types_equal(p->m_res_type, p->m_value_node->m_res_type),
"Block and result mismatch - " << context.m_ivars.fmt_type(p->m_res_type) << " != " << context.m_ivars.fmt_type(p->m_value_node->m_res_type));
// - Override the the result type to the desired result
@@ -4347,8 +5660,11 @@ namespace {
};
// TODO: Add a (two?) callback(s) that handle type equalities (and possible equalities) so this function doesn't have to mutate the context
- CoerceResult check_unsize_tys(Context& context, const Span& sp, const ::HIR::TypeRef& dst_raw, const ::HIR::TypeRef& src_raw, ::HIR::ExprNodeP* node_ptr_ptr=nullptr)
+ CoerceResult check_unsize_tys(Context& context_mut_r, const Span& sp, const ::HIR::TypeRef& dst_raw, const ::HIR::TypeRef& src_raw, ::HIR::ExprNodeP* node_ptr_ptr=nullptr, bool allow_mutate=true)
{
+ Context* context_mut = (allow_mutate ? &context_mut_r : nullptr);
+ const Context& context = context_mut_r;
+
const auto& dst = context.m_ivars.get_type(dst_raw);
const auto& src = context.m_ivars.get_type(src_raw);
TRACE_FUNCTION_F("dst=" << dst << ", src=" << src);
@@ -4386,8 +5702,11 @@ namespace {
DEBUG("Literal ivars");
return CoerceResult::Equality;
}
- context.possible_equate_type_unsize_to(src.m_data.as_Infer().index, dst);
- context.possible_equate_type_unsize_from(dst.m_data.as_Infer().index, src);
+ if( context_mut )
+ {
+ context_mut->possible_equate_type_unsize_to(src.m_data.as_Infer().index, dst);
+ context_mut->possible_equate_type_unsize_from(dst.m_data.as_Infer().index, src);
+ }
DEBUG("Both ivars");
return CoerceResult::Unknown;
}
@@ -4399,31 +5718,62 @@ namespace {
DEBUG("Literal with primitive");
return CoerceResult::Equality;
}
- context.possible_equate_type_unsize_from(dep->index, src);
+ if( context_mut )
+ {
+ context_mut->possible_equate_type_unsize_from(dep->index, src);
+ }
DEBUG("Dst ivar");
return CoerceResult::Unknown;
}
else if(const auto* sep = src.m_data.opt_Infer())
{
- if(sep->is_lit() && !dst.m_data.is_TraitObject())
+ if(sep->is_lit())
{
- // Literal to anything other than a trait object must be an equality
- DEBUG("Literal with primitive");
- return CoerceResult::Equality;
+ if( !dst.m_data.is_TraitObject())
+ {
+ // Literal to anything other than a trait object must be an equality
+ DEBUG("Literal with primitive");
+ return CoerceResult::Equality;
+ }
+ else
+ {
+ // Fall through
+ }
+ }
+ else
+ {
+ if( context_mut )
+ {
+ context_mut->possible_equate_type_unsize_to(sep->index, dst);
+ }
+ DEBUG("Src is ivar (" << src << "), return Unknown");
+ return CoerceResult::Unknown;
}
- context.possible_equate_type_unsize_to(sep->index, dst);
- DEBUG("Src ivar");
- return CoerceResult::Unknown;
}
else
{
// Neither side is an ivar, keep going.
}
+ // If either side is an unbound path, then return Unknown
+ if( TU_TEST1(src.m_data, Path, .binding.is_Unbound()) )
+ {
+ DEBUG("Source unbound path");
+ return CoerceResult::Unknown;
+ }
+ if( TU_TEST1(dst.m_data, Path, .binding.is_Unbound()) )
+ {
+ DEBUG("Destination unbound path");
+ return CoerceResult::Unknown;
+ }
+
// Array unsize (quicker than going into deref search)
if(dst.m_data.is_Slice() && src.m_data.is_Array())
{
- context.equate_types(sp, *dst.m_data.as_Slice().inner, *src.m_data.as_Array().inner);
+ if( context_mut )
+ {
+ context_mut->equate_types(sp, *dst.m_data.as_Slice().inner, *src.m_data.as_Array().inner);
+ }
if(node_ptr_ptr)
{
// TODO: Insert deref (instead of leading to a _Unsize op)
@@ -4457,10 +5807,9 @@ namespace {
// Deref coercions
// - If right can be dereferenced to left
- if(node_ptr_ptr)
+ if(node_ptr_ptr || !allow_mutate)
{
DEBUG("-- Deref coercions");
- auto& node_ptr = *node_ptr_ptr;
::HIR::TypeRef tmp_ty;
const ::HIR::TypeRef* out_ty_p = &src;
unsigned int count = 0;
@@ -4470,9 +5819,32 @@ namespace {
const auto& out_ty = context.m_ivars.get_type(*out_ty_p);
count += 1;
- if( out_ty.m_data.is_Infer() && !out_ty.m_data.as_Infer().is_lit() ) {
- // Hit a _, so can't keep going
- break;
+ if( const auto* sep = out_ty.m_data.opt_Infer() )
+ {
+ if( !sep->is_lit() )
+ {
+ // Hit a _, so can't keep going
+ if( context_mut )
+ {
+ // Could also be any deref chain of the destination type
+ ::HIR::TypeRef tmp_ty2;
+ const ::HIR::TypeRef* d_ty_p = &dst;
+ context_mut->possible_equate_type_unsize_to(sep->index, dst);
+ for(unsigned int i = 0; i < count && (d_ty_p = context.m_resolve.autoderef(sp, *d_ty_p, tmp_ty2)); i ++)
+ {
+ context_mut->possible_equate_type_unsize_to(sep->index, *d_ty_p);
+ }
+ }
+ DEBUG("Src derefs to ivar (" << src << "), return Unknown");
+ return CoerceResult::Unknown;
+ }
+ // Literal infer, keep going (but remember how many times we dereferenced?)
+ }
+
+ if( TU_TEST1(out_ty.m_data, Path, .binding.is_Unbound()) )
+ {
+ DEBUG("Src derefed to unbound type (" << out_ty << "), return Unknown");
+ return CoerceResult::Unknown;
}
types.push_back( out_ty.clone() );
@@ -4491,11 +5863,17 @@ namespace {
continue ;
}
DEBUG("Same tag and fuzzy match - assuming " << dst << " == " << out_ty);
- context.equate_types(sp, dst, out_ty);
+ if( context_mut )
+ {
+ context_mut->equate_types(sp, dst, out_ty);
+ }
),
(Slice,
// Equate!
- context.equate_types(sp, dst, out_ty);
+ if(context_mut)
+ {
+ context_mut->equate_types(sp, dst, out_ty);
+ }
// - Fall through
)
)
@@ -4505,21 +5883,25 @@ namespace {
}
}
- add_coerce_borrow(context, node_ptr, types.back(), [&](auto& node_ptr)->void {
- // node_ptr = node that yeilds ty_src
- assert( count == types.size() );
- for(unsigned int i = 0; i < types.size(); i ++ )
- {
- auto span = node_ptr->span();
- // TODO: Replace with a call to context.create_autoderef to handle cases where the below assertion would fire.
- ASSERT_BUG(span, !node_ptr->m_res_type.m_data.is_Array(), "Array->Slice shouldn't be in deref coercions");
- auto ty = mv$(types[i]);
- node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Deref( mv$(span), mv$(node_ptr) ));
- DEBUG("- Deref " << &*node_ptr << " -> " << ty);
- node_ptr->m_res_type = mv$(ty);
- context.m_ivars.get_type(node_ptr->m_res_type);
- }
- });
+ if( context_mut && node_ptr_ptr )
+ {
+ auto& node_ptr = *node_ptr_ptr;
+ add_coerce_borrow(*context_mut, node_ptr, types.back(), [&](auto& node_ptr)->void {
+ // node_ptr = node that yeilds ty_src
+ assert( count == types.size() );
+ for(unsigned int i = 0; i < types.size(); i ++ )
+ {
+ auto span = node_ptr->span();
+ // TODO: Replace with a call to context.create_autoderef to handle cases where the below assertion would fire.
+ ASSERT_BUG(span, !node_ptr->m_res_type.m_data.is_Array(), "Array->Slice shouldn't be in deref coercions");
+ auto ty = mv$(types[i]);
+ node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Deref( mv$(span), mv$(node_ptr) ));
+ DEBUG("- Deref " << &*node_ptr << " -> " << ty);
+ node_ptr->m_res_type = mv$(ty);
+ context.m_ivars.get_type(node_ptr->m_res_type);
+ }
+ });
+ }
return CoerceResult::Custom;
}
@@ -4542,9 +5924,12 @@ namespace {
}
const auto& tys_d = dep->m_trait.m_path.m_params.m_types;
const auto& tys_s = sep->m_trait.m_path.m_params.m_types;
- for(size_t i = 0; i < tys_d.size(); i ++)
+ if( context_mut )
{
- context.equate_types(sp, tys_d[i], tys_s.at(i));
+ for(size_t i = 0; i < tys_d.size(); i ++)
+ {
+ context_mut->equate_types(sp, tys_d[i], tys_s.at(i));
+ }
}
// 2. Destination markers must be a strict subset
@@ -4573,76 +5958,35 @@ namespace {
// Check for trait impl
if( trait.m_path != ::HIR::SimplePath() )
{
- ImplRef best_impl;
- unsigned int count = 0;
- bool found = context.m_resolve.find_trait_impls(sp, trait.m_path, trait.m_params, src, [&](auto impl, auto cmp) {
- DEBUG("TraitObject coerce from - cmp="<<cmp<<", " << impl);
- count ++;
- best_impl = mv$(impl);
- return cmp == ::HIR::Compare::Equal;
- });
- if( count == 0 )
+ // Just call equate_types_assoc to add the required bounds.
+ if( context_mut )
{
- // TODO: Get a better idea of when there won't ever be an applicable impl
- if( !context.m_ivars.type_contains_ivars(src) ) {
- ERROR(sp, E0000, "The trait " << dep->m_trait << " is not implemented for " << src);
- }
- DEBUG("No impl, but there may eventaully be one");
- return CoerceResult::Unknown;
- }
- if( !found )
- {
- if(count > 1)
- {
- DEBUG("Defer as there are multiple applicable impls");
- return CoerceResult::Unknown;
- }
-
- if( best_impl.has_magic_params() ) {
- DEBUG("Defer as there were magic parameters");
- return CoerceResult::Unknown;
- }
-
- // TODO: Get a better way of equating these that doesn't require getting copies of the impl's types
- context.equate_types(sp, src, best_impl.get_impl_type());
- auto args = best_impl.get_trait_params();
- assert(trait.m_params.m_types.size() == args.m_types.size());
- for(unsigned int i = 0; i < trait.m_params.m_types.size(); i ++)
+ for(const auto& tyb : dep->m_trait.m_type_bounds)
{
- context.equate_types(sp, trait.m_params.m_types[i], args.m_types[i]);
+ context_mut->equate_types_assoc(sp, tyb.second, trait.m_path, trait.m_params.clone(), src, tyb.first.c_str(), false);
}
- for(const auto& tyb : dep->m_trait.m_type_bounds)
+ if( dep->m_trait.m_type_bounds.empty() )
{
- auto ty = best_impl.get_type(tyb.first.c_str());
- if( ty != ::HIR::TypeRef() )
- {
- context.equate_types(sp, tyb.second, ty);
- }
- else
- {
- // Error? Log? ...
- DEBUG("Associated type " << tyb.first << " not present in impl, can't equate");
- }
+ context_mut->add_trait_bound(sp, src, trait.m_path, trait.m_params.clone());
}
}
+ else
+ {
+ // TODO: Should this check?
+ }
}
- for(const auto& marker : dep->m_markers)
+ if( context_mut )
{
- bool found = context.m_resolve.find_trait_impls(sp, marker.m_path, marker.m_params, src, [&](auto impl, auto cmp) {
- DEBUG("TraitObject coerce from - cmp="<<cmp<<", " << impl);
- return cmp == ::HIR::Compare::Equal;
- });
- // TODO: Allow fuzz and equate same as above?
- if( !found )
+ for(const auto& marker : dep->m_markers)
{
- // TODO: Get a better idea of when there won't ever be an applicable impl
- if( !context.m_ivars.type_contains_ivars(src) ) {
- ERROR(sp, E0000, "The trait " << marker << " is not implemented for " << src);
- }
- return CoerceResult::Unknown;
+ context_mut->add_trait_bound(sp, src, marker.m_path, marker.m_params.clone());
}
}
+ else
+ {
+ // TODO: Should this check?
+ }
// Add _Unsize operator
return CoerceResult::Unsize;
@@ -4673,13 +6017,23 @@ namespace {
unsigned int count = 0;
::HIR::PathParams pp { dst.clone() };
- bool found = context.m_resolve.find_trait_impls(sp, lang_Unsize, pp, src, [&best_impl,&count](auto impl, auto cmp){
+ bool found = context.m_resolve.find_trait_impls(sp, lang_Unsize, pp, src, [&best_impl,&count,&context](auto impl, auto cmp){
DEBUG("[check_unsize_tys] Found impl " << impl << (cmp == ::HIR::Compare::Fuzzy ? " (fuzzy)" : ""));
- if( impl.more_specific_than(best_impl) )
+ if( !impl.overlaps_with(context.m_crate, best_impl) )
{
- best_impl = mv$(impl);
+ // No overlap, count it as a new possibility
+ if( count == 0 )
+ best_impl = mv$(impl);
count ++;
}
+ else if( impl.more_specific_than(best_impl) )
+ {
+ best_impl = mv$(impl);
+ }
+ else
+ {
+ // Less specific
+ }
// TODO: Record the best impl (if fuzzy) and equate params
return cmp != ::HIR::Compare::Fuzzy;
});
@@ -4691,13 +6045,17 @@ namespace {
{
auto pp = best_impl.get_trait_params();
DEBUG("Fuzzy, best was Unsize" << pp);
- context.equate_types(sp, dst, pp.m_types.at(0));
+ if( context_mut )
+ {
+ context_mut->equate_types(sp, dst, pp.m_types.at(0));
+ }
return CoerceResult::Unsize;
}
else
{
// TODO: Fuzzy?
//context.equate_types(sp, *e.inner, *s_e.inner);
+ DEBUG("Multiple impls");
}
}
@@ -4718,6 +6076,13 @@ namespace {
(Opaque,
// Handled above in bounded
),
+ (ExternType,
+ // Must be equal
+ if( sbe == dbe )
+ {
+ return CoerceResult::Equality;
+ }
+ ),
(Enum,
// Must be equal
if( sbe == dbe )
@@ -4740,7 +6105,7 @@ namespace {
{
const auto& isrc = se.path.m_data.as_Generic().m_params.m_types.at(sm.unsized_param);
const auto& idst = de.path.m_data.as_Generic().m_params.m_types.at(sm.unsized_param);
- return check_unsize_tys(context, sp, idst, isrc, nullptr);
+ return check_unsize_tys(context_mut_r, sp, idst, isrc, nullptr, allow_mutate);
}
else
{
@@ -4755,9 +6120,17 @@ namespace {
)
}
- DEBUG("Reached end of check_unsize_tys, return Unknown");
+ // If the destination is an Unbound path, return Unknown
+ if( TU_TEST1(dst.m_data, Path, .binding.is_Unbound()) )
+ {
+ DEBUG("Unbound destination");
+ return CoerceResult::Unknown;
+ }
+
+
+ DEBUG("Reached end of check_unsize_tys, return Equality");
// TODO: Determine if this unsizing could ever happen.
- return CoerceResult::Unknown;
+ return CoerceResult::Equality;
}
/// Checks if two types can be a valid coercion
@@ -4864,15 +6237,23 @@ namespace {
// - Recurse/unsize inner value
if( src.m_data.is_Infer() && TU_TEST2(dst.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) )
{
+#if 0
auto new_src = H::make_pruned(context, dst);
context.equate_types(sp, src, new_src);
+#else
+ context.possible_equate_type_coerce_to(src.m_data.as_Infer().index, dst);
+#endif
// TODO: Avoid needless loop return
return CoerceResult::Unknown;
}
if( dst.m_data.is_Infer() && TU_TEST2(src.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) )
{
+#if 0
auto new_dst = H::make_pruned(context, src);
context.equate_types(sp, dst, new_dst);
+#else
+ context.possible_equate_type_coerce_from(dst.m_data.as_Infer().index, src);
+#endif
// TODO: Avoid needless loop return
return CoerceResult::Unknown;
}
@@ -4904,6 +6285,11 @@ namespace {
}
}
+ // If either side is an unbound UFCS, can't know yet
+ if( TU_TEST1(dst.m_data, Path, .binding.is_Unbound()) || TU_TEST1(src.m_data, Path, .binding.is_Unbound()) )
+ {
+ return CoerceResult::Unknown;
+ }
// Any other type, check for pointer
// - If not a pointer, return Equality
@@ -5049,6 +6435,7 @@ namespace {
// If the coercion is of a block, do the reborrow on the last node of the block
// - Cleans up the dumped MIR and prevents needing a reborrow elsewhere.
+ // - TODO: Alter the block's result types
::HIR::ExprNodeP* npp = node_ptr_ptr;
while( auto* p = dynamic_cast< ::HIR::ExprNode_Block*>(&**npp) )
{
@@ -5058,7 +6445,7 @@ namespace {
ASSERT_BUG( p->span(), context.m_ivars.types_equal(p->m_res_type, src),
"Block and result mismatch - " << context.m_ivars.fmt_type(p->m_res_type) << " != " << context.m_ivars.fmt_type(src)
);
- p->m_res_type = new_type.clone();
+ p->m_res_type = dst.clone();
npp = &p->m_value_node;
}
::HIR::ExprNodeP& node_ptr = *npp;
@@ -5077,17 +6464,27 @@ namespace {
context.m_ivars.mark_change();
// Continue on with coercion (now that node_ptr is updated)
- switch( check_unsize_tys(context, sp, *dep->inner, *se.inner, node_ptr_ptr) )
+ switch( check_unsize_tys(context, sp, *dep->inner, *se.inner, &node_ptr) )
{
case CoerceResult::Unknown:
- return CoerceResult::Unknown;
+ // Add new coercion at the new inner point
+ if( &node_ptr != node_ptr_ptr )
+ {
+ DEBUG("Unknown check_unsize_tys after autoderef - " << dst << " := " << node_ptr->m_res_type);
+ context.equate_types_coerce(sp, dst, node_ptr);
+ return CoerceResult::Custom;
+ }
+ else
+ {
+ return CoerceResult::Unknown;
+ }
case CoerceResult::Custom:
return CoerceResult::Custom;
case CoerceResult::Equality:
context.equate_types(sp, *dep->inner, *se.inner);
return CoerceResult::Custom;
case CoerceResult::Unsize:
- DEBUG("- NEWNODE _Unsize " << &*node_ptr << " -> " << dst);
+ DEBUG("- NEWNODE _Unsize " << &node_ptr << " " << &*node_ptr << " -> " << dst);
auto span = node_ptr->span();
node_ptr = NEWNODE( dst.clone(), span, _Unsize, mv$(node_ptr), dst.clone() );
return CoerceResult::Custom;
@@ -5116,6 +6513,75 @@ namespace {
return CoerceResult::Equality;
}
}
+ else if( src.m_data.is_Closure() )
+ {
+ const auto& se = src.m_data.as_Closure();
+ if( dst.m_data.is_Function() )
+ {
+ const auto& de = dst.m_data.as_Function();
+ auto& node_ptr = *node_ptr_ptr;
+ auto span = node_ptr->span();
+ if( de.m_abi != ABI_RUST ) {
+ ERROR(span, E0000, "Cannot use closure for extern function pointer");
+ }
+ if( de.m_arg_types.size() != se.m_arg_types.size() ) {
+ ERROR(span, E0000, "Mismatched argument count coercing closure to fn(...)");
+ }
+ for(size_t i = 0; i < de.m_arg_types.size(); i++)
+ {
+ context.equate_types(sp, de.m_arg_types[i], se.m_arg_types[i]);
+ }
+ context.equate_types(sp, *de.m_rettype, *se.m_rettype);
+ node_ptr = NEWNODE( dst.clone(), span, _Cast, mv$(node_ptr), dst.clone() );
+ return CoerceResult::Custom;
+ }
+ else if( const auto* dep = dst.m_data.opt_Infer() )
+ {
+ // Prevent inferrence of argument/return types
+ for(const auto& at : se.m_arg_types)
+ context.equate_types_to_shadow(sp, at);
+ context.equate_types_to_shadow(sp, *se.m_rettype);
+ // Add as a possiblity
+ context.possible_equate_type_coerce_from(dep->index, src);
+ return CoerceResult::Unknown;
+ }
+ else
+ {
+ return CoerceResult::Equality;
+ }
+ }
+ else if( const auto* se = src.m_data.opt_Function() )
+ {
+ if( const auto* de = dst.m_data.opt_Function() )
+ {
+ auto& node_ptr = *node_ptr_ptr;
+ auto span = node_ptr->span();
+ DEBUG("Function pointer coercion");
+ // ABI must match
+ if( se->m_abi != de->m_abi )
+ return CoerceResult::Equality;
+ // const can be removed
+ //if( se->is_const != de->is_const && de->is_const ) // Error going TO a const function pointer
+ // return CoerceResult::Equality;
+ // unsafe can be added
+ if( se->is_unsafe != de->is_unsafe && se->is_unsafe ) // Error going FROM an unsafe function pointer
+ return CoerceResult::Equality;
+ // argument/return types must match
+ if( de->m_arg_types.size() != se->m_arg_types.size() )
+ return CoerceResult::Equality;
+ for(size_t i = 0; i < de->m_arg_types.size(); i++)
+ {
+ context.equate_types(sp, de->m_arg_types[i], se->m_arg_types[i]);
+ }
+ context.equate_types(sp, *de->m_rettype, *se->m_rettype);
+ node_ptr = NEWNODE( dst.clone(), span, _Cast, mv$(node_ptr), dst.clone() );
+ return CoerceResult::Custom;
+ }
+ else
+ {
+ return CoerceResult::Equality;
+ }
+ }
else
{
// TODO: ! should be handled above or in caller?
@@ -5158,8 +6624,6 @@ namespace {
const auto& sp = v.span;
TRACE_FUNCTION_F(v);
- ::HIR::TypeRef possible_impl_ty;
- ::HIR::PathParams possible_params;
::HIR::TypeRef output_type;
struct H {
@@ -5217,13 +6681,34 @@ namespace {
// - This generates an exact equation.
if( v.left_ty != ::HIR::TypeRef() )
{
- context.equate_types_from_shadow(sp, v.left_ty);
+ context.equate_types_shadow_strong(sp, v.left_ty);
+ }
+
+ // HACK? Soft-prevent inferrence of the param types
+ for(const auto& t : v.params.m_types)
+ {
+ context.equate_types_to_shadow(sp, t);
+ }
+
+ // If the impl type is an unbounded ivar, and there's no trait args - don't bother searching
+ if( const auto* e = context.m_ivars.get_type(v.impl_ty).m_data.opt_Infer() )
+ {
+ // TODO: ?
+ if( !e->is_lit() && v.params.m_types.empty() )
+ {
+ return false;
+ }
}
// Locate applicable trait impl
unsigned int count = 0;
DEBUG("Searching for impl " << v.trait << v.params << " for " << context.m_ivars.fmt_type(v.impl_ty));
- ImplRef best_impl;
+ struct Possibility {
+ ::HIR::TypeRef impl_ty;
+ ::HIR::PathParams params;
+ ImplRef impl_ref;
+ };
+ ::std::vector<Possibility> possible_impls;
bool found = context.m_resolve.find_trait_impls(sp, v.trait, v.params, v.impl_ty,
[&](auto impl, auto cmp) {
DEBUG("[check_associated] Found cmp=" << cmp << " " << impl);
@@ -5231,7 +6716,6 @@ namespace {
auto out_ty_o = impl.get_type(v.name.c_str());
if( out_ty_o == ::HIR::TypeRef() )
{
- //BUG(sp, "Getting associated type '" << v.name << "' which isn't in " << v.trait << " (" << ty << ")");
out_ty_o = ::HIR::TypeRef(::HIR::Path( v.impl_ty.clone(), ::HIR::GenericPath(v.trait, v.params.clone()), v.name, ::HIR::PathParams() ));
}
out_ty_o = context.m_resolve.expand_associated_types(sp, mv$(out_ty_o));
@@ -5249,6 +6733,7 @@ namespace {
}
// if solid or fuzzy, leave as-is
output_type = mv$( out_ty_o );
+ DEBUG("[check_associated] cmp = " << cmp << " (2)");
}
if( cmp == ::HIR::Compare::Equal ) {
// NOTE: Sometimes equal can be returned when it's not 100% equal (TODO)
@@ -5265,47 +6750,59 @@ namespace {
count += 1;
DEBUG("[check_associated] - (possible) " << impl);
- if( possible_impl_ty == ::HIR::TypeRef() ) {
+ if( possible_impls.empty() ) {
DEBUG("[check_associated] First - " << impl);
- possible_impl_ty = impl.get_impl_type();
- possible_params = impl.get_trait_params();
- best_impl = mv$(impl);
+ possible_impls.push_back({ impl.get_impl_type(), impl.get_trait_params(), mv$(impl) });
}
- // TODO: If there is an existing impl, determine if this is part of the same specialisation tree
+ // If there is an existing impl, determine if this is part of the same specialisation tree
// - If more specific, replace. If less, ignore.
- #if 1
// NOTE: `overlaps_with` (should be) reflective
- else if( impl.overlaps_with(context.m_crate, best_impl) )
+ else
{
- DEBUG("[check_associated] - Overlaps with existing - " << best_impl);
- // if not more specific than the existing best, ignore.
- if( ! impl.more_specific_than(best_impl) )
+ bool was_used = false;
+ for(auto& possible_impl : possible_impls)
{
- DEBUG("[check_associated] - Less specific than existing");
- // NOTE: This picks the _least_ specific impl
- possible_impl_ty = impl.get_impl_type();
- possible_params = impl.get_trait_params();
- best_impl = mv$(impl);
- count -= 1;
+ const auto& best_impl = possible_impl.impl_ref;
+ // TODO: Handle duplicates (from overlapping bounds)
+ if( impl.overlaps_with(context.m_crate, best_impl) )
+ {
+ DEBUG("[check_associated] - Overlaps with existing - " << best_impl);
+ // if not more specific than the existing best, ignore.
+ if( ! impl.more_specific_than(best_impl) )
+ {
+ DEBUG("[check_associated] - Less specific than existing");
+ // NOTE: This picks the _least_ specific impl
+ possible_impl.impl_ty = impl.get_impl_type();
+ possible_impl.params = impl.get_trait_params();
+ possible_impl.impl_ref = mv$(impl);
+ count -= 1;
+ }
+ // If the existing best is not more specific than the new one, use the new one
+ else if( ! best_impl.more_specific_than(impl) )
+ {
+ DEBUG("[check_associated] - More specific than existing - " << best_impl);
+ count -= 1;
+ }
+ else
+ {
+ // Supposedly, `more_specific_than` should be reflexive...
+ DEBUG("[check_associated] > Neither is more specific. Error?");
+ }
+ was_used = true;
+ break;
+ }
+ else
+ {
+ // Disjoint impls.
+ DEBUG("[check_associated] Disjoint with " << best_impl);
+ }
}
- // If the existing best is not more specific than the new one, use the new one
- else if( ! best_impl.more_specific_than(impl) )
+ if( !was_used )
{
- DEBUG("[check_associated] - More specific than existing - " << impl);
- count -= 1;
+ DEBUG("[check_associated] Add new possible impl " << impl);
+ possible_impls.push_back({ impl.get_impl_type(), impl.get_trait_params(), mv$(impl) });
}
- else
- {
- // Supposedly, `more_specific_than` should be reflexive...
- DEBUG("[check_associated] > Neither is more specific. Error?");
- }
- }
- else
- {
- // Disjoint impls.
- DEBUG("[check_associated] Disjoint impl -" << impl);
}
- #endif
return false;
}
@@ -5328,12 +6825,17 @@ namespace {
}
context.equate_types(sp, v.left_ty, output_type);
}
+ // TODO: Any equating of type params?
return true;
}
else if( count == 0 ) {
// No applicable impl
// - TODO: This should really only fire when there isn't an impl. But it currently fires when _
- DEBUG("No impl of " << v.trait << context.m_ivars.fmt(v.params) << " for " << context.m_ivars.fmt_type(v.impl_ty));
+ if( v.name == "" )
+ DEBUG("No impl of " << v.trait << context.m_ivars.fmt(v.params) << " for " << context.m_ivars.fmt_type(v.impl_ty));
+ else
+ DEBUG("No impl of " << v.trait << context.m_ivars.fmt(v.params) << " for " << context.m_ivars.fmt_type(v.impl_ty)
+ << " with " << v.name << " = " << context.m_ivars.fmt_type(v.left_ty));
const auto& ty = context.get_type(v.impl_ty);
bool is_known = !ty.m_data.is_Infer() && !(ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Unbound());
@@ -5366,6 +6868,9 @@ namespace {
}
}
else if( count == 1 ) {
+ auto& possible_impl_ty = possible_impls.at(0).impl_ty;
+ auto& possible_params = possible_impls.at(0).params;
+ auto& best_impl = possible_impls.at(0).impl_ref;
DEBUG("Only one impl " << v.trait << context.m_ivars.fmt(possible_params) << " for " << context.m_ivars.fmt_type(possible_impl_ty)
<< " - out=" << output_type);
// - If there are any magic params in the impl, don't use it yet.
@@ -5385,6 +6890,7 @@ namespace {
if( TU_TEST1(impl_ty.m_data, Infer, .is_lit() == false) )
{
DEBUG("Unbounded ivar, waiting - TODO: Add possibility " << impl_ty << " == " << possible_impl_ty);
+ //context.possible_equate_type_bound(sp, impl_ty.m_data.as_Infer().index, possible_impl_ty);
return false;
}
// Only one possible impl
@@ -5440,636 +6946,1430 @@ namespace {
else {
// Multiple possible impls, don't know yet
DEBUG("Multiple impls");
+ for(const auto& pi : possible_impls)
+ {
+ DEBUG(pi.params << " for " << pi.impl_ty);
+ for(size_t i = 0; i < pi.params.m_types.size(); i++)
+ {
+ const auto& t = context.get_type(v.params.m_types[i]);
+ if( const auto* e = t.m_data.opt_Infer() ) {
+ const auto& pi_t = pi.params.m_types[i];
+ if( !type_contains_impl_placeholder(pi_t) )
+ {
+ context.possible_equate_type_bound(sp, e->index, pi_t);
+ }
+ else
+ {
+ DEBUG("Not adding placeholder-containing type as a bound - " << pi_t);
+ }
+ }
+ }
+ }
return false;
}
}
- bool check_ivar_poss(Context& context, unsigned int i, Context::IVarPossible& ivar_ent, bool honour_disable=true)
+ bool check_ivar_poss__fails_bounds(const Span& sp, Context& context, const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& new_ty)
+ {
+ for(const auto& bound : context.link_assoc)
+ {
+ bool used_ty = false;
+ auto cb = [&](const ::HIR::TypeRef& ty, ::HIR::TypeRef& out_ty){ if( ty == ty_l ) { out_ty = new_ty.clone(); used_ty = true; return true; } else { return false; }};
+ auto t = clone_ty_with(sp, bound.impl_ty, cb);
+ auto p = clone_path_params_with(sp, bound.params, cb);
+ if(!used_ty)
+ continue;
+ // - Run EAT on t and p
+ t = context.m_resolve.expand_associated_types( sp, mv$(t) );
+ // TODO: EAT on `p`
+ DEBUG("Check " << t << " : " << bound.trait << p);
+ DEBUG("- From " << bound.impl_ty << " : " << bound.trait << bound.params);
+
+ // Search for any trait impl that could match this,
+ bool bound_failed = true;
+ context.m_resolve.find_trait_impls(sp, bound.trait, p, t, [&](const auto impl, auto cmp){
+ // If this bound specifies an associated type, then check that that type could match
+ if( bound.name != "" )
+ {
+ auto aty = impl.get_type(bound.name.c_str());
+ // The associated type is not present, what does that mean?
+ if( aty == ::HIR::TypeRef() ) {
+ DEBUG("[check_ivar_poss__fails_bounds] No ATY for " << bound.name << " in impl");
+ // A possible match was found, so don't delete just yet
+ bound_failed = false;
+ // - Return false to keep searching
+ return false;
+ }
+ else if( aty.compare_with_placeholders(sp, bound.left_ty, context.m_ivars.callback_resolve_infer()) == HIR::Compare::Unequal ) {
+ DEBUG("[check_ivar_poss__fails_bounds] ATY " << context.m_ivars.fmt_type(aty) << " != left " << context.m_ivars.fmt_type(bound.left_ty));
+ bound_failed = true;
+ // - Bail instantly
+ return true;
+ }
+ else {
+ }
+ }
+ bound_failed = false;
+ return true;
+ });
+ if( bound_failed && ! t.m_data.is_Infer() ) {
+ // If none was found, remove from the possibility list
+ DEBUG("Remove possibility " << new_ty << " because it failed a bound");
+ return true;
+ }
+
+ // TODO: Check for the resultant associated type
+ }
+
+ // Handle methods
+ for(const auto* node_ptr_dyn : context.to_visit)
+ {
+ if( const auto* node_ptr = dynamic_cast<const ::HIR::ExprNode_CallMethod*>(node_ptr_dyn) )
+ {
+ const auto& node = *node_ptr;
+ const auto& ty_tpl = context.get_type(node.m_value->m_res_type);
+
+ bool used_ty = false;
+ auto t = clone_ty_with(sp, ty_tpl, [&](const auto& ty, auto& out_ty){ if( ty == ty_l ) { out_ty = new_ty.clone(); used_ty = true; return true; } else { return false; }});
+ if(!used_ty)
+ continue;
+
+ DEBUG("Check <" << t << ">::" << node.m_method);
+ ::std::vector<::std::pair<TraitResolution::AutoderefBorrow, ::HIR::Path>> possible_methods;
+ unsigned int deref_count = context.m_resolve.autoderef_find_method(node.span(), node.m_traits, node.m_trait_param_ivars, t, node.m_method.c_str(), possible_methods);
+ DEBUG("> deref_count = " << deref_count << ", " << possible_methods);
+ if( !t.m_data.is_Infer() && possible_methods.empty() )
+ {
+ // No method found, which would be an error
+ return true;
+ }
+ }
+ else
+ {
+ }
+ }
+
+ return false;
+ }
+
+ enum class IvarPossFallbackType {
+ None, // No fallback, only make safe decisions
+ Assume, // Picks an option, even if there's non source/destination types
+ IgnoreWeakDisable, // Ignores the weaker disable flags
+ FinalOption,
+ };
+ ::std::ostream& operator<<(::std::ostream& os, IvarPossFallbackType t) {
+ switch(t)
+ {
+ case IvarPossFallbackType::None: os << ""; break;
+ case IvarPossFallbackType::Assume: os << " weak"; break;
+ case IvarPossFallbackType::IgnoreWeakDisable: os << " unblock"; break;
+ case IvarPossFallbackType::FinalOption: os << " final"; break;
+ }
+ return os;
+ }
+ /// Check IVar possibilities, from both coercion/unsizing (which have well-encoded rules) and from trait impls
+ bool check_ivar_poss(Context& context, unsigned int i, Context::IVarPossible& ivar_ent, IvarPossFallbackType fallback_ty=IvarPossFallbackType::None)
{
static Span _span;
const auto& sp = _span;
+ const bool honour_disable = (fallback_ty != IvarPossFallbackType::IgnoreWeakDisable);
- if( ! ivar_ent.has_rules() ) {
- // No rules, don't do anything (and don't print)
- DEBUG(i << ": No rules");
+ if( ivar_ent.force_disable )
+ {
+ DEBUG(i << ": forced unknown");
return false;
}
+ if( ivar_ent.force_no_to || ivar_ent.force_no_from )
+ {
+ switch(fallback_ty)
+ {
+ case IvarPossFallbackType::IgnoreWeakDisable:
+ case IvarPossFallbackType::FinalOption:
+ break;
+ default:
+ DEBUG(i << ": coercion blocked");
+ return false;
+ }
+ }
::HIR::TypeRef ty_l_ivar;
ty_l_ivar.m_data.as_Infer().index = i;
const auto& ty_l = context.m_ivars.get_type(ty_l_ivar);
- bool allow_unsized = !(i < context.m_ivars_sized.size() ? context.m_ivars_sized.at(i) : false);
if( ty_l != ty_l_ivar ) {
- DEBUG("- IVar " << i << " had possibilities, but was known to be " << ty_l);
- // Completely clear by reinitialising
- ivar_ent = Context::IVarPossible();
+ if( ivar_ent.has_rules() )
+ {
+ DEBUG("- IVar " << i << " had possibilities, but was known to be " << ty_l);
+ // Completely clear by reinitialising
+ ivar_ent = Context::IVarPossible();
+ }
+ else
+ {
+ //DEBUG(i << ": known " << ty_l);
+ }
return false;
}
- enum class DedupKeep {
- Both,
- Left,
- Right,
- };
- struct H {
- static void dedup_type_list_with(::std::vector< ::HIR::TypeRef>& list, ::std::function<DedupKeep(const ::HIR::TypeRef& l, const ::HIR::TypeRef& r)> cmp) {
- if( list.size() <= 1 )
- return ;
+ // Don't attempt to guess literals
+ // - What about if they're bounded?
+ if( ty_l.m_data.as_Infer().is_lit() )
+ {
+ DEBUG(i << ": Literal " << ty_l);
+ return false;
+ }
+ if( ! ivar_ent.has_rules() )
+ {
+ if( ty_l.m_data.as_Infer().ty_class == ::HIR::InferClass::Diverge )
+ {
+ DEBUG("Set IVar " << i << " = ! (no rules, and is diverge-class ivar)");
+ context.m_ivars.get_type(ty_l_ivar) = ::HIR::TypeRef::new_diverge();
+ context.m_ivars.mark_change();
+ return true;
+ }
+ // No rules, don't do anything (and don't print)
+ DEBUG(i << ": No rules");
+ return false;
+ }
+
+ TRACE_FUNCTION_F(i << fallback_ty << " - " << ty_l);
+
- for( auto it = list.begin(); it != list.end(); )
+ bool has_no_coerce_posiblities;
+
+ // Fill a single list with all possibilities, and pick the most suitable type.
+ // - This list needs to include flags to say if the type can be dereferenced.
+ {
+ // TODO: Move this to its own function.
+ struct PossibleType {
+ bool is_pointer; // I.e. it's from a coerce
+ bool can_deref; // I.e. from an unsize or coerce, AND it's a "from"
+ const ::HIR::TypeRef* ty;
+
+ bool operator<(const PossibleType& o) const {
+ if( *ty != *o.ty )
+ return *ty < *o.ty;
+ if( is_pointer != o.is_pointer )
+ return is_pointer < o.is_pointer;
+ if( can_deref < o.can_deref )
+ return can_deref < o.can_deref;
+ return false;
+ }
+ ::std::ostream& fmt(::std::ostream& os) const {
+ return os << (is_pointer ? "C" : "-") << (can_deref ? "D" : "-") << " " << *ty;
+ }
+
+ bool is_source() const { return this->can_deref; }
+ bool is_dest() const { return !this->can_deref; }
+ static bool is_source_s(const PossibleType& self) { return self.is_source(); }
+ static bool is_dest_s(const PossibleType& self) { return self.is_dest(); }
+ };
+
+ bool allow_unsized = !(i < context.m_ivars_sized.size() ? context.m_ivars_sized.at(i) : false);
+
+ ::std::vector<PossibleType> possible_tys;
+ static ::HIR::TypeRef null_placeholder;
+ bool add_placeholders = (fallback_ty < IvarPossFallbackType::IgnoreWeakDisable);
+ if( add_placeholders && ivar_ent.force_no_from ) // TODO: This can't happen, there's an early return above.
+ {
+ possible_tys.push_back(PossibleType { false, true, &null_placeholder });
+ }
+ for(const auto& new_ty : ivar_ent.types_coerce_from )
+ {
+ possible_tys.push_back(PossibleType { true , true, &new_ty });
+ }
+ for(const auto& new_ty : ivar_ent.types_unsize_from )
+ {
+ possible_tys.push_back(PossibleType { false, true, &new_ty });
+ }
+ if( add_placeholders && ivar_ent.force_no_to ) // TODO: This can't happen, there's an early return above.
+ {
+ possible_tys.push_back(PossibleType { false, false, &null_placeholder });
+ }
+ for(const auto& new_ty : ivar_ent.types_coerce_to )
+ {
+ possible_tys.push_back(PossibleType { true , false, &new_ty });
+ }
+ for(const auto& new_ty : ivar_ent.types_unsize_to )
+ {
+ possible_tys.push_back(PossibleType { false, false, &new_ty });
+ }
+ DEBUG("possible_tys = " << possible_tys);
+
+ // If exactly the same type is both a source and destination, equate.
+ // - This is always correct, even if one of the types is an ivar (you can't go A -> B -> A with a coercion)
+ {
+ for(const auto& ent : possible_tys)
{
- bool found = false;
- for( auto it2 = list.begin(); it2 != it; ++ it2 ) {
- auto action = cmp(*it, *it2);
- if( action != DedupKeep::Both )
- {
- if( action == DedupKeep::Right ) {
- //DEBUG("Keep " << *it << ", toss " << *it2);
- }
- else {
- ::std::swap(*it2, *it);
- //DEBUG("Keep " << *it << ", toss " << *it2 << " (swapped)");
- }
- found = true;
- break;
+ if( !ent.can_deref )
+ continue ;
+ for(const auto& ent2 : possible_tys)
+ {
+ if( &ent == &ent2 ) {
+ continue;
}
- }
- if( found ) {
- it = list.erase(it);
- }
- else {
- ++ it;
+ if( ent2.can_deref ) {
+ continue ;
+ }
+ if( *ent.ty != ::HIR::TypeRef() && *ent.ty == *ent2.ty ) {
+ DEBUG("- Source/Destination type");
+ context.equate_types(sp, ty_l, *ent.ty);
+ return true;
+ }
+ // TODO: Compare such that &[_; 1] == &[u8; 1]?
}
}
}
- // De-duplicate list (taking into account other ivars)
- // - TODO: Use the direction and do a fuzzy equality based on coercion possibility
- static void dedup_type_list(const Context& context, ::std::vector< ::HIR::TypeRef>& list) {
- dedup_type_list_with(list, [&context](const auto& l, const auto& r){ return H::equal_to(context, l, r) ? DedupKeep::Left : DedupKeep::Both; });
+
+#if 1
+ if( ::std::count_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_source_s) == 1 && !ivar_ent.force_no_from )
+ {
+ // Single source, pick it?
+ const auto& ent = *::std::find_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_source_s);
+ // - Only if there's no ivars
+ if( !context.m_ivars.type_contains_ivars(*ent.ty) )
+ {
+ if( !check_ivar_poss__fails_bounds(sp, context, ty_l, *ent.ty) )
+ {
+ DEBUG("Single concrete source, " << *ent.ty);
+ context.equate_types(sp, ty_l, *ent.ty);
+ return true;
+ }
+ }
}
+#endif
- // Types are equal from the view of being coercion targets
- // - Inequality here means that the targets could coexist in the list (e.g. &[u8; N] and &[u8])
- // - Equality means that they HAVE to be equal (even if they're not currently due to ivars)
- // - E.g. &mut HashMap<_1> and &mut HashMap<T> would unify
- static bool equal_to(const Context& context, const ::HIR::TypeRef& ia, const ::HIR::TypeRef& ib) {
- const auto& a = context.m_ivars.get_type(ia);
- const auto& b = context.m_ivars.get_type(ib);
- if( a.m_data.tag() != b.m_data.tag() )
- return false;
- TU_MATCH_DEF(::HIR::TypeRef::Data, (a.m_data, b.m_data), (e_a, e_b),
- (
- return context.m_ivars.types_equal(a, b);
- ),
- (Borrow,
- if( e_a.type != e_b.type )
- return false;
- const auto& ia = context.m_ivars.get_type(*e_a.inner);
- const auto& ib = context.m_ivars.get_type(*e_b.inner);
- if( ia.m_data.tag() != ib.m_data.tag() )
- return false;
- TU_MATCH_DEF(::HIR::TypeRef::Data, (ia.m_data, ib.m_data), (e_ia, e_ib),
- (
- return context.m_ivars.types_equal(ia, ib);
- ),
- (Infer,
- return false;
- ),
- (Path,
- if( e_ia.binding.tag() != e_ib.binding.tag() )
- return false;
- TU_MATCHA( (e_ia.binding, e_ib.binding), (pbe_a, pbe_b),
- (Unbound, return false; ),
- (Opaque,
- // TODO: Check bounds?
- return false;
- ),
- (Struct,
- if(pbe_a != pbe_b) return false;
- if( !pbe_a->m_struct_markings.can_unsize )
- return true;
- // It _could_ unsize, so let it coexist
- return false;
- ),
- (Union,
- return false;
- ),
- (Enum,
- return false;
- )
- )
- ),
- (Slice,
- const auto& ia2 = context.m_ivars.get_type(*e_ia.inner);
- const auto& ib2 = context.m_ivars.get_type(*e_ib.inner);
- if(ia2.m_data.is_Infer() || ib2.m_data.is_Infer())
- return true;
- return context.m_ivars.types_equal(ia2, ib2);
- )
- )
- ),
- (Pointer,
- if( e_a.type != e_b.type )
- return false;
- // TODO: Rules are subtly different when coercing from a pointer?
- const auto& ia2 = context.m_ivars.get_type(*e_a.inner);
- const auto& ib2 = context.m_ivars.get_type(*e_b.inner);
- if(ia2.m_data.is_Infer() || ib2.m_data.is_Infer())
+
+ if( ty_l.m_data.as_Infer().ty_class == ::HIR::InferClass::Diverge )
+ {
+ // There's a coercion (not an unsizing) AND there's no sources
+ // - This ensures that the ! is directly as a value, and not as a generic param or behind a pointer
+ if( ::std::any_of(possible_tys.begin(), possible_tys.end(), [](const PossibleType& ent){ return ent.is_pointer; })
+ && ::std::none_of(possible_tys.begin(), possible_tys.end(), [](const PossibleType& ent){ return ent.can_deref; })
+ )
+ {
+ if( !ivar_ent.force_no_to && ::std::count_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_dest_s) == 1 )
+ {
+ auto ent = *::std::find_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_dest_s);
+ DEBUG("One destination (diverge, no source), setting to " << *ent.ty);
+ context.equate_types(sp, ty_l, *ent.ty);
return true;
- return context.m_ivars.types_equal(ia2, ib2);
- )
- )
- //
- return context.m_ivars.types_equal(a, b);
+ }
+
+ // There are no source possibilities, this has to be a `!`
+ DEBUG("- Diverge with no source types, force setting to !");
+ DEBUG("Set IVar " << i << " = !");
+ context.m_ivars.get_type(ty_l_ivar) = ::HIR::TypeRef::new_diverge();
+ context.m_ivars.mark_change();
+ return true;
+ }
}
- // Types are equal from the view of being coercion sources
- static bool equal_from(const Context& context, const ::HIR::TypeRef& a, const ::HIR::TypeRef& b) {
- return context.m_ivars.types_equal(a, b);
+
+ // If there's no disable flags set, and there's only one source, pick it.
+ // - Slight hack to speed up flow-down inference
+ if( possible_tys.size() == 1 && possible_tys[0].can_deref && !ivar_ent.force_no_from ) {
+ DEBUG("One possibility (before ivar removal), setting to " << *possible_tys[0].ty);
+ context.equate_types(sp, ty_l, *possible_tys[0].ty);
+ return true;
}
+ //if( possible_tys.size() == 1 && !possible_tys[0].can_deref && !ivar_ent.force_no_to ) {
+ // DEBUG("One possibility (before ivar removal), setting to " << *possible_tys[0].ty);
+ // context.equate_types(sp, ty_l, *possible_tys[0].ty);
+ // return true;
+ //}
- // TODO: `can_unsize_to`
- static bool can_coerce_to(const Context& context, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) {
- if( dst.m_data.is_Infer() )
- return false;
- if( src.m_data.is_Infer() )
+ // TODO: This shouldn't just return, instead the above null placeholders should be tested
+ if( ivar_ent.force_no_to || ivar_ent.force_no_from )
+ {
+ switch(fallback_ty)
+ {
+ case IvarPossFallbackType::IgnoreWeakDisable:
+ case IvarPossFallbackType::FinalOption:
+ break;
+ default:
+ DEBUG(i << ": coercion blocked");
return false;
+ }
+ }
- if( dst.m_data.is_Borrow() && src.m_data.is_Borrow() ) {
- const auto& d_e = dst.m_data.as_Borrow();
- const auto& s_e = src.m_data.as_Borrow();
+ // TODO: Single destination, and all sources are coerce-able
+ // - Pick the single destination
+ #if 0
+ if( !ivar_ent.force_no_to && ::std::count_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_dest_s) == 1 )
+ {
+ auto ent = *::std::find_if(possible_tys.begin(), possible_tys.end(), PossibleType::is_dest_s);
+ DEBUG("One destination, setting to " << *ent.ty);
+ context.equate_types(sp, ty_l, *ent.ty);
+ return true;
+ }
+ #endif
- // Higher = more specific (e.g. Unique > Shared)
- if( s_e.type < d_e.type ) {
- return false;
+ // Filter out ivars
+ // - TODO: Should this also remove &_ types? (maybe not, as they give information about borrow classes)
+ size_t n_ivars;
+ size_t n_src_ivars;
+ size_t n_dst_ivars;
+ {
+ n_src_ivars = 0;
+ n_dst_ivars = 0;
+ auto new_end = ::std::remove_if(possible_tys.begin(), possible_tys.end(), [&](const PossibleType& ent) {
+ // TODO: Should this remove Unbound associated types too?
+ if( ent.ty->m_data.is_Infer() )
+ {
+ if( ent.can_deref )
+ {
+ n_src_ivars += 1;
+ }
+ else
+ {
+ n_dst_ivars += 1;
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ });
+ n_ivars = possible_tys.end() - new_end;
+ possible_tys.erase(new_end, possible_tys.end());
+ }
+ DEBUG(n_ivars << " ivars (" << n_src_ivars << " src, " << n_dst_ivars << " dst)");
+ (void)n_ivars;
+
+ // === If there's no source ivars, find the least permissive source ===
+ // - If this source can't be unsized (e.g. in `&_, &str`, `&str` is the least permissive, and can't be
+ // coerced without a `*const _` in the list), then equate to that
+ // 1. Find the most accepting pointer type (if there is at least one coercion source)
+ // 2. Look for an option that uses that pointer type, and contains an unsized type (that isn't a trait
+ // object with markers)
+ // 3. Assign to that known most-permissive option
+ // TODO: Do the oposite for the destination types (least permissive pointer, pick any Sized type)
+ if( n_src_ivars == 0 || fallback_ty == IvarPossFallbackType::Assume )
+ {
+ static const ::HIR::TypeRef::Data::Tag tag_ordering[] = {
+ //::HIR::TypeRef::Data::TAG_Generic,
+ ::HIR::TypeRef::Data::TAG_Path, // Strictly speaking, Path == Generic?
+ ::HIR::TypeRef::Data::TAG_Borrow,
+ ::HIR::TypeRef::Data::TAG_Pointer,
+ };
+ struct H {
+ static Ordering ord_accepting_ptr(const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r)
+ {
+ // Ordering in increasing acceptiveness:
+ // - Paths, Borrows, Raw Pointers
+ if( ty_l.m_data.tag() != ty_r.m_data.tag() )
+ {
+ const auto* tag_ordering_end = tag_ordering+sizeof(tag_ordering)/sizeof(tag_ordering[0]);
+ auto it_l = ::std::find(tag_ordering, tag_ordering_end, ty_l.m_data.tag());
+ auto it_r = ::std::find(tag_ordering, tag_ordering_end, ty_r.m_data.tag());
+ if( it_l == tag_ordering_end || it_r == tag_ordering_end ) {
+ // Huh?
+ return OrdEqual;
+ }
+ if( it_l < it_r )
+ return OrdLess;
+ else if( it_l > it_r )
+ return OrdGreater;
+ else
+ throw "Impossible";
+ }
+
+ switch(ty_l.m_data.tag())
+ {
+ case ::HIR::TypeRef::Data::TAG_Borrow:
+ // Reverse order - Shared is numerically lower than Unique, but is MORE accepting
+ return ::ord( static_cast<int>(ty_r.m_data.as_Borrow().type), static_cast<int>(ty_l.m_data.as_Borrow().type) );
+ case ::HIR::TypeRef::Data::TAG_Pointer:
+ // Reverse order - Shared is numerically lower than Unique, but is MORE accepting
+ return ::ord( static_cast<int>(ty_r.m_data.as_Pointer().type), static_cast<int>(ty_l.m_data.as_Pointer().type) );
+ case ::HIR::TypeRef::Data::TAG_Path:
+ return OrdEqual;
+ case ::HIR::TypeRef::Data::TAG_Generic:
+ return OrdEqual;
+ default:
+ // Technically a bug/error
+ return OrdEqual;
+ }
}
- else if( s_e.type == d_e.type ) {
- // Check relationship
- // - 1. Deref chain.
- // - 2. Trait object?
+
+ static const ::HIR::TypeRef* match_and_extract_ptr_ty(const ::HIR::TypeRef& ptr_tpl, const ::HIR::TypeRef& ty)
+ {
+ if( ty.m_data.tag() != ptr_tpl.m_data.tag() )
+ return nullptr;
+ TU_MATCH_HDRA( (ty.m_data), { )
+ TU_ARMA(Borrow, te) {
+ if( te.type == ptr_tpl.m_data.as_Borrow().type ) {
+ return &*te.inner;
+ }
+ }
+ TU_ARMA(Pointer, te) {
+ if( te.type == ptr_tpl.m_data.as_Pointer().type ) {
+ return &*te.inner;
+ }
+ }
+ TU_ARMA(Path, te) {
+ if( te.binding == ptr_tpl.m_data.as_Path().binding ) {
+ // TODO: Get inner
+ }
+ } break;
+ default:
+ break;
+ }
+ return nullptr;
}
- else {
- return context.m_ivars.types_equal(*s_e.inner, *d_e.inner);
+ };
+ const ::HIR::TypeRef* ptr_ty = nullptr;
+ if( ::std::any_of(possible_tys.begin(), possible_tys.end(), [&](const auto& ent){ return ent.can_deref && ent.is_pointer; }) )
+ {
+ for(const auto& ent : possible_tys)
+ {
+ if( !ent.can_deref )
+ continue;
+
+ if( ptr_ty == nullptr )
+ {
+ ptr_ty = ent.ty;
+ }
+ else if( H::ord_accepting_ptr(*ent.ty, *ptr_ty) == OrdGreater )
+ {
+ ptr_ty = ent.ty;
+ }
+ else
+ {
+ }
}
}
- if( dst.m_data.is_Pointer() && src.m_data.is_Pointer() ) {
- const auto& d_e = dst.m_data.as_Pointer();
- const auto& s_e = src.m_data.as_Pointer();
- // Higher = more specific (e.g. Unique > Shared)
- if( s_e.type < d_e.type ) {
- return false;
+ for(const auto& ent : possible_tys)
+ {
+ // Sources only
+ if( ! ent.can_deref )
+ continue ;
+ // Must match `ptr_ty`'s outer pointer
+ const ::HIR::TypeRef* inner_ty = (ptr_ty ? H::match_and_extract_ptr_ty(*ptr_ty, *ent.ty) : ent.ty);
+ if( !inner_ty )
+ continue;
+
+ bool is_max_accepting = false;
+ if( inner_ty->m_data.is_Slice() ) {
+ is_max_accepting = true;
}
- else if( s_e.type == d_e.type ) {
- // Check relationship
- // - 1. Deref chain.
- // - 2. Trait object?
+ else if( TU_TEST1(inner_ty->m_data, Primitive, == ::HIR::CoreType::Str) ) {
+ is_max_accepting = true;
}
else {
- return context.m_ivars.types_equal(*s_e.inner, *d_e.inner);
+ }
+ if( is_max_accepting )
+ {
+ DEBUG("Most accepting pointer class, and most permissive inner type - " << *ent.ty);
+ context.equate_types(sp, ty_l, *ent.ty);
+ return true;
}
}
+ }
- if( dst.m_data.is_Pointer() && src.m_data.is_Borrow() ) {
- const auto& d_e = dst.m_data.as_Pointer();
- const auto& s_e = src.m_data.as_Borrow();
- if( s_e.type == d_e.type ) {
- return context.m_ivars.types_equal(*s_e.inner, *d_e.inner);
+ struct TypeRestrictiveOrdering {
+ static Ordering get_ordering_infer(const Span& sp, const ::HIR::TypeRef& r)
+ {
+ // For infer, only concrete types are more restrictive
+ TU_MATCH_HDRA( (r.m_data), { )
+ default:
+ return OrdLess;
+ TU_ARMA(Path, te) {
+ if( te.binding.is_Opaque() )
+ return OrdLess;
+ if( te.binding.is_Unbound() )
+ return OrdEqual;
+ // TODO: Check if the type is concrete? (Check an unsizing param if present)
+ return OrdLess;
+ }
+ TU_ARMA(Borrow, _)
+ return OrdEqual;
+ TU_ARMA(Infer, _)
+ return OrdEqual;
+ TU_ARMA(Pointer, _)
+ return OrdEqual;
}
+ throw "";
}
- return false;
- }
+ // Ordering of `l` relative to `r`, OrdLess means that the LHS is less restrictive
+ static Ordering get_ordering_ty(const Span& sp, const Context& context, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r)
+ {
+ if( l == r ) {
+ return OrdEqual;
+ }
+ if( l.m_data.is_Infer() ) {
+ return get_ordering_infer(sp, r);
+ }
+ if( r.m_data.is_Infer() ) {
+ switch( get_ordering_infer(sp, l) )
+ {
+ case OrdLess: return OrdGreater;
+ case OrdEqual: return OrdEqual;
+ case OrdGreater:return OrdLess;
+ }
+ }
+ if( l.m_data.is_Path() ) {
+ const auto& te_l = l.m_data.as_Path();
+ // Path types can be unsize targets, and can also act like infers
+ // - If it's a Unbound treat as Infer
+ // - If Opaque, then search for a CoerceUnsized/Unsize bound?
+ // - If Struct, look for ^ tag
+ // - Else, more/equal specific
+ TU_MATCH_HDRA( (r.m_data), { )
+ default:
+ // An ivar is less restrictive?
+ if( te_l.binding.is_Unbound() )
+ return OrdLess;
+ TODO(sp, l << " with " << r << " - LHS is Path, RHS is ?");
+ TU_ARMA(Path, te_r) {
+ if( te_l.binding.is_Unbound() && te_r.binding.is_Unbound() )
+ {
+ return OrdEqual;
+ }
+ if( te_l.binding.is_Unbound() )
+ return OrdLess;
+ if( te_r.binding.is_Unbound() )
+ {
+ return OrdGreater;
+ }
+ else if( te_r.binding.is_Opaque() )
+ {
+ TODO(sp, l << " with " << r << " - LHS is Path, RHS is opaque type");
+ }
+ else if( TU_TEST1(te_r.binding, Struct, ->m_struct_markings.can_unsize) )
+ {
+ TODO(sp, l << " with " << r << " - LHS is Path, RHS is unsize-capable struct");
+ }
+ else
+ {
+ return OrdEqual;
+ }
+ }
+ }
+ }
+ if( r.m_data.is_Path() ) {
+ // Path types can be unsize targets, and can also act like infers
+ switch( get_ordering_ty(sp, context, r, l) )
+ {
+ case OrdLess: return OrdGreater;
+ case OrdEqual: return OrdEqual;
+ case OrdGreater:return OrdLess;
+ }
+ }
- // Returns true if the `src` concretely cannot coerce to `dst`
- static bool cannot_coerce_to(const Context& context, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) {
- TU_IFLET( ::HIR::TypeRef::Data, src.m_data, Borrow, se,
- TU_IFLET( ::HIR::TypeRef::Data, dst.m_data, Borrow, de,
- )
- else TU_IFLET( ::HIR::TypeRef::Data, dst.m_data, Pointer, de,
- )
+ // Slice < Array
+ if( l.m_data.tag() == r.m_data.tag() ) {
+ return OrdEqual;
+ }
else {
- return true;
+ if( l.m_data.is_Slice() && r.m_data.is_Array() ) {
+ return OrdGreater;
+ }
+ if( l.m_data.is_Array() && r.m_data.is_Slice() ) {
+ return OrdLess;
+ }
+ TODO(sp, "Compare " << l << " and " << r);
}
+ }
+
+ // Returns the restrictiveness ordering of `l` relative to `r`
+ // - &T is more restrictive than *const T
+ // - &mut T is more restrictive than &T
+ // Restrictive means that left can't be coerced from right
+ static Ordering get_ordering_ptr(const Span& sp, const Context& context, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r)
+ {
+ Ordering cmp;
+ TRACE_FUNCTION_FR(l << " , " << r, cmp);
+ // Get ordering of this type to the current destination
+ // - If lesser/greater then ignore/update
+ // - If equal then what? (Instant error? Leave as-is and let the asignment happen? Disable the asignment?)
+ static const ::HIR::TypeRef::Data::Tag tag_ordering[] = {
+ ::HIR::TypeRef::Data::TAG_Pointer,
+ ::HIR::TypeRef::Data::TAG_Borrow,
+ ::HIR::TypeRef::Data::TAG_Path, // Strictly speaking, Path == Generic
+ ::HIR::TypeRef::Data::TAG_Generic,
+ };
+ static const ::HIR::TypeRef::Data::Tag* tag_ordering_end = &tag_ordering[ sizeof(tag_ordering) / sizeof(tag_ordering[0] )];
+ if( l.m_data.tag() != r.m_data.tag() )
+ {
+ auto p_l = ::std::find(tag_ordering, tag_ordering_end, l.m_data.tag());
+ auto p_r = ::std::find(tag_ordering, tag_ordering_end, r.m_data.tag());
+ if( p_l == tag_ordering_end ) {
+ TODO(sp, "Type " << l << " not in ordering list");
+ }
+ if( p_r == tag_ordering_end ) {
+ TODO(sp, "Type " << r << " not in ordering list");
+ }
+ cmp = ord( static_cast<int>(p_l-p_r), 0 );
+ }
+ else
+ {
+ TU_MATCH_HDRA( (l.m_data), { )
+ default:
+ BUG(sp, "Unexpected type class " << l << " in get_ordering_ty");
+ break;
+ TU_ARMA(Generic, _te_l) {
+ cmp = OrdEqual;
+ }
+ TU_ARMA(Path, te_l) {
+ //const auto& te = dest_type->m_data.as_Path();
+ // TODO: Prevent this rule from applying?
+ return OrdEqual;
+ }
+ TU_ARMA(Borrow, te_l) {
+ const auto& te_r = r.m_data.as_Borrow();
+ cmp = ord( (int)te_l.type, (int)te_r.type ); // Unique>Shared in the listing, and Unique is more restrictive than Shared
+ if( cmp == OrdEqual )
+ {
+ cmp = get_ordering_ty(sp, context, context.m_ivars.get_type(*te_l.inner), context.m_ivars.get_type(*te_r.inner));
+ }
+ }
+ TU_ARMA(Pointer, te_l) {
+ const auto& te_r = r.m_data.as_Pointer();
+ cmp = ord( (int)te_r.type, (int)te_l.type ); // Note, reversed ordering because we want Unique>Shared
+ if( cmp == OrdEqual )
+ {
+ cmp = get_ordering_ty(sp, context, context.m_ivars.get_type(*te_l.inner), context.m_ivars.get_type(*te_r.inner));
+ }
+ }
+ }
+ }
+ return cmp;
+ }
+ };
+
+ // If there's multiple source types (which means that this ivar has to be a coercion from one of them)
+ // Look for the least permissive of the available destination types and assign to that
+ #if 1
+ // NOTE: This only works for coercions (not usizings), so is restricted to all options being pointers
+ if( ::std::all_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; })
+ //|| ::std::none_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; })
)
- return false;
+ {
+ // 1. Count distinct (and non-ivar) source types
+ // - This also ignores &_ types
+ size_t num_distinct = 0;
+ for(const auto& ent : possible_tys)
+ {
+ if( !ent.can_deref )
+ continue ;
+ // Ignore infer borrows
+ if( TU_TEST1(ent.ty->m_data, Borrow, .inner->m_data.is_Infer()) )
+ continue;
+ bool is_duplicate = false;
+ for(const auto& ent2 : possible_tys)
+ {
+ if( &ent2 == &ent )
+ break;
+ if( !ent.can_deref )
+ continue ;
+ if( *ent.ty == *ent2.ty ) {
+ is_duplicate = true;
+ break;
+ }
+ // TODO: Compare such that &[_; 1] == &[u8; 1]?
+ }
+ if( !is_duplicate )
+ {
+ num_distinct += 1;
+ }
+ }
+ DEBUG("- " << num_distinct << " distinct possibilities");
+ // 2. Find the most restrictive destination type
+ // - Borrows are more restrictive than pointers
+ // - Borrows of Sized types are more restrictive than any other
+ // - Decreasing borrow type ordering: Owned, Unique, Shared
+ const ::HIR::TypeRef* dest_type = nullptr;
+ for(const auto& ent : possible_tys)
+ {
+ if( ent.can_deref )
+ continue ;
+ // Ignore &_ types?
+ // - No, need to handle them below
+ if( !dest_type ) {
+ dest_type = ent.ty;
+ continue ;
+ }
+
+ auto cmp = TypeRestrictiveOrdering::get_ordering_ptr(sp, context, *ent.ty, *dest_type);
+ switch(cmp)
+ {
+ case OrdLess:
+ // This entry is less restrictive, so DO update `dest_type`
+ dest_type = ent.ty;
+ break;
+ case OrdEqual:
+ break;
+ case OrdGreater:
+ // This entry is more restrictive, so don't update `dest_type`
+ break;
+ }
+ }
+ // TODO: Unsized types? Don't pick an unsized if coercions are present?
+ // TODO: If in a fallback mode, then don't require >1 (just require dest_type)
+ if( (num_distinct > 1 || fallback_ty == IvarPossFallbackType::Assume) && dest_type )
+ {
+ DEBUG("- Most-restrictive destination " << *dest_type);
+ context.equate_types(sp, ty_l, *dest_type);
+ return true;
+ }
}
+ #endif
- static const ::HIR::TypeRef* find_lowest_type(const Context& context, const ::std::vector< ::HIR::TypeRef>& list)
+ // TODO: Remove any types that are covered by another type
+ // - E.g. &[T] and &[U] can be considered equal, because [T] can't unsize again
+ // - Comparison function: Returns one of Incomparible,Less,Same,More - Representing the amount of type information present.
{
- // 1. Locate types that cannot coerce to anything
- // - &TraitObject and &[T] are the main pair
- for(const auto& ty : list) {
- TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Borrow, e,
- TU_MATCH_DEF(::HIR::TypeRef::Data, (e.inner->m_data), (e2),
+ struct InfoOrdering
+ {
+ enum Ordering {
+ Incompatible, // The types are incompatible
+ Less, // The LHS type provides less information (e.g. has more ivars)
+ Same, // Same number of ivars
+ More, // The RHS provides more information (less ivars)
+ };
+ static bool is_infer(const ::HIR::TypeRef& ty) {
+ if( ty.m_data.is_Infer() )
+ return true;
+ if( TU_TEST1(ty.m_data, Path, .binding.is_Unbound()) )
+ return true;
+ return false;
+ }
+ static Ordering compare(const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r) {
+ if( is_infer(ty_l) ) {
+ if( is_infer(ty_r) )
+ return Same;
+ return Less;
+ }
+ else {
+ if( is_infer(ty_r) )
+ return More;
+ }
+ if( ty_l.m_data.tag() != ty_r.m_data.tag() ) {
+ return Incompatible;
+ }
+ TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_l.m_data, ty_r.m_data), (le, re),
(
+ return Incompatible;
),
- (Slice,
- return &ty;
+ (Tuple,
+ if( le.size() != re.size() )
+ return Incompatible;
+ int score = 0;
+ for(size_t i = 0; i < le.size(); i ++)
+ {
+ switch(compare(le[i], re[i]))
+ {
+ case Incompatible:
+ return Incompatible;
+ case Less: score --; break;
+ case Same: break;
+ case More: score ++; break;
+ }
+ }
+ if( score < 0 )
+ return Less;
+ else if( score > 0 )
+ return More;
+ else
+ return Same;
+ )
+ )
+ }
+ static Ordering compare_top(const Context& context, const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r, bool should_deref) {
+ if( context.m_ivars.types_equal(ty_l, ty_r) )
+ return Same;
+ if( is_infer(ty_l) )
+ return Incompatible;
+ if( is_infer(ty_r) )
+ return Incompatible;
+ if( ty_l.m_data.tag() != ty_r.m_data.tag() ) {
+ return Incompatible;
+ }
+ if( should_deref ) {
+ if( const auto* le = ty_l.m_data.opt_Borrow() ) {
+ const auto& re = ty_r.m_data.as_Borrow();
+ if( le->type != re.type )
+ return Incompatible;
+ return compare_top(context, context.m_ivars.get_type(*le->inner), context.m_ivars.get_type(*re.inner), false);
+ }
+ else if( const auto* le = ty_l.m_data.opt_Pointer() ) {
+ const auto& re = ty_r.m_data.as_Pointer();
+ if( le->type != re.type )
+ return Incompatible;
+ return compare_top(context, context.m_ivars.get_type(*le->inner), context.m_ivars.get_type(*re.inner), false);
+ }
+ else if( TU_TEST2(ty_l.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) )
+ {
+ const auto& le = ty_l.m_data.as_Path();
+ const auto& re = ty_l.m_data.as_Path();
+ if( le.binding != re.binding )
+ return Incompatible;
+ auto param_idx = le.binding.as_Struct()->m_struct_markings.coerce_param;
+ assert(param_idx != ~0u);
+ return compare_top(context,
+ context.m_ivars.get_type(le.path.m_data.as_Generic().m_params.m_types.at(param_idx)),
+ context.m_ivars.get_type(re.path.m_data.as_Generic().m_params.m_types.at(param_idx)),
+ false
+ );
+ }
+ else
+ {
+ BUG(Span(), "Can't deref " << ty_l << " / " << ty_r);
+ }
+ }
+ TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_l.m_data, ty_r.m_data), (le, re),
+ (
+ return Incompatible;
),
- (TraitObject,
- return &ty;
+ (Slice,
+ switch(compare(context.m_ivars.get_type(*le.inner), context.m_ivars.get_type(*re.inner)))
+ {
+ case Less: return Less;
+ case More: return More;
+ case Same:
+ case Incompatible:
+ return Same;
+ }
+ throw "";
)
)
- )
- }
-
- // 2. Search the list for a type that is a valid coercion target for all other types in the list
- // - NOTE: Ivars return `false` nomatter what order
- const auto* cur_type = &list[0];
- for(const auto& ty : list) {
- // If ty can be coerced to the current type
- if( H::can_coerce_to(context, *cur_type, ty) ) {
- // - Keep current type
}
- else if( H::can_coerce_to(context, ty, *cur_type) ) {
- cur_type = &ty;
+ static const ::HIR::TypeRef& get_pointer_inner(const Context& context, const ::HIR::TypeRef& t_raw) {
+ const auto& t = context.m_ivars.get_type(t_raw);
+ if( const auto* te = t.m_data.opt_Borrow() ) {
+ return context.m_ivars.get_type(*te->inner);
+ }
+ else if( const auto* te = t.m_data.opt_Pointer() ) {
+ return context.m_ivars.get_type(*te->inner);
+ }
+ else if( TU_TEST2(t.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) )
+ {
+ const auto& te = t.m_data.as_Path();
+ auto param_idx = te.binding.as_Struct()->m_struct_markings.coerce_param;
+ assert(param_idx != ~0u);
+ const auto& path = te.path.m_data.as_Generic();
+ return context.m_ivars.get_type(path.m_params.m_types.at(param_idx));
+ }
+ else {
+ throw "";
+ //return t;
+ }
}
- else {
- // Error? Give up.
- cur_type = nullptr;
- break;
+ };
+
+ // De-duplicate destinations and sources separately
+ for(auto it = possible_tys.begin(); it != possible_tys.end(); ++it)
+ {
+ if( !it->ty )
+ continue;
+ for(auto it2 = it + 1; it2 != possible_tys.end(); ++it2)
+ {
+ if( !it2->ty )
+ continue;
+ if(it->can_deref != it2->can_deref) {
+ continue;
+ }
+ if(it->is_pointer != it2->is_pointer) {
+ continue;
+ }
+
+ switch(InfoOrdering::compare_top(context, *it->ty, *it2->ty, /*should_deref=*/it->is_pointer))
+ {
+ case InfoOrdering::Incompatible:
+ break;
+ case InfoOrdering::Less:
+ case InfoOrdering::Same:
+ DEBUG("Remove " << *it << ", keep " << *it2);
+ it->ty = it2->ty;
+ it->is_pointer = it2->is_pointer;
+ it2->ty = nullptr;
+ break;
+ case InfoOrdering::More:
+ DEBUG("Keep " << *it << ", remove " << *it2);
+ it2->ty = nullptr;
+ break;
+ }
}
}
- if( cur_type ) {
- // TODO: Replace
- //return cur_type;
- }
-
- return nullptr;
+ auto new_end = ::std::remove_if(possible_tys.begin(), possible_tys.end(), [](const auto& e){ return e.ty == nullptr; });
+ DEBUG("Removing " << (possible_tys.end() - new_end) << " redundant possibilities");
+ possible_tys.erase(new_end, possible_tys.end());
}
- /// Returns true if `dst` is found when dereferencing `src`
- static bool type_derefs_from(const Span& sp, const Context& context, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src)
+ // TODO: If in fallback mode, pick the most permissive option
+ // - E.g. If the options are &mut T and *const T, use the *const T
+ if( fallback_ty == IvarPossFallbackType::Assume )
{
- ::HIR::TypeRef tmp;
- const ::HIR::TypeRef* ty = &src;
- do
+ // All are coercions (not unsizings)
+ if( ::std::all_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; }) && n_ivars == 0 )
{
- if( context.m_ivars.types_equal(*ty, dst) )
+ // Find the least restrictive destination, and most restrictive source
+ const ::HIR::TypeRef* dest_type = nullptr;
+ bool any_ivar_present = false;
+ for(const auto& ent : possible_tys)
+ {
+ if( visit_ty_with(*ent.ty, [](const ::HIR::TypeRef& t){ return t.m_data.is_Infer(); }) ) {
+ any_ivar_present = true;
+ }
+ if( !dest_type ) {
+ dest_type = ent.ty;
+ continue ;
+ }
+
+ auto cmp = TypeRestrictiveOrdering::get_ordering_ptr(sp, context, *ent.ty, *dest_type);
+ switch(cmp)
+ {
+ case OrdLess:
+ // This entry is less restrictive, so DO update `dest_type`
+ dest_type = ent.ty;
+ break;
+ case OrdEqual:
+ break;
+ case OrdGreater:
+ // This entry is more restrictive, so don't update `dest_type`
+ break;
+ }
+ }
+
+ if( dest_type && n_ivars == 0 && any_ivar_present == false )
+ {
+ DEBUG("Suitable option " << *dest_type << " from " << possible_tys);
+ context.equate_types(sp, ty_l, *dest_type);
return true;
- } while( (ty = context.m_resolve.autoderef(sp, *ty, tmp)) );
- return false;
+ }
+ }
}
- static ::std::vector<::HIR::TypeRef>& merge_lists(const Context& context, ::std::vector<::HIR::TypeRef>& list_a, ::std::vector<::HIR::TypeRef>& list_b, ::std::vector<::HIR::TypeRef>& out)
+ DEBUG("possible_tys = " << possible_tys);
+ DEBUG("- Bounded [" << ivar_ent.bounded << "]");
+#if 1
+ if( !possible_tys.empty() )
{
- if( list_a.size() == 0 )
- return list_b;
- else if( list_b.size() == 0 )
- return list_a;
- else {
- for(const auto& t : list_a) {
- out.push_back( t.clone() );
+ for(const auto& new_ty : ivar_ent.bounded)
+ {
+ bool failed_a_bound = false;
+ // Check if this bounded type _cannot_ work with any of the existing bounds
+ // - Don't add to the possiblity list if so
+ for(const auto& opt : possible_tys)
+ {
+ CoerceResult res;
+ if( opt.can_deref ) {
+ DEBUG(" > " << new_ty << " =? " << *opt.ty);
+ res = check_unsize_tys(context, sp, new_ty, *opt.ty, nullptr, false);
+ }
+ else {
+ // Destination type, this option must deref to it
+ DEBUG(" > " << *opt.ty << " =? " << new_ty);
+ res = check_unsize_tys(context, sp, *opt.ty, new_ty, nullptr, false);
+ }
+ DEBUG(" = " << res);
+ if( res == CoerceResult::Equality ) {
+ failed_a_bound = true;
+ break;
+ }
+ else if( res == CoerceResult::Unknown ) {
+ // Should this also be treated as a fail?
+ }
}
- for(const auto& t : list_b ) {
- out.push_back( t.clone() );
+ if( !failed_a_bound )
+ {
+ // TODO: Don't add ivars?
+ if( new_ty == ty_l )
+ {
+ }
+ else if( new_ty.m_data.is_Infer() )
+ {
+ n_ivars += 1;
+ }
+ else
+ {
+ possible_tys.push_back(PossibleType { false, false, &new_ty });
+ }
}
- H::dedup_type_list(context, out);
- return out;
}
}
- };
-
- // If this type has an infer class active, don't allw a non-primitive to coerce over it.
- if( ty_l.m_data.as_Infer().is_lit() )
- {
- DEBUG("Literal checks");
- // TODO: Actively search possibility list for the real type.
- for(const auto& ty : ivar_ent.types_coerce_to)
- if( ty.m_data.is_Primitive() ) {
- context.equate_types(sp, ty_l, ty);
- return true;
- }
- for(const auto& ty : ivar_ent.types_unsize_to)
- if( ty.m_data.is_Primitive() ) {
- context.equate_types(sp, ty_l, ty);
- return true;
- }
- for(const auto& ty : ivar_ent.types_coerce_from)
- if( ty.m_data.is_Primitive() ) {
- context.equate_types(sp, ty_l, ty);
- return true;
- }
- for(const auto& ty : ivar_ent.types_unsize_from)
- if( ty.m_data.is_Primitive() ) {
- context.equate_types(sp, ty_l, ty);
- return true;
- }
- return false;
- }
-
- if( honour_disable && (ivar_ent.force_no_to || ivar_ent.force_no_from) )
- {
- DEBUG("- IVar " << ty_l << " is forced unknown");
- return false;
- }
- else
- {
- TRACE_FUNCTION_F(i);
-
-
- // TODO: Dedup based on context?
- // - The dedup should probably be aware of the way the types are used (for coercions).
- H::dedup_type_list(context, ivar_ent.types_coerce_to);
- H::dedup_type_list(context, ivar_ent.types_unsize_to);
- H::dedup_type_list(context, ivar_ent.types_coerce_from);
- H::dedup_type_list(context, ivar_ent.types_unsize_from);
-
- #if 0
- // If there is a default type compatible with all possibilities, use that.
- if( ivar_ent.types_default.size() > 0 ) {
- // TODO: Should multiple options be valid?
- ASSERT_BUG(Span(), ivar_ent.types_def.size() == 1, "TODO: Multiple default types for an ivar - " << ivar_ent.types_def);
- }
- #endif
-
- if( ivar_ent.types_coerce_from.size() == 0 && ivar_ent.types_coerce_to.size() == 0
- && ivar_ent.types_unsize_from.size() == 0 && ivar_ent.types_unsize_to.size() == 0
- )
+#endif
+ DEBUG("possible_tys = " << possible_tys);
+ // Filter out useless options and impossiblities
+ for(auto it = possible_tys.begin(); it != possible_tys.end(); )
{
- DEBUG("-- No known options for " << ty_l);
- return false;
- }
- DEBUG("-- " << ty_l << " FROM=Coerce:{" << ivar_ent.types_coerce_from << "} / Unsize:{" << ivar_ent.types_unsize_from << "},"
- << " TO=Coerce:{" << ivar_ent.types_coerce_to << "} / Unsize:{" << ivar_ent.types_unsize_to << "}");
-
- // Find an entry in the `types_unsize_from` list that all other entries can unsize to
- H::dedup_type_list_with(ivar_ent.types_unsize_from, [&](const auto& l, const auto& r) {
- if( l.m_data.is_Infer() || r.m_data.is_Infer() )
- return DedupKeep::Both;
-
- // Check for fuzzy equality of types, and keep only one
- // TODO: Ensure that whatever ivar differs can't be different (i.e. it wouldn't change the unsize/coerce)
- // TODO: Use `check_unsize_tys` instead
- if( l.compare_with_placeholders(sp, r, context.m_ivars.callback_resolve_infer()) != ::HIR::Compare::Unequal )
+ bool remove_option = false;
+ if( *it->ty == ty_l )
{
- DEBUG("Possible match, keep left");
- return DedupKeep::Left;
+ remove_option = true;
}
-
- // &T and T
- TU_IFLET( ::HIR::TypeRef::Data, l.m_data, Borrow, le,
- TU_IFLET( ::HIR::TypeRef::Data, r.m_data, Borrow, re,
- )
- else {
- // if *le.inner == r, return DedupKeep::Right
- if( context.m_ivars.types_equal(*le.inner, r) )
- return DedupKeep::Right;
- }
- )
- else {
- TU_IFLET( ::HIR::TypeRef::Data, r.m_data, Borrow, re,
- // if *re.inner == l, return DedupKeep::Left
- if( context.m_ivars.types_equal(*re.inner, l) )
- return DedupKeep::Left;
- )
+ else if( !allow_unsized && context.m_resolve.type_is_sized(sp, *it->ty) == ::HIR::Compare::Unequal )
+ {
+ remove_option = true;
}
- return DedupKeep::Both;
- });
- // Find an entry in the `types_coerce_from` list that all other entries can coerce to
- H::dedup_type_list_with(ivar_ent.types_coerce_from, [&](const auto& l, const auto& r) {
- if( l.m_data.is_Infer() || r.m_data.is_Infer() )
- return DedupKeep::Both;
-
- // Check for fuzzy equality of types, and keep only one
- // TODO: Ensure that whatever ivar differs can't be different (i.e. it wouldn't change the unsize/coerce)
- // TODO: Use `check_coerce_tys` instead
- if( l.compare_with_placeholders(sp, r, context.m_ivars.callback_resolve_infer()) != ::HIR::Compare::Unequal )
+ else
{
- DEBUG("Possible match, keep left");
- return DedupKeep::Left;
+ // Keep
}
- if( l.m_data.is_Borrow() )
+ // TODO: Ivars have been removed, this sort of check should be moved elsewhere.
+ if( !remove_option && ty_l.m_data.as_Infer().ty_class == ::HIR::InferClass::Integer )
{
- const auto& le = l.m_data.as_Borrow();
- ASSERT_BUG(sp, r.m_data.is_Borrow() || r.m_data.is_Pointer(), "Coerce source for borrow isn't a borrow/pointert - " << r);
- const auto re_borrow_type = r.m_data.is_Borrow() ? r.m_data.as_Borrow().type : r.m_data.as_Pointer().type;
- const auto& re_inner = r.m_data.is_Borrow() ? r.m_data.as_Borrow().inner : r.m_data.as_Pointer().inner;
-
- if( le.type < re_borrow_type ) {
- return DedupKeep::Left;
+ if( const auto* te = it->ty->m_data.opt_Primitive() ) {
+ (void)te;
+ }
+ else if( const auto* te = it->ty->m_data.opt_Path() ) {
+ // If not Unbound, remove option
+ (void)te;
}
- else if( le.type > re_borrow_type ) {
- return DedupKeep::Right;
+ else if( const auto* te = it->ty->m_data.opt_Infer() ) {
+ (void)te;
}
else {
+ remove_option = true;
}
-
- // Dereference `*re.inner` until it isn't possible or it equals `*le.inner`
- // - Repeat going the other direction.
- if( H::type_derefs_from(sp, context, *le.inner, *re_inner) )
- return DedupKeep::Left;
- if( H::type_derefs_from(sp, context, *re_inner, *le.inner) )
- return DedupKeep::Right;
}
- return DedupKeep::Both;
- });
-
- // If there's one option for both desination types, and nothing for the source ...
- if( ivar_ent.types_coerce_to.size() == 1 && ivar_ent.types_unsize_to.size() == 1 && ivar_ent.types_coerce_from.empty() && ivar_ent.types_unsize_from.empty() )
- {
- // And the coercion can unsize to the unsize, pick the coercion (it's valid, the other way around isn't)
- // TODO: Use a `can_unsize_to` functon instead (that handles Unsize as well as Deref)
- if( H::type_derefs_from(sp, context, ivar_ent.types_unsize_to[0], ivar_ent.types_coerce_to[0]) )
- {
- const auto& new_ty = ivar_ent.types_coerce_to[0];
- DEBUG("- IVar " << ty_l << " = " << new_ty << " (unsize to)");
- context.equate_types(sp, ty_l, new_ty);
- return true;
- }
+ it = (remove_option ? possible_tys.erase(it) : it + 1);
}
- #if 0
- // If there's only one coerce and unsize from, ...
- if( ivar_ent.types_coerce_from.size() == 1 && ivar_ent.types_unsize_from.size() == 1 && ivar_ent.types_coerce_to.empty() && ivar_ent.types_unsize_to.empty() )
+ DEBUG("possible_tys = " << possible_tys);
+ for(auto it = possible_tys.begin(); it != possible_tys.end(); )
{
- // and if the coerce can unsize to the unsize target.
- if( H::can_coerce_to(context, ivar_ent.types_unsize_from[0], ivar_ent.types_coerce_from[0]) )
+ bool remove_option = false;
+ for(const auto& other_opt : possible_tys)
{
- const auto& new_ty = ivar_ent.types_coerce_from[0];
- DEBUG("- IVar " << ty_l << " = " << new_ty << " (coerce from)");
- context.equate_types(sp, ty_l, new_ty);
- return true;
+ if( &other_opt == &*it )
+ continue ;
+ if( *other_opt.ty == *it->ty )
+ {
+ // Potential duplicate
+ // - If the flag set is the same, then it is a duplicate
+ if( other_opt.can_deref == it->can_deref && other_opt.is_pointer == it->is_pointer ) {
+ remove_option = true;
+ break;
+ }
+ // If not an ivar, AND both are either unsize/pointer AND the deref flags are different
+ // TODO: Ivars have been removed?
+ if( !it->ty->m_data.is_Infer() && other_opt.is_pointer == it->is_pointer && other_opt.can_deref != it->can_deref )
+ {
+ // TODO: Possible duplicate with a check above...
+ DEBUG("Source and destination possibility, picking " << *it->ty);
+ context.equate_types(sp, ty_l, *it->ty);
+ return true;
+ }
+ // - Otherwise, we want to keep the option which doesn't allow dereferencing (remove current
+ // if it's the deref option)
+ if( it->can_deref && other_opt.is_pointer == it->is_pointer ) {
+ remove_option = true;
+ break;
+ }
+ }
}
+ it = (remove_option ? possible_tys.erase(it) : it + 1);
}
- #endif
-
- //
-
- // HACK: Merge into a single lists
- ::std::vector< ::HIR::TypeRef> types_from_o;
- auto& types_from = H::merge_lists(context, ivar_ent.types_coerce_from, ivar_ent.types_unsize_from, types_from_o);
- ::std::vector< ::HIR::TypeRef> types_to_o;
- auto& types_to = H::merge_lists(context, ivar_ent.types_coerce_to , ivar_ent.types_unsize_to , types_to_o );
- DEBUG(" " << ty_l << " FROM={" << types_from << "}, TO={" << types_to << "}");
-
- // TODO: If there is only a single option and it's from an Unsize, is it valid?
-
- // TODO: Loop both lists and if there's T<_{int}> and T<uN/iN> unify those.
-
- // Same type on both sides, pick it.
- if( types_from == types_to && types_from.size() == 1 ) {
- const auto& new_ty = types_from[0];
- DEBUG("- IVar " << ty_l << " = " << new_ty << " (only)");
- context.equate_types(sp, ty_l, new_ty);
- return true;
- }
-
- // Eliminate possibilities that don't fit known constraints
- if( types_to.size() > 0 && types_from.size() > 0 )
+ DEBUG("possible_tys = " << possible_tys);
+ // Remove any options that are filled by other options (e.g. `str` and a derferencable String)
+ for(auto it = possible_tys.begin(); it != possible_tys.end(); )
{
- // TODO: Search `types_to` too
- for(auto it = types_from.begin(); it != types_from.end(); )
+ bool remove_option = false;
+ if( it->can_deref && !it->ty->m_data.is_Infer() )
{
- bool remove = false;
- const auto& new_ty = context.get_type(*it);
- if( !new_ty.m_data.is_Infer() )
+ DEBUG("> " << *it);
+ // Dereference once before starting the search
+ ::HIR::TypeRef tmp, tmp2;
+ const auto* dty = it->ty;
+ auto src_bty = ::HIR::BorrowType::Shared;
+ if(it->is_pointer)
+ {
+ if( dty->m_data.is_Borrow() )
+ src_bty = dty->m_data.as_Borrow().type;
+ dty = context.m_resolve.autoderef(sp, *dty, tmp);
+ // NOTE: Coercions can also do closure->fn, so deref isn't always possible
+ //ASSERT_BUG(sp, dty, "Pointer (coercion source) that can't dereference - " << *it->ty);
+ }
+ //while( dty && !remove_option && (dty = context.m_resolve.autoderef(sp, *dty, tmp)) )
+ if( dty )
{
- for(const auto& bound : context.link_assoc)
+ for(const auto& other_opt : possible_tys)
{
- if( bound.impl_ty != ty_l )
+ if( &other_opt == &*it )
continue ;
+ if( other_opt.ty->m_data.is_Infer() )
+ continue ;
+ DEBUG(" > " << other_opt);
- // TODO: Monomorphise this type replacing mentions of the current ivar with the replacement?
-
- // Search for any trait impl that could match this,
- bool has = context.m_resolve.find_trait_impls(sp, bound.trait, bound.params, new_ty, [&](const auto , auto){return true;});
- if( !has ) {
- // If none was found, remove from the possibility list
- remove = true;
- DEBUG("Remove possibility " << new_ty << " because it failed a bound");
- break ;
+ const auto* oty = other_opt.ty;
+ auto o_bty = ::HIR::BorrowType::Owned;
+ if(other_opt.is_pointer)
+ {
+ if( oty->m_data.is_Borrow() )
+ o_bty = oty->m_data.as_Borrow().type;
+ oty = context.m_resolve.autoderef(sp, *oty, tmp2);
+ //ASSERT_BUG(sp, oty, "Pointer (coercion src/dst) that can't dereference - " << *other_opt.ty);
+ }
+ if( o_bty > src_bty ) // Smaller means less powerful. Converting & -> &mut is invalid
+ {
+ // Borrow types aren't compatible
+ DEBUG("BT " << o_bty << " > " << src_bty);
+ break;
+ }
+ // TODO: Check if unsize is possible from `dty` to `oty`
+ if( oty )
+ {
+ DEBUG(" > " << *dty << " =? " << *oty);
+ auto cmp = check_unsize_tys(context, sp, *oty, *dty, nullptr, false);
+ DEBUG(" = " << cmp);
+ if( cmp == CoerceResult::Equality )
+ {
+ //TODO(sp, "Impossibility for " << *oty << " := " << *dty);
+ }
+ else if( cmp == CoerceResult::Unknown )
+ {
+ }
+ else
+ {
+ remove_option = true;
+ DEBUG("- Remove " << *it << ", can deref to " << other_opt);
+ break;
+ }
}
}
+ }
+ }
+ if( !remove_option && !it->ty->m_data.is_Infer() && check_ivar_poss__fails_bounds(sp, context, ty_l, *it->ty) )
+ {
+ remove_option = true;
+ DEBUG("- Remove " << *it << " due to bounds");
+ }
+ it = (remove_option ? possible_tys.erase(it) : it + 1);
+ }
+ DEBUG("possible_tys = " << possible_tys << " (" << n_src_ivars << " src ivars, " << n_dst_ivars << " dst ivars)");
- if( !remove && !allow_unsized )
+ // Find a CD option that can deref to a `--` option
+ for(const auto& e : possible_tys)
+ {
+ if( e.is_pointer && e.can_deref )
+ {
+ ::HIR::TypeRef tmp;
+ const auto* dty = context.m_resolve.autoderef(sp, *e.ty, tmp);
+ if( dty && !dty->m_data.is_Infer() )
+ {
+ for(const auto& e2 : possible_tys)
{
- if( context.m_resolve.type_is_sized(sp, new_ty) == ::HIR::Compare::Unequal )
+ if( !e2.is_pointer && !e2.can_deref )
{
- remove = true;
- DEBUG("Remove possibility " << new_ty << " because it isn't Sized");
+ if( context.m_ivars.types_equal(*dty, *e2.ty) )
+ {
+ DEBUG("Coerce source can deref once to an unsize destination, picking source " << *e.ty);
+ context.equate_types(sp, ty_l, *e.ty);
+ return true;
+ }
}
}
}
-
- if( remove ) {
- it = types_from.erase(it);
- }
- else {
- ++it;
- }
}
+ }
- // Eliminate `to` types that can't be coerced from `from` types
- if(types_from.size() > 0)
- for(auto it = types_to.begin(); it != types_to.end(); )
+ // If there's only one option (or one real option w/ ivars, if in fallback mode) - equate it
+ //if( possible_tys.size() == 1 && (n_ivars == 0 || !honour_disable) )
+ if( possible_tys.size() == 1 && n_ivars == 0 )
+ {
+ const auto& new_ty = *possible_tys[0].ty;
+ DEBUG("Only " << new_ty << " is an option");
+ context.equate_types(sp, ty_l, new_ty);
+ return true;
+ }
+ // If there's only one non-deref in the list OR there's only one deref in the list
+ if( !honour_disable && n_src_ivars == 0 && ::std::count_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return pt.can_deref; }) == 1 )
+ {
+ auto it = ::std::find_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return pt.can_deref; });
+ const auto& new_ty = *it->ty;
+ DEBUG("Picking " << new_ty << " as the only source [" << possible_tys << "]");
+ context.equate_types(sp, ty_l, new_ty);
+ return true;
+ }
+ if( !honour_disable && n_dst_ivars == 0 && ::std::count_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return !pt.can_deref; }) == 1 )
+ {
+ auto it = ::std::find_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return !pt.can_deref; });
+ const auto& new_ty = *it->ty;
+ if( it->is_pointer )
{
- if( it->m_data.is_Infer() ) {
- ++ it;
- continue;
- }
- bool remove = false;
+ DEBUG("Picking " << new_ty << " as the only target [" << possible_tys << "]");
+ context.equate_types(sp, ty_l, new_ty);
+ return true;
+ }
+ else
+ {
+ // HACK: Work around failure in librustc
+ DEBUG("Would pick " << new_ty << " as the only target, but it's an unsize");
+ }
+ }
+ // If there's multiple possiblilties, we're in fallback mode, AND there's no ivars in the list
+ if( possible_tys.size() > 0 && !honour_disable && n_ivars == 0 )
+ {
+ //::std::sort(possible_tys.begin(), possible_tys.end()); // Sorts ivars to the front
+ const auto& new_ty = *possible_tys.back().ty;
+ DEBUG("Picking " << new_ty << " as an arbitary an option from [" << possible_tys << "]");
+ context.equate_types(sp, ty_l, new_ty);
+ return true;
+ }
- for(const auto& src : types_from)
- {
- if( H::cannot_coerce_to(context, *it, src) ) {
- remove = true;
- DEBUG("Remove target type " << *it << " because it cannot be created from a source type");
- break;
+ // If there's no ivars, and no instances of &_ or Box<_>, then error/bug here.
+#if 0
+ if( possible_tys.size() > 0 )
+ {
+ struct H {
+ static const ::HIR::TypeRef& get_pointer_inner(const Context& context, const ::HIR::TypeRef& t_raw) {
+ const auto& t = context.m_ivars.get_type(t_raw);
+ if( const auto* te = t.m_data.opt_Borrow() ) {
+ return get_pointer_inner(context, *te->inner);
}
- }
-
- if( !remove && !allow_unsized )
- {
- if( context.m_resolve.type_is_sized(sp, *it) == ::HIR::Compare::Unequal )
+ else if( const auto* te = t.m_data.opt_Pointer() ) {
+ return get_pointer_inner(context, *te->inner);
+ }
+ else if( TU_TEST2(t.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) )
{
- remove = true;
- DEBUG("Remove possibility " << *it << " because it isn't Sized");
+ const auto& te = t.m_data.as_Path();
+ auto param_idx = te.binding.as_Struct()->m_struct_markings.coerce_param;
+ assert(param_idx != ~0u);
+ const auto& path = te.path.m_data.as_Generic();
+ return get_pointer_inner(context, path.m_params.m_types.at(param_idx));
+ }
+ else {
+ return t;
}
}
-
- if( remove ) {
- it = types_to.erase(it);
+ };
+ bool has_all_info = true;
+ if( n_ivars > 0 )
+ {
+ has_all_info = false;
+ }
+ for(const auto& e : possible_tys)
+ {
+ const auto& inner = H::get_pointer_inner(context, *e.ty);
+ DEBUG(e << ", inner=" << inner);
+ if( inner.m_data.is_Infer() )
+ {
+ has_all_info = false;
}
- else {
- ++it;
+ if( TU_TEST1(inner.m_data, Path, .binding.is_Unbound()) )
+ {
+ has_all_info = false;
}
}
- }
-
- // De-duplicate lists (after unification) using strict equality
- H::dedup_type_list_with(types_from, [&](const auto& l, const auto& r) {
- return context.m_ivars.types_equal(l, r) ? DedupKeep::Left : DedupKeep::Both;
- });
- H::dedup_type_list_with(types_to, [&](const auto& l, const auto& r) {
- return context.m_ivars.types_equal(l, r) ? DedupKeep::Left : DedupKeep::Both;
- });
-
- // If there is a common type in both lists, use it
- for(const auto& t1 : types_from)
- {
- for(const auto& t2 : types_to)
+ if( has_all_info )
{
- if(t1 == t2) {
- DEBUG("- IVar " << ty_l << " = " << t1 << " (present in both lists)");
- context.equate_types(sp, ty_l, t1);
- return true;
- }
+ BUG(sp, "Sufficient information for " << ty_l << " but didn't pick a type - options are [" << possible_tys << "]");
}
}
+#endif
- // Prefer cases where this type is being created from a known type
- if( types_from.size() == 1 || types_to.size() == 1 ) {
- const char* list_name = (types_from.size() ? "from" : "to");
- const ::HIR::TypeRef& ty_r = (types_from.size() == 1 ? types_from[0] : types_to[0]);
- // Only one possibility
- // - If it would ivar unify, don't if the target has guessing disabled
- if( const auto* e = ty_r.m_data.opt_Infer() )
+ // If only one bound meets the possible set, use it
+ if( ! possible_tys.empty() )
+ {
+ DEBUG("Checking bounded [" << ivar_ent.bounded << "]");
+ ::std::vector<const ::HIR::TypeRef*> feasable_bounds;
+ for(const auto& new_ty : ivar_ent.bounded)
{
- if( e->index < context.possible_ivar_vals.size() )
+ bool failed_a_bound = false;
+ // TODO: Check if this bounded type _cannot_ work with any of the existing bounds
+ // - Don't add to the possiblity list if so
+ for(const auto& opt : possible_tys)
{
- const auto& p = context.possible_ivar_vals[e->index];
- if( honour_disable && (p.force_no_to || p.force_no_from) )
- {
- DEBUG("- IVar " << ty_l << " ?= " << ty_r << " (single " << list_name << ", rhs disabled)");
- return false;
+ if( opt.can_deref ) {
+ const auto* dty = opt.ty;
+
+ DEBUG(" > " << new_ty << " =? " << *dty);
+ auto cmp = check_unsize_tys(context, sp, new_ty, *dty, nullptr, false);
+ DEBUG(" = " << cmp);
+ if( cmp == CoerceResult::Equality ) {
+ failed_a_bound = true;
+ break;
+ }
+ }
+ else {
+ // Destination type, this option must deref to it
+ DEBUG(" > " << *opt.ty << " =? " << new_ty);
+ auto cmp = check_unsize_tys(context, sp, *opt.ty, new_ty, nullptr, false);
+ DEBUG(" = " << cmp);
+ if( cmp == CoerceResult::Equality ) {
+ failed_a_bound = true;
+ break;
+ }
}
}
+ // TODO: Should this also check check_ivar_poss__fails_bounds
+ if( !failed_a_bound )
+ {
+ feasable_bounds.push_back(&new_ty);
+ }
}
- // If there are from options, AND the to option is an Unsize
- if( types_from.size() > 1 && ivar_ent.types_unsize_to.size() == 1 && ivar_ent.types_coerce_to.size() == 0
- && ::std::any_of(types_from.begin(), types_from.end(), [](const auto&x){ return x.m_data.is_Infer(); }) ) {
- DEBUG("- IVar " << ty_l << " != " << ty_r << " (single " << list_name << ", but was unsize and from has ivars)");
- return false;
+ if( feasable_bounds.size() == 1 )
+ {
+ const auto& new_ty = *feasable_bounds.front();
+ DEBUG("Picking " << new_ty << " as it's the only bound that fits coercions");
+ context.equate_types(sp, ty_l, new_ty);
+ return true;
}
-
- DEBUG("- IVar " << ty_l << " = " << ty_r << " (single " << list_name << ")");
- context.equate_types(sp, ty_l, ty_r);
- return true;
}
- else {
- DEBUG("- IVar " << ty_l << " not concretely known {" << types_from << "} and {" << types_to << "}" );
+ else
+ {
+ // Not checking bounded list, because there's nothing to check
+ }
+
+ has_no_coerce_posiblities = possible_tys.empty() && n_ivars == 0;
+ }
- // If one side is completely unknown, pick the most liberal of the other side
- if( types_to.size() == 0 && types_from.size() > 0 )
+ if( has_no_coerce_posiblities && !ivar_ent.bounded.empty() )
+ {
+ // TODO: Search know possibilties and check if they satisfy the bounds for this ivar
+ DEBUG("Options: " << ivar_ent.bounded);
+ unsigned int n_good_ints = 0;
+ ::std::vector<const ::HIR::TypeRef*> good_types;
+ good_types.reserve(ivar_ent.bounded.size());
+ for(const auto& new_ty : ivar_ent.bounded)
+ {
+ DEBUG("- Test " << new_ty << " against current rules");
+ if( check_ivar_poss__fails_bounds(sp, context, ty_l, new_ty) )
{
- // Search for the lowest-level source type (e.g. &[T])
- const auto* lowest_type = H::find_lowest_type(context, types_from);
- if( lowest_type )
- {
- const ::HIR::TypeRef& ty_r = *lowest_type;
- DEBUG("- IVar " << ty_l << " = " << ty_r << " (from, lowest)");
- context.equate_types(sp, ty_l, ty_r);
- return true;
- }
}
- else if( types_to.size() > 0 && types_from.size() == 0 )
+ else
+ {
+ good_types.push_back(&new_ty);
+
+ if( new_ty.m_data.is_Primitive() )
+ n_good_ints ++;
+
+ DEBUG("> " << new_ty << " feasible");
+ }
+ }
+ DEBUG(good_types.size() << " valid options (" << n_good_ints << " primitives)");
+ // Picks the first if in fallback mode (which is signalled by `honour_disable` being false)
+ // - This handles the case where there's multiple valid options (needed for libcompiler_builtins)
+ // TODO: Only pick any if all options are the same class (or just all are integers)
+ if( good_types.empty() )
+ {
+
+ }
+ else if( good_types.size() == 1 )
+ {
+ // Since it's the only possibility, choose it?
+ DEBUG("Only " << *good_types.front() << " fits current bound sets");
+ context.equate_types(sp, ty_l, *good_types.front());
+ return true;
+ }
+ else if( good_types.size() > 0 && fallback_ty == IvarPossFallbackType::FinalOption )
+ {
+ auto typ_is_borrow = [&](const ::HIR::TypeRef* typ) { return typ->m_data.is_Borrow(); };
+ // NOTE: We want to select from sets of primitives and generics (which can be interchangable)
+ if( ::std::all_of(good_types.begin(), good_types.end(), typ_is_borrow) == ::std::any_of(good_types.begin(), good_types.end(), typ_is_borrow) )
{
- // TODO: Get highest-level target type
+ DEBUG("Picking " << *good_types.front() << " as first of " << good_types.size() << " options [" << FMT_CB(ss, for(auto e:good_types) ss << *e << ",";) << "]");
+ context.equate_types(sp, ty_l, *good_types.front());
+ return true;
}
else
{
+ // Mix of borrows with non-borrows
}
}
}
@@ -6085,10 +8385,11 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
TRACE_FUNCTION;
auto root_ptr = expr.into_unique();
- Context context { ms.m_crate, ms.m_impl_generics, ms.m_item_generics };
+ assert(!ms.m_mod_paths.empty());
+ Context context { ms.m_crate, ms.m_impl_generics, ms.m_item_generics, ms.m_mod_paths.back() };
for( auto& arg : args ) {
- context.add_binding( Span(), arg.first, arg.second );
+ context.handle_pattern( Span(), arg.first, arg.second );
}
// - Build up ruleset from node tree
@@ -6120,11 +8421,18 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
return false;
});
+ if(true)
+ {
+ ExprVisitor_AddIvars visitor(context);
+ context.add_ivars(root_ptr->m_res_type);
+ root_ptr->visit(visitor);
+ }
+
ExprVisitor_Enum visitor(context, ms.m_traits, result_type);
context.add_ivars(root_ptr->m_res_type);
root_ptr->visit(visitor);
- DEBUG("Return type = " << new_res_ty);
+ DEBUG("Return type = " << new_res_ty << ", root_ptr = " << typeid(*root_ptr).name() << " " << root_ptr->m_res_type);
context.equate_types_coerce(sp, new_res_ty, root_ptr);
}
@@ -6149,6 +8457,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
{
DEBUG("- Consumed coercion " << ent.left_ty << " := " << src_ty);
+#if 0
// If this isn't the last item in the list
if( i != context.link_coerce.size() - 1 )
{
@@ -6157,6 +8466,9 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
}
// Remove the last item.
context.link_coerce.pop_back();
+#else
+ context.link_coerce.erase( context.link_coerce.begin() + i );
+#endif
}
else
{
@@ -6177,6 +8489,10 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
}
if( rule.name != "" ) {
rule.left_ty = context.m_resolve.expand_associated_types(rule.span, mv$(rule.left_ty));
+ // HACK: If the left type is `!`, remove the type bound
+ //if( rule.left_ty.m_data.is_Diverge() ) {
+ // rule.name = "";
+ //}
}
rule.impl_ty = context.m_resolve.expand_associated_types(rule.span, mv$(rule.impl_ty));
@@ -6217,14 +8533,19 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
++ it;
}
}
- for( auto it = context.adv_revisits.begin(); it != context.adv_revisits.end(); )
{
- auto& ent = **it;
- if( ent.revisit(context) ) {
- it = context.adv_revisits.erase(it);
+ ::std::vector<bool> adv_revisit_remove_list;
+ size_t len = context.adv_revisits.size();
+ for(size_t i = 0; i < len; i ++)
+ {
+ auto& ent = *context.adv_revisits[i];
+ adv_revisit_remove_list.push_back( ent.revisit(context, /*is_fallback=*/false) );
}
- else {
- ++ it;
+ for(size_t i = len; i --;)
+ {
+ if( adv_revisit_remove_list[i] ) {
+ context.adv_revisits.erase( context.adv_revisits.begin() + i );
+ }
}
}
@@ -6234,12 +8555,13 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
{
// Check the possible equations
DEBUG("--- IVar possibilities");
- // NOTE: Ordering is a hack for libgit2
- for(unsigned int i = context.possible_ivar_vals.size(); i --; )
+ // TODO: De-duplicate this with the block ~80 lines below
+ //for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
+ for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
{
if( check_ivar_poss(context, i, context.possible_ivar_vals[i]) ) {
static Span sp;
- assert( context.possible_ivar_vals[i].has_rules() );
+ //assert( context.possible_ivar_vals[i].has_rules() );
// Disable all metioned ivars in the possibilities
for(const auto& ty : context.possible_ivar_vals[i].types_coerce_to)
context.equate_types_from_shadow(sp,ty);
@@ -6251,6 +8573,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
context.equate_types_to_shadow(sp,ty);
// Also disable inferrence (for this pass) for all ivars in affected bounds
+ if(false)
for(const auto& la : context.link_assoc)
{
bool found = false;
@@ -6276,47 +8599,70 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
}
} // `if peek_changed` (ivar possibilities)
+#if 0
if( !context.m_ivars.peek_changed() )
{
- DEBUG("--- Node revisits (fallback)");
- for( auto it = context.to_visit.begin(); it != context.to_visit.end(); )
+ DEBUG("--- Coercion consume");
+ if( ! context.link_coerce.empty() )
{
- ::HIR::ExprNode& node = **it;
- ExprVisitor_Revisit visitor { context, true };
- DEBUG("> " << &node << " " << typeid(node).name() << " -> " << context.m_ivars.fmt_type(node.m_res_type));
- node.visit( visitor );
- // - If the node is completed, remove it
- if( visitor.node_completed() ) {
- DEBUG("- Completed " << &node << " - " << typeid(node).name());
- it = context.to_visit.erase(it);
- }
- else {
- ++ it;
- }
+ auto ent = mv$(context.link_coerce.front());
+ context.link_coerce.erase( context.link_coerce.begin() );
+
+ const auto& sp = (*ent.right_node_ptr)->span();
+ auto& src_ty = (**ent.right_node_ptr).m_res_type;
+ //src_ty = context.m_resolve.expand_associated_types( sp, mv$(src_ty) );
+ ent.left_ty = context.m_resolve.expand_associated_types( sp, mv$(ent.left_ty) );
+ DEBUG("- Equate coercion R" << ent.rule_idx << " " << ent.left_ty << " := " << src_ty);
+
+ context.equate_types(sp, ent.left_ty, src_ty);
}
- #if 0
- for( auto it = context.adv_revisits.begin(); it != context.adv_revisits.end(); )
+ }
+#endif
+ // If nothing has changed, run check_ivar_poss again but allow it to assume is has all the options
+ if( !context.m_ivars.peek_changed() )
+ {
+ // Check the possible equations
+ DEBUG("--- IVar possibilities (fallback 1)");
+ //for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
+ for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
{
- auto& ent = **it;
- if( ent.revisit(context, true) ) {
- it = context.adv_revisits.erase(it);
- }
- else {
- ++ it;
+ if( check_ivar_poss(context, i, context.possible_ivar_vals[i], IvarPossFallbackType::Assume) ) {
+ break;
}
}
- #endif
- } // `if peek_changed` (node revisits)
+ }
+#if 0
+ if( !context.m_ivars.peek_changed() )
+ {
+ DEBUG("--- Coercion consume");
+ if( ! context.link_coerce.empty() )
+ {
+ auto ent = mv$(context.link_coerce.front());
+ context.link_coerce.erase( context.link_coerce.begin() );
+
+ const auto& sp = (*ent.right_node_ptr)->span();
+ auto& src_ty = (**ent.right_node_ptr).m_res_type;
+ //src_ty = context.m_resolve.expand_associated_types( sp, mv$(src_ty) );
+ ent.left_ty = context.m_resolve.expand_associated_types( sp, mv$(ent.left_ty) );
+ DEBUG("- Equate coercion R" << ent.rule_idx << " " << ent.left_ty << " := " << src_ty);
+ context.equate_types(sp, ent.left_ty, src_ty);
+ }
+ }
+#endif
// If nothing has changed, run check_ivar_poss again but ignoring the 'disable' flag
+#if 1
if( !context.m_ivars.peek_changed() )
{
// Check the possible equations
DEBUG("--- IVar possibilities (fallback)");
- // NOTE: Ordering is a hack for libgit2
- for(unsigned int i = context.possible_ivar_vals.size(); i --; )
+ //for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
+ for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
{
- if( check_ivar_poss(context, i, context.possible_ivar_vals[i], /*honour_disable=*/false) ) {
+ if( check_ivar_poss(context, i, context.possible_ivar_vals[i], IvarPossFallbackType::IgnoreWeakDisable) ) {
+# if 1
+ break;
+# else
static Span sp;
assert( context.possible_ivar_vals[i].has_rules() );
// Disable all metioned ivars in the possibilities
@@ -6348,13 +8694,95 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
context.equate_types_shadow(sp, t, false);
}
}
+# endif
}
else {
//assert( !context.m_ivars.peek_changed() );
}
}
+#endif
} // `if peek_changed` (ivar possibilities #2)
+ if( !context.m_ivars.peek_changed() )
+ {
+ DEBUG("--- Node revisits (fallback)");
+ for( auto it = context.to_visit.begin(); it != context.to_visit.end(); )
+ {
+ ::HIR::ExprNode& node = **it;
+ ExprVisitor_Revisit visitor { context, true };
+ DEBUG("> " << &node << " " << typeid(node).name() << " -> " << context.m_ivars.fmt_type(node.m_res_type));
+ node.visit( visitor );
+ // - If the node is completed, remove it
+ if( visitor.node_completed() ) {
+ DEBUG("- Completed " << &node << " - " << typeid(node).name());
+ it = context.to_visit.erase(it);
+ }
+ else {
+ ++ it;
+ }
+ }
+ #if 0
+ for( auto it = context.adv_revisits.begin(); it != context.adv_revisits.end(); )
+ {
+ auto& ent = **it;
+ if( ent.revisit(context, true) ) {
+ it = context.adv_revisits.erase(it);
+ }
+ else {
+ ++ it;
+ }
+ }
+ #endif
+ } // `if peek_changed` (node revisits)
+
+ if( !context.m_ivars.peek_changed() )
+ {
+ size_t len = context.adv_revisits.size();
+ for(size_t i = 0; i < len; i ++)
+ {
+ auto& ent = *context.adv_revisits[i];
+ ent.revisit(context, /*is_fallback=*/true);
+ if( context.m_ivars.peek_changed() ) {
+ break;
+ }
+ }
+ }
+
+#if 1
+ if( !context.m_ivars.peek_changed() )
+ {
+ // Check the possible equations
+ DEBUG("--- IVar possibilities (final fallback)");
+ //for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2
+ for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ )
+ {
+ if( check_ivar_poss(context, i, context.possible_ivar_vals[i], IvarPossFallbackType::FinalOption) ) {
+ break;
+ }
+ }
+ }
+#endif
+
+#if 1
+ if( !context.m_ivars.peek_changed() )
+ {
+ DEBUG("--- Coercion consume");
+ if( ! context.link_coerce.empty() )
+ {
+ auto ent = mv$(context.link_coerce.front());
+ context.link_coerce.erase( context.link_coerce.begin() );
+
+ const auto& sp = (*ent.right_node_ptr)->span();
+ auto& src_ty = (**ent.right_node_ptr).m_res_type;
+ //src_ty = context.m_resolve.expand_associated_types( sp, mv$(src_ty) );
+ ent.left_ty = context.m_resolve.expand_associated_types( sp, mv$(ent.left_ty) );
+ DEBUG("- Equate coercion " << ent.left_ty << " := " << src_ty);
+
+ context.equate_types(sp, ent.left_ty, src_ty);
+ }
+ }
+#endif
+
// Finally. If nothing changed, apply ivar defaults
if( !context.m_ivars.peek_changed() )
{
@@ -6404,14 +8832,19 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
const auto& sp = node->span();
if( const auto* np = dynamic_cast<::HIR::ExprNode_CallMethod*>(node) )
{
- WARNING(sp, W0000, "Spare Rule - {" << context.m_ivars.fmt_type(np->m_value->m_res_type) << "}." << np->m_method);
+ WARNING(sp, W0000, "Spare Rule - {" << context.m_ivars.fmt_type(np->m_value->m_res_type) << "}." << np->m_method << " -> " << context.m_ivars.fmt_type(np->m_res_type));
}
else
{
}
}
+ for(const auto& adv : context.adv_revisits)
+ {
+ WARNING(adv->span(), W0000, "Spare Rule - " << FMT_CB(os, adv->fmt(os)));
+ }
BUG(root_ptr->span(), "Spare rules left after typecheck stabilised");
}
+ DEBUG("root_ptr = " << typeid(*root_ptr).name() << " " << root_ptr->m_res_type);
// - Recreate the pointer
expr.reset( root_ptr.release() );
@@ -6429,5 +8862,18 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
ExprVisitor_Apply visitor { context };
visitor.visit_node_ptr( expr );
}
+
+ {
+ StaticTraitResolve static_resolve(ms.m_crate);
+ if( ms.m_impl_generics )
+ {
+ static_resolve.set_impl_generics_raw(*ms.m_impl_generics);
+ }
+ if( ms.m_item_generics )
+ {
+ static_resolve.set_item_generics_raw(*ms.m_item_generics);
+ }
+ Typecheck_Expressions_ValidateOne(static_resolve, args, result_type, expr);
+ }
}
diff --git a/src/hir_typeck/expr_visit.cpp b/src/hir_typeck/expr_visit.cpp
index 1a153aaf..df27b7d7 100644
--- a/src/hir_typeck/expr_visit.cpp
+++ b/src/hir_typeck/expr_visit.cpp
@@ -19,6 +19,90 @@ void Typecheck_Code(const typeck::ModuleState& ms, t_args& args, const ::HIR::Ty
}
}
+namespace typeck {
+ void ModuleState::prepare_from_path(const ::HIR::ItemPath& ip)
+ {
+ static Span sp;
+ ASSERT_BUG(sp, ip.parent, "prepare_from_path with too-short path - " << ip);
+ struct H {
+ static const ::HIR::Module& get_mod_for_ip(const ::HIR::Crate& crate, const ::HIR::ItemPath& ip)
+ {
+ if( ip.parent )
+ {
+ const auto& mod = H::get_mod_for_ip(crate, *ip.parent);
+ return mod.m_mod_items.at(ip.name)->ent.as_Module();
+ }
+ else
+ {
+ assert(ip.crate_name);
+ return (ip.crate_name[0] ? crate.m_ext_crates.at(ip.crate_name).m_data->m_root_module : crate.m_root_module);
+ }
+ }
+ static void add_traits_from_mod(ModuleState& ms, const ::HIR::Module& mod)
+ {
+ // In-scope traits.
+ ms.m_traits.clear();
+ for(const auto& tp : mod.m_traits)
+ {
+ const auto& trait = ms.m_crate.get_trait_by_path(sp, tp);
+ ms.m_traits.push_back(::std::make_pair( &tp, &trait ));
+ }
+ }
+ };
+ if( ip.parent->trait && ip.parent->ty )
+ {
+ // Trait impl
+ TODO(sp, "prepare_from_path - Trait impl " << ip);
+ }
+ else if( ip.parent->trait )
+ {
+ // Trait definition
+ //const auto& trait_mod = H::get_mod_for_ip(m_crate, *ip.parent->trait->parent);
+ //const auto& trait = trait_mod.m_mod_items.at(ip.parent->trait->name).ent.as_Trait();
+ const auto& trait = m_crate.get_trait_by_path(sp, *ip.parent->trait);
+ const auto& item = trait.m_values.at(ip.name);
+ TU_MATCH_HDRA( (item), { )
+ TU_ARMA(Function, e) {
+ m_item_generics = &e.m_params;
+ }
+ TU_ARMA(Constant, e) {
+ m_item_generics = &e.m_params;
+ }
+ TU_ARMA(Static, e) {
+ m_item_generics = nullptr;
+ }
+ }
+ }
+ else if( ip.parent->ty )
+ {
+ // Inherent impl
+ TODO(sp, "prepare_from_path - Type impl " << ip);
+ }
+ else
+ {
+ // Namespace path
+ const auto& mod = H::get_mod_for_ip(m_crate, *ip.parent);
+ H::add_traits_from_mod(*this, mod);
+ const auto& item = mod.m_value_items.at(ip.name)->ent;
+ m_impl_generics = nullptr;
+ TU_MATCH_HDRA( (item), { )
+ TU_ARMA(Constant, e) {
+ m_item_generics = &e.m_params;
+ }
+ TU_ARMA(Static, e) {
+ //m_item_generics = &e.m_params;
+ }
+ TU_ARMA(Function, e) {
+ m_item_generics = &e.m_params;
+ }
+ TU_ARMA(StructConstant, _e) BUG(sp, ip << " is StructConstant");
+ TU_ARMA(StructConstructor, _e) BUG(sp, ip << " is StructConstructor");
+ TU_ARMA(Import, _e) BUG(sp, ip << " is Import");
+ }
+ }
+ }
+} // namespace typeck
+
namespace {
@@ -36,7 +120,7 @@ namespace {
public:
void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override
{
- m_ms.push_traits(mod);
+ m_ms.push_traits(p, mod);
::HIR::Visitor::visit_module(p, mod);
m_ms.pop_traits(mod);
}
@@ -58,7 +142,7 @@ namespace {
auto _ = this->m_ms.set_impl_generics(impl.m_params);
const auto& mod = this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module);
- m_ms.push_traits(mod);
+ m_ms.push_traits(impl.m_src_module, mod);
::HIR::Visitor::visit_type_impl(impl);
m_ms.pop_traits(mod);
}
@@ -68,7 +152,7 @@ namespace {
auto _ = this->m_ms.set_impl_generics(impl.m_params);
const auto& mod = this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module);
- m_ms.push_traits(mod);
+ m_ms.push_traits(impl.m_src_module, mod);
m_ms.m_traits.push_back( ::std::make_pair( &trait_path, &this->m_ms.m_crate.get_trait_by_path(Span(), trait_path) ) );
::HIR::Visitor::visit_trait_impl(trait_path, impl);
m_ms.m_traits.pop_back( );
@@ -80,7 +164,7 @@ namespace {
auto _ = this->m_ms.set_impl_generics(impl.m_params);
const auto& mod = this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module);
- m_ms.push_traits(mod);
+ m_ms.push_traits(impl.m_src_module, mod);
::HIR::Visitor::visit_marker_impl(trait_path, impl);
m_ms.pop_traits(mod);
}
diff --git a/src/hir_typeck/expr_visit.hpp b/src/hir_typeck/expr_visit.hpp
index 21a775dc..fbd22704 100644
--- a/src/hir_typeck/expr_visit.hpp
+++ b/src/hir_typeck/expr_visit.hpp
@@ -5,16 +5,18 @@
* hir_typeck/expr_visit.hpp
* - Helpers for the HIR typecheck expression visiting
*/
+#include <hir/item_path.hpp>
namespace typeck {
struct ModuleState
{
const ::HIR::Crate& m_crate;
- ::HIR::GenericParams* m_impl_generics;
- ::HIR::GenericParams* m_item_generics;
+ const ::HIR::GenericParams* m_impl_generics;
+ const ::HIR::GenericParams* m_item_generics;
::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > m_traits;
+ ::std::vector<HIR::SimplePath> m_mod_paths;
ModuleState(const ::HIR::Crate& crate):
m_crate(crate),
@@ -33,19 +35,22 @@ namespace typeck {
ptr = nullptr;
}
};
- NullOnDrop< ::HIR::GenericParams> set_impl_generics(::HIR::GenericParams& gps) {
+ NullOnDrop<const ::HIR::GenericParams> set_impl_generics(::HIR::GenericParams& gps) {
assert( !m_impl_generics );
m_impl_generics = &gps;
- return NullOnDrop< ::HIR::GenericParams>(m_impl_generics);
+ return NullOnDrop<const ::HIR::GenericParams>(m_impl_generics);
}
- NullOnDrop< ::HIR::GenericParams> set_item_generics(::HIR::GenericParams& gps) {
+ NullOnDrop<const ::HIR::GenericParams> set_item_generics(::HIR::GenericParams& gps) {
assert( !m_item_generics );
m_item_generics = &gps;
- return NullOnDrop< ::HIR::GenericParams>(m_item_generics);
+ return NullOnDrop<const ::HIR::GenericParams>(m_item_generics);
}
- void push_traits(const ::HIR::Module& mod) {
+ void prepare_from_path(const ::HIR::ItemPath& ip);
+
+ void push_traits(::HIR::ItemPath p, const ::HIR::Module& mod) {
auto sp = Span();
+ m_mod_paths.push_back( p.get_simple_path() );
DEBUG("Module has " << mod.m_traits.size() << " in-scope traits");
// - Push a NULL entry to prevent parent module import lists being searched
m_traits.push_back( ::std::make_pair(nullptr, nullptr) );
@@ -59,6 +64,7 @@ namespace typeck {
for(unsigned int i = 0; i < mod.m_traits.size(); i ++ )
m_traits.pop_back();
m_traits.pop_back();
+ m_mod_paths.pop_back();
}
};
}
diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp
index 0a56e9cb..010df546 100644
--- a/src/hir_typeck/helpers.cpp
+++ b/src/hir_typeck/helpers.cpp
@@ -188,17 +188,17 @@ bool HMTypeInferrence::apply_defaults()
break;
case ::HIR::InferClass::Diverge:
rv = true;
- DEBUG("- " << *v.type << " -> !");
+ DEBUG("- IVar " << e.index << " = !");
*v.type = ::HIR::TypeRef(::HIR::TypeRef::Data::make_Diverge({}));
break;
case ::HIR::InferClass::Integer:
rv = true;
- DEBUG("- " << *v.type << " -> i32");
+ DEBUG("- IVar " << e.index << " = i32");
*v.type = ::HIR::TypeRef( ::HIR::CoreType::I32 );
break;
case ::HIR::InferClass::Float:
rv = true;
- DEBUG("- " << *v.type << " -> f64");
+ DEBUG("- IVar " << e.index << " = f64");
*v.type = ::HIR::TypeRef( ::HIR::CoreType::F64 );
break;
}
@@ -558,30 +558,38 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type)
DEBUG("set_ivar_to(" << slot << " { " << *root_ivar.type << " }, " << type << ")");
// If the left type was '_', alias the right to it
- TU_IFLET(::HIR::TypeRef::Data, type.m_data, Infer, l_e,
- assert( l_e.index != slot );
- DEBUG("Set IVar " << slot << " = @" << l_e.index);
-
- if( l_e.ty_class != ::HIR::InferClass::None ) {
+ if( const auto* l_e = type.m_data.opt_Infer() )
+ {
+ assert( l_e->index != slot );
+ if( l_e->ty_class != ::HIR::InferClass::None ) {
TU_MATCH_DEF(::HIR::TypeRef::Data, (root_ivar.type->m_data), (e),
(
ERROR(sp, E0000, "Type unificiation of literal with invalid type - " << *root_ivar.type);
),
(Primitive,
- check_type_class_primitive(sp, type, l_e.ty_class, e);
+ check_type_class_primitive(sp, type, l_e->ty_class, e);
),
(Infer,
// Check for right having a ty_class
- if( e.ty_class != ::HIR::InferClass::None && e.ty_class != l_e.ty_class ) {
+ if( e.ty_class != ::HIR::InferClass::None && e.ty_class != l_e->ty_class ) {
ERROR(sp, E0000, "Unifying types with mismatching literal classes - " << type << " := " << *root_ivar.type);
}
)
)
}
- root_ivar.alias = l_e.index;
+ #if 1
+ // Alias `l_e.index` to this slot
+ DEBUG("Set IVar " << l_e->index << " = @" << slot);
+ auto& r_ivar = this->get_pointed_ivar(l_e->index);
+ r_ivar.alias = slot;
+ r_ivar.type.reset();
+ #else
+ DEBUG("Set IVar " << slot << " = @" << l_e->index);
+ root_ivar.alias = l_e->index;
root_ivar.type.reset();
- )
+ #endif
+ }
else if( *root_ivar.type == type ) {
return ;
}
@@ -597,13 +605,15 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type)
case ::HIR::InferClass::Integer:
case ::HIR::InferClass::Float:
// `type` can't be an ivar, so it has to be a primitive (or an associated?)
- TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (l_e),
- (
- ),
- (Primitive,
- check_type_class_primitive(sp, type, e.ty_class, l_e);
- )
- )
+ if( const auto* l_e = type.m_data.opt_Primitive() ) {
+ check_type_class_primitive(sp, type, e.ty_class, *l_e);
+ }
+ else if( type.m_data.is_Diverge() ) {
+ // ... acceptable
+ }
+ else {
+ BUG(sp, "Setting primitive to " << type);
+ }
break;
}
)
@@ -617,9 +627,13 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type)
}
#if 1
- TU_IFLET(::HIR::TypeRef::Data, type.m_data, Diverge, e,
- root_ivar.type->m_data.as_Infer().ty_class = ::HIR::InferClass::Diverge;
- )
+ if( type.m_data.is_Diverge() )
+ {
+ if( root_ivar.type->m_data.as_Infer().ty_class == ::HIR::InferClass::None )
+ {
+ root_ivar.type->m_data.as_Infer().ty_class = ::HIR::InferClass::Diverge;
+ }
+ }
else
#endif
root_ivar.type = box$( type );
@@ -914,8 +928,8 @@ bool HMTypeInferrence::types_equal(const ::HIR::TypeRef& rl, const ::HIR::TypeRe
return pathparams_equal(le.m_trait.m_path.m_params, re.m_trait.m_path.m_params);
),
(ErasedType,
+ ASSERT_BUG(Span(), le.m_origin != ::HIR::SimplePath(), "Erased type with unset origin");
return H::compare_path(*this, le.m_origin, re.m_origin);
- //TODO(Span(), "ErasedType");
),
(Tuple,
return type_list_equal(*this, le, re);
@@ -932,13 +946,26 @@ void TraitResolution::prep_indexes()
static Span sp_AAA;
const Span& sp = sp_AAA;
+ // TODO: Create a list of all known type rules in this scope (recursively)
+ // - What if there's recursive bounds (e.g. on ATYs)
+
auto add_equality = [&](::HIR::TypeRef long_ty, ::HIR::TypeRef short_ty){
DEBUG("[prep_indexes] ADD " << long_ty << " => " << short_ty);
// TODO: Sort the two types by "complexity" (most of the time long >= short)
this->m_type_equalities.insert(::std::make_pair( mv$(long_ty), mv$(short_ty) ));
};
+ DEBUG("m_impl_params = " << m_impl_params << ", m_item_params = " << m_item_params);
+ if( m_impl_params ) {
+ DEBUG("- impl" << m_impl_params->fmt_args() << " " << m_impl_params->fmt_bounds());
+ }
+ if( m_item_params ) {
+ DEBUG("- fn ..." << m_item_params->fmt_args() << " " << m_item_params->fmt_bounds());
+ }
+ // Obtain type equality bounds.
+ // TODO: Also flatten the bounds list into known trait bounds?
this->iterate_bounds([&](const auto& b)->bool {
+ DEBUG("[prep_indexes] " << b);
if(const auto* bep = b.opt_TraitBound())
{
const auto& be = *bep;
@@ -949,7 +976,7 @@ void TraitResolution::prep_indexes()
// Locate the source trait
::HIR::GenericPath source_trait_path;
- bool rv = this->trait_contains_type(sp, be.trait.m_path, m_crate.get_trait_by_path(sp, be.trait.m_path.m_path), tb.first, source_trait_path);
+ bool rv = this->trait_contains_type(sp, be.trait.m_path, m_crate.get_trait_by_path(sp, be.trait.m_path.m_path), tb.first.c_str(), source_trait_path);
ASSERT_BUG(sp, rv, "Can't find `" << tb.first << "` in " << be.trait.m_path);
auto ty_l = ::HIR::TypeRef( ::HIR::Path( be.type.clone(), mv$(source_trait_path), tb.first ) );
@@ -994,7 +1021,7 @@ void TraitResolution::prep_indexes()
// Find the source trait for this associated type
::HIR::GenericPath source_trait_path;
- bool rv = this->trait_contains_type(sp, trait_mono.m_path, itrait, tb.first, source_trait_path);
+ bool rv = this->trait_contains_type(sp, trait_mono.m_path, itrait, tb.first.c_str(), source_trait_path);
ASSERT_BUG(sp, rv, "Can't find `" << tb.first << "` in " << trait_mono.m_path);
auto ty_l = ::HIR::TypeRef( ::HIR::Path( ty_a.clone(), mv$(source_trait_path), tb.first ) );
@@ -1047,11 +1074,42 @@ bool TraitResolution::iterate_bounds( ::std::function<bool(const ::HIR::GenericB
}
return false;
}
+bool TraitResolution::iterate_bounds_traits(const Span& sp, ::std::function<bool(const ::HIR::TypeRef&, const ::HIR::TraitPath& trait)> cb) const
+{
+ // Iterate all bounds, finding trait
+ return this->iterate_bounds([&](const auto& gb) {
+ if( const auto* be = gb.opt_TraitBound() )
+ {
+ // TODO: Type filter (to avoid the cost of checking parent bounds)
+ if( cb(be->type, be->trait) )
+ return true;
+
+ // TODO: Remove, or fix places where `find_named_trait_in_trait` is used along with this function
+ // - Using both leads to duplicate detections, which can confuse callers
+#if 0
+ assert(be->trait.m_trait_ptr);
+ const auto& trait_ref = *be->trait.m_trait_ptr;
+ auto monomorph_cb = monomorphise_type_get_cb(sp, &be->type, &be->trait.m_path.m_params, nullptr, nullptr);
+ for(const auto& parent_tp : trait_ref.m_all_parent_traits)
+ {
+ ::HIR::TraitPath tp_mono_o;
+ const auto& tp_mono = (monomorphise_traitpath_needed(parent_tp) ? tp_mono_o = monomorphise_traitpath_with(sp, parent_tp, monomorph_cb, false) : parent_tp);
+ // TODO: Monomorphise the bound
+ if( cb(be->type, tp_mono) )
+ return true;
+ }
+#endif
+ }
+ return false;
+ });
+}
bool TraitResolution::iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function<bool(const ::HIR::TraitPath&)> cb) const
{
::HIR::GenericPath trait_path;
- if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), pe.item, trait_path) )
+ DEBUG("Checking ATY bounds on " << pe.trait << " :: " << pe.item);
+ if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), pe.item.c_str(), trait_path) )
BUG(sp, "Cannot find associated type " << pe.item << " anywhere in trait " << pe.trait);
+ DEBUG("trait_path=" << trait_path);
const auto& trait_ref = m_crate.get_trait_by_path(sp, trait_path.m_path);
const auto& aty_def = trait_ref.m_types.find(pe.item)->second;
@@ -1084,37 +1142,23 @@ bool TraitResolution::iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data
return false;
}
-bool TraitResolution::find_trait_impls(const Span& sp,
+bool TraitResolution::find_trait_impls_magic(const Span& sp,
const ::HIR::SimplePath& trait, const ::HIR::PathParams& params,
const ::HIR::TypeRef& ty,
t_cb_trait_impl_r callback
) const
{
static ::HIR::PathParams null_params;
- static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc;
-
- const auto& type = this->m_ivars.get_type(ty);
- TRACE_FUNCTION_F("trait = " << trait << params << ", type = " << type);
-
-#if 0
- if( const auto* te = type.m_data.opt_Infer() )
- {
- if( !te->is_lit() ) {
- // NOTE: Can't hope to find an impl if we know nothing about the type.
- return false;
- }
- }
-#endif
+ static ::std::map<RcString, ::HIR::TypeRef> null_assoc;
const auto& lang_Sized = this->m_crate.get_lang_item_path(sp, "sized");
const auto& lang_Copy = this->m_crate.get_lang_item_path(sp, "copy");
+ //const auto& lang_Clone = this->m_crate.get_lang_item_path(sp, "clone");
const auto& lang_Unsize = this->m_crate.get_lang_item_path(sp, "unsize");
const auto& lang_CoerceUnsized = this->m_crate.get_lang_item_path(sp, "coerce_unsized");
- const auto& trait_fn = this->m_crate.get_lang_item_path(sp, "fn");
- const auto& trait_fn_mut = this->m_crate.get_lang_item_path(sp, "fn_mut");
- const auto& trait_fn_once = this->m_crate.get_lang_item_path(sp, "fn_once");
- const auto& trait_index = this->m_crate.get_lang_item_path(sp, "index");
- const auto& trait_indexmut = this->m_crate.get_lang_item_path(sp, "index_mut");
+
+ const auto& type = this->m_ivars.get_type(ty);
+ TRACE_FUNCTION_F("trait = " << trait << params << ", type = " << type);
if( trait == lang_Sized ) {
auto cmp = type_is_sized(sp, type);
@@ -1136,6 +1180,105 @@ bool TraitResolution::find_trait_impls(const Span& sp,
}
}
+ if( TARGETVER_1_29 && trait == this->m_crate.get_lang_item_path(sp, "clone") )
+ {
+ auto cmp = this->type_is_clone(sp, type);
+ if( cmp != ::HIR::Compare::Unequal ) {
+ return callback( ImplRef(&type, &null_params, &null_assoc), cmp );
+ }
+ else {
+ return false;
+ }
+ }
+
+ // Magic Unsize impls to trait objects
+ if( trait == lang_Unsize )
+ {
+ ASSERT_BUG(sp, params.m_types.size() == 1, "Unsize trait requires a single type param");
+ const auto& dst_ty = this->m_ivars.get_type(params.m_types[0]);
+
+ if( find_trait_impls_bound(sp, trait, params, type, callback) )
+ return true;
+
+ bool rv = false;
+ auto cb = [&](auto new_dst) {
+ ::HIR::PathParams real_params { mv$(new_dst) };
+ rv = callback( ImplRef(type.clone(), mv$(real_params), {}), ::HIR::Compare::Fuzzy );
+ };
+ //if( dst_ty.m_data.is_Infer() || type.m_data.is_Infer() )
+ //{
+ // rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Fuzzy );
+ // return rv;
+ //}
+ auto cmp = this->can_unsize(sp, dst_ty, type, cb);
+ if( cmp == ::HIR::Compare::Equal )
+ {
+ assert(!rv);
+ rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Equal );
+ }
+ return rv;
+ }
+
+ // Magical CoerceUnsized impls for various types
+ if( trait == lang_CoerceUnsized ) {
+ const auto& dst_ty = params.m_types.at(0);
+ // - `*mut T => *const T`
+ TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Pointer, e,
+ TU_IFLET( ::HIR::TypeRef::Data, dst_ty.m_data, Pointer, de,
+ if( de.type < e.type ) {
+ auto cmp = e.inner->compare_with_placeholders(sp, *de.inner, this->m_ivars.callback_resolve_infer());
+ if( cmp != ::HIR::Compare::Unequal )
+ {
+ ::HIR::PathParams pp;
+ pp.m_types.push_back( dst_ty.clone() );
+ if( callback( ImplRef(type.clone(), mv$(pp), {}), cmp ) ) {
+ return true;
+ }
+ }
+ }
+ )
+ )
+ }
+
+ return false;
+}
+
+bool TraitResolution::find_trait_impls(const Span& sp,
+ const ::HIR::SimplePath& trait, const ::HIR::PathParams& params,
+ const ::HIR::TypeRef& ty,
+ t_cb_trait_impl_r callback,
+ bool magic_trait_impls /*=true*/
+ ) const
+{
+ static ::HIR::PathParams null_params;
+ static ::std::map<RcString, ::HIR::TypeRef> null_assoc;
+
+ const auto& type = this->m_ivars.get_type(ty);
+ TRACE_FUNCTION_F("trait = " << trait << params << ", type = " << type);
+
+#if 0
+ if( const auto* te = type.m_data.opt_Infer() )
+ {
+ if( !te->is_lit() ) {
+ // NOTE: Can't hope to find an impl if we know nothing about the type.
+ return false;
+ }
+ }
+#endif
+
+ const auto& trait_fn = this->m_crate.get_lang_item_path(sp, "fn");
+ const auto& trait_fn_mut = this->m_crate.get_lang_item_path(sp, "fn_mut");
+ const auto& trait_fn_once = this->m_crate.get_lang_item_path(sp, "fn_once");
+ const auto& trait_index = this->m_crate.get_lang_item_path(sp, "index");
+ const auto& trait_indexmut = this->m_crate.get_lang_item_path(sp, "index_mut");
+
+ if( magic_trait_impls )
+ {
+ if( find_trait_impls_magic(sp, trait, params, ty, callback) ) {
+ return true;
+ }
+ }
+
// Magic impls of the Fn* traits for closure types
TU_IFLET(::HIR::TypeRef::Data, type.m_data, Closure, e,
DEBUG("Closure, " << trait << " ?= " << trait_fn << " " << trait_fn_mut << " " << trait_fn_once);
@@ -1168,7 +1311,7 @@ bool TraitResolution::find_trait_impls(const Span& sp,
::HIR::PathParams pp;
pp.m_types.push_back( ::HIR::TypeRef(mv$(args)) );
- ::std::map< ::std::string, ::HIR::TypeRef> types;
+ ::std::map<RcString, ::HIR::TypeRef> types;
types.insert( ::std::make_pair( "Output", e.m_rettype->clone() ) );
return callback( ImplRef(type.clone(), mv$(pp), mv$(types)), cmp );
}
@@ -1210,7 +1353,7 @@ bool TraitResolution::find_trait_impls(const Span& sp,
::HIR::PathParams pp;
pp.m_types.push_back( ::HIR::TypeRef(mv$(args)) );
- ::std::map< ::std::string, ::HIR::TypeRef> types;
+ ::std::map<RcString, ::HIR::TypeRef> types;
types.insert( ::std::make_pair( "Output", e.m_rettype->clone() ) );
return callback( ImplRef(type.clone(), mv$(pp), mv$(types)), cmp );
}
@@ -1235,7 +1378,7 @@ bool TraitResolution::find_trait_impls(const Span& sp,
{
::HIR::PathParams pp;
pp.m_types.push_back( mv$(ty_usize) );
- ::std::map< ::std::string, ::HIR::TypeRef> types;
+ ::std::map<RcString, ::HIR::TypeRef> types;
types.insert( ::std::make_pair( "Output", e.inner->clone() ) );
return callback( ImplRef(type.clone(), mv$(pp), mv$(types)), cmp );
}
@@ -1275,8 +1418,7 @@ bool TraitResolution::find_trait_impls(const Span& sp,
if( trait == mt.m_path ) {
auto cmp = compare_pp(sp, mt.m_params, params);
if( cmp != ::HIR::Compare::Unequal ) {
- static ::std::map< ::std::string, ::HIR::TypeRef> types;
- return callback( ImplRef(&type, &mt.m_params, &types), cmp );
+ return callback( ImplRef(&type, &mt.m_params, &null_assoc), cmp );
}
}
}
@@ -1290,7 +1432,7 @@ bool TraitResolution::find_trait_impls(const Span& sp,
auto cmp = this->compare_pp(sp, i_params, params);
if( cmp != ::HIR::Compare::Unequal ) {
// Invoke callback with a proper ImplRef
- ::std::map< ::std::string, ::HIR::TypeRef> assoc_clone;
+ ::std::map<RcString, ::HIR::TypeRef> assoc_clone;
for(const auto& e : i_assoc)
assoc_clone.insert( ::std::make_pair(e.first, e.second.clone()) );
auto ir = ImplRef(i_ty.clone(), i_params.clone(), mv$(assoc_clone));
@@ -1327,7 +1469,7 @@ bool TraitResolution::find_trait_impls(const Span& sp,
auto cmp = this->compare_pp(sp, i_params, params);
if( cmp != ::HIR::Compare::Unequal ) {
// Invoke callback with a proper ImplRef
- ::std::map< ::std::string, ::HIR::TypeRef> assoc_clone;
+ ::std::map<RcString, ::HIR::TypeRef> assoc_clone;
for(const auto& e : i_assoc)
assoc_clone.insert( ::std::make_pair(e.first, e.second.clone()) );
auto ir = ImplRef(i_ty.clone(), i_params.clone(), mv$(assoc_clone));
@@ -1361,12 +1503,19 @@ bool TraitResolution::find_trait_impls(const Span& sp,
ASSERT_BUG(sp, e.path.m_data.is_UfcsKnown(), "Opaque bound type wasn't UfcsKnown - " << type);
const auto& pe = e.path.m_data.as_UfcsKnown();
+ // TODO: Should Self here be `type` or `*pe.type`
+ // - Depends... if implicit it should be `type` (as it relates to the associated type), but if explicit it's referring to the trait
auto monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &pe.trait.m_params, nullptr, nullptr);
auto rv = this->iterate_aty_bounds(sp, pe, [&](const auto& bound) {
+ DEBUG("Bound on ATY: " << bound);
const auto& b_params = bound.m_path.m_params;
::HIR::PathParams params_mono_o;
const auto& b_params_mono = (monomorphise_pathparams_needed(b_params) ? params_mono_o = monomorphise_path_params_with(sp, b_params, monomorph_cb, false) : b_params);
+ // TODO: Monormophise and EAT associated types
+ ::std::map<RcString, ::HIR::TypeRef> b_atys;
+ for(const auto& aty : bound.m_type_bounds)
+ b_atys.insert(::std::make_pair( aty.first, monomorphise_type_with(sp, aty.second, monomorph_cb) ));
if( bound.m_path.m_path == trait )
{
@@ -1375,28 +1524,32 @@ bool TraitResolution::find_trait_impls(const Span& sp,
{
if( &b_params_mono == &params_mono_o )
{
- if( callback( ImplRef(type.clone(), mv$(params_mono_o), {}), cmp ) )
+ // TODO: assoc bounds
+ if( callback( ImplRef(type.clone(), mv$(params_mono_o), mv$(b_atys)), cmp ) )
return true;
params_mono_o = monomorphise_path_params_with(sp, b_params, monomorph_cb, false);
}
else
{
- if( callback( ImplRef(&type, &bound.m_path.m_params, &null_assoc), cmp ) )
+ //if( callback( ImplRef(&type, &bound.m_path.m_params, &null_assoc), cmp ) )
+ if( callback( ImplRef(&type, &bound.m_path.m_params, &b_atys), cmp ) )
return true;
}
}
}
+ bool rv = false;
bool ret = this->find_named_trait_in_trait(sp, trait, params, *bound.m_trait_ptr, bound.m_path.m_path, b_params_mono, type,
[&](const auto& i_ty, const auto& i_params, const auto& i_assoc) {
auto cmp = this->compare_pp(sp, i_params, params);
DEBUG("cmp=" << cmp << ", impl " << trait << i_params << " for " << i_ty << " -- desired " << trait << params);
- return cmp != ::HIR::Compare::Unequal && callback( ImplRef(i_ty.clone(), i_params.clone(), {}), cmp );
+ rv |= (cmp != ::HIR::Compare::Unequal && callback( ImplRef(i_ty.clone(), i_params.clone(), {}), cmp ));
+ return true; // NOTE: actually ignored?
});
if( ret )
{
// NOTE: Callback called in closure's return statement
- return true;
+ return rv;
}
return false;
});
@@ -1405,55 +1558,6 @@ bool TraitResolution::find_trait_impls(const Span& sp,
}
)
- // Magic Unsize impls to trait objects
- if( trait == lang_Unsize )
- {
- ASSERT_BUG(sp, params.m_types.size() == 1, "Unsize trait requires a single type param");
- const auto& dst_ty = this->m_ivars.get_type(params.m_types[0]);
-
- if( find_trait_impls_bound(sp, trait, params, type, callback) )
- return true;
-
- bool rv = false;
- auto cb = [&](auto new_dst) {
- ::HIR::PathParams real_params { mv$(new_dst) };
- rv = callback( ImplRef(type.clone(), mv$(real_params), {}), ::HIR::Compare::Fuzzy );
- };
- //if( dst_ty.m_data.is_Infer() || type.m_data.is_Infer() )
- //{
- // rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Fuzzy );
- // return rv;
- //}
- auto cmp = this->can_unsize(sp, dst_ty, type, cb);
- if( cmp == ::HIR::Compare::Equal )
- {
- assert(!rv);
- rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Equal );
- }
- return rv;
- }
-
- // Magical CoerceUnsized impls for various types
- if( trait == lang_CoerceUnsized ) {
- const auto& dst_ty = params.m_types.at(0);
- // - `*mut T => *const T`
- TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Pointer, e,
- TU_IFLET( ::HIR::TypeRef::Data, dst_ty.m_data, Pointer, de,
- if( de.type < e.type ) {
- auto cmp = e.inner->compare_with_placeholders(sp, *de.inner, this->m_ivars.callback_resolve_infer());
- if( cmp != ::HIR::Compare::Unequal )
- {
- ::HIR::PathParams pp;
- pp.m_types.push_back( dst_ty.clone() );
- if( callback( ImplRef(type.clone(), mv$(pp), {}), cmp ) ) {
- return true;
- }
- }
- }
- )
- )
- }
-
// 1. Search generic params
if( find_trait_impls_bound(sp, trait, params, type, callback) )
return true;
@@ -1898,7 +2002,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
(
),
(TraitBound,
- DEBUG("Trait bound - " << be.type << " : " << be.trait);
+ DEBUG("[expand_associated_types_inplace__UfcsKnown] Trait bound - " << be.type << " : " << be.trait);
// 1. Check if the type matches
// - TODO: This should be a fuzzier match?
if( be.type != *pe.type )
@@ -1910,7 +2014,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
if( it == be.trait.m_type_bounds.end() ) {
// If not, assume it's opaque and return as such
// TODO: What happens if there's two bounds that overlap? 'F: FnMut<()>, F: FnOnce<(), Output=Bar>'
- DEBUG("Found impl for " << input << " but no bound on item, assuming opaque");
+ DEBUG("[expand_associated_types_inplace__UfcsKnown] Found impl for " << input << " but no bound on item, assuming opaque");
}
else {
assume_opaque = false;
@@ -1983,6 +2087,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
}
// If the type of this UfcsKnown is ALSO a UfcsKnown - Check if it's bounded by this trait with equality
+ // e.g. `<<Foo as Bar>::Baz as Trait2>::Type` may have an ATY bound `trait Bar { type Baz: Trait2<Type=...> }`
// Use bounds on other associated types too (if `pe.type` was resolved to a fixed associated type)
TU_IFLET(::HIR::TypeRef::Data, pe.type->m_data, Path, te_inner,
TU_IFLET(::HIR::Path::Data, te_inner.path.m_data, UfcsKnown, pe_inner,
@@ -1990,7 +2095,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
// - Does simplification of complex associated types
//
::HIR::GenericPath trait_path;
- if( !this->trait_contains_type(sp, pe_inner.trait, this->m_crate.get_trait_by_path(sp, pe_inner.trait.m_path), pe_inner.item, trait_path) )
+ if( !this->trait_contains_type(sp, pe_inner.trait, this->m_crate.get_trait_by_path(sp, pe_inner.trait.m_path), pe_inner.item.c_str(), trait_path) )
BUG(sp, "Cannot find associated type " << pe_inner.item << " anywhere in trait " << pe_inner.trait);
const auto& trait_ptr = this->m_crate.get_trait_by_path(sp, trait_path.m_path);
const auto& assoc_ty = trait_ptr.m_types.at(pe_inner.item);
@@ -2016,7 +2121,10 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
{
// If the bound is for Self and the outer trait
// - TODO: Fuzzy check the parameters?
- if( bound.m_path == pe.trait ) {
+ ::HIR::GenericPath tmp_tp;
+ const auto& bound_tp = monomorphise_genericpath_with_opt(sp, tmp_tp, bound.m_path, cb_placeholders_trait);
+ DEBUG(bound_tp << " ?= " << pe.trait);
+ if( bound_tp == pe.trait ) {
auto it = bound.m_type_bounds.find( pe.item );
if( it != bound.m_type_bounds.end() ) {
if( monomorphise_type_needed(it->second) ) {
@@ -2032,10 +2140,10 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
}
// TODO: Find trait in this trait.
- const auto& bound_trait = m_crate.get_trait_by_path(sp, bound.m_path.m_path);
+ const auto& bound_trait = m_crate.get_trait_by_path(sp, bound_tp.m_path);
bool replaced = this->find_named_trait_in_trait(sp,
pe.trait.m_path,pe.trait.m_params,
- bound_trait, bound.m_path.m_path,bound.m_path.m_params, *pe.type,
+ bound_trait, bound_tp.m_path,bound_tp.m_params, *pe.type,
[&](const auto&, const auto& x, const auto& assoc){
auto it = assoc.find(pe.item);
if( it != assoc.end() ) {
@@ -2057,7 +2165,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
// TODO: Search for the actual trait containing this associated type
::HIR::GenericPath trait_path;
//if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), *pe.type, pe.item, trait_path) )
- if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), pe.item, trait_path) )
+ if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), pe.item.c_str(), trait_path) )
BUG(sp, "Cannot find associated type " << pe.item << " anywhere in trait " << pe.trait);
//pe.trait = mv$(trait_path);
@@ -2185,15 +2293,16 @@ bool TraitResolution::find_named_trait_in_trait(const Span& sp,
{
auto pt_mono = monomorphise_traitpath_with(sp, pt, monomorph_cb, false);
- DEBUG(pt << " => " << pt_mono);
+ //DEBUG(pt << " => " << pt_mono);
if( pt.m_path.m_path == des ) {
+ //DEBUG("Found potential " << pt_mono);
// NOTE: Doesn't quite work...
//auto cmp = this->compare_pp(sp, pt_mono.m_path.m_params, des_params);
//if( cmp != ::HIR::Compare::Unequal )
//{
- callback( target_type, pt_mono.m_path.m_params, pt_mono.m_type_bounds );
+ if( callback( target_type, pt_mono.m_path.m_params, pt_mono.m_type_bounds ) )
+ return true;
//}
- return true;
}
}
@@ -2209,134 +2318,139 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple
)
)
-#if 0
- if( m_ivars.get_type(type).m_data.is_Infer() )
+ if(type.m_data.is_Infer()) {
return false;
- if( TU_TEST1(m_ivars.get_type(type).m_data, Path, .binding.is_Unbound()) )
- return false;
-#endif
+ }
+
+ // NOTE: Even if the type is completely unknown (infer or unbound UFCS), search the bound list.
// TODO: A bound can imply something via its associated types. How deep can this go?
// E.g. `T: IntoIterator<Item=&u8>` implies `<T as IntoIterator>::IntoIter : Iterator<Item=&u8>`
- return this->iterate_bounds([&](const auto& b)->bool {
- if( b.is_TraitBound() )
- {
- const auto& e = b.as_TraitBound();
- const auto& b_params = e.trait.m_path.m_params;
+ // > Would maybe want a list of all explicit and implied bounds instead.
+ return this->iterate_bounds_traits(sp, [&](const auto& bound_ty, const ::HIR::TraitPath& bound_trait)->bool {
+ const auto& b_params = bound_trait.m_path.m_params;
- auto cmp = e.type .compare_with_placeholders(sp, type, m_ivars.callback_resolve_infer());
- if( cmp == ::HIR::Compare::Unequal )
+ auto cmp = bound_ty .compare_with_placeholders(sp, type, m_ivars.callback_resolve_infer());
+ if( cmp == ::HIR::Compare::Unequal )
+ return false;
+ DEBUG("[find_trait_impls_bound] " << bound_trait << " for " << bound_ty << " cmp = " << cmp);
+
+ if( bound_trait.m_path.m_path == trait ) {
+ // Check against `params`
+ DEBUG("[find_trait_impls_bound] Checking params " << params << " vs " << b_params);
+ auto ord = cmp;
+ ord &= this->compare_pp(sp, b_params, params);
+ if( ord == ::HIR::Compare::Unequal )
return false;
-
- if( e.trait.m_path.m_path == trait ) {
- // Check against `params`
- DEBUG("[find_trait_impls_bound] Checking params " << params << " vs " << b_params);
- auto ord = cmp;
- ord &= this->compare_pp(sp, b_params, params);
- if( ord == ::HIR::Compare::Unequal )
- return false;
- if( ord == ::HIR::Compare::Fuzzy ) {
- DEBUG("Fuzzy match");
- }
- DEBUG("[find_trait_impls_bound] Match " << b);
- // Hand off to the closure, and return true if it does
- // TODO: The type bounds are only the types that are specified.
- if( callback( ImplRef(&e.type, &e.trait.m_path.m_params, &e.trait.m_type_bounds), ord) ) {
- return true;
- }
+ if( ord == ::HIR::Compare::Fuzzy ) {
+ DEBUG("Fuzzy match");
}
+ DEBUG("[find_trait_impls_bound] Match " << bound_ty << " : " << bound_trait);
+ // Hand off to the closure, and return true if it does
+ // TODO: The type bounds are only the types that are specified.
+ auto b = bound_trait.clone();
+ if( callback( ImplRef(bound_ty.clone(), mv$(b.m_path.m_params), mv$(b.m_type_bounds)), ord) ) {
+ return true;
+ }
+ }
- // TODO: Allow fuzzy equality?
- if( cmp == ::HIR::Compare::Equal )
- {
- // HACK: The wrapping closure takes associated types from this bound and applies them to the returned set
- // - XXX: This is actually wrong (false-positive) in many cases. FIXME
- bool rv = this->find_named_trait_in_trait(sp,
- trait,params,
- *e.trait.m_trait_ptr, e.trait.m_path.m_path,e.trait.m_path.m_params,
- type,
- [&](const auto& ty, const auto& params, const auto& assoc) {
- // TODO: Avoid duplicating this map every time
- ::std::map< ::std::string,::HIR::TypeRef> assoc2;
- for(const auto& i : assoc) {
+ // TODO: Allow fuzzy equality?
+ if( cmp == ::HIR::Compare::Equal )
+ {
+ // HACK: The wrapping closure takes associated types from this bound and applies them to the returned set
+ // - XXX: This is actually wrong (false-positive) in many cases. FIXME
+ bool rv = this->find_named_trait_in_trait(sp,
+ trait,params,
+ *bound_trait.m_trait_ptr, bound_trait.m_path.m_path,bound_trait.m_path.m_params,
+ type,
+ [&](const auto& ty, const auto& b_params, const auto& assoc) {
+ // TODO: Avoid duplicating this map every time
+ ::std::map< RcString,::HIR::TypeRef> assoc2;
+ for(const auto& i : assoc) {
+ assoc2.insert( ::std::make_pair(i.first, i.second.clone()) );
+ }
+ for(const auto& i : bound_trait.m_type_bounds) {
+ // TODO: Only include from above when needed
+ //if( des_trait_ref.m_types.count(i.first) ) {
assoc2.insert( ::std::make_pair(i.first, i.second.clone()) );
- }
- for(const auto& i : e.trait.m_type_bounds) {
- // TODO: Only include from above when needed
- //if( des_trait_ref.m_types.count(i.first) ) {
- assoc2.insert( ::std::make_pair(i.first, i.second.clone()) );
- //}
- }
- return callback( ImplRef(ty.clone(), params.clone(), mv$(assoc2)), ::HIR::Compare::Equal );
- });
- if( rv ) {
- return true;
- }
+ //}
+ }
+ // TODO: Check param equality
+ auto ord = ::HIR::Compare::Equal;
+ ord &= this->compare_pp(sp, b_params, params);
+ if( ord == ::HIR::Compare::Unequal )
+ return false;
+ if( ord == ::HIR::Compare::Fuzzy ) {
+ DEBUG("Fuzzy match");
+ }
+ return callback( ImplRef(ty.clone(), b_params.clone(), mv$(assoc2)), ord );
+ });
+ if( rv ) {
+ return true;
}
+ }
- // If the input type is an associated type controlled by this trait bound, check for added bounds.
- // TODO: This just checks a single layer, but it's feasable that there could be multiple layers
- if( assoc_info && e.trait.m_path.m_path == assoc_info->trait.m_path && e.type == *assoc_info->type )
- {
- // Check the trait params
- auto ord = this->compare_pp(sp, b_params, assoc_info->trait.m_params);
- if( ord == ::HIR::Compare::Fuzzy ) {
- //TODO(sp, "Handle fuzzy matches searching for associated type bounds");
- }
- else if( ord == ::HIR::Compare::Unequal ) {
- return false;
- }
- auto outer_ord = ord;
+ // If the input type is an associated type controlled by this trait bound, check for added bounds.
+ // TODO: This just checks a single layer, but it's feasable that there could be multiple layers
+ if( assoc_info && bound_trait.m_path.m_path == assoc_info->trait.m_path && bound_ty == *assoc_info->type )
+ {
+ // Check the trait params
+ auto ord = this->compare_pp(sp, b_params, assoc_info->trait.m_params);
+ if( ord == ::HIR::Compare::Fuzzy ) {
+ //TODO(sp, "Handle fuzzy matches searching for associated type bounds");
+ }
+ else if( ord == ::HIR::Compare::Unequal ) {
+ return false;
+ }
+ auto outer_ord = ord;
- const auto& trait_ref = *e.trait.m_trait_ptr;
- const auto& at = trait_ref.m_types.at(assoc_info->item);
- for(const auto& bound : at.m_trait_bounds) {
- if( bound.m_path.m_path == trait )
- {
- auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& {
- const auto& ge = gt.m_data.as_Generic();
- if( ge.binding == 0xFFFF ) {
- return *assoc_info->type;
- }
- else {
- if( ge.binding >= assoc_info->trait.m_params.m_types.size() )
- BUG(sp, "find_trait_impls_bound - Generic #" << ge.binding << " " << ge.name << " out of range");
- return assoc_info->trait.m_params.m_types[ge.binding];
- }
- };
-
- DEBUG("- Found an associated type bound for this trait via another bound");
- ::HIR::Compare ord = outer_ord;
- if( monomorphise_pathparams_needed(bound.m_path.m_params) ) {
- // TODO: Use a compare+callback method instead
- auto b_params_mono = monomorphise_path_params_with(sp, bound.m_path.m_params, monomorph_cb, false);
- ord &= this->compare_pp(sp, b_params_mono, params);
+ const auto& trait_ref = *bound_trait.m_trait_ptr;
+ const auto& at = trait_ref.m_types.at(assoc_info->item);
+ for(const auto& bound : at.m_trait_bounds) {
+ if( bound.m_path.m_path == trait )
+ {
+ auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& {
+ const auto& ge = gt.m_data.as_Generic();
+ if( ge.binding == 0xFFFF ) {
+ return *assoc_info->type;
}
else {
- ord &= this->compare_pp(sp, bound.m_path.m_params, params);
- }
- if( ord == ::HIR::Compare::Unequal )
- return false;
- if( ord == ::HIR::Compare::Fuzzy ) {
- DEBUG("Fuzzy match");
+ if( ge.binding >= assoc_info->trait.m_params.m_types.size() )
+ BUG(sp, "find_trait_impls_bound - Generic #" << ge.binding << " " << ge.name << " out of range");
+ return assoc_info->trait.m_params.m_types[ge.binding];
}
+ };
- auto tp_mono = monomorphise_traitpath_with(sp, bound, monomorph_cb, false);
- // - Expand associated types
- for(auto& ty : tp_mono.m_type_bounds) {
- ty.second = this->expand_associated_types(sp, mv$(ty.second));
- }
- DEBUG("- tp_mono = " << tp_mono);
- // TODO: Instead of using `type` here, build the real type
- if( callback( ImplRef(type.clone(), mv$(tp_mono.m_path.m_params), mv$(tp_mono.m_type_bounds)), ord ) ) {
- return true;
- }
+ DEBUG("- Found an associated type bound for this trait via another bound");
+ ::HIR::Compare ord = outer_ord;
+ if( monomorphise_pathparams_needed(bound.m_path.m_params) ) {
+ // TODO: Use a compare+callback method instead
+ auto b_params_mono = monomorphise_path_params_with(sp, bound.m_path.m_params, monomorph_cb, false);
+ ord &= this->compare_pp(sp, b_params_mono, params);
+ }
+ else {
+ ord &= this->compare_pp(sp, bound.m_path.m_params, params);
+ }
+ if( ord == ::HIR::Compare::Unequal )
+ return false;
+ if( ord == ::HIR::Compare::Fuzzy ) {
+ DEBUG("Fuzzy match");
+ }
+
+ auto tp_mono = monomorphise_traitpath_with(sp, bound, monomorph_cb, false);
+ // - Expand associated types
+ for(auto& ty : tp_mono.m_type_bounds) {
+ ty.second = this->expand_associated_types(sp, mv$(ty.second));
+ }
+ DEBUG("- tp_mono = " << tp_mono);
+ // TODO: Instead of using `type` here, build the real type
+ if( callback( ImplRef(type.clone(), mv$(tp_mono.m_path.m_params), mv$(tp_mono.m_type_bounds)), ord ) ) {
+ return true;
}
}
}
-
- return false;
}
+
return false;
});
}
@@ -2346,7 +2460,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
t_cb_trait_impl_r callback
) const
{
- static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc;
+ // TODO: Have a global cache of impls that don't reference either generics or ivars
+
+ static ::std::map<RcString, ::HIR::TypeRef> null_assoc;
TRACE_FUNCTION_F(trait << FMT_CB(ss, if(params_ptr) { ss << *params_ptr; } else { ss << "<?>"; }) << " for " << type);
// Handle auto traits (aka OIBITs)
@@ -2380,21 +2496,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
TU_IFLET( ::HIR::TypeRef::Data, (type.m_data), Path, e,
if( e.path.m_data.is_Generic() && e.path.m_data.as_Generic().m_params.m_types.size() == 0 )
{
- TU_MATCH( ::HIR::TypeRef::TypePathBinding, (e.binding), (tpb),
- (Unbound,
- ),
- (Opaque,
- ),
- (Struct,
- markings = &tpb->m_markings;
- ),
- (Union,
- markings = &tpb->m_markings;
- ),
- (Enum,
- markings = &tpb->m_markings;
- )
- )
+ markings = e.binding.get_trait_markings();
}
)
@@ -2491,7 +2593,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
if( cmp != ::HIR::Compare::Unequal )
{
if( markings ) {
- ASSERT_BUG(sp, cmp == ::HIR::Compare::Equal, "Auto trait with no params returned a fuzzy match from destructure");
+ ASSERT_BUG(sp, cmp == ::HIR::Compare::Equal, "Auto trait with no params returned a fuzzy match from destructure - " << trait << " for " << type);
markings->auto_impls.insert( ::std::make_pair(trait, ::HIR::TraitMarkings::AutoMarking { {}, true }) );
}
return callback( ImplRef(&type, params_ptr, &null_assoc), cmp );
@@ -2535,10 +2637,12 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
};
// - If the type is a path (struct/enum/...), search for impls for all contained types.
- TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Path, e,
+ if(const auto* ep = type.m_data.opt_Path())
+ {
+ const auto& e = *ep;
::HIR::Compare res = ::HIR::Compare::Equal;
- TU_MATCH( ::HIR::Path::Data, (e.path.m_data), (pe),
- (Generic,
+ TU_MATCH_HDRA( (e.path.m_data), {)
+ TU_ARMA(Generic, pe) { //(
::HIR::TypeRef tmp;
auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& {
const auto& ge = gt.m_data.as_Generic();
@@ -2557,7 +2661,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
// HELPER: Get a possibily monomorphised version of the input type (stored in `tmp` if needed)
auto monomorph_get = [&](const auto& ty)->const ::HIR::TypeRef& {
if( monomorphise_type_needed(ty) ) {
- return (tmp = monomorphise_type_with(sp, ty, monomorph_cb));
+ return (tmp = this->expand_associated_types(sp, monomorphise_type_with(sp, ty, monomorph_cb)));
}
else {
return ty;
@@ -2618,28 +2722,40 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
),
(Union,
TODO(sp, "Check auto trait destructure on union " << type);
+ ),
+ (ExternType,
+ TODO(sp, "Check auto trait destructure on extern type " << type);
)
)
DEBUG("- Nothing failed, calling callback");
- ),
- (UfcsUnknown,
+ }
+ TU_ARMA(UfcsUnknown, pe) {
BUG(sp, "UfcsUnknown in typeck - " << type);
- ),
- (UfcsKnown,
- // If unbound, use Fuzzy
- if(e.binding.is_Unbound())
+ }
+ TU_ARMA(UfcsKnown, pe) {
+ // If unbound, use Fuzzy {
+ if(e.binding.is_Unbound()) {
+ DEBUG("- Unbound UfcsKnown, returning Fuzzy");
return ::HIR::Compare::Fuzzy;
+ }
// Otherwise, it's opaque. Check the bounds on the trait.
+ if( TU_TEST1(pe.type->m_data, Generic, .binding >> 8 == 2) )
+ {
+ DEBUG("- UfcsKnown of placeholder, returning Fuzzy");
+ return ::HIR::Compare::Fuzzy;
+ }
TODO(sp, "Check trait bounds for bound on " << type);
- ),
- (UfcsInherent,
+ }
+ TU_ARMA(UfcsInherent, pe) {
TODO(sp, "Auto trait lookup on UFCS Inherent type");
- )
- )
+ }
+ }
return res;
- )
+ }
else TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Generic, e,
- TODO(sp, "Check trait bounds on " << type);
+ auto l_res = ::HIR::Compare::Unequal;
+ this->find_trait_impls(sp, trait, *params_ptr, type, [&](auto, auto cmp){ l_res = cmp; return (cmp == ::HIR::Compare::Equal); });
+ return l_res;
)
else TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Tuple, e,
::HIR::Compare res = ::HIR::Compare::Equal;
@@ -2714,7 +2830,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
// TODO: Some impl blocks have type params used as part of type bounds.
// - A rough idea is to have monomorph return a third class of generic for params that are not yet bound.
// - compare_with_placeholders gets called on both ivars and generics, so that can be used to replace it once known.
- ::std::string placeholder_name = FMT("impl_?_" << &impl_params);
+ auto placeholder_name = RcString::new_interned(FMT("impl_?_" << &impl_params));
for(unsigned int i = 0; i < impl_params.size(); i ++ ) {
if( !impl_params[i] ) {
if( placeholders.size() == 0 )
@@ -2761,6 +2877,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
auto i = idx % 256;
ASSERT_BUG(sp, !impl_params[i], "Placeholder to populated type returned - " << *impl_params[i] << " vs " << ty);
auto& ph = placeholders[i];
+ // TODO: Only want to do this if ... what?
+ // - Problem: This can poison the output if the result was fuzzy
+ // - E.g. `Q: Borrow<V>` can equate Q and V
if( ph.m_data.is_Generic() && ph.m_data.as_Generic().binding == idx ) {
DEBUG("[ftic_check_params:cb_match] Bind placeholder " << i << " to " << ty);
ph = ty.clone();
@@ -2780,6 +2899,10 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
if( ty.m_data.is_Infer() && !ty.m_data.as_Infer().is_lit() ) {
return ::HIR::Compare::Fuzzy;
}
+ // If the RHS is an unbound UfcsKnown, also fuzzy
+ if( ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Unbound() ) {
+ return ::HIR::Compare::Fuzzy;
+ }
return ::HIR::Compare::Unequal;
}
};
@@ -2794,6 +2917,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
}
return *impl_params[ge.binding];
};
+ //::std::vector<::HIR::TypeRef> saved_ph;
+ //for(const auto& t : placeholders)
+ // saved_ph.push_back(t.clone());
// Check bounds for this impl
// - If a bound fails, then this can't be a valid impl
@@ -2805,6 +2931,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
(TypeLifetime,
),
(TraitBound,
+
DEBUG("Check bound " << be.type << " : " << be.trait);
auto real_type = monomorphise_type_with(sp, be.type, monomorph, false);
auto real_trait = monomorphise_traitpath_with(sp, be.trait, monomorph, false);
@@ -2828,8 +2955,15 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
DEBUG("- Bounded type is an ivar, assuming fuzzy match");
found_fuzzy_match = true;
}
+ // TODO: Save the placeholder state and restore if the result was Fuzzy
+ ::std::vector<::HIR::TypeRef> saved_ph;
+ for(const auto& t : placeholders)
+ saved_ph.push_back(t.clone());
+ ::std::vector<::HIR::TypeRef> fuzzy_ph;
+ unsigned num_fuzzy = 0;
// TODO: Pass the `match_test_generics` callback? Or another one that handles the impl placeholders.
auto rv = this->find_trait_impls(sp, real_trait_path.m_path, real_trait_path.m_params, real_type, [&](auto impl, auto impl_cmp) {
+ // TODO: Save and restore placeholders if this isn't a full match
DEBUG("[ftic_check_params] impl_cmp = " << impl_cmp << ", impl = " << impl);
auto cmp = impl_cmp;
if( cmp == ::HIR::Compare::Fuzzy )
@@ -2840,9 +2974,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
auto i_tp = impl.get_trait_params();
for(auto& t : i_tp.m_types)
this->expand_associated_types_inplace( sp, t, {} );
- DEBUG(real_type << " ?= " << i_ty);
+ DEBUG("[ftic_check_params] " << real_type << " ?= " << i_ty);
cmp &= real_type .match_test_generics_fuzz(sp, i_ty, cb_infer, cb_match);
- DEBUG(real_trait_path.m_params << " ?= " << i_tp);
+ DEBUG("[ftic_check_params] " << real_trait_path.m_params << " ?= " << i_tp);
cmp &= real_trait_path.m_params .match_test_generics_fuzz(sp, i_tp, cb_infer, cb_match);
DEBUG("[ftic_check_params] - Re-check result: " << cmp);
}
@@ -2872,22 +3006,41 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
{
case ::HIR::Compare::Equal:
DEBUG("Equal");
- continue;
+ break;
case ::HIR::Compare::Unequal:
DEBUG("Assoc `" << assoc_bound.first << "` didn't match - " << ty << " != " << assoc_bound.second);
- return false;
+ cmp = ::HIR::Compare::Unequal;
+ break;
case ::HIR::Compare::Fuzzy:
// TODO: When a fuzzy match is encountered on a conditional bound, returning `false` can lead to an false negative (and a compile error)
// BUT, returning `true` could lead to it being selected. (Is this a problem, should a later validation pass check?)
DEBUG("[ftic_check_params] Fuzzy match assoc bound between " << ty << " and " << assoc_bound.second);
cmp = ::HIR::Compare::Fuzzy;
- continue ;
+ break ;
}
+ if( cmp == ::HIR::Compare::Unequal )
+ break;
}
DEBUG("[ftic_check_params] impl_cmp = " << impl_cmp << ", cmp = " << cmp);
- if( cmp == ::HIR::Compare::Fuzzy ) {
- found_fuzzy_match = true;
+ if( cmp == ::HIR::Compare::Fuzzy )
+ {
+ found_fuzzy_match |= true;
+ num_fuzzy += 1;
+ if( num_fuzzy )
+ {
+ fuzzy_ph = ::std::move(placeholders);
+ placeholders.resize(fuzzy_ph.size());
+ }
+ }
+ if( cmp != ::HIR::Compare::Equal )
+ {
+ // Restore placeholders
+ // - Maybe save the results for later?
+ DEBUG("[ftic_check_params] Restore placeholders: " << saved_ph);
+ DEBUG("[ftic_check_params] OVERWRITTEN placeholders: " << placeholders);
+ for(size_t i = 0; i < placeholders.size(); i ++)
+ placeholders[i] = saved_ph[i].clone();
}
// If the match isn't a concrete equal, return false (to keep searching)
return (cmp == ::HIR::Compare::Equal);
@@ -2897,6 +3050,15 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
}
else if( found_fuzzy_match ) {
DEBUG("- Bound " << real_type << " : " << real_trait_path << " fuzzed");
+ if( num_fuzzy == 1 )
+ {
+ DEBUG("Use placeholders " << fuzzy_ph);
+ placeholders = ::std::move(fuzzy_ph);
+ }
+ else
+ {
+ DEBUG("TODO: Multiple fuzzy matches, which placeholder set to use?");
+ }
match = ::HIR::Compare::Fuzzy;
}
else if( TU_TEST1(real_type.m_data, Infer, .ty_class == ::HIR::InferClass::None) ) {
@@ -2911,6 +3073,10 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
DEBUG("- Bound " << real_type << " : " << real_trait_path << " failed");
return ::HIR::Compare::Unequal;
}
+
+ //if( !rv ) {
+ // placeholders = ::std::move(saved_ph);
+ //}
),
(TypeEquality,
TODO(sp, "Check bound " << be.type << " = " << be.other_type);
@@ -2935,18 +3101,22 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
}
}
+ //if( match == ::HIR::Compare::Fuzzy ) {
+ // placeholders = ::std::move(saved_ph);
+ //}
+
return match;
}
namespace {
- bool trait_contains_method_inner(const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::Function::Receiver& receiver)
+ bool trait_contains_method_inner(const ::HIR::Trait& trait_ptr, const char* name, const ::HIR::Function*& out_fcn_ptr)
{
auto it = trait_ptr.m_values.find(name);
if( it != trait_ptr.m_values.end() )
{
if( it->second.is_Function() ) {
const auto& v = it->second.as_Function();
- receiver = v.m_receiver;
+ out_fcn_ptr = &v;
return true;
}
}
@@ -2954,29 +3124,32 @@ namespace {
}
}
-bool TraitResolution::trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const ::std::string& name, ::HIR::Function::Receiver& out_receiver, ::HIR::GenericPath& out_path) const
+const ::HIR::Function* TraitResolution::trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const char* name, ::HIR::GenericPath& out_path) const
{
TRACE_FUNCTION_FR("trait_path=" << trait_path << ",name=" << name, out_path);
+ const ::HIR::Function* rv = nullptr;
- if( trait_contains_method_inner(trait_ptr, name, out_receiver) )
+ if( trait_contains_method_inner(trait_ptr, name, rv) )
{
+ assert(rv);
out_path = trait_path.clone();
- return true;
+ return rv;
}
auto monomorph_cb = monomorphise_type_get_cb(sp, &self, &trait_path.m_params, nullptr);
for(const auto& st : trait_ptr.m_all_parent_traits)
{
- if( trait_contains_method_inner(*st.m_trait_ptr, name, out_receiver) )
+ if( trait_contains_method_inner(*st.m_trait_ptr, name, rv) )
{
+ assert(rv);
out_path.m_path = st.m_path.m_path;
out_path.m_params = monomorphise_path_params_with(sp, st.m_path.m_params, monomorph_cb, false);
- return true;
+ return rv;
}
}
- return false;
+ return nullptr;
}
-bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const
+bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const char* name, ::HIR::GenericPath& out_path) const
{
TRACE_FUNCTION_FR(trait_path << " has " << name, out_path);
@@ -3038,6 +3211,10 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa
(Opaque,
// TODO: Check bounds
),
+ (ExternType,
+ // Is it sized? No.
+ return ::HIR::Compare::Unequal;
+ ),
(Enum,
// HAS to be Sized
),
@@ -3156,6 +3333,100 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa
)
)
}
+::HIR::Compare TraitResolution::type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const
+{
+ TRACE_FUNCTION_F(ty);
+ const auto& type = this->m_ivars.get_type(ty);
+ const auto& lang_Clone = this->m_crate.get_lang_item_path(sp, "clone");
+ TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (e),
+ (
+ // NOTE: Don't use find_trait_impls, because that calls this
+ bool is_fuzzy = false;
+ bool has_eq = find_trait_impls(sp, lang_Clone, ::HIR::PathParams{}, ty, [&](auto , auto c)->bool{
+ switch(c)
+ {
+ case ::HIR::Compare::Equal: return true;
+ case ::HIR::Compare::Fuzzy:
+ is_fuzzy = true;
+ return false;
+ case ::HIR::Compare::Unequal:
+ return false;
+ }
+ throw "";
+ }, false);
+ if( has_eq ) {
+ return ::HIR::Compare::Equal;
+ }
+ else if( is_fuzzy ) {
+ return ::HIR::Compare::Fuzzy;
+ }
+ else {
+ return ::HIR::Compare::Unequal;
+ }
+ ),
+ (Infer,
+ switch(e.ty_class)
+ {
+ case ::HIR::InferClass::Integer:
+ case ::HIR::InferClass::Float:
+ return ::HIR::Compare::Equal;
+ default:
+ DEBUG("Fuzzy Clone impl for ivar?");
+ return ::HIR::Compare::Fuzzy;
+ }
+ ),
+ (Generic,
+ // TODO: Store this result - or even pre-calculate it.
+ return this->iterate_bounds([&](const auto& b)->bool {
+ TU_IFLET(::HIR::GenericBound, b, TraitBound, be,
+ if(be.type == ty)
+ {
+ if(be.trait.m_path == lang_Clone)
+ return true;
+ ::HIR::PathParams pp;
+ bool rv = this->find_named_trait_in_trait(sp,
+ lang_Clone,pp, *be.trait.m_trait_ptr, be.trait.m_path.m_path, be.trait.m_path.m_params, type,
+ [&](const auto& , const auto&, const auto&)->bool { return true; }
+ );
+ if(rv)
+ return true;
+ }
+ )
+ return false;
+ }) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal ;
+ ),
+ (Primitive,
+ if( e == ::HIR::CoreType::Str )
+ return ::HIR::Compare::Unequal;
+ return ::HIR::Compare::Equal;
+ ),
+ (Borrow,
+ return e.type == ::HIR::BorrowType::Shared ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal ;
+ ),
+ (Pointer,
+ return ::HIR::Compare::Equal;
+ ),
+ (Tuple,
+ auto rv = ::HIR::Compare::Equal;
+ for(const auto& sty : e)
+ rv &= type_is_clone(sp, sty);
+ return rv;
+ ),
+ (Slice,
+ return ::HIR::Compare::Unequal;
+ ),
+ (Function,
+ return ::HIR::Compare::Equal;
+ ),
+ (Closure,
+ // NOTE: This isn't strictly true, we're leaving the actual checking up to the validate pass
+ return ::HIR::Compare::Equal;
+ ),
+ (Array,
+ return type_is_clone(sp, *e.inner);
+ )
+ )
+}
// Checks if a type can unsize to another
// - Returns Compare::Equal if the unsize is possible and fully known
// - Returns Compare::Fuzzy if the unsize is possible, but still unknown.
@@ -3444,12 +3715,16 @@ const ::HIR::TypeRef* TraitResolution::autoderef(const Span& sp, const ::HIR::Ty
DEBUG("Deref " << ty << " into " << *e.inner);
return &this->m_ivars.get_type(*e.inner);
)
- // TODO: Just doing `*[1,2,3]` doesn't work, but this is needed to allow `[1,2,3].iter()` to work
+ // HACK?: Just doing `*[1,2,3]` doesn't work, but this is needed to allow `[1,2,3].iter()` to work
else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e,
DEBUG("Deref " << ty << " into [" << *e.inner << "]");
tmp_type = ::HIR::TypeRef::new_slice( e.inner->clone() );
return &tmp_type;
)
+ // Shortcut, don't look up a Deref impl for primitives or slices
+ else if( ty.m_data.is_Slice() || ty.m_data.is_Primitive() ) {
+ return nullptr;
+ }
else {
bool succ = this->find_trait_impls(sp, this->m_crate.get_lang_item_path(sp, "deref"), ::HIR::PathParams {}, ty, [&](auto impls, auto match) {
tmp_type = impls.get_type("Target");
@@ -3471,7 +3746,7 @@ const ::HIR::TypeRef* TraitResolution::autoderef(const Span& sp, const ::HIR::Ty
}
unsigned int TraitResolution::autoderef_find_method(const Span& sp,
- const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& top_ty, const ::std::string& method_name,
+ const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& top_ty, const char* method_name,
/* Out -> */::std::vector<::std::pair<AutoderefBorrow,::HIR::Path>>& possibilities
) const
{
@@ -3536,6 +3811,7 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp,
}
if( !possibilities.empty() )
{
+ DEBUG("FOUND " << possibilities.size() << " options: " << possibilities);
return deref_count;
}
@@ -3553,9 +3829,9 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp,
}
} while(current_ty);
- // Dereference failed! This is a hard error (hitting _ is checked above and returns ~0)
- //this->m_ivars.dump();
- ERROR(sp, E0000, "Could not find method `" << method_name << "` on type `" << top_ty << "`");
+ // No method found, return an empty list and return 0
+ assert( possibilities.empty() );
+ return 0;
}
::std::ostream& operator<<(::std::ostream& os, const TraitResolution::AutoderefBorrow& x)
@@ -3594,9 +3870,9 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp,
// Checks that a given real receiver type matches a desired receiver type (with the correct access)
// Returns the pointer to the `Self` type, or nullptr if there's a mismatch
-const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, ::HIR::Function::Receiver receiver, const ::HIR::TypeRef& ty, TraitResolution::MethodAccess access) const
+const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, const ::HIR::Function& fcn, const ::HIR::TypeRef& ty, TraitResolution::MethodAccess access) const
{
- switch(receiver)
+ switch(fcn.m_receiver)
{
case ::HIR::Function::Receiver::Free:
// Free functions are never usable
@@ -3604,7 +3880,7 @@ const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, ::H
case ::HIR::Function::Receiver::Value:
if( access >= TraitResolution::MethodAccess::Move )
{
- return &ty;
+ return &this->m_ivars.get_type(ty);
}
break;
case ::HIR::Function::Receiver::BorrowOwned:
@@ -3643,6 +3919,24 @@ const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, ::H
return &this->m_ivars.get_type(*ty.m_data.as_Borrow().inner);
}
break;
+ case ::HIR::Function::Receiver::Custom:
+ // TODO: Handle custom-receiver functions
+ // - match_test_generics, if it succeeds return the matched Self
+ {
+ const ::HIR::TypeRef* detected_self_ty = nullptr;
+ auto cb_getself = [&](auto idx, const auto& /*name*/, const auto& ty)->::HIR::Compare{
+ if( idx == 0xFFFF )
+ {
+ detected_self_ty = &ty;
+ }
+ return ::HIR::Compare::Equal;
+ };
+ if( fcn.m_args.front().second .match_test_generics(sp, ty, this->m_ivars.callback_resolve_infer(), cb_getself) ) {
+ assert(detected_self_ty);
+ return &this->m_ivars.get_type(*detected_self_ty);
+ }
+ }
+ return nullptr;
case ::HIR::Function::Receiver::Box:
if(const auto* ity = this->type_is_owned_box(sp, ty))
{
@@ -3660,12 +3954,12 @@ const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, ::H
}
bool TraitResolution::find_method(const Span& sp,
- const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& ty, const ::std::string& method_name, MethodAccess access,
+ const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& ty, const char* method_name, MethodAccess access,
AutoderefBorrow borrow_type, /* Out -> */::std::vector<::std::pair<AutoderefBorrow,::HIR::Path>>& possibilities
) const
{
bool rv = false;
- TRACE_FUNCTION_F("ty=" << ty << ", name=" << method_name << ", access=" << access);
+ TRACE_FUNCTION_FR("ty=" << ty << ", name=" << method_name << ", access=" << access, possibilities);
auto cb_infer = m_ivars.callback_resolve_infer();
// 1. Search generic bounds for a match
@@ -3682,16 +3976,19 @@ bool TraitResolution::find_method(const Span& sp,
assert(e.trait.m_trait_ptr);
// 1. Find the named method in the trait.
::HIR::GenericPath final_trait_path;
- ::HIR::Function::Receiver receiver;
- if( !this->trait_contains_method(sp, e.trait.m_path, *e.trait.m_trait_ptr, e.type, method_name, receiver, final_trait_path) ) {
+ const ::HIR::Function* fcn_ptr;
+ if( !(fcn_ptr = this->trait_contains_method(sp, e.trait.m_path, *e.trait.m_trait_ptr, e.type, method_name, final_trait_path)) ) {
DEBUG("- Method '" << method_name << "' missing");
continue ;
}
DEBUG("- Found trait " << final_trait_path << " (bound)");
// 2. Compare the receiver of the above to this type and the bound.
- if(const auto* self_ty = check_method_receiver(sp, receiver, ty, access))
+ if(const auto* self_ty = check_method_receiver(sp, *fcn_ptr, ty, access))
{
+ // If the type is an unbounded ivar, don't check.
+ if( TU_TEST1(self_ty->m_data, Infer, .is_lit() == false) )
+ return false;
// TODO: Do a fuzzy match here?
auto cmp = self_ty->compare_with_placeholders(sp, e.type, cb_infer);
if( cmp == ::HIR::Compare::Equal )
@@ -3707,12 +4004,23 @@ bool TraitResolution::find_method(const Span& sp,
method_name,
{}
}) ) ));
+ DEBUG("++ " << possibilities.back());
rv = true;
- break;
}
else if( cmp == ::HIR::Compare::Fuzzy )
{
- TODO(sp, "Fuzzy match checking bounded method - " << *self_ty << " != " << e.type);
+ DEBUG("Fuzzy match checking bounded method - " << *self_ty << " != " << e.type);
+
+ // Found the method, return the UFCS path for it
+ possibilities.push_back(::std::make_pair( borrow_type,
+ ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({
+ box$( self_ty->clone() ),
+ mv$(final_trait_path),
+ method_name,
+ {}
+ }) ) ));
+ DEBUG("++ " << possibilities.back());
+ rv = true;
}
else
{
@@ -3760,17 +4068,23 @@ bool TraitResolution::find_method(const Span& sp,
const auto& trait = this->m_crate.get_trait_by_path(sp, e.m_trait.m_path.m_path);
::HIR::GenericPath final_trait_path;
- ::HIR::Function::Receiver receiver;
- if( this->trait_contains_method(sp, e.m_trait.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) )
+ if( const auto* fcn_ptr = this->trait_contains_method(sp, e.m_trait.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path) )
{
DEBUG("- Found trait " << final_trait_path);
// - If the receiver is valid, then it's correct (no need to check the type again)
- if(const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access))
+ if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access))
{
possibilities.push_back(::std::make_pair(borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) ));
+ DEBUG("++ " << possibilities.back());
rv = true;
}
}
+
+ // If the method was found on the trait object, prefer that over all others.
+ if( !possibilities.empty() )
+ {
+ return rv;
+ }
}
// 3. Mutually exclusive searches
@@ -3783,14 +4097,14 @@ bool TraitResolution::find_method(const Span& sp,
const auto& trait = this->m_crate.get_trait_by_path(sp, trait_path.m_path.m_path);
::HIR::GenericPath final_trait_path;
- ::HIR::Function::Receiver receiver;
- if( this->trait_contains_method(sp, trait_path.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) )
+ if( const auto* fcn_ptr = this->trait_contains_method(sp, trait_path.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path) )
{
DEBUG("- Found trait " << final_trait_path);
- if(const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access))
+ if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access))
{
possibilities.push_back(::std::make_pair(borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) ));
+ DEBUG("++ " << possibilities.back());
rv = true;
}
}
@@ -3835,21 +4149,23 @@ bool TraitResolution::find_method(const Span& sp,
{
ASSERT_BUG(sp, bound.m_trait_ptr, "Pointer to trait " << bound.m_path << " not set in " << e.trait.m_path);
::HIR::GenericPath final_trait_path;
- ::HIR::Function::Receiver receiver;
- if( !this->trait_contains_method(sp, bound.m_path, *bound.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) )
- continue ;
- DEBUG("- Found trait " << final_trait_path);
- if(const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access))
+ if( const auto* fcn_ptr = this->trait_contains_method(sp, bound.m_path, *bound.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path) )
{
- if( monomorphise_pathparams_needed(final_trait_path.m_params) ) {
- final_trait_path.m_params = monomorphise_path_params_with(sp, final_trait_path.m_params, monomorph_cb, false);
- DEBUG("- Monomorph to " << final_trait_path);
- }
+ DEBUG("- Found trait " << final_trait_path);
- // Found the method, return the UFCS path for it
- possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) ));
- rv = true;
+ if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access))
+ {
+ if( monomorphise_pathparams_needed(final_trait_path.m_params) ) {
+ final_trait_path.m_params = monomorphise_path_params_with(sp, final_trait_path.m_params, monomorph_cb, false);
+ DEBUG("- Monomorph to " << final_trait_path);
+ }
+
+ // Found the method, return the UFCS path for it
+ possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) ));
+ DEBUG("++ " << possibilities.back());
+ rv = true;
+ }
}
}
@@ -3873,21 +4189,22 @@ bool TraitResolution::find_method(const Span& sp,
// Found such a bound, now to test if it is useful
::HIR::GenericPath final_trait_path;
- ::HIR::Function::Receiver receiver;
- if( !this->trait_contains_method(sp, be.trait.m_path, *be.trait.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) )
- continue ;
- DEBUG("- Found trait " << final_trait_path);
-
- if(const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access))
+ if( const auto* fcn_ptr = this->trait_contains_method(sp, be.trait.m_path, *be.trait.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path) )
{
- if( monomorphise_pathparams_needed(final_trait_path.m_params) ) {
- final_trait_path.m_params = monomorphise_path_params_with(sp, final_trait_path.m_params, monomorph_cb, false);
- DEBUG("- Monomorph to " << final_trait_path);
- }
+ DEBUG("- Found trait " << final_trait_path);
- // Found the method, return the UFCS path for it
- possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) ));
- rv = true;
+ if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access))
+ {
+ if( monomorphise_pathparams_needed(final_trait_path.m_params) ) {
+ final_trait_path.m_params = monomorphise_path_params_with(sp, final_trait_path.m_params, monomorph_cb, false);
+ DEBUG("- Monomorph to " << final_trait_path);
+ }
+
+ // Found the method, return the UFCS path for it
+ possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) ));
+ DEBUG("++ " << possibilities.back());
+ rv = true;
+ }
}
}
}
@@ -3907,12 +4224,13 @@ bool TraitResolution::find_method(const Span& sp,
if( it == impl.m_methods.end() )
return false ;
const ::HIR::Function& fcn = it->second.data;
- if( const auto* self_ty_p = this->check_method_receiver(sp, fcn.m_receiver, ty, access) )
+ if( const auto* self_ty_p = this->check_method_receiver(sp, fcn, ty, access) )
{
DEBUG("Found `impl" << impl.m_params.fmt_args() << " " << impl.m_type << "` fn " << method_name/* << " - " << top_ty*/);
if( *self_ty_p == *cur_check_ty )
{
possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), method_name, {}) ));
+ DEBUG("++ " << possibilities.back());
return true;
}
}
@@ -3943,12 +4261,12 @@ bool TraitResolution::find_method(const Span& sp,
break;
::HIR::GenericPath final_trait_path;
- ::HIR::Function::Receiver receiver;
- if( !this->trait_contains_method(sp, *trait_ref.first, *trait_ref.second, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) )
+ const ::HIR::Function* fcn_ptr;
+ if( !(fcn_ptr = this->trait_contains_method(sp, *trait_ref.first, *trait_ref.second, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path)) )
continue ;
DEBUG("- Found trait " << final_trait_path);
- if( const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access) )
+ if( const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access) )
{
const auto& self_ty = *self_ty_p;
DEBUG("Search for impl of " << *trait_ref.first << " for " << self_ty);
@@ -3965,10 +4283,24 @@ bool TraitResolution::find_method(const Span& sp,
// TODO: Re-monomorphise the trait path!
- //if( find_trait_impls(sp, *trait_ref.first, trait_params, self_ty, [](auto , auto ) { return true; }) ) {
- if( find_trait_impls_crate(sp, *trait_ref.first, &trait_params, self_ty, [](auto , auto ) { return true; }) ) {
+ bool magic_found = false;
+ bool crate_impl_found = false;
+
+ crate_impl_found = find_trait_impls_magic(sp, *trait_ref.first, trait_params, self_ty, [&](auto impl, auto cmp) {
+ return true;
+ });
+
+ // NOTE: This just detects the presence of a trait impl, not the specifics
+ find_trait_impls_crate(sp, *trait_ref.first, &trait_params, self_ty, [&](auto impl, auto cmp) {
+ DEBUG("[find_method] " << impl << ", cmp = " << cmp);
+ magic_found = true;
+ crate_impl_found = true;
+ return true;
+ });
+ if( crate_impl_found ) {
DEBUG("Found trait impl " << *trait_ref.first << trait_params << " for " << self_ty << " ("<<m_ivars.fmt_type(self_ty)<<")");
possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty.clone(), ::HIR::GenericPath( *trait_ref.first, mv$(trait_params) ), method_name, {}) ));
+ DEBUG("++ " << possibilities.back());
rv = true;
}
}
@@ -3981,7 +4313,7 @@ bool TraitResolution::find_method(const Span& sp,
return rv;
}
-unsigned int TraitResolution::autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& field_name, /* Out -> */::HIR::TypeRef& field_type) const
+unsigned int TraitResolution::autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const char* field_name, /* Out -> */::HIR::TypeRef& field_type) const
{
unsigned int deref_count = 0;
::HIR::TypeRef tmp_type; // Temporary type used for handling Deref
@@ -4021,7 +4353,7 @@ unsigned int TraitResolution::autoderef_find_field(const Span& sp, const ::HIR::
this->m_ivars.dump();
TODO(sp, "Error when no field could be found, but type is known - (: " << top_ty << ")." << field_name);
}
-bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_ty) const
+bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const char* name, /* Out -> */::HIR::TypeRef& field_ty) const
{
TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, e,
TU_MATCH(::HIR::TypeRef::TypePathBinding, (e.binding), (be),
@@ -4056,8 +4388,8 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const
(Tuple,
for( unsigned int i = 0; i < se.size(); i ++ )
{
- // TODO: Privacy
- if( FMT(i) == name ) {
+ DEBUG(i << ": " << se[i].publicity);
+ if( se[i].publicity.is_visible(this->m_vis_path) && FMT(i) == name ) {
field_ty = monomorphise_type_with(sp, se[i].ent, monomorph);
return true;
}
@@ -4066,8 +4398,8 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const
(Named,
for( const auto& fld : se )
{
- // TODO: Privacy
- if( fld.first == name ) {
+ DEBUG(fld.first << ": " << fld.second.publicity << ", " << this->m_vis_path);
+ if( fld.second.publicity.is_visible(this->m_vis_path) && fld.first == name ) {
field_ty = monomorphise_type_with(sp, fld.second.ent, monomorph);
return true;
}
@@ -4078,6 +4410,9 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const
(Enum,
// No fields on enums either
),
+ (ExternType,
+ // No fields on extern types
+ ),
(Union,
const auto& unm = *be;
const auto& params = e.path.m_data.as_Generic().m_params;
@@ -4098,7 +4433,7 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const
for( const auto& fld : unm.m_variants )
{
// TODO: Privacy
- if( fld.first == name ) {
+ if( fld.second.publicity.is_visible(this->m_vis_path) && fld.first == name ) {
field_ty = monomorphise_type_with(sp, fld.second.ent, monomorph);
return true;
}
diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp
index 58688d6e..00befd63 100644
--- a/src/hir_typeck/helpers.hpp
+++ b/src/hir_typeck/helpers.hpp
@@ -57,6 +57,7 @@ public:
public: // ?? - Needed once, anymore?
struct IVar
{
+ //bool could_be_diverge; // TODO: use this instead of InferClass::Diverge
unsigned int alias; // If not ~0, this points to another ivar
::std::unique_ptr< ::HIR::TypeRef> type; // Type (only nullptr if alias!=0)
@@ -149,17 +150,19 @@ class TraitResolution
const ::HIR::Crate& m_crate;
const ::HIR::GenericParams* m_impl_params;
const ::HIR::GenericParams* m_item_params;
+ const ::HIR::SimplePath& m_vis_path;
::std::map< ::HIR::TypeRef, ::HIR::TypeRef> m_type_equalities;
::HIR::SimplePath m_lang_Box;
mutable ::std::vector< ::HIR::TypeRef> m_eat_active_stack;
public:
- TraitResolution(const HMTypeInferrence& ivars, const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params):
+ TraitResolution(const HMTypeInferrence& ivars, const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params, const ::HIR::SimplePath& vis_path):
m_ivars(ivars),
m_crate(crate),
m_impl_params( impl_params ),
m_item_params( item_params )
+ ,m_vis_path(vis_path)
{
prep_indexes();
m_lang_Box = crate.get_lang_item_path_opt("owned_box");
@@ -201,13 +204,14 @@ public:
/// Iterate over in-scope bounds (function then top)
bool iterate_bounds( ::std::function<bool(const ::HIR::GenericBound&)> cb) const;
+ bool iterate_bounds_traits(const Span& sp, ::std::function<bool(const ::HIR::TypeRef&, const ::HIR::TraitPath& trait)> cb) const;
bool iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function<bool(const ::HIR::TraitPath&)> cb) const;
- typedef ::std::function<bool(const ::HIR::TypeRef&, const ::HIR::PathParams&, const ::std::map< ::std::string,::HIR::TypeRef>&)> t_cb_trait_impl;
+ typedef ::std::function<bool(const ::HIR::TypeRef&, const ::HIR::PathParams&, const ::std::map< RcString,::HIR::TypeRef>&)> t_cb_trait_impl;
typedef ::std::function<bool(ImplRef, ::HIR::Compare)> t_cb_trait_impl_r;
/// Searches for a trait impl that matches the provided trait name and type
- bool find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const;
+ bool find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback, bool magic_trait_impls=true) const;
/// Locate a named trait in the provied trait (either itself or as a parent trait)
bool find_named_trait_in_trait(const Span& sp,
@@ -224,6 +228,8 @@ public:
}
/// Search for a trait implementation in the crate (allows nullptr to ignore params)
bool find_trait_impls_crate(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams* params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const;
+ /// Check for magic (automatically determined) trait implementations
+ bool find_trait_impls_magic(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const;
private:
::HIR::Compare check_auto_trait_impl_destructure(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams* params_ptr, const ::HIR::TypeRef& type) const;
@@ -244,17 +250,17 @@ public:
/// Locate the named method by applying auto-dereferencing.
/// \return Number of times deref was applied (or ~0 if _ was hit)
unsigned int autoderef_find_method(const Span& sp,
- const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& top_ty, const ::std::string& method_name,
+ const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& top_ty, const char* method_name,
/* Out -> */::std::vector<::std::pair<AutoderefBorrow,::HIR::Path>>& possibilities
) const;
/// Locate the named field by applying auto-dereferencing.
/// \return Number of times deref was applied (or ~0 if _ was hit)
- unsigned int autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) const;
+ unsigned int autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const char* name, /* Out -> */::HIR::TypeRef& field_type) const;
/// Apply an automatic dereference
const ::HIR::TypeRef* autoderef(const Span& sp, const ::HIR::TypeRef& ty, ::HIR::TypeRef& tmp_type) const;
- bool find_field(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) const;
+ bool find_field(const Span& sp, const ::HIR::TypeRef& ty, const char* name, /* Out -> */::HIR::TypeRef& field_type) const;
enum class MethodAccess {
Shared,
@@ -262,7 +268,7 @@ public:
Move,
};
private:
- const ::HIR::TypeRef* check_method_receiver(const Span& sp, ::HIR::Function::Receiver receiver, const ::HIR::TypeRef& ty, TraitResolution::MethodAccess access) const;
+ const ::HIR::TypeRef* check_method_receiver(const Span& sp, const ::HIR::Function& fcn, const ::HIR::TypeRef& ty, TraitResolution::MethodAccess access) const;
public:
enum class AllowedReceivers {
All,
@@ -273,16 +279,17 @@ public:
};
friend ::std::ostream& operator<<(::std::ostream& os, const AllowedReceivers& x);
bool find_method(const Span& sp,
- const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& ty, const ::std::string& method_name, MethodAccess access,
+ const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& ty, const char* method_name, MethodAccess access,
AutoderefBorrow borrow_type, /* Out -> */::std::vector<::std::pair<AutoderefBorrow,::HIR::Path>>& possibilities
) const;
/// Locates a named method in a trait, and returns the path of the trait that contains it (with fixed parameters)
- bool trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const ::std::string& name, ::HIR::Function::Receiver& out_receiver, ::HIR::GenericPath& out_path) const;
- bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const;
+ const ::HIR::Function* trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const char* name, ::HIR::GenericPath& out_path) const;
+ bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const char* name, ::HIR::GenericPath& out_path) const;
::HIR::Compare type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const;
::HIR::Compare type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const;
+ ::HIR::Compare type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const;
// If `new_type_callback` is populated, it will be called with the actual/possible dst_type
// If `infer_callback` is populated, it will be called when either side is an ivar
diff --git a/src/hir_typeck/impl_ref.cpp b/src/hir_typeck/impl_ref.cpp
index e8966b38..910a3c5e 100644
--- a/src/hir_typeck/impl_ref.cpp
+++ b/src/hir_typeck/impl_ref.cpp
@@ -32,10 +32,24 @@ bool ImplRef::more_specific_than(const ImplRef& other) const
)
),
(BoundedPtr,
- return true;
+ if( !other.m_data.is_BoundedPtr() )
+ return false;
+ const auto& oe = other.m_data.as_BoundedPtr();
+ assert( *te.type == *oe.type );
+ assert( *te.trait_args == *oe.trait_args );
+ if( te.assoc->size() > oe.assoc->size() )
+ return true;
+ return false;
),
(Bounded,
- return true;
+ if( !other.m_data.is_Bounded() )
+ return false;
+ const auto& oe = other.m_data.as_Bounded();
+ assert( te.type == oe.type );
+ assert( te.trait_args == oe.trait_args );
+ if( te.assoc.size() > oe.assoc.size() )
+ return true;
+ return false;
)
)
throw "";
@@ -50,12 +64,34 @@ bool ImplRef::overlaps_with(const ::HIR::Crate& crate, const ImplRef& other) con
return te.impl->overlaps_with( crate, *oe.impl );
),
(BoundedPtr,
+ // TODO: Bounded and BoundedPtr are compatible
+ if( *te.type != *oe.type )
+ return false;
+ if( *te.trait_args != *oe.trait_args )
+ return false;
+ // Don't check associated types
+ return true;
),
(Bounded,
+ if( te.type != oe.type )
+ return false;
+ if( te.trait_args != oe.trait_args )
+ return false;
+ // Don't check associated types
+ return true;
)
)
return false;
}
+bool ImplRef::has_magic_params() const
+{
+ TU_IFLET(Data, m_data, TraitImpl, e,
+ for(const auto& t : e.params_ph)
+ if( visit_ty_with(t, [](const ::HIR::TypeRef& t){ return t.m_data.is_Generic() && (t.m_data.as_Generic().binding >> 8) == 2; }) )
+ return true;
+ )
+ return false;
+}
bool ImplRef::type_is_specialisable(const char* name) const
{
TU_MATCH(Data, (this->m_data), (e),
@@ -189,11 +225,11 @@ bool ImplRef::type_is_specialisable(const char* name) const
static Span sp;
TU_MATCH(Data, (this->m_data), (e),
(TraitImpl,
- DEBUG("name=" << name << " " << *this);
auto it = e.impl->m_types.find(name);
if( it == e.impl->m_types.end() )
return ::HIR::TypeRef();
const ::HIR::TypeRef& tpl_ty = it->second.data;
+ DEBUG("name=" << name << " tpl_ty=" << tpl_ty << " " << *this);
if( monomorphise_type_needed(tpl_ty) ) {
return monomorphise_type_with(sp, tpl_ty, this->get_cb_monomorph_traitimpl(sp));
}
@@ -219,8 +255,8 @@ bool ImplRef::type_is_specialisable(const char* name) const
::std::ostream& operator<<(::std::ostream& os, const ImplRef& x)
{
- TU_MATCH(ImplRef::Data, (x.m_data), (e),
- (TraitImpl,
+ TU_MATCH_HDR( (x.m_data), { )
+ TU_ARM(x.m_data, TraitImpl, e) {
if( e.impl == nullptr ) {
os << "none";
}
@@ -258,13 +294,16 @@ bool ImplRef::type_is_specialisable(const char* name) const
}
os << "}";
}
- ),
- (BoundedPtr,
+ }
+ TU_ARM(x.m_data, BoundedPtr, e) {
+ assert(e.type);
+ assert(e.trait_args);
+ assert(e.assoc);
os << "bound (ptr) " << *e.type << " : ?" << *e.trait_args << " + {" << *e.assoc << "}";
- ),
- (Bounded,
+ }
+ TU_ARM(x.m_data, Bounded, e) {
os << "bound " << e.type << " : ?" << e.trait_args << " + {"<<e.assoc<<"}";
- )
- )
+ }
+ }
return os;
}
diff --git a/src/hir_typeck/impl_ref.hpp b/src/hir_typeck/impl_ref.hpp
index b1190c61..c67c8a81 100644
--- a/src/hir_typeck/impl_ref.hpp
+++ b/src/hir_typeck/impl_ref.hpp
@@ -27,12 +27,12 @@ struct ImplRef
(BoundedPtr, struct {
const ::HIR::TypeRef* type;
const ::HIR::PathParams* trait_args;
- const ::std::map< ::std::string, ::HIR::TypeRef>* assoc;
+ const ::std::map< RcString, ::HIR::TypeRef>* assoc;
}),
(Bounded, struct {
::HIR::TypeRef type;
::HIR::PathParams trait_args;
- ::std::map< ::std::string, ::HIR::TypeRef> assoc;
+ ::std::map< RcString, ::HIR::TypeRef> assoc;
})
);
@@ -45,10 +45,10 @@ struct ImplRef
m_data(Data::make_TraitImpl({ mv$(params), mv$(params_ph), &trait, &impl }))
{}
- ImplRef(const ::HIR::TypeRef* type, const ::HIR::PathParams* args, const ::std::map< ::std::string, ::HIR::TypeRef>* assoc):
+ ImplRef(const ::HIR::TypeRef* type, const ::HIR::PathParams* args, const ::std::map< RcString, ::HIR::TypeRef>* assoc):
m_data(Data::make_BoundedPtr({ type, mv$(args), mv$(assoc) }))
{}
- ImplRef(::HIR::TypeRef type, ::HIR::PathParams args, ::std::map< ::std::string, ::HIR::TypeRef> assoc):
+ ImplRef(::HIR::TypeRef type, ::HIR::PathParams args, ::std::map< RcString, ::HIR::TypeRef> assoc):
m_data(Data::make_Bounded({ mv$(type), mv$(args), mv$(assoc) }))
{}
@@ -59,14 +59,7 @@ struct ImplRef
bool more_specific_than(const ImplRef& other) const;
bool overlaps_with(const ::HIR::Crate& crate, const ImplRef& other) const;
- bool has_magic_params() const {
- TU_IFLET(Data, m_data, TraitImpl, e,
- for(const auto& t : e.params_ph)
- if( t.m_data.is_Generic() && (t.m_data.as_Generic().binding >> 8) == 2 )
- return true;
- )
- return false;
- }
+ bool has_magic_params() const;
/// HELPER: Returns callback to monomorphise a type using parameters from Data::TraitImpl
::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> get_cb_monomorph_traitimpl(const Span& sp) const;
diff --git a/src/hir_typeck/outer.cpp b/src/hir_typeck/outer.cpp
index dddb7731..38c6f652 100644
--- a/src/hir_typeck/outer.cpp
+++ b/src/hir_typeck/outer.cpp
@@ -52,6 +52,10 @@ namespace {
(TypeAlias,
BUG(sp, "Type path pointed to type alias - " << path);
),
+ (ExternType,
+ static ::HIR::GenericParams empty_params;
+ return empty_params;
+ ),
(Module,
BUG(sp, "Type path pointed to module - " << path);
),
@@ -201,13 +205,16 @@ namespace {
{
while( param_vals.m_types.size() < param_def.m_types.size() ) {
unsigned int i = param_vals.m_types.size();
- if( param_def.m_types[i].m_default.m_data.is_Infer() ) {
+ const auto& ty_def = param_def.m_types[i];
+ if( ty_def.m_default.m_data.is_Infer() ) {
ERROR(sp, E0000, "Unspecified parameter with no default");
}
// Replace and expand
- param_vals.m_types.push_back( param_def.m_types[i].m_default.clone() );
+ param_vals.m_types.push_back( ty_def.m_default.clone() );
auto& ty = param_vals.m_types.back();
+ // TODO: Monomorphise?
+ // Replace `Self` here with the real Self
update_self_type(sp, ty);
}
@@ -220,7 +227,7 @@ namespace {
if( param_vals.m_types[i] == ::HIR::TypeRef() ) {
//if( param_def.m_types[i].m_default == ::HIR::TypeRef() )
// ERROR(sp, E0000, "Unspecified parameter with no default");
- // TODO: Monomorph?
+ // TODO: Monomorphise?
param_vals.m_types[i] = param_def.m_types[i].m_default.clone();
update_self_type(sp, param_vals.m_types[i]);
}
@@ -288,24 +295,53 @@ namespace {
TU_IFLET(::HIR::TypeRef::Data, ty.m_data, ErasedType, e,
if( e.m_origin == ::HIR::SimplePath() )
{
- // If not, ensure taht we're checking a function return type, and error if not
- if( ! m_fcn_path )
+ // If not, figure out what to do with it
+
+ // If the function path is set, we're processing the return type of a function
+ // - Add this to the list of erased types associated with the function
+ if( m_fcn_path )
+ {
+ assert(m_fcn_ptr);
+ DEBUG(*m_fcn_path << " " << m_fcn_erased_count);
+
+ ::HIR::PathParams params;
+ for(unsigned int i = 0; i < m_fcn_ptr->m_params.m_types.size(); i ++)
+ params.m_types.push_back(::HIR::TypeRef(m_fcn_ptr->m_params.m_types[i].m_name, 256+i));
+ // Populate with function path
+ e.m_origin = m_fcn_path->get_full_path();
+ TU_MATCHA( (e.m_origin.m_data), (e2),
+ (Generic, e2.m_params = mv$(params); ),
+ (UfcsInherent, e2.params = mv$(params); ),
+ (UfcsKnown, e2.params = mv$(params); ),
+ (UfcsUnknown, throw ""; )
+ )
+ e.m_index = m_fcn_erased_count++;
+ }
+ // If the function _pointer_ is set (but not the path), then we're in the function arguments
+ // - Add a un-namable generic parameter (TODO: Prevent this from being explicitly set when called)
+ else if( m_fcn_ptr )
+ {
+ size_t idx = m_fcn_ptr->m_params.m_types.size();
+ auto name = RcString::new_interned(FMT("impl$" << idx));
+ auto new_ty = ::HIR::TypeRef( name, 256 + idx );
+ m_fcn_ptr->m_params.m_types.push_back({ name, ::HIR::TypeRef(), true });
+ for( const auto& trait : e.m_traits )
+ {
+ m_fcn_ptr->m_params.m_bounds.push_back(::HIR::GenericBound::make_TraitBound({
+ new_ty.clone(),
+ trait.clone()
+ }));
+ }
+ if( e.m_lifetime != ::HIR::LifetimeRef() )
+ {
+ TODO(sp, "Add bound " << new_ty << " : " << e.m_lifetime);
+ }
+ ty = ::std::move(new_ty);
+ }
+ else
+ {
ERROR(sp, E0000, "Use of an erased type outside of a function return - " << ty);
- assert(m_fcn_ptr);
- DEBUG(*m_fcn_path << " " << m_fcn_erased_count);
-
- ::HIR::PathParams params;
- for(unsigned int i = 0; i < m_fcn_ptr->m_params.m_types.size(); i ++)
- params.m_types.push_back(::HIR::TypeRef(m_fcn_ptr->m_params.m_types[i].m_name, 256+i));
- // Populate with function path
- e.m_origin = m_fcn_path->get_full_path();
- TU_MATCHA( (e.m_origin.m_data), (e2),
- (Generic, e2.m_params = mv$(params); ),
- (UfcsInherent, e2.params = mv$(params); ),
- (UfcsKnown, e2.params = mv$(params); ),
- (UfcsUnknown, throw ""; )
- )
- e.m_index = m_fcn_erased_count++;
+ }
}
)
}
@@ -429,6 +465,16 @@ namespace {
}
return trait_path_g;
}
+ ::HIR::GenericPath get_current_trait_gp() const
+ {
+ assert(m_current_trait_path);
+ assert(m_current_trait);
+ auto trait_path = ::HIR::GenericPath( m_current_trait_path->get_simple_path() );
+ for(unsigned int i = 0; i < m_current_trait->m_params.m_types.size(); i ++ ) {
+ trait_path.m_params.m_types.push_back( ::HIR::TypeRef(m_current_trait->m_params.m_types[i].m_name, i) );
+ }
+ return trait_path;
+ }
void visit_path_UfcsUnknown(const Span& sp, ::HIR::Path& p, ::HIR::Visitor::PathContext pc)
{
TRACE_FUNCTION_FR("UfcsUnknown - p=" << p, p);
@@ -449,10 +495,7 @@ namespace {
// If processing a trait, and the type is 'Self', search for the type/method on the trait
// - TODO: This could be encoded by a `Self: Trait` bound in the generics, but that may have knock-on issues?
if( te.name == "Self" && m_current_trait ) {
- auto trait_path = ::HIR::GenericPath( m_current_trait_path->get_simple_path() );
- for(unsigned int i = 0; i < m_current_trait->m_params.m_types.size(); i ++ ) {
- trait_path.m_params.m_types.push_back( ::HIR::TypeRef(m_current_trait->m_params.m_types[i].m_name, i) );
- }
+ auto trait_path = this->get_current_trait_gp();
if( this->locate_in_trait_and_set(sp, pc, trait_path, *m_current_trait, p.m_data) ) {
// Success!
return ;
@@ -463,26 +506,25 @@ namespace {
)
else {
// 1. Search for applicable inherent methods (COMES FIRST!)
- for( const auto& impl : this->crate.m_type_impls )
- {
- if( !impl.matches_type(*e.type) ) {
- continue ;
- }
+ if( this->crate.find_type_impls(*e.type, [](const auto& ty)->const auto&{return ty;}, [&](const auto& impl) {
DEBUG("- matched inherent impl " << *e.type);
// Search for item in this block
switch( pc )
{
case ::HIR::Visitor::PathContext::VALUE:
if( impl.m_methods.find(e.item) == impl.m_methods.end() ) {
- continue ;
+ return false;
}
// Found it, just keep going (don't care about details here)
break;
case ::HIR::Visitor::PathContext::TRAIT:
case ::HIR::Visitor::PathContext::TYPE:
- continue ;
+ return false;
}
+ return true;
+ }) )
+ {
auto new_data = ::HIR::Path::Data::make_UfcsInherent({ mv$(e.type), mv$(e.item), mv$(e.params)} );
p.m_data = mv$(new_data);
DEBUG("- Resolved, replace with " << p);
@@ -616,6 +658,17 @@ namespace {
auto _ = m_resolve.set_item_generics(item.m_params);
::HIR::Visitor::visit_enum(p, item);
}
+ void visit_associatedtype(::HIR::ItemPath p, ::HIR::AssociatedType& item)
+ {
+ // Push `Self = <Self as CurTrait>::Type` for processing defaults in the bounds.
+ auto path_aty = ::HIR::Path( ::HIR::TypeRef("Self", 0xFFFF), this->get_current_trait_gp(), p.get_name() );
+ auto ty_aty = ::HIR::TypeRef::new_path( mv$(path_aty), ::HIR::TypeRef::TypePathBinding::make_Opaque({}) );
+ m_self_types.push_back(&ty_aty);
+
+ ::HIR::Visitor::visit_associatedtype(p, item);
+
+ m_self_types.pop_back();
+ }
void visit_type_impl(::HIR::TypeImpl& impl) override
{
@@ -661,6 +714,12 @@ namespace {
m_fcn_erased_count = 0;
visit_type(item.m_return);
m_fcn_path = nullptr;
+ // TODO: Visit arguments
+ for(auto& arg : item.m_args)
+ {
+ visit_type(arg.second);
+ }
+ m_fcn_ptr = nullptr;
::HIR::Visitor::visit_function(p, item);
}
diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp
index 8000f5af..51e4b831 100644
--- a/src/hir_typeck/static.cpp
+++ b/src/hir_typeck/static.cpp
@@ -7,6 +7,7 @@
*/
#include "static.hpp"
#include <algorithm>
+#include <hir/expr.hpp>
void StaticTraitResolve::prep_indexes()
{
@@ -96,7 +97,7 @@ bool StaticTraitResolve::find_impl(
auto cb_ident = [](const ::HIR::TypeRef&ty)->const ::HIR::TypeRef& { return ty; };
static ::HIR::PathParams null_params;
- static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc;
+ static ::std::map<RcString, ::HIR::TypeRef> null_assoc;
if( !dont_handoff_to_specialised ) {
if( trait_path == m_lang_Copy ) {
@@ -104,6 +105,16 @@ bool StaticTraitResolve::find_impl(
return found_cb( ImplRef(&type, &null_params, &null_assoc), false );
}
}
+ else if( TARGETVER_1_29 && trait_path == m_lang_Clone ) {
+ // NOTE: Duplicated check for enumerate
+ if( type.m_data.is_Tuple() || type.m_data.is_Array() || type.m_data.is_Function() || type.m_data.is_Closure()
+ || TU_TEST1(type.m_data, Path, .is_closure()) )
+ {
+ if( this->type_is_clone(sp, type) ) {
+ return found_cb( ImplRef(&type, &null_params, &null_assoc), false );
+ }
+ }
+ }
else if( trait_path == m_lang_Sized ) {
if( this->type_is_sized(sp, type) ) {
return found_cb( ImplRef(&type, &null_params, &null_assoc), false );
@@ -118,6 +129,16 @@ bool StaticTraitResolve::find_impl(
}
}
+ if(const auto* e = type.m_data.opt_Generic() )
+ {
+ if( (e->binding >> 8) == 2 )
+ {
+ // TODO: If the type is a magic placeholder, assume it impls the specified trait.
+ // TODO: Restructure so this knows that the placehlder impls the impl-provided bounds.
+ return found_cb( ImplRef(&type, trait_params, &null_assoc), false );
+ }
+ }
+
// --- MAGIC IMPLS ---
// TODO: There should be quite a few more here, but laziness
TU_IFLET(::HIR::TypeRef::Data, type.m_data, Function, e,
@@ -139,11 +160,52 @@ bool StaticTraitResolve::find_impl(
{
trait_params = &null_params;
}
- ::std::map< ::std::string, ::HIR::TypeRef> assoc;
+ ::std::map< RcString, ::HIR::TypeRef> assoc;
assoc.insert( ::std::make_pair("Output", e.m_rettype->clone()) );
return found_cb( ImplRef(type.clone(), trait_params->clone(), mv$(assoc)), false );
}
)
+ if(const auto* e = type.m_data.opt_Closure())
+ {
+ if( trait_path == m_lang_Fn || trait_path == m_lang_FnMut || trait_path == m_lang_FnOnce )
+ {
+ if( trait_params )
+ {
+ const auto& des_arg_tys = trait_params->m_types.at(0).m_data.as_Tuple();
+ if( des_arg_tys.size() != e->m_arg_types.size() ) {
+ return false;
+ }
+ for(unsigned int i = 0; i < des_arg_tys.size(); i ++)
+ {
+ if( des_arg_tys[i] != e->m_arg_types[i] ) {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ trait_params = &null_params;
+ }
+ switch( e->node->m_class )
+ {
+ case ::HIR::ExprNode_Closure::Class::Unknown:
+ break;
+ case ::HIR::ExprNode_Closure::Class::NoCapture:
+ break;
+ case ::HIR::ExprNode_Closure::Class::Once:
+ if( trait_path == m_lang_FnMut )
+ return false;
+ case ::HIR::ExprNode_Closure::Class::Mut:
+ if( trait_path == m_lang_Fn )
+ return false;
+ case ::HIR::ExprNode_Closure::Class::Shared:
+ break;
+ }
+ ::std::map< RcString, ::HIR::TypeRef> assoc;
+ assoc.insert( ::std::make_pair("Output", e->m_rettype->clone()) );
+ return found_cb( ImplRef(type.clone(), trait_params->clone(), mv$(assoc)), false );
+ }
+ }
// ----
// TraitObject traits and supertraits
@@ -162,7 +224,7 @@ bool StaticTraitResolve::find_impl(
if( trait_path == mt.m_path ) {
if( !trait_params || mt.m_params == *trait_params )
{
- static ::std::map< ::std::string, ::HIR::TypeRef> types;
+ static ::std::map< RcString, ::HIR::TypeRef> types;
return found_cb( ImplRef(&type, &mt.m_params, &types), false );
}
}
@@ -174,7 +236,7 @@ bool StaticTraitResolve::find_impl(
bool is_supertrait = trait_params && this->find_named_trait_in_trait(sp, trait_path,*trait_params, *e.m_trait.m_trait_ptr, e.m_trait.m_path.m_path,e.m_trait.m_path.m_params, type,
[&](const auto& i_params, const auto& i_assoc) {
// Invoke callback with a proper ImplRef
- ::std::map< ::std::string, ::HIR::TypeRef> assoc_clone;
+ ::std::map< RcString, ::HIR::TypeRef> assoc_clone;
for(const auto& e : i_assoc)
assoc_clone.insert( ::std::make_pair(e.first, e.second.clone()) );
// HACK! Just add all the associated type bounds (only inserted if not already present)
@@ -204,7 +266,7 @@ bool StaticTraitResolve::find_impl(
bool is_supertrait = trait_params && this->find_named_trait_in_trait(sp, trait_path,*trait_params, *trait.m_trait_ptr, trait.m_path.m_path,trait.m_path.m_params, type,
[&](const auto& i_params, const auto& i_assoc) {
// Invoke callback with a proper ImplRef
- ::std::map< ::std::string, ::HIR::TypeRef> assoc_clone;
+ ::std::map< RcString, ::HIR::TypeRef> assoc_clone;
for(const auto& e : i_assoc)
assoc_clone.insert( ::std::make_pair(e.first, e.second.clone()) );
// HACK! Just add all the associated type bounds (only inserted if not already present)
@@ -251,7 +313,7 @@ bool StaticTraitResolve::find_impl(
{
if( &b_params_mono == &params_mono_o || ::std::any_of(bound.m_type_bounds.begin(), bound.m_type_bounds.end(), [&](const auto& x){ return monomorphise_type_needed(x.second); }) )
{
- ::std::map< ::std::string, ::HIR::TypeRef> atys;
+ ::std::map< RcString, ::HIR::TypeRef> atys;
if( ! bound.m_type_bounds.empty() )
{
for(const auto& tb : bound.m_type_bounds)
@@ -416,7 +478,9 @@ bool StaticTraitResolve::find_impl__check_bound(
static bool compare_pp(const Span& sp, const ::HIR::PathParams& left, const ::HIR::PathParams& right) {
ASSERT_BUG( sp, left.m_types.size() == right.m_types.size(), "Parameter count mismatch" );
for(unsigned int i = 0; i < left.m_types.size(); i ++) {
- if( left.m_types[i] != right.m_types[i] ) {
+ // TODO: Permits fuzzy comparison to handle placeholder params, should instead do a match/test/assign
+ if( left.m_types[i].compare_with_placeholders(sp, right.m_types[i], [](const auto&t)->const ::HIR::TypeRef&{return t;}) == ::HIR::Compare::Unequal ) {
+ //if( left.m_types[i] != right.m_types[i] ) {
return false;
}
}
@@ -521,6 +585,8 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
auto cb_ident = [](const auto&ty)->const ::HIR::TypeRef&{return ty;};
TRACE_FUNCTION_F("impl" << impl_params_def.fmt_args() << " " << des_trait_path << impl_trait_params << " for " << impl_type << impl_params_def.fmt_bounds());
+ // TODO: What if `des_trait_params` already has impl placeholders?
+
::std::vector< const ::HIR::TypeRef*> impl_params;
impl_params.resize( impl_params_def.m_types.size() );
@@ -528,6 +594,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
assert( idx < impl_params.size() );
if( ! impl_params[idx] ) {
impl_params[idx] = &ty;
+ DEBUG("[find_impl__check_crate_raw:cb] Set placeholder " << idx << " to " << ty);
return ::HIR::Compare::Equal;
}
else {
@@ -535,15 +602,34 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
}
};
auto match = impl_type.match_test_generics_fuzz(sp, des_type, cb_ident, cb);
+ unsigned base_impl_placeholder_idx = 0;
if( des_trait_params )
{
assert( des_trait_params->m_types.size() == impl_trait_params.m_types.size() );
+ unsigned max_impl_idx = 0;
for( unsigned int i = 0; i < impl_trait_params.m_types.size(); i ++ )
{
const auto& l = impl_trait_params.m_types[i];
const auto& r = des_trait_params->m_types[i];
match &= l.match_test_generics_fuzz(sp, r, cb_ident, cb);
+
+ visit_ty_with(r, [&](const ::HIR::TypeRef& t)->bool {
+ if( t.m_data.is_Generic() && (t.m_data.as_Generic().binding >> 8) == 2 ) {
+ unsigned impl_idx = t.m_data.as_Generic().binding & 0xFF;
+ max_impl_idx = ::std::max(max_impl_idx, impl_idx+1);
+ }
+ return false;
+ });
}
+ base_impl_placeholder_idx = max_impl_idx;
+
+ size_t n_placeholders_needed = 0;
+ for(unsigned int i = 0; i < impl_params.size(); i ++ ) {
+ if( !impl_params[i] ) {
+ n_placeholders_needed ++;
+ }
+ }
+ ASSERT_BUG(sp, base_impl_placeholder_idx + n_placeholders_needed <= 256, "Out of impl placeholders");
}
if( match == ::HIR::Compare::Unequal ) {
DEBUG(" > Type mismatch");
@@ -555,7 +641,8 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
if( !impl_params[i] ) {
if( placeholders.size() == 0 )
placeholders.resize(impl_params.size());
- placeholders[i] = ::HIR::TypeRef("impl_?", 2*256 + i);
+ placeholders[i] = ::HIR::TypeRef("impl_?", 2*256 + i + base_impl_placeholder_idx);
+ DEBUG("Placeholder " << placeholders[i] << " for " << impl_params_def.m_types[i].m_name);
}
}
// Callback that matches placeholders to concrete types
@@ -563,16 +650,24 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding == idx )
return ::HIR::Compare::Equal;
if( idx >> 8 == 2 ) {
- auto i = idx % 256;
- ASSERT_BUG(sp, !impl_params[i], "Placeholder to populated type returned");
- auto& ph = placeholders[i];
- if( ph.m_data.is_Generic() && ph.m_data.as_Generic().binding == idx ) {
- DEBUG("[find_impl__check_crate_raw:cb_match] Bind placeholder " << i << " to " << ty);
- ph = ty.clone();
- return ::HIR::Compare::Equal;
+ if( (idx % 256) >= base_impl_placeholder_idx ) {
+ auto i = idx % 256 - base_impl_placeholder_idx;
+ ASSERT_BUG(sp, !impl_params[i], "Placeholder to populated type returned. new " << ty << ", existing " << *impl_params[i]);
+ auto& ph = placeholders[i];
+ if( ph.m_data.is_Generic() && ph.m_data.as_Generic().binding == idx ) {
+ DEBUG("[find_impl__check_crate_raw:cb_match] Bind placeholder " << i << " to " << ty);
+ ph = ty.clone();
+ return ::HIR::Compare::Equal;
+ }
+ else if( ph == ty ) {
+ return ::HIR::Compare::Equal;
+ }
+ else {
+ TODO(sp, "[find_impl__check_crate_raw:cb_match] Compare placeholder " << i << " " << ph << " == " << ty);
+ }
}
else {
- TODO(sp, "[find_impl__check_crate_raw:cb_match] Compare placeholder " << i << " " << ph << " == " << ty);
+ return ::HIR::Compare::Fuzzy;
}
}
else {
@@ -628,7 +723,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
const ::HIR::TypeRef& exp = assoc_bound.second;
::HIR::GenericPath aty_src_trait;
- trait_contains_type(sp, b_tp_mono.m_path, *e.trait.m_trait_ptr, aty_name, aty_src_trait);
+ trait_contains_type(sp, b_tp_mono.m_path, *e.trait.m_trait_ptr, aty_name.c_str(), aty_src_trait);
bool rv = false;
if( b_ty_mono.m_data.is_Generic() && (b_ty_mono.m_data.as_Generic().binding >> 8) == 2 ) {
@@ -640,6 +735,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
::HIR::TypeRef have = impl.get_type(aty_name.c_str());
this->expand_associated_types(sp, have);
+ DEBUG("::" << aty_name << " - " << have << " ?= " << exp);
//auto cmp = have .match_test_generics_fuzz(sp, exp, cb_ident, cb_match);
auto cmp = exp .match_test_generics_fuzz(sp, have, cb_ident, cb_match);
if( cmp == ::HIR::Compare::Unequal )
@@ -648,7 +744,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
});
}
if( !rv ) {
- DEBUG("> Fail (assoc) - " << b_ty_mono << " : " << aty_src_trait);
+ DEBUG("> Fail (assoc " << aty_name << ") - " << b_ty_mono << " : " << aty_src_trait);
return false;
}
}
@@ -799,6 +895,9 @@ bool StaticTraitResolve::find_impl__check_crate(
),
(Union,
TODO(sp, "Check auto trait destructure on union " << type);
+ ),
+ (ExternType,
+ TODO(sp, "Check auto trait destructure on extern type " << type);
)
)
DEBUG("- Nothing failed, calling callback");
@@ -924,6 +1023,9 @@ void StaticTraitResolve::expand_associated_types_inner(const Span& sp, ::HIR::Ty
),
(Closure,
// Recurse?
+ for(auto& ty : e.m_arg_types)
+ expand_associated_types_inner(sp, ty);
+ expand_associated_types_inner(sp, *e.m_rettype);
)
)
}
@@ -1143,7 +1245,7 @@ bool StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI
// - Search for the actual trait containing this associated type
::HIR::GenericPath trait_path;
- if( !this->trait_contains_type(sp, e2.trait, this->m_crate.get_trait_by_path(sp, e2.trait.m_path), e2.item, trait_path) )
+ if( !this->trait_contains_type(sp, e2.trait, this->m_crate.get_trait_by_path(sp, e2.trait.m_path), e2.item.c_str(), trait_path) )
BUG(sp, "Cannot find associated type " << e2.item << " anywhere in trait " << e2.trait);
//e2.trait = mv$(trait_path);
@@ -1284,7 +1386,7 @@ bool StaticTraitResolve::find_named_trait_in_trait(const Span& sp,
const ::HIR::SimplePath& des, const ::HIR::PathParams& des_params,
const ::HIR::Trait& trait_ptr, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& pp,
const ::HIR::TypeRef& target_type,
- ::std::function<void(const ::HIR::PathParams&, ::std::map< ::std::string, ::HIR::TypeRef>)> callback
+ ::std::function<void(const ::HIR::PathParams&, ::std::map<RcString, ::HIR::TypeRef>)> callback
) const
{
TRACE_FUNCTION_F(des << des_params << " from " << trait_path << pp);
@@ -1309,16 +1411,23 @@ bool StaticTraitResolve::find_named_trait_in_trait(const Span& sp,
auto pt_mono = monomorphise_traitpath_with(sp, pt, monomorph_cb, false);
DEBUG(pt << " => " << pt_mono);
- if( pt.m_path.m_path == des && pt_mono.m_path.m_params == des_params )
+ // TODO: When in pre-typecheck mode, this needs to be a fuzzy match (because there might be a UfcsUnknown in the
+ // monomorphed version) OR, there may be placeholders
+ if( pt.m_path.m_path == des )
{
- callback( pt_mono.m_path.m_params, mv$(pt_mono.m_type_bounds) );
- return true;
+ auto cmp = pt_mono.m_path.m_params.compare_with_placeholders(sp, des_params, [](const auto& t)->const ::HIR::TypeRef&{return t;});
+ // pt_mono.m_path.m_params == des_params )
+ if( cmp != ::HIR::Compare::Unequal )
+ {
+ callback( pt_mono.m_path.m_params, mv$(pt_mono.m_type_bounds) );
+ return true;
+ }
}
}
return false;
}
-bool StaticTraitResolve::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const
+bool StaticTraitResolve::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const char* name, ::HIR::GenericPath& out_path) const
{
TRACE_FUNCTION_FR("name="<<name << ", trait=" << trait_path, out_path);
auto it = trait_ptr.m_types.find(name);
@@ -1364,6 +1473,13 @@ bool StaticTraitResolve::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty)
return rv;
),
(Path,
+ const auto* markings = e.binding.get_trait_markings();
+ if( markings && ! markings->is_copy )
+ {
+ return false;
+ }
+ // TODO: Also have a marking that indicates that the type is unconditionally Copy
+
{
auto it = m_copy_cache.find(ty);
if( it != m_copy_cache.end() )
@@ -1379,6 +1495,11 @@ bool StaticTraitResolve::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty)
return true;
),
(Closure,
+ if( TARGETVER_1_29 )
+ {
+ // TODO: Auto-gerated impls
+ return e.node->m_is_copy;
+ }
return false;
),
(Infer,
@@ -1430,101 +1551,99 @@ bool StaticTraitResolve::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty)
)
throw "";
}
-
-bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const
+bool StaticTraitResolve::type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const
{
+ if( !TARGETVER_1_29 ) BUG(sp, "Calling type_is_clone when not in 1.29 mode");
+
TU_MATCH(::HIR::TypeRef::Data, (ty.m_data), (e),
(Generic,
- if( e.binding == 0xFFFF ) {
- // TODO: Self: Sized?
- return true;
- }
- else if( (e.binding >> 8) == 0 ) {
- auto idx = e.binding & 0xFF;
- assert( m_impl_generics );
- assert( idx < m_impl_generics->m_types.size() );
- return m_impl_generics->m_types[idx].m_is_sized;
- }
- else if( (e.binding >> 8) == 1 ) {
- auto idx = e.binding & 0xFF;
- assert( m_item_generics );
- assert( idx < m_item_generics->m_types.size() );
- return m_item_generics->m_types[idx].m_is_sized;
- }
- else {
- BUG(sp, "");
+ {
+ auto it = m_clone_cache.find(ty);
+ if( it != m_clone_cache.end() )
+ {
+ return it->second;
+ }
}
+ bool rv = this->iterate_bounds([&](const auto& b)->bool {
+ auto pp = ::HIR::PathParams();
+ return this->find_impl__check_bound(sp, m_lang_Clone, &pp, ty, [&](auto , bool ){ return true; }, b);
+ });
+ m_clone_cache.insert(::std::make_pair( ty.clone(), rv ));
+ return rv;
),
(Path,
- TU_MATCHA( (e.binding), (pbe),
- (Unbound,
- ),
- (Opaque,
- //auto pp = ::HIR::PathParams();
- //return this->find_impl(sp, m_lang_Sized, &pp, ty, [&](auto , bool){ return true; }, true);
- // TODO: This can only be with UfcsKnown, so check if the trait specifies ?Sized
- return true;
- ),
- (Struct,
- // TODO: Destructure?
- switch( pbe->m_struct_markings.dst_type )
- {
- case ::HIR::StructMarkings::DstType::None:
- return true;
- case ::HIR::StructMarkings::DstType::Possible:
- return type_is_sized( sp, e.path.m_data.as_Generic().m_params.m_types.at(pbe->m_struct_markings.unsized_param) );
- case ::HIR::StructMarkings::DstType::Slice:
- case ::HIR::StructMarkings::DstType::TraitObject:
- return false;
- }
- ),
- (Enum,
- ),
- (Union,
- )
- )
- return true;
+ if(true) {
+ auto it = m_clone_cache.find(ty);
+ if( it != m_clone_cache.end() )
+ return it->second;
+ }
+ if( e.is_closure() )
+ {
+ bool rv = true;
+ // TODO: Check all captures
+ m_clone_cache.insert(::std::make_pair( ty.clone(), rv ));
+ return rv;
+ }
+ auto pp = ::HIR::PathParams();
+ bool rv = this->find_impl(sp, m_lang_Clone, &pp, ty, [&](auto , bool){ return true; }, true);
+ m_clone_cache.insert(::std::make_pair( ty.clone(), rv ));
+ return rv;
),
(Diverge,
- // The ! type is kinda Copy ...
+ // The ! type is kinda Copy/Clone ...
return true;
),
(Closure,
- return true;
+ if( TARGETVER_1_29 )
+ {
+ // TODO: Auto-gerated impls
+ return e.node->m_is_copy;
+ }
+ return false;
),
(Infer,
// Shouldn't be hit
return false;
),
(Borrow,
- return true;
+ // Only shared &-ptrs are copy/clone
+ return (e.type == ::HIR::BorrowType::Shared);
),
(Pointer,
+ // All raw pointers are Copy/Clone
return true;
),
(Function,
+ // All function pointers are Copy/Clone
return true;
),
(Primitive,
- // All primitives (except the unsized `str`) are Sized
+ // All primitives (except the unsized `str`) are Copy/Clone
return e != ::HIR::CoreType::Str;
),
(Array,
- return true;
+ return e.size_val == 0 || type_is_clone(sp, *e.inner);
),
(Slice,
+ // [T] isn't Sized, so isn't Copy ether
return false;
),
(TraitObject,
+ // (Trait) isn't Sized, so isn't Copy ether
return false;
),
(ErasedType,
- // NOTE: All erased types are implicitly Sized
- return true;
+ for(const auto& trait : e.m_traits)
+ {
+ if( find_named_trait_in_trait(sp, m_lang_Clone, {}, *trait.m_trait_ptr, trait.m_path.m_path, trait.m_path.m_params, ty, [](const auto&, auto ){ }) ) {
+ return true;
+ }
+ }
+ return false;
),
(Tuple,
for(const auto& ty : e)
- if( !type_is_sized(sp, ty) )
+ if( !type_is_clone(sp, ty) )
return false;
return true;
)
@@ -1532,6 +1651,100 @@ bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty)
throw "";
}
+bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const
+{
+ switch( this->metadata_type(sp, ty) )
+ {
+ case MetadataType::None:
+ return true;
+ default:
+ return false;
+ }
+}
+bool StaticTraitResolve::type_is_impossible(const Span& sp, const ::HIR::TypeRef& ty) const
+{
+ TU_MATCH_HDRA( (ty.m_data), {)
+ break;
+ default:
+ return false;
+ TU_ARMA(Diverge, _e)
+ return true;
+ TU_ARMA(Path, e) {
+ TU_MATCHA( (e.binding), (pbe),
+ (Unbound,
+ // BUG?
+ return false;
+ ),
+ (Opaque,
+ // TODO: This can only be with UfcsKnown, so check if the trait specifies ?Sized
+ return false;
+ ),
+ (Struct,
+ const auto& params = e.path.m_data.as_Generic().m_params;
+ // TODO: Check all fields, if one flags this, then it's impossible.
+ const auto& str = *pbe;
+ TU_MATCH_HDRA( (str.m_data), {)
+ TU_ARMA(Unit, e)
+ return false;
+ TU_ARMA(Tuple, e) {
+ for(const auto& fld : e)
+ {
+ const auto& tpl = fld.ent;
+ ::HIR::TypeRef tmp;
+ const auto& ty = (monomorphise_type_needed(tpl) ? tmp = monomorphise_type_with(sp, tpl, monomorphise_type_get_cb(sp, nullptr, &params, nullptr)) : tpl);
+ if( type_is_impossible(sp, ty) )
+ return true;
+ }
+ return false;
+ }
+ TU_ARMA(Named, e)
+ for(const auto& fld : e)
+ {
+ TODO(sp, "type_is_impossible for struct " << ty << " - " << fld.second.ent);
+ }
+ }
+ ),
+ (Enum,
+ // TODO: Check all variants.
+ TODO(sp, "type_is_impossible for enum " << ty);
+ ),
+ (Union,
+ // TODO: Check all variants? Or just one?
+ TODO(sp, "type_is_impossible for union " << ty);
+ ),
+ (ExternType,
+ // Extern types are possible, just not usable
+ return false;
+ )
+ )
+ return true;
+ }
+ TU_ARMA(Borrow, e)
+ return type_is_impossible(sp, *e.inner);
+ TU_ARMA(Pointer, e) {
+ return false;
+ //return type_is_impossible(sp, *e.inner);
+ }
+ TU_ARMA(Function, e) {
+ // TODO: Check all arguments?
+ return true;
+ }
+ TU_ARMA(Array, e) {
+ return type_is_impossible(sp, *e.inner);
+ }
+ TU_ARMA(Slice, e) {
+ return type_is_impossible(sp, *e.inner);
+ }
+ TU_ARMA(Tuple, e) {
+ for(const auto& ty : e)
+ if( type_is_impossible(sp, ty) )
+ return true;
+ return false;
+ }
+ }
+ throw "";
+}
+
bool StaticTraitResolve::can_unsize(const Span& sp, const ::HIR::TypeRef& dst_ty, const ::HIR::TypeRef& src_ty) const
{
TRACE_FUNCTION_F(dst_ty << " <- " << src_ty);
@@ -1717,7 +1930,133 @@ bool StaticTraitResolve::can_unsize(const Span& sp, const ::HIR::TypeRef& dst_ty
DEBUG("Can't unsize, no rules matched");
return false;
+}
+MetadataType StaticTraitResolve::metadata_type(const Span& sp, const ::HIR::TypeRef& ty, bool err_on_unknown/*=false*/) const
+{
+ TU_MATCH(::HIR::TypeRef::Data, (ty.m_data), (e),
+ (Generic,
+ if( e.binding == 0xFFFF ) {
+ // TODO: Self: Sized?
+ return MetadataType::None;
+ }
+ else if( (e.binding >> 8) == 0 ) {
+ auto idx = e.binding & 0xFF;
+ assert( m_impl_generics );
+ assert( idx < m_impl_generics->m_types.size() );
+ if( m_impl_generics->m_types[idx].m_is_sized ) {
+ return MetadataType::None;
+ }
+ else {
+ return MetadataType::Unknown;
+ }
+ }
+ else if( (e.binding >> 8) == 1 ) {
+ auto idx = e.binding & 0xFF;
+ assert( m_item_generics );
+ assert( idx < m_item_generics->m_types.size() );
+ if( m_item_generics->m_types[idx].m_is_sized ) {
+ return MetadataType::None;
+ }
+ else {
+ return MetadataType::Unknown;
+ }
+ }
+ else {
+ BUG(sp, "Unknown generic binding on " << ty);
+ }
+ ),
+ (Path,
+ TU_MATCHA( (e.binding), (pbe),
+ (Unbound,
+ // TODO: Should this return something else?
+ return MetadataType::Unknown;
+ ),
+ (Opaque,
+ //auto pp = ::HIR::PathParams();
+ //return this->find_impl(sp, m_lang_Sized, &pp, ty, [&](auto , bool){ return true; }, true);
+ // TODO: This can only be with UfcsKnown, so check if the trait specifies ?Sized
+ //return MetadataType::Unknown;
+ return MetadataType::None;
+ ),
+ (Struct,
+ // TODO: Destructure?
+ switch( pbe->m_struct_markings.dst_type )
+ {
+ case ::HIR::StructMarkings::DstType::None:
+ return MetadataType::None;
+ case ::HIR::StructMarkings::DstType::Possible:
+ return this->metadata_type( sp, e.path.m_data.as_Generic().m_params.m_types.at(pbe->m_struct_markings.unsized_param) );
+ case ::HIR::StructMarkings::DstType::Slice:
+ return MetadataType::Slice;
+ case ::HIR::StructMarkings::DstType::TraitObject:
+ return MetadataType::TraitObject;
+ }
+ ),
+ (ExternType,
+ // Extern types aren't Sized, but have no metadata
+ return MetadataType::Zero;
+ ),
+ (Enum,
+ ),
+ (Union,
+ )
+ )
+ return MetadataType::None;
+ ),
+ (Diverge,
+ // The ! type is kinda Sized ...
+ return MetadataType::None;
+ ),
+ (Closure,
+ return MetadataType::None;
+ ),
+ (Infer,
+ // Shouldn't be hit
+ BUG(sp, "Found ivar? " << ty);
+ ),
+ (Borrow,
+ return MetadataType::None;
+ ),
+ (Pointer,
+ return MetadataType::None;
+ ),
+ (Function,
+ return MetadataType::None;
+ ),
+ (Primitive,
+ // All primitives (except the unsized `str`) are Sized
+ if( e == ::HIR::CoreType::Str )
+ {
+ return MetadataType::Slice;
+ }
+ else
+ {
+ return MetadataType::None;
+ }
+ ),
+ (Array,
+ return MetadataType::None;
+ ),
+ (Slice,
+ return MetadataType::Slice;
+ ),
+ (TraitObject,
+ return MetadataType::TraitObject;
+ ),
+ (ErasedType,
+ // NOTE: All erased types are implicitly Sized
+ return MetadataType::None;
+ ),
+ (Tuple,
+ // TODO: Unsized tuples? are they a thing?
+ //for(const auto& ty : e)
+ // if( !type_is_sized(sp, ty) )
+ // return false;
+ return MetadataType::None;
+ )
+ )
+ throw "bug";
}
bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeRef& ty) const
@@ -1735,10 +2074,25 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR
if( e.binding.is_Opaque() )
return true;
+ // In 1.29, "manually_drop" is a struct with special behaviour (instead of being a union)
+ if( TARGETVER_1_29 && e.path.m_data.as_Generic().m_path == m_crate.get_lang_item_path_opt("manually_drop") )
+ {
+ return false;
+ }
+
+ auto it = m_drop_cache.find(ty);
+ if( it != m_drop_cache.end() )
+ {
+ return it->second;
+ }
+
auto pp = ::HIR::PathParams();
bool has_direct_drop = this->find_impl(sp, m_lang_Drop, &pp, ty, [&](auto , bool){ return true; }, true);
if( has_direct_drop )
+ {
+ m_drop_cache.insert(::std::make_pair(ty.clone(), true));
return true;
+ }
::HIR::TypeRef tmp_ty;
const auto& pe = e.path.m_data.as_Generic();
@@ -1753,6 +2107,7 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR
return tpl;
}
};
+ bool needs_drop_glue = false;
TU_MATCHA( (e.binding), (pbe),
(Unbound,
BUG(sp, "Unbound path");
@@ -1769,18 +2124,23 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR
for(const auto& e : se)
{
if( type_needs_drop_glue(sp, monomorph(e.ent)) )
- return true;
+ {
+ needs_drop_glue = true;
+ break;
+ }
}
),
(Named,
for(const auto& e : se)
{
if( type_needs_drop_glue(sp, monomorph(e.second.ent)) )
- return true;
+ {
+ needs_drop_glue = true;
+ break;
+ }
}
)
)
- return false;
),
(Enum,
if(const auto* e = pbe->m_data.opt_Data())
@@ -1788,16 +2148,24 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR
for(const auto& var : *e)
{
if( type_needs_drop_glue(sp, monomorph(var.type)) )
- return true;
+ {
+ needs_drop_glue = true;
+ break;
+ }
}
}
- return false;
),
(Union,
// Unions don't have drop glue unless they impl Drop
- return false;
+ needs_drop_glue = false;
+ ),
+ (ExternType,
+ // Extern types don't have drop glue
+ needs_drop_glue = false;
)
)
+ m_drop_cache.insert(::std::make_pair(ty.clone(), needs_drop_glue));
+ return needs_drop_glue;
),
(Diverge,
return false;
@@ -1892,8 +2260,8 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
{
TRACE_FUNCTION_F(p << ", signature_only=" << signature_only);
out_params = MonomorphState {};
- TU_MATCHA( (p.m_data), (pe),
- (Generic,
+ TU_MATCH_HDR( (p.m_data), {)
+ TU_ARM(p.m_data, Generic, pe) {
if( pe.m_path.m_components.size() > 1 )
{
const auto& ti = m_crate.get_typeitem_by_path(sp, pe.m_path, /*ignore_crate_name=*/false, /*ignore_last_node=*/true);
@@ -1937,8 +2305,8 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
)
)
throw "";
- ),
- (UfcsKnown,
+ }
+ TU_ARM(p.m_data, UfcsKnown, pe) {
out_params.self_ty = &*pe.type;
out_params.pp_impl = &pe.trait.m_params;
out_params.pp_method = &pe.params;
@@ -1960,8 +2328,10 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
return false;
const auto& ti = *impl.m_data.as_TraitImpl().impl;
auto it = ti.m_constants.find(pe.item);
- if(it == ti.m_constants.end())
+ if(it == ti.m_constants.end()) {
+ // An impl was found, but it did't have the value
return false;
+ }
if( impl.more_specific_than(best_impl) )
{
@@ -1994,8 +2364,8 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
return &c.data;
}
throw "";
- ),
- (UfcsInherent,
+ }
+ TU_ARM(p.m_data, UfcsInherent, pe) {
out_params.self_ty = &*pe.type;
//out_params.pp_impl = &out_params.pp_impl_data;
out_params.pp_impl = &pe.impl_params;
@@ -2004,12 +2374,12 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
m_crate.find_type_impls(*pe.type, [](const auto&x)->const ::HIR::TypeRef& { return x; }, [&](const auto& impl) {
DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type);
// TODO: Populate pp_impl
- ASSERT_BUG(sp, impl.m_params.m_types.size() == pe.impl_params.m_types.size(), "");
// TODO: Specialisation
{
auto fit = impl.m_methods.find(pe.item);
if( fit != impl.m_methods.end() )
{
+ ASSERT_BUG(sp, impl.m_params.m_types.size() == pe.impl_params.m_types.size(), "Mismatch in param counts " << p << ", params are " << impl.m_params.fmt_args());
DEBUG("- Contains method, good");
rv = ValuePtr { &fit->second.data };
return true;
@@ -2019,6 +2389,7 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
auto it = impl.m_constants.find(pe.item);
if( it != impl.m_constants.end() )
{
+ ASSERT_BUG(sp, impl.m_params.m_types.size() == pe.impl_params.m_types.size(), "Mismatch in param counts " << p << ", params are " << impl.m_params.fmt_args());
rv = ValuePtr { &it->second.data };
return true;
}
@@ -2026,10 +2397,10 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const
return false;
});
return rv;
- ),
- (UfcsUnknown,
+ }
+ TU_ARM(p.m_data, UfcsUnknown, pe) {
BUG(sp, "UfcsUnknown - " << p);
- )
- )
+ }
+ }
throw "";
}
diff --git a/src/hir_typeck/static.hpp b/src/hir_typeck/static.hpp
index 8c9cb9a6..652bad50 100644
--- a/src/hir_typeck/static.hpp
+++ b/src/hir_typeck/static.hpp
@@ -11,18 +11,27 @@
#include "common.hpp"
#include "impl_ref.hpp"
+enum class MetadataType {
+ Unknown, // Unknown still
+ None, // Sized pointer
+ Zero, // No metadata, but still unsized
+ Slice, // usize metadata
+ TraitObject, // VTable pointer metadata
+};
+
class StaticTraitResolve
{
public:
const ::HIR::Crate& m_crate;
- ::HIR::GenericParams* m_impl_generics;
- ::HIR::GenericParams* m_item_generics;
+ const ::HIR::GenericParams* m_impl_generics;
+ const ::HIR::GenericParams* m_item_generics;
::std::map< ::HIR::TypeRef, ::HIR::TypeRef> m_type_equalities;
::HIR::SimplePath m_lang_Copy;
+ ::HIR::SimplePath m_lang_Clone; // 1.29
::HIR::SimplePath m_lang_Drop;
::HIR::SimplePath m_lang_Sized;
::HIR::SimplePath m_lang_Unsize;
@@ -34,6 +43,8 @@ public:
private:
mutable ::std::map< ::HIR::TypeRef, bool > m_copy_cache;
+ mutable ::std::map< ::HIR::TypeRef, bool > m_clone_cache;
+ mutable ::std::map< ::HIR::TypeRef, bool > m_drop_cache;
public:
StaticTraitResolve(const ::HIR::Crate& crate):
@@ -42,6 +53,8 @@ public:
m_item_generics(nullptr)
{
m_lang_Copy = m_crate.get_lang_item_path_opt("copy");
+ if( TARGETVER_1_29 )
+ m_lang_Clone = m_crate.get_lang_item_path_opt("clone");
m_lang_Drop = m_crate.get_lang_item_path_opt("drop");
m_lang_Sized = m_crate.get_lang_item_path_opt("sized");
m_lang_Unsize = m_crate.get_lang_item_path_opt("unsize");
@@ -71,30 +84,35 @@ public:
/// \brief State manipulation
/// \{
- template<typename T>
- class NullOnDrop {
- T*& ptr;
- public:
- NullOnDrop(T*& ptr):
- ptr(ptr)
- {}
- ~NullOnDrop() {
- ptr = nullptr;
- }
- };
- NullOnDrop< ::HIR::GenericParams> set_impl_generics(::HIR::GenericParams& gps) {
+ NullOnDrop<const ::HIR::GenericParams> set_impl_generics(const ::HIR::GenericParams& gps) {
+ set_impl_generics_raw(gps);
+ return NullOnDrop<const ::HIR::GenericParams>(m_impl_generics);
+ }
+ NullOnDrop<const ::HIR::GenericParams> set_item_generics(const ::HIR::GenericParams& gps) {
+ set_item_generics_raw(gps);
+ return NullOnDrop<const ::HIR::GenericParams>(m_item_generics);
+ }
+ void set_impl_generics_raw(const ::HIR::GenericParams& gps) {
assert( !m_impl_generics );
m_impl_generics = &gps;
m_type_equalities.clear();
prep_indexes();
- return NullOnDrop< ::HIR::GenericParams>(m_impl_generics);
}
- NullOnDrop< ::HIR::GenericParams> set_item_generics(::HIR::GenericParams& gps) {
+ void clear_impl_generics() {
+ m_impl_generics = nullptr;
+ m_type_equalities.clear();
+ prep_indexes();
+ }
+ void set_item_generics_raw(const ::HIR::GenericParams& gps) {
assert( !m_item_generics );
m_item_generics = &gps;
m_type_equalities.clear();
prep_indexes();
- return NullOnDrop< ::HIR::GenericParams>(m_item_generics);
+ }
+ void clear_item_generics() {
+ m_item_generics = nullptr;
+ m_type_equalities.clear();
+ prep_indexes();
}
/// \}
@@ -167,10 +185,10 @@ public:
const ::HIR::SimplePath& des, const ::HIR::PathParams& params,
const ::HIR::Trait& trait_ptr, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& pp,
const ::HIR::TypeRef& self_type,
- ::std::function<void(const ::HIR::PathParams&, ::std::map< ::std::string, ::HIR::TypeRef>)> callback
+ ::std::function<void(const ::HIR::PathParams&, ::std::map< RcString, ::HIR::TypeRef>)> callback
) const;
///
- bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const;
+ bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const char* name, ::HIR::GenericPath& out_path) const;
bool iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function<bool(const ::HIR::TraitPath&)> cb) const;
@@ -178,9 +196,13 @@ public:
// Common bounds
// -------------
bool type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const;
+ bool type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const; // 1.29
bool type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const;
+ bool type_is_impossible(const Span& sp, const ::HIR::TypeRef& ty) const;
bool can_unsize(const Span& sp, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) const;
+ MetadataType metadata_type(const Span& sp, const ::HIR::TypeRef& ty, bool err_on_unknown=false) const;
+
/// Returns `true` if the passed type either implements Drop, or contains a type that implements Drop
bool type_needs_drop_glue(const Span& sp, const ::HIR::TypeRef& ty) const;
diff --git a/src/ident.cpp b/src/ident.cpp
index da029e21..63fe57ed 100644
--- a/src/ident.cpp
+++ b/src/ident.cpp
@@ -34,7 +34,10 @@ bool Ident::Hygiene::is_visible(const Hygiene& src) const
}
::std::ostream& operator<<(::std::ostream& os, const Ident::Hygiene& x) {
- os << "{" << x.contexts << "}";
+ os << "{" << x.contexts;
+ if( x.search_module )
+ os << " " << x.search_module->ents;
+ os << "}";
return os;
}
diff --git a/src/include/debug.hpp b/src/include/debug.hpp
index 3f059301..534523c2 100644
--- a/src/include/debug.hpp
+++ b/src/include/debug.hpp
@@ -14,13 +14,18 @@
extern int g_debug_indent_level;
+#ifndef DEBUG_EXTRA_ENABLE
+# define DEBUG_EXTRA_ENABLE // Files can override this with their own flag if needed (e.g. `&& g_my_debug_on`)
+#endif
+
#ifndef DISABLE_DEBUG
+# define DEBUG_ENABLED (debug_enabled() DEBUG_EXTRA_ENABLE)
# define INDENT() do { g_debug_indent_level += 1; assert(g_debug_indent_level<300); } while(0)
# define UNINDENT() do { g_debug_indent_level -= 1; } while(0)
-# define DEBUG(ss) do{ if(debug_enabled()) { debug_output(g_debug_indent_level, __FUNCTION__) << ss << ::std::endl; } } while(0)
-# define TRACE_FUNCTION TraceLog _tf_(__func__)
-# define TRACE_FUNCTION_F(ss) TraceLog _tf_(__func__, [&](::std::ostream&__os){ __os << ss; })
-# define TRACE_FUNCTION_FR(ss,ss2) TraceLog _tf_(__func__, [&](::std::ostream&__os){ __os << ss; }, [&](::std::ostream&__os){ __os << ss2;})
+# define DEBUG(ss) do{ if(DEBUG_ENABLED) { debug_output(g_debug_indent_level, __FUNCTION__) << ss << ::std::endl; } } while(0)
+# define TRACE_FUNCTION TraceLog _tf_( DEBUG_ENABLED ? __func__ : nullptr)
+# define TRACE_FUNCTION_F(ss) TraceLog _tf_(DEBUG_ENABLED ? __func__ : nullptr, [&](::std::ostream&__os){ __os << ss; })
+# define TRACE_FUNCTION_FR(ss,ss2) TraceLog _tf_(DEBUG_ENABLED ? __func__ : nullptr, [&](::std::ostream&__os){ __os << ss; }, [&](::std::ostream&__os){ __os << ss2;})
#else
# define INDENT() do { } while(0)
# define UNINDENT() do {} while(0)
diff --git a/src/include/ident.hpp b/src/include/ident.hpp
index b9a6dec5..e8cc4e12 100644
--- a/src/include/ident.hpp
+++ b/src/include/ident.hpp
@@ -8,14 +8,21 @@
#pragma once
#include <vector>
#include <string>
+#include <memory>
+#include <rc_string.hpp>
struct Ident
{
+ struct ModPath
+ {
+ ::std::vector<RcString> ents;
+ };
class Hygiene
{
static unsigned g_next_scope;
::std::vector<unsigned int> contexts;
+ ::std::shared_ptr<ModPath> search_module;
Hygiene(unsigned int index):
contexts({index})
@@ -32,6 +39,7 @@ struct Ident
static Hygiene new_scope_chained(const Hygiene& parent)
{
Hygiene rv;
+ rv.search_module = parent.search_module;
rv.contexts.reserve( parent.contexts.size() + 1 );
rv.contexts.insert( rv.contexts.begin(), parent.contexts.begin(), parent.contexts.end() );
rv.contexts.push_back( ++g_next_scope );
@@ -45,12 +53,22 @@ struct Ident
return rv;
}
+ bool has_mod_path() const {
+ return this->search_module != 0;
+ }
+ const ModPath& mod_path() const {
+ return *this->search_module;
+ }
+ void set_mod_path(ModPath p) {
+ this->search_module.reset( new ModPath(::std::move(p)) );
+ }
+
Hygiene(Hygiene&& x) = default;
Hygiene(const Hygiene& x) = default;
Hygiene& operator=(Hygiene&& x) = default;
Hygiene& operator=(const Hygiene& x) = default;
- // Returns true if an ident with hygine `souce` can see an ident with this hygine
+ // Returns true if an ident with hygine `source` can see an ident with this hygine
bool is_visible(const Hygiene& source) const;
//bool operator==(const Hygiene& x) const { return scope_index == x.scope_index; }
//bool operator!=(const Hygiene& x) const { return scope_index != x.scope_index; }
@@ -59,17 +77,17 @@ struct Ident
};
Hygiene hygiene;
- ::std::string name;
+ RcString name;
Ident(const char* name):
hygiene(),
name(name)
{ }
- Ident(::std::string name):
+ Ident(RcString name):
hygiene(),
name(::std::move(name))
{ }
- Ident(Hygiene hygiene, ::std::string name):
+ Ident(Hygiene hygiene, RcString name):
hygiene(::std::move(hygiene)), name(::std::move(name))
{ }
@@ -78,7 +96,7 @@ struct Ident
Ident& operator=(Ident&& x) = default;
Ident& operator=(const Ident& x) = default;
- ::std::string into_string() {
+ RcString into_string() {
return ::std::move(name);
}
diff --git a/src/include/main_bindings.hpp b/src/include/main_bindings.hpp
index c9e573d4..8085eb4c 100644
--- a/src/include/main_bindings.hpp
+++ b/src/include/main_bindings.hpp
@@ -18,6 +18,7 @@ namespace AST {
/// Parse a crate from the given file
extern AST::Crate Parse_Crate(::std::string mainfile);
+extern void Expand_Init();
extern void Expand(::AST::Crate& crate);
extern void Expand_TestHarness(::AST::Crate& crate);
extern void Expand_ProcMacro(::AST::Crate& crate);
diff --git a/src/include/rc_string.hpp b/src/include/rc_string.hpp
index 914228c6..0d6ab155 100644
--- a/src/include/rc_string.hpp
+++ b/src/include/rc_string.hpp
@@ -9,67 +9,135 @@
#include <cstring>
#include <ostream>
+#include "../common.hpp"
class RcString
{
unsigned int* m_ptr;
- unsigned int m_len;
public:
RcString():
- m_ptr(nullptr),
- m_len(0)
+ m_ptr(nullptr)
{}
RcString(const char* s, unsigned int len);
RcString(const char* s):
RcString(s, ::std::strlen(s))
{
}
- RcString(const ::std::string& s):
+ explicit RcString(const ::std::string& s):
RcString(s.data(), s.size())
{
}
- RcString(const RcString& x);
+ static RcString new_interned(const ::std::string& s);
+ static RcString new_interned(const char* s);
+
+ RcString(const RcString& x):
+ m_ptr(x.m_ptr)
+ {
+ if( m_ptr ) *m_ptr += 1;
+ }
RcString(RcString&& x):
- m_ptr(x.m_ptr),
- m_len(x.m_len)
+ m_ptr(x.m_ptr)
{
x.m_ptr = nullptr;
- x.m_len = 0;
}
~RcString();
RcString& operator=(const RcString& x)
{
- if( !(&x != this) ) throw "";
-
- this->~RcString();
- new (this) RcString(x);
-
+ if( &x != this )
+ {
+ this->~RcString();
+ m_ptr = x.m_ptr;
+ if( m_ptr ) *m_ptr += 1;
+ }
return *this;
}
RcString& operator=(RcString&& x)
{
- if( !(&x != this) ) throw "";
-
- this->~RcString();
- new (this) RcString( ::std::move(x) );
+ if( &x != this )
+ {
+ this->~RcString();
+ m_ptr = x.m_ptr;
+ x.m_ptr = nullptr;
+ }
return *this;
}
+ const char* begin() const { return c_str(); }
+ const char* end() const { return c_str() + size(); }
+ size_t size() const { return m_ptr ? m_ptr[1] : 0; }
const char* c_str() const {
- if( m_len > 0 ) {
- return reinterpret_cast<const char*>(m_ptr + 1);
+ if( m_ptr )
+ {
+ return reinterpret_cast<const char*>(m_ptr + 2);
}
- else {
+ else
+ {
return "";
}
}
- bool operator==(const RcString& s) const { return *this == s.c_str(); }
- bool operator==(const char* s) const;
- friend ::std::ostream& operator<<(::std::ostream& os, const RcString& x) {
- return os << x.c_str();
+
+ char back() const {
+ assert(size() > 0 );
+ return *(c_str() + size() - 1);
+ }
+
+ Ordering ord(const char* s, size_t l) const;
+ Ordering ord(const RcString& s) const {
+ if( m_ptr == s.m_ptr )
+ return OrdEqual;
+ return ord(s.c_str(), s.size());
+ }
+ bool operator==(const RcString& s) const {
+ if(s.size() != this->size())
+ return false;
+ return this->ord(s) == OrdEqual;
+ }
+ bool operator!=(const RcString& s) const {
+ if(s.size() != this->size())
+ return true;
+ return this->ord(s) != OrdEqual;
+ }
+ bool operator<(const RcString& s) const { return this->ord(s) == OrdLess; }
+ bool operator>(const RcString& s) const { return this->ord(s) == OrdGreater; }
+
+ Ordering ord(const std::string& s) const { return ord(s.data(), s.size()); }
+ bool operator==(const std::string& s) const { return this->ord(s) == OrdEqual; }
+ bool operator!=(const std::string& s) const { return this->ord(s) != OrdEqual; }
+ bool operator<(const std::string& s) const { return this->ord(s) == OrdLess; }
+ bool operator>(const std::string& s) const { return this->ord(s) == OrdGreater; }
+
+ Ordering ord(const char* s) const;
+ bool operator==(const char* s) const { return this->ord(s) == OrdEqual; }
+ bool operator!=(const char* s) const { return this->ord(s) != OrdEqual; }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const RcString& x);
+
+ friend bool operator==(const char* a, const RcString& b) {
+ return b == a;
+ }
+ friend bool operator!=(const char* a, const RcString& b) {
+ return b != a;
+ }
+
+ int compare(size_t o, size_t l, const char* s) const {
+ assert(o <= this->size());
+ return memcmp(this->c_str() + o, s, l);
}
};
+
+namespace std {
+ static inline bool operator==(const string& a, const ::RcString& b) {
+ return b == a;
+ }
+ static inline bool operator!=(const string& a, const ::RcString& b) {
+ return b != a;
+ }
+ template<> struct hash<RcString>
+ {
+ size_t operator()(const RcString& s) const noexcept;
+ };
+}
diff --git a/src/include/span.hpp b/src/include/span.hpp
index d41fa81e..970a2ad0 100644
--- a/src/include/span.hpp
+++ b/src/include/span.hpp
@@ -31,6 +31,7 @@ struct ProtoSpan
};
struct Span
{
+//public:
::std::shared_ptr<Span> outer_span; // Expansion target for macros
RcString filename;
diff --git a/src/include/synext_decorator.hpp b/src/include/synext_decorator.hpp
index 1e16ce09..88a6258c 100644
--- a/src/include/synext_decorator.hpp
+++ b/src/include/synext_decorator.hpp
@@ -12,6 +12,7 @@
#include <string>
#include <memory>
#include <span.hpp>
+#include <slice.hpp>
#include "../ast/item.hpp"
#include "../ast/expr.hpp"
@@ -49,7 +50,7 @@ public:
virtual AttrStage stage() const = 0;
virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate) const { unexpected(sp, mi, "crate"); }
- virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const { unexpected(sp, mi, "item"); }
+ virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, const AST::Path& path, AST::Module& mod, slice<const AST::Attribute> attrs, AST::Item&i) const { unexpected(sp, mi, "item"); }
// NOTE: To delete, set the type to `_`
virtual void handle(const Span& sp, const AST::Attribute& mi, AST::Crate& crate, const AST::Module& mod, AST::ImplDef& impl) const { unexpected(sp, mi, "impl"); }
// NOTE: To delete, clear the name
diff --git a/src/include/synext_macro.hpp b/src/include/synext_macro.hpp
index 60b52d89..e62a6126 100644
--- a/src/include/synext_macro.hpp
+++ b/src/include/synext_macro.hpp
@@ -27,8 +27,10 @@ class TokenStream;
class ExpandProcMacro
{
public:
- virtual ~ExpandProcMacro() = default;
- virtual ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) = 0;
+ virtual ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) = 0;
+ virtual ::std::unique_ptr<TokenStream> expand_ident(const Span& sp, const AST::Crate& crate, const RcString& ident, const TokenTree& tt, AST::Module& mod) {
+ ERROR(sp, E0000, "macro doesn't take an identifier");
+ }
};
struct MacroDef;
diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp
index bcc9eb3d..5a3359b8 100644
--- a/src/include/tagged_union.hpp
+++ b/src/include/tagged_union.hpp
@@ -28,7 +28,6 @@
#define TU_CASE(mod, class, var, name,src, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(src,mod,var,name) __VA_ARGS__)
#define TU_CASE2(mod, class, var, n1,s1, n2,s2, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(s1,mod,var,n1) TU_CASE_ITEM(s2,mod,var,n2) __VA_ARGS__)
-
// Argument iteration
#define TU_DISP0(n)
#define TU_DISP1(n, _1) n _1
@@ -105,7 +104,7 @@
*/ TU_MATCH_ARMS(CLASS, VAR, NAME, __VA_ARGS__)/*
*/ default: {TU_EXP DEF;} break;/*
*/}
-#define TU_MATCH_BIND1(TAG, VAR, NAME) /*MATCH_BIND*/ auto& NAME = (VAR).as_##TAG(); (void)&NAME;
+#define TU_MATCH_BIND1(TAG, VAR, NAME) /*MATCH_BIND*/ decltype((VAR).as_##TAG()) NAME = (VAR).as_##TAG(); (void)&NAME;
#define TU_MATCH_BIND2_(TAG, v1,v2, n1,n2) TU_MATCH_BIND1(TAG, v1, n1) TU_MATCH_BIND1(TAG, v2, n2)
#define TU_MATCH_BIND2(...) TU_EXP1( TU_MATCH_BIND2_(__VA_ARGS__) ) // << Exists to cause expansion of the vars
#define TU_MATCH_ARM(CLASS, VAR, NAME, TAG, ...) case CLASS::TAG_##TAG: {/*
@@ -116,8 +115,15 @@
#define TU_IFLET(CLASS, VAR, TAG, NAME, ...) if(VAR.tag() == CLASS::TAG_##TAG) { auto& NAME = VAR.as_##TAG(); (void)&NAME; __VA_ARGS__ }
+#define TU_MATCH_HDR(VARS, brace) TU_MATCH_HDR_(::std::remove_reference<decltype(TU_FIRST VARS)>::type, VARS, brace)
+#define TU_MATCH_HDR_(CLASS, VARS, brace) switch( (TU_FIRST VARS).tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used");
+// Evil hack: two for loops, the inner stops the outer after it's done.
+#define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference<decltype(VAR)>::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(decltype((VAR).as_##TAG()) NAME = (VAR).as_##TAG(); (void)NAME, tu_lc; tu_lc=false)
+
+#define TU_MATCH_HDRA(VARS, brace) TU_MATCH_HDRA_(::std::remove_reference<decltype(TU_FIRST VARS)>::type, VARS, brace)
+#define TU_MATCH_HDRA_(CLASS, VARS, brace) auto& tu_match_hdr2_v = (TU_FIRST VARS); switch( tu_match_hdr2_v.tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used");
// Evil hack: two for loops, the inner stops the outer after it's done.
-#define TU_ARM(VAR, TAG, NAME) case ::std::remove_reference<decltype(VAR)>::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = VAR.as_##TAG(); (void)NAME, tu_lc; tu_lc=false)
+#define TU_ARMA(TAG, NAME) break; case ::std::remove_reference<decltype(tu_match_hdr2_v)>::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(decltype(tu_match_hdr2_v.as_##TAG()) NAME = tu_match_hdr2_v.as_##TAG(); (void)NAME, tu_lc; tu_lc=false)
//#define TU_TEST(VAL, ...) (VAL.is_##TAG() && VAL.as_##TAG() TEST)
#define TU_TEST1(VAL, TAG1, TEST) (VAL.is_##TAG1() && VAL.as_##TAG1() TEST)
diff --git a/src/include/target_version.hpp b/src/include/target_version.hpp
new file mode 100644
index 00000000..07528276
--- /dev/null
+++ b/src/include/target_version.hpp
@@ -0,0 +1,19 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * include/target_version.hpp
+ * - mrustc target lanuage version definitions
+ */
+#pragma once
+
+enum class TargetVersion {
+ Rustc1_19,
+ Rustc1_29,
+};
+
+// Defined in main.cpp
+extern TargetVersion gTargetVersion;
+
+#define TARGETVER_1_19 (gTargetVersion == TargetVersion::Rustc1_19)
+#define TARGETVER_1_29 (gTargetVersion == TargetVersion::Rustc1_29)
diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp
index a393ba46..927a3585 100644
--- a/src/macro_rules/eval.cpp
+++ b/src/macro_rules/eval.cpp
@@ -93,60 +93,43 @@ private:
CapturedVal& get_cap(const ::std::vector<unsigned int>& iterations, unsigned int name_idx);
};
-/// Simple pattern entry for macro_rules! arm patterns
-TAGGED_UNION( SimplePatEnt, End,
- // End of the pattern stream
- (End, struct{}),
- // Expect a specific token
- (ExpectTok, Token),
- // Expect a pattern match
- (ExpectPat, struct {
- MacroPatEnt::Type type;
- unsigned int idx;
- }),
- // Compare the head of the input stream and poke the pattern stream
- (IfTok, struct {
- bool is_equal;
- Token tok;
- }),
- // Compare the head of the input stream and poke the pattern stream
- (IfPat, struct {
- bool is_equal;
- MacroPatEnt::Type type;
- })
- );
class MacroPatternStream
{
- const ::std::vector<MacroPatEnt>* m_pattern;
- // Position in each nested pattern
- ::std::vector<unsigned int> m_pos;
+ const ::std::vector<SimplePatEnt>& m_simple_ents;
+ size_t m_cur_pos;
+
+ bool m_last_was_cond;
+ bool m_condition_met;
+ ::std::vector<bool> m_condition_history;
+
+ const ::std::vector<bool>* m_condition_replay;
+ size_t m_condition_replay_pos;
+
// Iteration index of each active loop level
::std::vector<unsigned int> m_loop_iterations;
- ::std::vector<SimplePatEnt> m_stack;
- unsigned int m_skip_count;
-
- SimplePatEnt m_peek_cache;
bool m_peek_cache_valid = false;
+ const SimplePatEnt* m_peek_cache;
- bool m_break_if_not = false;
- bool m_condition_fired = false;
public:
- MacroPatternStream(const ::std::vector<MacroPatEnt>& pattern):
- m_pattern(&pattern),
- m_pos({0})
+ MacroPatternStream(const ::std::vector<SimplePatEnt>& ents, const ::std::vector<bool>* condition_replay=nullptr):
+ m_simple_ents(ents),
+ m_cur_pos(0),
+ m_last_was_cond(false),
+ m_condition_replay(condition_replay),
+ m_condition_replay_pos(0)
{
}
/// Get the next pattern entry
- SimplePatEnt next();
+ const SimplePatEnt& next();
const SimplePatEnt& peek() {
if( !m_peek_cache_valid ) {
- m_peek_cache = next();
+ m_peek_cache = &next();
m_peek_cache_valid = true;
}
- return m_peek_cache;
+ return *m_peek_cache;
}
/// Inform the stream that the `if` rule that was just returned succeeded
@@ -156,16 +139,9 @@ public:
return m_loop_iterations;
}
-private:
- SimplePatEnt emit_loop_start(const MacroPatEnt& pat);
-
- SimplePatEnt emit_seq(SimplePatEnt v1, SimplePatEnt v2) {
- assert( m_stack.empty() );
- m_stack.push_back( mv$(v2) );
- return v1;
+ ::std::vector<bool> take_history() {
+ return ::std::move(m_condition_history);
}
-
- void break_loop();
};
// === Prototypes ===
@@ -312,223 +288,76 @@ bool ParameterMappings::dec_count(const ::std::vector<unsigned int>& iterations,
// MacroPatternStream
// ------------------------------------
-SimplePatEnt MacroPatternStream::next()
+const SimplePatEnt& MacroPatternStream::next()
{
- TRACE_FUNCTION_F("m_pos=[" << m_pos << "], m_stack.size()=" << m_stack.size());
- assert(m_pos.size() >= 1);
-
if( m_peek_cache_valid ) {
m_peek_cache_valid = false;
- return mv$(m_peek_cache);
+ return *m_peek_cache;
}
- // Pop off the generation stack
- if( ! m_stack.empty() ) {
- auto rv = mv$(m_stack.back());
- m_stack.pop_back();
- return rv;
- }
-
- if( m_break_if_not && ! m_condition_fired ) {
- // Break out of the current loop then continue downwards.
- break_loop();
- }
-
- m_skip_count = 0;
- m_break_if_not = false;
- m_condition_fired = false;
-
- const MacroPatEnt* parent_pat = nullptr;
- decltype(m_pattern) parent_ents = nullptr;
- const auto* ents = m_pattern;
- for(unsigned int i = 0; i < m_pos.size() - 1; i ++)
- {
- auto idx = m_pos[i];
- //DEBUG(i << " idx=" << idx << " ents->size()=" << ents->size());
- assert( idx < ents->size() );
- assert( (*ents)[idx].type == MacroPatEnt::PAT_LOOP );
- parent_pat = &(*ents)[idx];
- parent_ents = ents;
- ents = &parent_pat->subpats;
- }
-
- DEBUG( (m_pos.size()-1) << " " << m_pos.back() << " / " << ents->size());
- if( m_pos.back() < ents->size() )
- {
- const auto& pat = ents->at( m_pos.back() );
-
- if( pat.type == MacroPatEnt::PAT_LOOP ) {
- DEBUG("Enter " << pat);
- // Increase level, return entry control
- m_pos.push_back( 0 );
- m_loop_iterations.push_back( 0 );
-
- if( pat.name == "*" )
- {
- return emit_loop_start(pat);
- }
- else
- {
- // If the name is "+" then this is should always be entered, so just recurse
- assert( pat.name == "+" );
- return next();
- }
- }
- else if( pat.type == MacroPatEnt::PAT_TOKEN ) {
- m_pos.back() += 1;
- return SimplePatEnt::make_ExpectTok( pat.tok.clone() );
- }
- else {
- m_pos.back() += 1;
- return SimplePatEnt::make_ExpectPat({ pat.type, pat.name_index });
- }
- }
- else
+ for(;;)
{
- if( parent_pat )
+ // If not replaying, and the previous entry was a conditional, record the result of that conditional
+ if( !m_condition_replay && m_last_was_cond )
{
- // Last entry in a loop - return the breakout control
- // - Reset the loop back to the start
- m_pos.back() = 0;
- m_loop_iterations.back() += 1;
-
- // - Emit break conditions
- if( parent_pat->tok == TOK_NULL ) {
- // Loop separator is TOK_NULL - get the first token of the loop and use it.
- // - This shares the code that controls if a loop is entered
- DEBUG("No separator");
- return emit_loop_start(*parent_pat);
- }
- else {
- // If the next token is the same as the separator emit: Expect(separator), ShouldEnter
-
- auto i = m_pos[ m_pos.size() - 2 ] + 1;
- if( i < parent_ents->size() )
- {
- DEBUG("sep = " << parent_pat->tok << ", next = " << parent_ents->at(i) << ", start = " << ents->at(0));
- if( parent_ents->at(i).type == MacroPatEnt::PAT_TOKEN && parent_pat->tok == parent_ents->at(i).tok )
- {
- DEBUG("MAGIC: Reverse conditions for case where sep==next");
- // > Mark to skip the next token after the end of the loop
- m_skip_count = 1;
- // - Yeild `EXPECT sep` then the entry condition of this loop
- auto pat = emit_loop_start(*parent_pat);
- m_stack.push_back( mv$(pat) );
- return SimplePatEnt::make_ExpectTok( parent_pat->tok.clone() );
- }
- }
- // - Yeild `IF NOT sep BREAK` and `EXPECT sep`
- DEBUG("Separator = " << parent_pat->tok);
- return emit_seq(
- SimplePatEnt::make_IfTok({ false, parent_pat->tok.clone() }),
- SimplePatEnt::make_ExpectTok( parent_pat->tok.clone() )
- );
- }
+ m_condition_history.push_back(m_condition_met);
}
- else
- {
- // End of the input sequence
- return SimplePatEnt::make_End({});
+ m_last_was_cond = false;
+ // End of list? return End entry
+ if( m_cur_pos == m_simple_ents.size() ) {
+ static SimplePatEnt END = SimplePatEnt::make_End({});
+ return END;
}
- }
-}
-
-namespace {
- void get_loop_entry_pats(const MacroPatEnt& pat, ::std::vector<const MacroPatEnt*>& entry_pats)
- {
- assert( pat.type == MacroPatEnt::PAT_LOOP );
-
- // If this pattern is a loop, get the entry concrete patterns for it
- // - Otherwise, just
- unsigned int i = 0;
- while( i < pat.subpats.size() && pat.subpats[i].type == MacroPatEnt::PAT_LOOP )
+ const auto& cur_ent = m_simple_ents[m_cur_pos];
+ // If replaying, and this is a conditional
+ if( m_condition_replay && cur_ent.is_If() )
{
- const auto& cur_pat = pat.subpats[i];
- bool is_optional = (cur_pat.name == "*");
-
- get_loop_entry_pats(cur_pat, entry_pats);
-
- if( !is_optional )
- {
- // Non-optional loop, MUST be entered, so return after recursing
- return ;
- }
- // Optional, so continue the loop.
- i ++;
- }
-
- // First non-loop pattern
- if( i < pat.subpats.size() )
- {
- entry_pats.push_back( &pat.subpats[i] );
- }
- }
-} // namespace
-
-/// Returns (and primes m_stack) the rules to control the start of a loop
-/// This code emits rules to break out of the loop if the entry conditions are not met
-SimplePatEnt MacroPatternStream::emit_loop_start(const MacroPatEnt& pat)
-{
- // Find the next non-loop pattern to control if this loop should be entered
- ::std::vector<const MacroPatEnt*> m_entry_pats;
-
- get_loop_entry_pats(pat, m_entry_pats);
- DEBUG("m_entry_pats = [" << FMT_CB(ss, for(const auto* p : m_entry_pats) { ss << *p << ","; }) << "]");
-
- struct H {
- static SimplePatEnt get_if(bool flag, const MacroPatEnt& mpe) {
- if( mpe.type == MacroPatEnt::PAT_TOKEN )
- return SimplePatEnt::make_IfTok({ flag, mpe.tok.clone() });
+ // Skip the conditional (following its target or just skipping over)
+ if( (*m_condition_replay)[m_condition_replay_pos++] )
+ m_cur_pos = cur_ent.as_If().jump_target;
else
- return SimplePatEnt::make_IfPat({ flag, mpe.type });
+ m_cur_pos += 1;
+ continue ;
}
- };
-
- const auto* entry_pat = m_entry_pats.back();
- m_entry_pats.pop_back();
- if( m_entry_pats.size() > 0 )
- {
- DEBUG("Multiple entry possibilities, reversing condition");
- m_break_if_not = true;
- for(auto pat_ptr : m_entry_pats)
- {
- m_stack.push_back( H::get_if(true, *pat_ptr) );
+ m_cur_pos += 1;
+ TU_MATCH_HDRA( (cur_ent), {)
+ default:
+ if( cur_ent.is_If() )
+ {
+ m_last_was_cond = true;
+ m_condition_met = false;
+ }
+ return cur_ent;
+ TU_ARMA(End, _e)
+ BUG(Span(), "Unexpected End");
+ TU_ARMA(Jump, e)
+ m_cur_pos = e.jump_target;
+ TU_ARMA(LoopStart, _e) {
+ m_loop_iterations.push_back(0);
+ }
+ TU_ARMA(LoopNext, _e) {
+ m_loop_iterations.back() += 1;
+ }
+ TU_ARMA(LoopEnd, _e) {
+ m_loop_iterations.pop_back();
+ }
}
- return H::get_if(true, *entry_pat);
- }
- else
- {
- // Emit an if based on it
- return H::get_if(false, *entry_pat);
}
}
void MacroPatternStream::if_succeeded()
{
- if( m_break_if_not )
- {
- m_condition_fired = true;
- }
- else
- {
- break_loop();
+ assert(m_cur_pos > 0);
+ assert(m_last_was_cond);
+ TU_MATCH_HDRA( (m_simple_ents[m_cur_pos-1]), {)
+ default:
+ BUG(Span(), "Unexpected " << m_simple_ents[m_cur_pos-1]);
+ TU_ARMA(If, e) {
+ ASSERT_BUG(Span(), e.jump_target < m_simple_ents.size(), "Jump target " << e.jump_target << " out of range " << m_simple_ents.size());
+ m_cur_pos = e.jump_target;
+ }
}
-}
-void MacroPatternStream::break_loop()
-{
- DEBUG("- Break out of loop, m_skip_count = " << m_skip_count);
- // Break out of an active loop (pop level and increment parent level)
- assert( m_pos.size() >= 1 );
- // - This should never be called when on the top level
- assert( m_pos.size() != 1 );
-
- // HACK: Clear the stack if an if succeeded
- m_stack.clear();
-
- m_pos.pop_back();
- m_pos.back() += 1 + m_skip_count;
-
- m_loop_iterations.pop_back();
+ m_condition_met = true;
}
// ----------------------------------------------------------------
@@ -576,7 +405,7 @@ class MacroExpander:
{
const RcString m_macro_filename;
- const ::std::string m_crate_name;
+ const RcString m_crate_name;
::std::shared_ptr<Span> m_invocation_span;
ParameterMappings m_mappings;
@@ -589,7 +418,7 @@ class MacroExpander:
public:
MacroExpander(const MacroExpander& x) = delete;
- MacroExpander(const ::std::string& macro_name, const Span& sp, const Ident::Hygiene& parent_hygiene, const ::std::vector<MacroExpansionEnt>& contents, ParameterMappings mappings, ::std::string crate_name):
+ MacroExpander(const ::std::string& macro_name, const Span& sp, const Ident::Hygiene& parent_hygiene, const ::std::vector<MacroExpansionEnt>& contents, ParameterMappings mappings, RcString crate_name):
m_macro_filename( FMT("Macro:" << macro_name) ),
m_crate_name( mv$(crate_name) ),
m_invocation_span( new Span(sp) ),
@@ -616,69 +445,6 @@ namespace {
}
}
-// TODO: This shouldn't exist, and can false-positives
-// - Ideally, this would use consume_from_frag (which takes a clone-able input)
-bool Macro_TryPatternCap(TokenStream& lex, MacroPatEnt::Type type)
-{
- switch(type)
- {
- case MacroPatEnt::PAT_TOKEN:
- BUG(lex.point_span(), "");
- case MacroPatEnt::PAT_LOOP:
- BUG(lex.point_span(), "");
- case MacroPatEnt::PAT_BLOCK:
- return LOOK_AHEAD(lex) == TOK_BRACE_OPEN || LOOK_AHEAD(lex) == TOK_INTERPOLATED_BLOCK;
- case MacroPatEnt::PAT_IDENT:
- return LOOK_AHEAD(lex) == TOK_IDENT || is_reserved_word(LOOK_AHEAD(lex));
- case MacroPatEnt::PAT_TT:
- switch(LOOK_AHEAD(lex))
- {
- case TOK_EOF:
- case TOK_PAREN_CLOSE:
- case TOK_BRACE_CLOSE:
- case TOK_SQUARE_CLOSE:
- return false;
- default:
- return true;
- }
- case MacroPatEnt::PAT_PATH:
- return is_token_path( LOOK_AHEAD(lex) );
- case MacroPatEnt::PAT_TYPE:
- return is_token_type( LOOK_AHEAD(lex) );
- case MacroPatEnt::PAT_EXPR:
- return is_token_expr( LOOK_AHEAD(lex) );
- case MacroPatEnt::PAT_STMT:
- return is_token_stmt( LOOK_AHEAD(lex) );
- case MacroPatEnt::PAT_PAT:
- return is_token_pat( LOOK_AHEAD(lex) );
- case MacroPatEnt::PAT_META:
- return LOOK_AHEAD(lex) == TOK_IDENT || LOOK_AHEAD(lex) == TOK_INTERPOLATED_META;
- case MacroPatEnt::PAT_ITEM:
- return is_token_item( LOOK_AHEAD(lex) ) || LOOK_AHEAD(lex) == TOK_IDENT;
- }
- BUG(lex.point_span(), "Fell through");
-}
-bool Macro_TryPattern(TokenStream& lex, const MacroPatEnt& pat)
-{
- DEBUG("pat = " << pat);
- Token tok;
- switch(pat.type)
- {
- case MacroPatEnt::PAT_TOKEN: {
- GET_TOK(tok, lex);
- bool rv = (tok == pat.tok);
- PUTBACK(tok, lex);
- return rv;
- }
- case MacroPatEnt::PAT_LOOP:
- if( pat.name == "*" )
- return true;
- return Macro_TryPattern(lex, pat.subpats[0]);
- default:
- return Macro_TryPatternCap(lex, pat.type);
- }
-}
-
InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type type)
{
Token tok;
@@ -723,6 +489,11 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type
CHECK_TOK(tok, TOK_IDENT);
// TODO: TOK_INTERPOLATED_IDENT
return InterpolatedFragment( TokenTree(lex.getHygiene(), tok) );
+ case MacroPatEnt::PAT_VIS:
+ return InterpolatedFragment( Parse_Publicity(lex, /*allow_restricted=*/true) );
+ case MacroPatEnt::PAT_LIFETIME:
+ GET_CHECK_TOK(tok, lex, TOK_LIFETIME);
+ return InterpolatedFragment( TokenTree(lex.getHygiene(), tok) );
}
throw "";
}
@@ -731,6 +502,7 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type
::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, const Span& sp, TokenTree input, AST::Module& mod)
{
TRACE_FUNCTION_F("'" << name << "', " << input);
+ DEBUG("rules.m_hygiene = " << rules.m_hygiene);
ParameterMappings bound_tts;
unsigned int rule_index = Macro_InvokeRules_MatchPattern(sp, rules, mv$(input), mod, bound_tts);
@@ -752,7 +524,6 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type
return ::std::unique_ptr<TokenStream>( ret_ptr );
}
-#if 1
// Collection of functions that consume a specific fragment type from a token stream
// - Does very loose consuming
namespace
@@ -1069,9 +840,11 @@ namespace
case TOK_PAREN_OPEN:
case TOK_SQUARE_OPEN:
return consume_tt(lex);
+ case TOK_IDENT:
+ if( TARGETVER_1_29 && lex.next_tok().istr() == "dyn" )
+ lex.consume();
case TOK_RWORD_SUPER:
case TOK_RWORD_SELF:
- case TOK_IDENT:
case TOK_DOUBLE_COLON:
case TOK_INTERPOLATED_IDENT:
case TOK_INTERPOLATED_PATH:
@@ -1189,7 +962,8 @@ namespace
}
if(lex.consume_if(TOK_AT))
continue;
- if( lex.consume_if(TOK_TRIPLE_DOT) )
+ // ... or ..=
+ if( lex.consume_if(TOK_TRIPLE_DOT) || lex.consume_if(TOK_DOUBLE_DOT_EQUAL) )
{
switch(lex.next())
{
@@ -1335,6 +1109,11 @@ namespace
lex.consume();
break;
+ // Possibly a left-open (or full-open) range literal
+ case TOK_DOUBLE_DOT:
+ case TOK_DOUBLE_DOT_EQUAL:
+ case TOK_TRIPLE_DOT:
+ break;
case TOK_RWORD_UNSAFE:
lex.consume();
@@ -1490,10 +1269,28 @@ namespace
case TOK_EXCLAM_EQUAL:
case TOK_DOUBLE_AMP:
case TOK_DOUBLE_PIPE:
- case TOK_DOUBLE_DOT:
+ case TOK_DOUBLE_DOT_EQUAL:
case TOK_TRIPLE_DOT:
lex.consume();
break;
+ case TOK_DOUBLE_DOT:
+ lex.consume();
+ DEBUG("TOK_DOUBLE_DOT => " << lex.next());
+ switch(lex.next())
+ {
+ case TOK_EOF:
+ return true;
+ case TOK_COMMA:
+ case TOK_SEMICOLON:
+ case TOK_BRACE_CLOSE:
+ case TOK_PAREN_CLOSE:
+ case TOK_SQUARE_CLOSE:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ break;
case TOK_EQUAL:
case TOK_PLUS_EQUAL:
case TOK_DASH_EQUAL:
@@ -1570,7 +1367,7 @@ namespace
return true;
// Macro invocation
// TODO: What about `union!` as a macro? Needs to be handled below
- if( (lex.next() == TOK_IDENT && lex.next_tok().str() != "union")
+ if( (lex.next() == TOK_IDENT && lex.next_tok().istr() != "union")
|| lex.next() == TOK_RWORD_SELF
|| lex.next() == TOK_RWORD_SUPER
|| lex.next() == TOK_DOUBLE_COLON
@@ -1580,6 +1377,7 @@ namespace
return false;
if( !lex.consume_if(TOK_EXCLAM) )
return false;
+ lex.consume_if(TOK_IDENT);
bool need_semicolon = (lex.next() != TOK_BRACE_OPEN);
consume_tt(lex);
if( need_semicolon )
@@ -1705,29 +1503,46 @@ namespace
return false;
return consume_tt(lex);
case TOK_IDENT:
- if( lex.next_tok().str() != "union" )
- return false;
- lex.consume();
- if( lex.next() == TOK_EXCLAM )
+ if( lex.next_tok().istr() == "union" )
{
- bool need_semicolon = (lex.next() != TOK_BRACE_OPEN);
- consume_tt(lex);
- if( need_semicolon )
+ lex.consume();
+ if( lex.next() == TOK_EXCLAM )
+ {
+ bool need_semicolon = (lex.next() != TOK_BRACE_OPEN);
+ consume_tt(lex);
+ if( need_semicolon )
+ {
+ if( !lex.consume_if(TOK_SEMICOLON) )
+ return false;
+ }
+ return true;
+ }
+ else
{
- if( !lex.consume_if(TOK_SEMICOLON) )
+ if( !H::maybe_generics(lex) )
return false;
+ if( !H::maybe_where(lex) )
+ return false;
+ if( lex.next() != TOK_BRACE_OPEN )
+ return false;
+ return consume_tt(lex);
}
- return true;
}
- else
+ else if( lex.next_tok().istr() == "auto" )
{
- if( !H::maybe_generics(lex) )
- return false;
- if( !H::maybe_where(lex) )
- return false;
- if( lex.next() != TOK_BRACE_OPEN )
+ lex.consume();
+ if( lex.consume_if(TOK_RWORD_TRAIT) )
+ {
+ goto trait;
+ }
+ else
+ {
return false;
- return consume_tt(lex);
+ }
+ }
+ else
+ {
+ return false;
}
break;
// const fn
@@ -1754,6 +1569,19 @@ namespace
return false;
}
break;
+ case TOK_RWORD_TRAIT:
+ lex.consume();
+ trait:
+ if( !lex.consume_if(TOK_IDENT) )
+ return false;
+
+ if( !H::maybe_generics(lex) )
+ return false;
+ if(lex.next() != TOK_BRACE_OPEN)
+ return false;
+ if( !consume_tt(lex) )
+ return false;
+ break;
case TOK_RWORD_EXTERN:
lex.consume();
if( lex.consume_if(TOK_RWORD_CRATE) )
@@ -1815,6 +1643,26 @@ namespace
}
return true;
}
+ bool consume_vis(TokenStreamRO& lex)
+ {
+ TRACE_FUNCTION;
+ if( lex.consume_if(TOK_INTERPOLATED_VIS) || lex.consume_if(TOK_RWORD_CRATE) )
+ {
+ return true;
+ }
+ else if( lex.consume_if(TOK_RWORD_PUB) )
+ {
+ if( lex.next() == TOK_PAREN_OPEN )
+ {
+ return consume_tt(lex);
+ }
+ return true;
+ }
+ else
+ {
+ return true;
+ }
+ }
bool consume_from_frag(TokenStreamRO& lex, MacroPatEnt::Type type)
{
@@ -1823,7 +1671,7 @@ namespace
{
case MacroPatEnt::PAT_TOKEN:
case MacroPatEnt::PAT_LOOP:
- throw "";
+ BUG(Span(), "Encountered " << type << " in consume_from_frag");;
case MacroPatEnt::PAT_BLOCK:
if( lex.next() == TOK_BRACE_OPEN ) {
return consume_tt(lex);
@@ -1889,6 +1737,10 @@ namespace
break;
case MacroPatEnt::PAT_ITEM:
return consume_item(lex);
+ case MacroPatEnt::PAT_VIS:
+ return consume_vis(lex);
+ case MacroPatEnt::PAT_LIFETIME:
+ return lex.consume_if(TOK_LIFETIME);
}
return true;
}
@@ -1897,14 +1749,9 @@ namespace
unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& rules, TokenTree input, AST::Module& mod, ParameterMappings& bound_tts)
{
TRACE_FUNCTION;
+ ASSERT_BUG(sp, rules.m_rules.size() > 0, "Empty macro_rules set");
- struct ActiveArm {
- unsigned int index;
- MacroPatternStream pat_stream;
- TokenStreamRO in_stream;
- };
-
- ::std::vector<size_t> matches;
+ ::std::vector< ::std::pair<size_t, ::std::vector<bool>> > matches;
for(size_t i = 0; i < rules.m_rules.size(); i ++)
{
auto lex = TokenStreamRO(input);
@@ -1913,29 +1760,38 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
bool fail = false;
for(;;)
{
- auto pat = arm_stream.next();
+ const auto& pat = arm_stream.next();
+ DEBUG(i << " " << pat);
if(pat.is_End())
{
- DEBUG(i << " End");
if( lex.next() != TOK_EOF )
fail = true;
break;
}
- else if( const auto* e = pat.opt_IfPat() )
+ else if( const auto* e = pat.opt_If() )
{
- DEBUG(i << " IfPat(" << (e->is_equal ? "==" : "!=") << " ?" << e->type << ")");
auto lc = lex.clone();
- if( consume_from_frag(lc, e->type) == e->is_equal )
+ bool rv = true;
+ for(const auto& check : e->ents)
{
- DEBUG("- Succeeded");
- arm_stream.if_succeeded();
+ if( check.ty != MacroPatEnt::PAT_TOKEN ) {
+ if( !consume_from_frag(lc, check.ty) )
+ {
+ rv = false;
+ break;
+ }
+ }
+ else
+ {
+ if( lc.next_tok() != check.tok )
+ {
+ rv = false;
+ break;
+ }
+ lc.consume();
+ }
}
- }
- else if( const auto* e = pat.opt_IfTok() )
- {
- DEBUG(i << " IfTok(" << (e->is_equal ? "==" : "!=") << " ?" << e->tok << ")");
- const auto& tok = lex.next_tok();
- if( (tok == e->tok) == e->is_equal )
+ if( rv == e->is_equal )
{
DEBUG("- Succeeded");
arm_stream.if_succeeded();
@@ -1970,7 +1826,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
if( ! fail )
{
- matches.push_back(i);
+ matches.push_back( ::std::make_pair(i, arm_stream.take_history()) );
DEBUG(i << " MATCHED");
}
else
@@ -1982,6 +1838,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
if( matches.size() == 0 )
{
// ERROR!
+ // TODO: Keep track of where each arm failed.
TODO(sp, "No arm matched");
}
else
@@ -1989,12 +1846,13 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
// yay!
// NOTE: There can be multiple arms active, take the first.
- auto i = matches[0];
+ auto i = matches[0].first;
+ const auto& history = matches[0].second;
DEBUG("Evalulating arm " << i);
auto lex = TTStreamO(sp, mv$(input));
SET_MODULE(lex, mod);
- auto arm_stream = MacroPatternStream(rules.m_rules[i].m_pattern);
+ auto arm_stream = MacroPatternStream(rules.m_rules[i].m_pattern, &history);
struct Capture {
unsigned int binding_idx;
@@ -2006,30 +1864,15 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
for(;;)
{
- auto pat = arm_stream.next();
+ const auto& pat = arm_stream.next();
+ DEBUG(i << " " << pat);
if(pat.is_End())
{
break;
}
- else if( const auto* e = pat.opt_IfPat() )
+ else if( pat.is_If() )
{
- DEBUG(i << " IfPat(" << (e->is_equal ? "==" : "!=") << " ?" << e->type << ")");
- if( Macro_TryPatternCap(lex, e->type) == e->is_equal )
- {
- DEBUG("- Succeeded");
- arm_stream.if_succeeded();
- }
- }
- else if( const auto* e = pat.opt_IfTok() )
- {
- DEBUG(i << " IfTok(" << (e->is_equal ? "==" : "!=") << " ?" << e->tok << ")");
- auto tok = lex.getToken();
- if( (tok == e->tok) == e->is_equal )
- {
- DEBUG("- Succeeded");
- arm_stream.if_succeeded();
- }
- lex.putback( mv$(tok) );
+ BUG(sp, "Unexpected If pattern during final matching - " << pat);
}
else if( const auto* e = pat.opt_ExpectTok() )
{
@@ -2037,7 +1880,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
DEBUG(i << " ExpectTok(" << *e << ") == " << tok);
if( tok != *e )
{
- ERROR(sp, E0000, "Expected token in match arm");
+ ERROR(sp, E0000, "Expected token " << *e << " in match arm, got " << tok);
break;
}
}
@@ -2064,305 +1907,6 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru
return i;
}
}
-#else
-unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& rules, TokenTree input, AST::Module& mod, ParameterMappings& bound_tts)
-{
- TRACE_FUNCTION;
- Span sp;// = input.span();
-
- struct Capture {
- unsigned int binding_idx;
- ::std::vector<unsigned int> iterations;
- unsigned int cap_idx;
- };
- struct ActiveArm {
- unsigned int index;
- ::std::vector<Capture> captures;
- MacroPatternStream stream;
- };
- // - List of active rules (rules that haven't yet failed)
- ::std::vector< ActiveArm > active_arms;
- active_arms.reserve( rules.m_rules.size() );
- for(unsigned int i = 0; i < rules.m_rules.size(); i ++)
- {
- active_arms.push_back( ActiveArm { i, {}, MacroPatternStream(rules.m_rules[i].m_pattern) } );
- }
-
- // - List of captured values
- ::std::vector<InterpolatedFragment> captures;
-
- TTStreamO lex(sp, mv$(input) );
- SET_MODULE(lex, mod);
- while(true)
- {
- DEBUG("--- ---");
- // 1. Get concrete patterns for all active rules (i.e. no If* patterns)
- ::std::vector<SimplePatEnt> arm_pats;
- for(auto& arm : active_arms)
- {
- auto idx = arm.index;
- SimplePatEnt pat;
- // Consume all If* rules
- do
- {
- pat = arm.stream.next();
- TU_IFLET( SimplePatEnt, pat, IfPat, e,
- DEBUG(idx << " IfPat(" << (e.is_equal ? "==" : "!=") << " ?" << e.type << ")");
- if( Macro_TryPatternCap(lex, e.type) == e.is_equal )
- {
- DEBUG("- Succeeded");
- arm.stream.if_succeeded();
- }
- )
- else TU_IFLET( SimplePatEnt, pat, IfTok, e,
- DEBUG(idx << " IfTok(" << (e.is_equal ? "==" : "!=") << " ?" << e.tok << ")");
- auto tok = lex.getToken();
- if( (tok == e.tok) == e.is_equal )
- {
- DEBUG("- Succeeded");
- arm.stream.if_succeeded();
- }
- lex.putback( mv$(tok) );
- )
- else {
- break;
- }
- } while( pat.is_IfPat() || pat.is_IfTok() );
-
- TU_MATCH( SimplePatEnt, (pat), (e),
- (IfPat, BUG(sp, "IfTok unexpected here");),
- (IfTok, BUG(sp, "IfTok unexpected here");),
- (ExpectTok,
- DEBUG(idx << " ExpectTok(" << e << ")");
- ),
- (ExpectPat,
- DEBUG(idx << " ExpectPat(" << e.type << " => $" << e.idx << ")");
- ),
- (End,
- DEBUG(idx << " End");
- )
- )
- arm_pats.push_back( mv$(pat) );
- }
- assert( arm_pats.size() == active_arms.size() );
-
- // 2. Prune imposible arms
- for(unsigned int i = 0, j = 0; i < arm_pats.size(); )
- {
- auto idx = active_arms[i].index;
- const auto& pat = arm_pats[i];
- bool fail = false;
-
- TU_MATCH( SimplePatEnt, (pat), (e),
- (IfPat, BUG(sp, "IfTok unexpected here");),
- (IfTok, BUG(sp, "IfTok unexpected here");),
- (ExpectTok,
- auto tok = lex.getToken();
- DEBUG(j<<"="<<idx << " ExpectTok(" << e << ") == " << tok);
- fail = !(tok == e);
- lex.putback( mv$(tok) );
- ),
- (ExpectPat,
- DEBUG(j<<"="<<idx << " ExpectPat(" << e.type << " => $" << e.idx << ")");
- fail = !Macro_TryPatternCap(lex, e.type);
- ),
- (End,
- DEBUG(j<<"="<<idx << " End");
- fail = !(lex.lookahead(0) == TOK_EOF);
- )
- )
- if( fail ) {
- DEBUG("- Failed arm " << active_arms[i].index);
- arm_pats.erase( arm_pats.begin() + i );
- active_arms.erase( active_arms.begin() + i );
- }
- else {
- i ++;
- }
- j ++;
- }
-
- if( arm_pats.size() == 0 ) {
- auto tok = lex.getToken();
- ERROR(tok.get_pos(), E0000, "No rules expected " << tok);
- }
-
- // 3. If there is a token pattern in the list, take that arm (and any other token arms)
- const SimplePatEnt* tok_pat = nullptr;
- unsigned int ident_pat_idx = arm_pats.size();
- bool has_non_ident_pat = false;
- for( unsigned int i = 0; i < arm_pats.size(); i ++ )
- {
- const auto& pat = arm_pats[i];
- TU_IFLET(SimplePatEnt, pat, ExpectTok, e,
- if( tok_pat ) {
- if( e != tok_pat->as_ExpectTok() )
- ERROR(lex.getPosition(), E0000, "Incompatible macro arms - " << tok_pat->as_ExpectTok() << " vs " << e);
- }
- else {
- tok_pat = &pat;
- }
- )
- else TU_IFLET(SimplePatEnt, pat, ExpectPat, e,
- if( e.type == MacroPatEnt::PAT_IDENT ) {
- ident_pat_idx = i;
- }
- else {
- has_non_ident_pat = true;
- }
- )
- }
-
- if( tok_pat )
- {
- auto tok = lex.getToken();
- const auto& e = tok_pat->as_ExpectTok();
- // NOTE: This should never fail.
- if( tok != e ) {
- ERROR(lex.getPosition(), E0000, "Unexpected " << tok << ", expected " << e);
- }
- }
- else
- {
- if( has_non_ident_pat && ident_pat_idx < arm_pats.size() )
- {
- // For all :ident patterns present, check the next rule.
- // - If this rule would fail, remove the arm.
- bool ident_rule_kept = false;
- for( unsigned int i = 0; i < arm_pats.size(); )
- {
- bool discard = false;
- const auto& pat = arm_pats[i];
- const auto& e = pat.as_ExpectPat();
- if( e.type == MacroPatEnt::PAT_IDENT )
- {
- const auto& next = active_arms[i].stream.peek();
- TU_MATCHA( (next), (ne),
- (IfPat, TODO(sp, "Handle IfPat following a conflicting :ident");),
- (IfTok, TODO(sp, "IfTok following a conflicting :ident");),
- (ExpectTok,
- if( ne.type() != lex.lookahead(1) ) {
- DEBUG("Discard active arm " << i << " due to next token mismatch");
- discard = true;
- }
- else {
- ident_rule_kept = true;
- }
- ),
- (ExpectPat,
- TODO(sp, "Handle ExpectPat following a conflicting :ident");
- ),
- (End, TODO(sp, "Handle End following a conflicting :ident"); )
- )
- }
-
- if( discard ) {
- arm_pats.erase( arm_pats.begin() + i );
- active_arms.erase( active_arms.begin() + i );
- }
- else {
- ++ i;
- }
- }
-
- // If there are any remaining ident rules, erase the non-ident rules.
- if( ident_rule_kept ) {
- // If no rules were discarded, remove the non-ident rules
- for( unsigned int i = 0; i < arm_pats.size(); )
- {
- if( arm_pats[i].as_ExpectPat().type != MacroPatEnt::PAT_IDENT ) {
- arm_pats.erase( arm_pats.begin() + i );
- active_arms.erase( active_arms.begin() + i );
- }
- else {
- ++ i;
- }
- }
- }
- assert(arm_pats.size() > 0);
- assert(arm_pats.size() == active_arms.size());
- }
-
- // 3. Check that all remaining arms are the same pattern.
- const auto& active_pat = arm_pats[0];
- for(unsigned int i = 1; i < arm_pats.size(); i ++)
- {
- if( active_pat.tag() != arm_pats[i].tag() ) {
- ERROR(lex.getPosition(), E0000, "Incompatible macro arms "
- << "- " << active_arms[0].index << " SimplePatEnt::" << active_pat.tag_str()
- << " vs " << active_arms[i].index<< " SimplePatEnt::" << arm_pats[i].tag_str()
- );
- }
- TU_MATCH( SimplePatEnt, (active_pat, arm_pats[i]), (e1, e2),
- (IfPat, BUG(sp, "IfPat unexpected here");),
- (IfTok, BUG(sp, "IfTok unexpected here");),
- (ExpectTok,
- BUG(sp, "ExpectTok unexpected here");
- ),
- (ExpectPat,
- // Can fail, as :expr and :stmt overlap in their trigger set
- if( e1.type != e2.type ) {
- ERROR(lex.getPosition(), E0000, "Incompatible macro arms - mismatched patterns " << e1.type << " and " << e2.type);
- }
- ),
- (End,
- )
- )
- }
-
- // 4. Apply patterns.
- TU_MATCH( SimplePatEnt, (arm_pats[0]), (e),
- (End,
- auto tok = lex.getToken();
- if( tok.type() != TOK_EOF ) {
- ERROR(lex.getPosition(), E0000, "Unexpected " << tok << ", expected TOK_EOF");
- }
- // NOTE: There can be multiple arms active, take the first.
- for(const auto& cap : active_arms[0].captures)
- {
- bound_tts.insert( cap.binding_idx, cap.iterations, mv$(captures[cap.cap_idx]) );
- }
- return active_arms[0].index;
- ),
- (IfPat, BUG(sp, "IfPat unexpected here");),
- (IfTok, BUG(sp, "IfTok unexpected here");),
- (ExpectTok,
- BUG(sp, "ExpectTok should have been handled already");
- ),
- (ExpectPat,
- struct H {
- static bool is_prefix(const ::std::vector<unsigned>& needle, const ::std::vector<unsigned>& haystack) {
- if( needle.size() > haystack.size() ) {
- return false;
- }
- else {
- for(unsigned int i = 0; i < needle.size(); i ++) {
- if(needle[i] != haystack[i])
- return false;
- }
- return true;
- }
- }
- };
-
- auto cap = Macro_HandlePatternCap(lex, e.type);
-
- unsigned int cap_idx = captures.size();
- captures.push_back( mv$(cap) );
- for(unsigned int i = 0; i < active_arms.size(); i ++)
- {
- auto& arm = active_arms[i];
- const auto& pat_e = arm_pats[i].as_ExpectPat();
- arm.captures.push_back( Capture { pat_e.idx, arm.stream.get_loop_iters(), cap_idx } );
- }
- )
- )
- }
-
- // Keep looping - breakout is handled in 'End' above
- }
-}
-#endif
void Macro_InvokeRules_CountSubstUses(ParameterMappings& bound_tts, const ::std::vector<MacroExpansionEnt>& contents)
{
@@ -2438,7 +1982,7 @@ Token MacroExpander::realGetToken()
DEBUG("Crate name hack");
if( m_crate_name != "" )
{
- m_next_token = Token(TOK_STRING, m_crate_name);
+ m_next_token = Token(TOK_STRING, ::std::string(m_crate_name.c_str()));
return Token(TOK_DOUBLE_COLON);
}
break;
diff --git a/src/macro_rules/macro_rules.hpp b/src/macro_rules/macro_rules.hpp
index c04e3548..05b1e065 100644
--- a/src/macro_rules/macro_rules.hpp
+++ b/src/macro_rules/macro_rules.hpp
@@ -18,6 +18,7 @@
#include <set>
class MacroExpander;
+class SimplePatEnt;
TAGGED_UNION(MacroExpansionEnt, Token,
// TODO: have a "raw" stream instead of just tokens
@@ -40,8 +41,9 @@ extern ::std::ostream& operator<<(::std::ostream& os, const MacroExpansionEnt& x
/// Matching pattern entry
struct MacroPatEnt
{
- ::std::string name;
+ RcString name;
unsigned int name_index = 0;
+ // TODO: Include a point span for the token?
Token tok;
::std::vector<MacroPatEnt> subpats;
@@ -60,6 +62,8 @@ struct MacroPatEnt
PAT_BLOCK,
PAT_META,
PAT_ITEM, // :item
+ PAT_VIS,
+ PAT_LIFETIME,
} type;
MacroPatEnt():
@@ -73,7 +77,7 @@ struct MacroPatEnt
{
}
- MacroPatEnt(::std::string name, unsigned int name_index, Type type):
+ MacroPatEnt(RcString name, unsigned int name_index, Type type):
name( mv$(name) ),
name_index( name_index ),
tok(),
@@ -93,21 +97,55 @@ struct MacroPatEnt
friend ::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt::Type& x);
};
+struct SimplePatIfCheck
+{
+ MacroPatEnt::Type ty; // If PAT_TOKEN, token is checked
+ Token tok;
+};
+
+/// Simple pattern entry for macro_rules! arm patterns
+TAGGED_UNION( SimplePatEnt, End,
+ // End of the pattern stream (expects EOF, and terminates the match process)
+ (End, struct{}),
+ (LoopStart, struct{}),
+ (LoopNext, struct{}),
+ (LoopEnd, struct{}),
+ (Jump, struct {
+ size_t jump_target;
+ }),
+ // Expect a specific token, erroring/failing the arm if nt met
+ (ExpectTok, Token),
+ // Expect a pattern match
+ (ExpectPat, struct {
+ MacroPatEnt::Type type;
+ unsigned int idx;
+ }),
+ // Compare the head of the input stream and poke the pattern stream
+ (If, struct {
+ bool is_equal;
+ size_t jump_target;
+ ::std::vector<SimplePatIfCheck> ents;
+ })
+ );
+
+extern::std::ostream& operator<<(::std::ostream& os, const SimplePatEnt& x);
+
/// An expansion arm within a macro_rules! blcok
struct MacroRulesArm
{
/// Names for the parameters
- ::std::vector< ::std::string> m_param_names;
+ ::std::vector<RcString> m_param_names;
/// Patterns
- ::std::vector<MacroPatEnt> m_pattern;
+ ::std::vector<SimplePatEnt> m_pattern;
/// Rule contents
::std::vector<MacroExpansionEnt> m_contents;
+ ~MacroRulesArm();
MacroRulesArm()
{}
- MacroRulesArm(::std::vector<MacroPatEnt> pattern, ::std::vector<MacroExpansionEnt> contents):
+ MacroRulesArm(::std::vector<SimplePatEnt> pattern, ::std::vector<MacroExpansionEnt> contents):
m_pattern( mv$(pattern) ),
m_contents( mv$(contents) )
{}
@@ -126,7 +164,7 @@ public:
/// Crate that defined this macro
/// - Populated on deserialise if not already set
- ::std::string m_source_crate;
+ RcString m_source_crate;
Ident::Hygiene m_hygiene;
@@ -143,4 +181,8 @@ public:
extern ::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, const Span& sp, TokenTree input, AST::Module& mod);
extern MacroRulesPtr Parse_MacroRules(TokenStream& lex);
+extern ::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close, ::std::vector<RcString>& names);
+extern ::std::vector<MacroExpansionEnt> Parse_MacroRules_Cont(TokenStream& lex, enum eTokenType open, enum eTokenType close, const ::std::vector<RcString>& var_names, ::std::map<unsigned int,bool>* var_set_ptr=nullptr);
+extern MacroRulesArm Parse_MacroRules_MakeArm(Span pat_sp, ::std::vector<MacroPatEnt> pattern, ::std::vector<MacroExpansionEnt> contents);
+
#endif // MACROS_HPP_INCLUDED
diff --git a/src/macro_rules/mod.cpp b/src/macro_rules/mod.cpp
index f9754286..2ad325b8 100644
--- a/src/macro_rules/mod.cpp
+++ b/src/macro_rules/mod.cpp
@@ -156,6 +156,17 @@ bool is_token_item(eTokenType tt) {
return false;
}
}
+bool is_token_vis(eTokenType tt) {
+ switch(tt)
+ {
+ case TOK_RWORD_PUB:
+ case TOK_RWORD_CRATE:
+ case TOK_INTERPOLATED_VIS:
+ return true;
+ default:
+ return true; // TODO: Is this true? it can capture just nothing
+ }
+}
MacroRulesPtr::MacroRulesPtr(MacroRules* p):
m_ptr(p)
@@ -177,7 +188,7 @@ MacroRulesPtr::~MacroRulesPtr()
switch(x.type)
{
case MacroPatEnt::PAT_TOKEN: os << "=" << x.tok; break;
- case MacroPatEnt::PAT_LOOP: os << "loop w/ " << x.tok << " [" << x.subpats << "]"; break;
+ case MacroPatEnt::PAT_LOOP: os << "loop" << x.name << " w/ " << x.tok << " [" << x.subpats << "]"; break;
default:
os << "$" << x.name << ":";
switch(x.type)
@@ -194,6 +205,8 @@ MacroRulesPtr::~MacroRulesPtr()
case MacroPatEnt::PAT_BLOCK: os << "block"; break;
case MacroPatEnt::PAT_META: os << "meta"; break;
case MacroPatEnt::PAT_ITEM: os << "item"; break;
+ case MacroPatEnt::PAT_VIS: os << "vis"; break;
+ case MacroPatEnt::PAT_LIFETIME: os << "lifetime"; break;
}
break;
}
@@ -215,6 +228,39 @@ MacroRulesPtr::~MacroRulesPtr()
case MacroPatEnt::PAT_BLOCK: os << "PAT_BLOCK"; break;
case MacroPatEnt::PAT_META: os << "PAT_META"; break;
case MacroPatEnt::PAT_ITEM: os << "PAT_ITEM"; break;
+ case MacroPatEnt::PAT_VIS: os << "PAT_VIS"; break;
+ case MacroPatEnt::PAT_LIFETIME: os << "PAT_LIFETIME"; break;
+ }
+ return os;
+}
+
+::std::ostream& operator<<(::std::ostream& os, const SimplePatEnt& x)
+{
+ TU_MATCH_HDRA( (x), { )
+ TU_ARMA(End, _e) os << "End";
+ TU_ARMA(LoopStart, _e) os << "LoopStart";
+ TU_ARMA(LoopNext, _e) os << "LoopNext";
+ TU_ARMA(LoopEnd, _e) os << "LoopEnd";
+ TU_ARMA(Jump, e) {
+ os << "Jump(->" << e.jump_target << ")";
+ }
+ TU_ARMA(ExpectTok, e) {
+ os << "Expect(" << e << ")";
+ }
+ TU_ARMA(ExpectPat, e) {
+ os << "Expect($" << e.idx << " = " << e.type << ")";
+ }
+ TU_ARMA(If, e) {
+ os << "If(" << (e.is_equal ? "=" : "!=") << "[";
+ for(const auto& p : e.ents) {
+ if(p.ty == MacroPatEnt::PAT_TOKEN)
+ os << p.tok;
+ else
+ os << p.ty;
+ os << ", ";
+ }
+ os << "] ->" << e.jump_target << ")";
+ }
}
return os;
}
@@ -243,4 +289,7 @@ MacroRulesPtr::~MacroRulesPtr()
MacroRules::~MacroRules()
{
}
+MacroRulesArm::~MacroRulesArm()
+{
+}
diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp
index 0cc7b3a8..6a476ef1 100644
--- a/src/macro_rules/parse.cpp
+++ b/src/macro_rules/parse.cpp
@@ -12,17 +12,25 @@
#include "pattern_checks.hpp"
MacroRulesPtr Parse_MacroRules(TokenStream& lex);
+namespace {
+ ::std::vector<SimplePatEnt> macro_pattern_to_simple(const Span& sp, const ::std::vector<MacroPatEnt>& pattern);
+}
/// A rule within a macro_rules! blcok
class MacroRule
{
public:
::std::vector<MacroPatEnt> m_pattern;
+ Span m_pat_span;
::std::vector<MacroExpansionEnt> m_contents;
+
+ MacroRule() {}
+ MacroRule(MacroRule&&) = default;
+ MacroRule(const MacroRule&) = delete;
};
/// Parse the pattern of a macro_rules! arm
-::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close, ::std::vector< ::std::string>& names)
+::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close, ::std::vector<RcString>& names)
{
TRACE_FUNCTION;
Token tok;
@@ -32,6 +40,7 @@ public:
int depth = 0;
while( GET_TOK(tok, lex) != close || depth > 0 )
{
+ DEBUG("tok = " << tok);
if( tok.type() == open )
{
depth ++;
@@ -49,13 +58,14 @@ public:
switch( GET_TOK(tok, lex) )
{
// TODO: Allow any reserved word
- case TOK_RWORD_TYPE:
- case TOK_RWORD_PUB:
+ default:
+ if( !(TOK_RWORD_PUB <= tok.type() && tok.type() <= TOK_RWORD_UNSIZED) )
+ throw ParseError::Unexpected(lex, tok);
case TOK_IDENT: {
- ::std::string name = tok.type() == TOK_IDENT ? mv$(tok.str()) : FMT(tok);
+ auto name = tok.type() == TOK_IDENT ? tok.istr() : RcString::new_interned(FMT(tok));
GET_CHECK_TOK(tok, lex, TOK_COLON);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- ::std::string type = mv$(tok.str());
+ RcString type = tok.istr();
unsigned int idx = ::std::find( names.begin(), names.end(), name ) - names.begin();
if( idx == names.size() )
@@ -83,6 +93,10 @@ public:
ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_BLOCK) );
else if( type == "item" )
ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_ITEM) );
+ else if( /*TARGETVER_1_29 && */ type == "vis" ) // TODO: Should this be selective?
+ ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_VIS) );
+ else if( /*TARGETVER_1_29 && */ type == "lifetime" ) // TODO: Should this be selective?
+ ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_LIFETIME) );
else
ERROR(lex.point_span(), E0000, "Unknown fragment type '" << type << "'");
break; }
@@ -111,8 +125,6 @@ public:
throw ParseError::Unexpected(lex, tok);
}
break; }
- default:
- throw ParseError::Unexpected(lex, tok);
}
break;
case TOK_EOF:
@@ -130,8 +142,8 @@ public:
::std::vector<MacroExpansionEnt> Parse_MacroRules_Cont(
TokenStream& lex,
enum eTokenType open, enum eTokenType close,
- const ::std::vector< ::std::string>& var_names,
- ::std::map<unsigned int,bool>* var_set_ptr=nullptr
+ const ::std::vector<RcString>& var_names,
+ ::std::map<unsigned int,bool>* var_set_ptr/*=nullptr*/
)
{
TRACE_FUNCTION;
@@ -200,13 +212,16 @@ public:
default:
throw ParseError::Unexpected(lex, tok);
}
-
+ }
+ else if( tok.type() == TOK_RWORD_CRATE )
+ {
+ ret.push_back( MacroExpansionEnt( (1<<30) | 0 ) );
}
//else if( tok.type() == TOK_IDENT || tok_is_rword(tok.type()) )
- else if( tok.type() == TOK_IDENT || tok.type() == TOK_RWORD_TYPE || tok.type() == TOK_RWORD_PUB )
+ else if( tok.type() == TOK_IDENT || tok.type() >= TOK_RWORD_PUB )
{
// Look up the named parameter in the list of param names for this arm
- auto name = tok.type() == TOK_IDENT ? tok.str() : FMT(tok);
+ auto name = tok.type() == TOK_IDENT ? tok.istr() : RcString::new_interned(FMT(tok));
unsigned int idx = ::std::find(var_names.begin(), var_names.end(), name) - var_names.begin();
if( idx == var_names.size() ) {
// TODO: `error-chain`'s quick_error macro has an arm which refers to an undefined metavar.
@@ -222,10 +237,6 @@ public:
}
ret.push_back( MacroExpansionEnt(idx) );
}
- else if( tok.type() == TOK_RWORD_CRATE )
- {
- ret.push_back( MacroExpansionEnt( (1<<30) | 0 ) );
- }
else
{
throw ParseError::Unexpected(lex, tok);
@@ -259,8 +270,12 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex)
throw ParseError::Unexpected(lex, tok);
}
// - Pattern entries
- ::std::vector< ::std::string> names;
- rule.m_pattern = Parse_MacroRules_Pat(lex, tok.type(), close, names);
+ ::std::vector<RcString> names;
+ {
+ auto ps = lex.start_span();
+ rule.m_pattern = Parse_MacroRules_Pat(lex, tok.type(), close, names);
+ rule.m_pat_span = lex.end_span(ps);
+ }
GET_CHECK_TOK(tok, lex, TOK_FATARROW);
@@ -279,164 +294,9 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex)
return rule;
}
-bool patterns_are_same(const Span& sp, const MacroPatEnt& left, const MacroPatEnt& right)
-{
- if( left.type > right.type )
- return patterns_are_same(sp, right, left);
-
- //if( left.name != right.name ) {
- // TODO(sp, "Handle different binding names " << left << " != " << right);
- //}
-
- // NOTE: left.type <= right.type
- switch(right.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- assert( left.type == MacroPatEnt::PAT_TOKEN );
- return right.tok == left.tok;
- case MacroPatEnt::PAT_LOOP:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- // - Check for compatibility, but these two don't match
- if( patterns_are_same(sp, left, right.subpats.at(0)) == true )
- ERROR(sp, E0000, "Incompatible use of loop with matching non-loop");
- return false;
- case MacroPatEnt::PAT_LOOP:
- TODO(sp, "patterns_are_same - PAT_LOOP");
- default:
- assert( !"" );
- }
-
- case MacroPatEnt::PAT_TT:
- if( left.type == right.type )
- return true;
- ERROR(sp, E0000, "Incompatible macro fragments - " << right << " used with " << left);
- break;
-
- case MacroPatEnt::PAT_PAT:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- // - If this token is a valid pattern token, error
- if( is_token_pat(left.tok.type()) )
- ERROR(sp, E0000, "Incompatible macro fragments - " << right << " used with " << left);
- return false;
- case MacroPatEnt::PAT_PAT:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments - " << right << " used with " << left);
- }
- break;
- // `:ident` - Compatible with just other tokens
- case MacroPatEnt::PAT_IDENT:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( left.tok.type() == TOK_IDENT )
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- return false;
- case MacroPatEnt::PAT_IDENT:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- case MacroPatEnt::PAT_PATH:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( is_token_path(left.tok.type()) )
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- return false;
- case MacroPatEnt::PAT_PATH:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- case MacroPatEnt::PAT_TYPE:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( is_token_type(left.tok.type()) )
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- return false;
- case MacroPatEnt::PAT_TYPE:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- case MacroPatEnt::PAT_EXPR:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( is_token_expr(left.tok.type()) )
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- return false;
- // TODO: Allow a loop starting with an expr?
- // - Consume, add split based on loop condition or next arm
- // - Possible problem with binding levels.
- case MacroPatEnt::PAT_EXPR:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- case MacroPatEnt::PAT_STMT:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( is_token_stmt(left.tok.type()) )
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- return false;
- case MacroPatEnt::PAT_STMT:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- // Block - Expects '{' - Compatible with everything but a literal '{'
- case MacroPatEnt::PAT_BLOCK:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( left.tok.type() == TOK_BRACE_OPEN )
- ERROR(sp, E0000, "Incompatible macro fragments");
- return false;
- case MacroPatEnt::PAT_BLOCK:
- return true;
- default:
- return false;
- }
- // Matches meta/attribute fragments.
- case MacroPatEnt::PAT_META:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( left.tok.type() == TOK_IDENT )
- ERROR(sp, E0000, "Incompatible macro fragments");
- return false;
- case MacroPatEnt::PAT_META:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- // Matches items
- case MacroPatEnt::PAT_ITEM:
- switch(left.type)
- {
- case MacroPatEnt::PAT_TOKEN:
- if( is_token_item(left.tok.type()) )
- ERROR(sp, E0000, "Incompatible macro fragments");
- return false;
- case MacroPatEnt::PAT_ITEM:
- return true;
- default:
- ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left);
- }
- }
- throw "";
-}
-
// TODO: Also count the number of times each variable is used?
-void enumerate_names(const ::std::vector<MacroPatEnt>& pats, ::std::vector< ::std::string>& names) {
+void enumerate_names(const ::std::vector<MacroPatEnt>& pats, ::std::vector<RcString>& names)
+{
for( const auto& pat : pats )
{
if( pat.type == MacroPatEnt::PAT_LOOP ) {
@@ -452,6 +312,15 @@ void enumerate_names(const ::std::vector<MacroPatEnt>& pats, ::std::vector< ::st
}
}
+MacroRulesArm Parse_MacroRules_MakeArm(Span pat_sp, ::std::vector<MacroPatEnt> pattern, ::std::vector<MacroExpansionEnt> contents)
+{
+ // - Convert the rule into an instruction stream
+ auto rule_sequence = macro_pattern_to_simple(pat_sp, pattern);
+ auto arm = MacroRulesArm( mv$(rule_sequence), mv$(contents) );
+ enumerate_names(pattern, arm.m_param_names);
+ return arm;
+}
+
/// Parse an entire macro_rules! block into a format that exec.cpp can use
MacroRulesPtr Parse_MacroRules(TokenStream& lex)
{
@@ -478,11 +347,7 @@ MacroRulesPtr Parse_MacroRules(TokenStream& lex)
// Re-parse the patterns into a unified form
for(auto& rule : rules)
{
- MacroRulesArm arm = MacroRulesArm( mv$(rule.m_pattern), mv$(rule.m_contents) );
-
- enumerate_names(arm.m_pattern, arm.m_param_names);
-
- rule_arms.push_back( mv$(arm) );
+ rule_arms.push_back( Parse_MacroRules_MakeArm(rule.m_pat_span, mv$(rule.m_pattern), mv$(rule.m_contents)) );
}
auto rv = new MacroRules( );
@@ -491,3 +356,287 @@ MacroRulesPtr Parse_MacroRules(TokenStream& lex)
return MacroRulesPtr(rv);
}
+
+namespace {
+
+ struct ExpTok {
+ MacroPatEnt::Type ty;
+ const Token* tok;
+ ExpTok(MacroPatEnt::Type ty, const Token* tok): ty(ty), tok(tok) {}
+ bool operator==(const ExpTok& t) const { return this->ty == t.ty && *this->tok == *t.tok; }
+ };
+ ::std::ostream& operator<<(::std::ostream& os, const ExpTok& t) {
+ os << "ExpTok(" << t.ty << " " << *t.tok << ")";
+ return os;
+ }
+
+ // Yields all possible ExpectTok/ExpectPat entries from a pattern position
+ // Returns `true` if there's no fall-through
+ bool macro_pattern_get_head_set_inner(::std::vector<ExpTok>& rv, const ::std::vector<MacroPatEnt>& pattern, size_t direct_pos, size_t indirect_ofs)
+ {
+ for(size_t idx = direct_pos; idx < pattern.size(); idx ++)
+ {
+ const auto& ent = pattern[idx];
+ switch(ent.type)
+ {
+ case MacroPatEnt::PAT_LOOP:
+ if( macro_pattern_get_head_set_inner(rv, ent.subpats, 0, indirect_ofs) )
+ {
+ // + loops have to iterate at least once, so if the set is closed by the sub-patterns, close us too
+ if(ent.name == "+")
+ {
+ return true;
+ }
+ // for * and ? loops, they can be skipped entirely.
+ // - No separator, this is for the skip case
+ }
+ else
+ {
+ // If the inner pattern didn't close the option set, then the next token can be the separator
+ if( ent.tok != TOK_NULL )
+ {
+ // If indirect is non-zero, decrement without doing anything
+ if( indirect_ofs > 0 )
+ {
+ indirect_ofs --;
+ }
+ else
+ {
+ rv.push_back(ExpTok(MacroPatEnt::PAT_TOKEN, &ent.tok));
+ }
+ }
+ }
+ break;
+ default:
+ // If indirect is non-zero, decrement
+ if( indirect_ofs > 0 )
+ {
+ indirect_ofs --;
+ }
+ else
+ {
+ rv.push_back( ExpTok(ent.type, &ent.tok) );
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+ }
+ ::std::vector<ExpTok> macro_pattern_get_head_set(const ::std::vector<MacroPatEnt>& pattern, size_t direct_pos, size_t indirect_ofs)
+ {
+ ::std::vector<ExpTok> rv;
+ macro_pattern_get_head_set_inner(rv, pattern, direct_pos, indirect_ofs);
+ return rv;
+ }
+
+ void macro_pattern_to_simple_inner(const Span& sp, ::std::vector<SimplePatEnt>& rv, const ::std::vector<MacroPatEnt>& pattern)
+ {
+ size_t level_start = rv.size();
+ TRACE_FUNCTION_FR("[" << pattern << "]", "[" << FMT_CB(ss, for(auto it = rv.begin()+level_start; it != rv.end(); ++it) { ss << *it << ", "; }) << "]");
+ auto push = [&rv](SimplePatEnt spe) {
+ DEBUG("[macro_pattern_to_simple_inner] rv[" << rv.size() << "] = " << spe);
+ rv.push_back( ::std::move(spe) );
+ };
+ auto push_ifv = [&push](bool is_equal, ::std::vector<SimplePatIfCheck> ents, size_t tgt) {
+ push(SimplePatEnt::make_If({ is_equal, tgt, mv$(ents) }));
+ };
+ auto push_if = [&push_ifv](bool is_equal, MacroPatEnt::Type ty, const Token& tok, size_t tgt) {
+ push_ifv(is_equal, make_vec1(SimplePatIfCheck { ty, tok }), tgt);
+ };
+ for(size_t idx = 0; idx < pattern.size(); idx ++)
+ {
+ const auto& ent = pattern[idx];
+ DEBUG("[" << idx << "] ent = " << ent);
+ switch(ent.type)
+ {
+ case MacroPatEnt::PAT_LOOP: {
+ auto entry_pats = macro_pattern_get_head_set(ent.subpats, 0, 0);
+ DEBUG("Entry = [" << entry_pats << "]");
+ ASSERT_BUG(sp, entry_pats.size() > 0, "No entry conditions extracted from sub-pattern [" << ent.subpats << "]");
+ auto skip_pats = macro_pattern_get_head_set(pattern, idx+1, 0);
+ DEBUG("Skip = [" << skip_pats << "]");
+
+ // - Duplicates need special handling (build up a subseqent set)
+ for(const auto& ee : entry_pats)
+ {
+ if( ::std::find(skip_pats.begin(), skip_pats.end(), ee) != skip_pats.end() )
+ {
+ TODO(sp, "Entry and skip patterns share an entry, ambigious - " << ee);
+ }
+ }
+
+ // TODO: Combine the two cases below into one
+
+ // If the loop is a $()+ loop, then just recurse into it
+ if( ent.name == "+" )
+ {
+ push( SimplePatEnt::make_LoopStart({}) );
+ size_t start = rv.size();
+ macro_pattern_to_simple_inner(sp, rv, ent.subpats);
+ push( SimplePatEnt::make_LoopNext({}) );
+ size_t rewrite_start = rv.size();
+ if( ent.tok != TOK_NULL )
+ {
+ // If the loop terminator is also valid after the loop
+ // - Terminate the loop if the next two tokens aren't `<SEP>` folled by any of `<ENTRY>`
+ if( ::std::find(skip_pats.begin(), skip_pats.end(), ExpTok(MacroPatEnt::PAT_TOKEN, &ent.tok)) != skip_pats.end() ) {
+ size_t expect_and_jump_pos = rv.size() + entry_pats.size() + 1;
+ for(const auto& p : entry_pats)
+ {
+ auto v = ::make_vec2<SimplePatIfCheck>(
+ { MacroPatEnt::PAT_TOKEN, ent.tok},
+ { p.ty, *p.tok }
+ );
+ // Jump if equal
+ push_ifv(true, mv$(v), expect_and_jump_pos);
+ }
+ // If any of the above succeeded, they'll jump past this jump
+ push( SimplePatEnt::make_Jump({ ~0u }) );
+ }
+ else {
+ size_t end = rv.size() + 3;
+ push_if( false, MacroPatEnt::PAT_TOKEN, ent.tok, end );
+ }
+ push( SimplePatEnt::make_ExpectTok(ent.tok) );
+ push( SimplePatEnt::make_Jump({ start }) );
+ }
+ else
+ {
+ // TODO: What if there's a collision at this level?
+ for(const auto& p : entry_pats)
+ {
+ push_if(true, p.ty, *p.tok, start);
+ }
+ }
+
+ size_t post_loop = rv.size();
+ for(size_t i = rewrite_start; i < post_loop; i++)
+ {
+ if( auto* pe = rv[i].opt_If() ) {
+ if(pe->jump_target == ~0u) {
+ pe->jump_target = post_loop;
+ }
+ }
+ if( auto* pe = rv[i].opt_Jump() ) {
+ if(pe->jump_target == ~0u) {
+ pe->jump_target = post_loop;
+ }
+ }
+ }
+ push( SimplePatEnt::make_LoopEnd({}) );
+ }
+ else
+ {
+ push( SimplePatEnt::make_LoopStart({}) );
+
+ // Options:
+ // - Enter the loop (if the next token is one of the head set of the loop)
+ // - Skip the loop (the next token is the head set of the subsequent entries)
+ size_t rewrite_start = rv.size();
+ if( ent.name != "+" )
+ {
+ if( entry_pats.size() == 1 )
+ {
+ // If not the entry pattern, skip.
+ push_if(false, entry_pats.front().ty, *entry_pats.front().tok, ~0u);
+ }
+ else if( skip_pats.empty() )
+ {
+ // No skip patterns, try all entry patterns
+ size_t start = rv.size() + entry_pats.size() + 1;
+ for(const auto& p : entry_pats)
+ {
+ push_if(true, p.ty, *p.tok, start);
+ }
+ push(SimplePatEnt::make_Jump({ ~0u }));
+ }
+ else
+ {
+ for(const auto& p : skip_pats)
+ {
+ push_if(true, p.ty, *p.tok, ~0u);
+ }
+ }
+ }
+
+ macro_pattern_to_simple_inner(sp, rv, ent.subpats);
+ push( SimplePatEnt::make_LoopNext({}) );
+
+ if( ent.name != "?" )
+ {
+ if( ent.tok != TOK_NULL )
+ {
+ // If the joiner is also valid after the loop, handle by also checking the entry conditions
+ if( ::std::find(skip_pats.begin(), skip_pats.end(), ExpTok(MacroPatEnt::PAT_TOKEN, &ent.tok)) != skip_pats.end() ) {
+ // Try all re-loop (joiner + entry) patterns, if any fail then jump to the end.
+ for(const auto& p : entry_pats) {
+ auto v = ::make_vec2<SimplePatIfCheck>(
+ { MacroPatEnt::PAT_TOKEN, ent.tok},
+ { p.ty, *p.tok }
+ );
+ push_ifv(false, mv$(v), ~0u);
+ }
+ }
+ else {
+ // If not the joiner, jump to the end
+ push_if(false, MacroPatEnt::PAT_TOKEN, ent.tok, ~0u);
+ }
+ push( SimplePatEnt::make_ExpectTok(ent.tok) );
+ }
+ // Jump back to the entry check.
+ push(SimplePatEnt::make_Jump({ rewrite_start }));
+ }
+ else
+ {
+ ASSERT_BUG(sp, ent.tok == TOK_NULL, "$()? with a separator isn't valid");
+ }
+ size_t post_loop = rv.size();
+ for(size_t i = rewrite_start; i < post_loop; i++)
+ {
+ if( auto* pe = rv[i].opt_If() ) {
+ if(pe->jump_target == ~0u) {
+ pe->jump_target = post_loop;
+ }
+ }
+ if( auto* pe = rv[i].opt_Jump() ) {
+ if(pe->jump_target == ~0u) {
+ pe->jump_target = post_loop;
+ }
+ }
+ }
+ push( SimplePatEnt::make_LoopEnd({}) );
+ }
+ } break;
+ case MacroPatEnt::PAT_TOKEN:
+ push( SimplePatEnt::make_ExpectTok(ent.tok) );
+ break;
+ default:
+ push( SimplePatEnt::make_ExpectPat({ ent.type, ent.name_index }) );
+ break;
+ }
+ }
+
+ for(size_t i = level_start; i < rv.size(); i ++)
+ {
+ TU_MATCH_HDRA( (rv[i]), { )
+ default:
+ // Ignore
+ TU_ARMA(If, e) {
+ ASSERT_BUG(sp, e.jump_target < rv.size(), "If target out of bounds, " << e.jump_target << " >= " << rv.size());
+ }
+ TU_ARMA(Jump, e) {
+ ASSERT_BUG(sp, e.jump_target < rv.size(), "Jump target out of bounds, " << e.jump_target << " >= " << rv.size());
+ }
+ }
+ }
+ }
+
+ ::std::vector<SimplePatEnt> macro_pattern_to_simple(const Span& sp, const ::std::vector<MacroPatEnt>& pattern)
+ {
+ ::std::vector<SimplePatEnt> rv;
+ TRACE_FUNCTION_FR(pattern, rv);
+ macro_pattern_to_simple_inner(sp, rv, pattern);
+ return rv;
+ }
+}
diff --git a/src/macro_rules/pattern_checks.hpp b/src/macro_rules/pattern_checks.hpp
index 4ebbe915..6ce15050 100644
--- a/src/macro_rules/pattern_checks.hpp
+++ b/src/macro_rules/pattern_checks.hpp
@@ -13,3 +13,4 @@ extern bool is_token_type(eTokenType tt);
extern bool is_token_expr(eTokenType tt);
extern bool is_token_stmt(eTokenType tt);
extern bool is_token_item(eTokenType tt);
+extern bool is_token_vis(eTokenType tt);
diff --git a/src/main.cpp b/src/main.cpp
index a50fe095..d63d4041 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -34,6 +34,8 @@ bool g_debug_enabled = true;
::std::string g_cur_phase;
::std::set< ::std::string> g_debug_disable_map;
+TargetVersion gTargetVersion = TargetVersion::Rustc1_29;
+
void init_debug_list()
{
g_debug_disable_map.insert( "Target Load" );
@@ -51,6 +53,7 @@ void init_debug_list()
g_debug_disable_map.insert( "Resolve Type Aliases" );
g_debug_disable_map.insert( "Resolve Bind" );
+ g_debug_disable_map.insert( "Resolve UFCS Outer" );
g_debug_disable_map.insert( "Resolve UFCS paths" );
g_debug_disable_map.insert( "Resolve HIR Markings" );
g_debug_disable_map.insert( "Constant Evaluate" );
@@ -79,6 +82,7 @@ void init_debug_list()
g_debug_disable_map.insert( "HIR Serialise" );
g_debug_disable_map.insert( "Trans Enumerate" );
+ g_debug_disable_map.insert( "Trans Auto Impls" );
g_debug_disable_map.insert( "Trans Monomorph" );
g_debug_disable_map.insert( "MIR Optimise Inline" );
g_debug_disable_map.insert( "Trans Codegen" );
@@ -96,7 +100,6 @@ void init_debug_list()
{
s = ::std::string { debug_string, end };
debug_string = end + 1;
- g_debug_disable_map.erase( s );
}
else
{
@@ -239,6 +242,8 @@ int main(int argc, char *argv[])
Cfg_SetFlag("test");
}
+ Expand_Init();
+
try
{
// Parse the crate into AST
@@ -247,6 +252,7 @@ int main(int argc, char *argv[])
});
crate.m_test_harness = params.test_harness;
crate.m_crate_name_suffix = params.crate_name_suffix;
+ //crate.m_crate_name = params.crate_name;
if( params.last_stage == ProgramParams::STAGE_PARSE ) {
return 0;
@@ -263,6 +269,10 @@ int main(int argc, char *argv[])
crate.load_externs();
});
+ if( params.crate_name != "" ) {
+ crate.m_crate_name = params.crate_name;
+ }
+
// Iterate all items in the AST, applying syntax extensions
CompilePhaseV("Expand", [&]() {
Expand(crate);
@@ -331,7 +341,7 @@ int main(int argc, char *argv[])
switch( crate.m_crate_type )
{
case ::AST::Crate::Type::RustLib:
- params.outfile = FMT(params.output_dir << "lib" << crate.m_crate_name << ".hir");
+ params.outfile = FMT(params.output_dir << "lib" << crate.m_crate_name << ".rlib");
break;
case ::AST::Crate::Type::Executable:
params.outfile = FMT(params.output_dir << crate.m_crate_name);
@@ -363,9 +373,9 @@ int main(int argc, char *argv[])
if( crate.m_crate_type == ::AST::Crate::Type::Executable || params.test_harness || crate.m_crate_type == ::AST::Crate::Type::ProcMacro )
{
bool allocator_crate_loaded = false;
- ::std::string alloc_crate_name;
+ RcString alloc_crate_name;
bool panic_runtime_loaded = false;
- ::std::string panic_crate_name;
+ RcString panic_crate_name;
bool panic_runtime_needed = false;
for(const auto& ec : crate.m_extern_crates)
{
@@ -411,17 +421,15 @@ int main(int argc, char *argv[])
}
});
+ /// Emit the dependency files
if( params.emit_depfile != "" )
{
- ::std::ofstream of { params.emit_depfile };
- of << params.outfile << ":";
// - Iterate all loaded files for modules
- struct H {
- ::std::ofstream& of;
- H(::std::ofstream& of): of(of) {}
+ struct PathEnumerator {
+ ::std::vector<::std::string> out;
void visit_module(::AST::Module& mod) {
if( mod.m_file_info.path != "!" && mod.m_file_info.path.back() != '/' ) {
- of << " " << mod.m_file_info.path;
+ out.push_back( mod.m_file_info.path );
}
// TODO: Should we check anon modules?
//for(auto& amod : mod.anon_mods()) {
@@ -434,7 +442,19 @@ int main(int argc, char *argv[])
}
}
};
- H(of).visit_module(crate.m_root_module);
+ PathEnumerator pe;
+ pe.visit_module(crate.m_root_module);
+
+ ::std::ofstream of { params.emit_depfile };
+ // TODO: Escape spaces and colons in these paths
+ of << params.outfile << ": " << params.infile;
+ for(const auto& mod_path : pe.out)
+ {
+ of << " " << mod_path;
+ }
+ of << ::std::endl;
+
+ of << params.outfile << ":";
// - Iterate all loaded crates files
for(const auto& ec : crate.m_extern_crates)
{
@@ -476,6 +496,13 @@ int main(int argc, char *argv[])
});
// Deallocate the original crate
crate = ::AST::Crate();
+ if( params.debug.dump_hir )
+ {
+ CompilePhaseV("Dump HIR", [&]() {
+ ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
+ HIR_Dump( os, *hir_crate );
+ });
+ }
// Replace type aliases (`type`) into the actual type
// - Also inserts defaults in trait impls
@@ -490,6 +517,16 @@ int main(int argc, char *argv[])
CompilePhaseV("Resolve HIR Markings", [&]() {
ConvertHIR_Markings(*hir_crate);
});
+ // Determine what trait to use for <T>::Foo in outer scope
+ CompilePhaseV("Resolve UFCS Outer", [&]() {
+ ConvertHIR_ResolveUFCS_Outer(*hir_crate);
+ });
+ if( params.debug.dump_hir ) {
+ CompilePhaseV("Dump HIR", [&]() {
+ ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
+ HIR_Dump( os, *hir_crate );
+ });
+ }
// Determine what trait to use for <T>::Foo (and does some associated type expansion)
CompilePhaseV("Resolve UFCS paths", [&]() {
ConvertHIR_ResolveUFCS(*hir_crate);
@@ -651,6 +688,8 @@ int main(int argc, char *argv[])
crate_type = ::AST::Crate::Type::Executable;
}
+ // TODO: For 1.29 executables/dylibs, add oom/panic shims
+
// Enumerate items to be passed to codegen
TransList items = CompilePhase<TransList>("Trans Enumerate", [&]() {
switch( crate_type )
@@ -671,6 +710,11 @@ int main(int argc, char *argv[])
}
throw ::std::runtime_error("Invalid crate_type value");
});
+ // - Generate automatic impls (mainly Clone for 1.29)
+ CompilePhaseV("Trans Auto Impls", [&]() {
+ // TODO: Drop glue generation?
+ Trans_AutoImpls(*hir_crate, items);
+ });
// - Generate monomorphised versions of all functions
CompilePhaseV("Trans Monomorph", [&]() { Trans_Monomorphise_List(*hir_crate, items); });
// - Do post-monomorph inlining
@@ -683,50 +727,43 @@ int main(int argc, char *argv[])
case ::AST::Crate::Type::Unknown:
throw "";
case ::AST::Crate::Type::RustLib:
- // Generate a loadable .o
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, /*is_executable=*/false); });
// Save a loadable HIR dump
- CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); });
- // TODO: Link metatdata and object into a .rlib
- //Trans_Link(params.outfile, params.outfile + ".hir", params.outfile + ".o", CodegenOutput::StaticLibrary);
+ CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile + ".hir", *hir_crate); });
+ // Generate a loadable .o
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, CodegenOutput::StaticLibrary, trans_opt, *hir_crate, items, params.outfile + ".hir"); });
break;
case ::AST::Crate::Type::RustDylib:
- // Generate a .so
- //CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".so", trans_opt, *hir_crate, items, CodegenOutput::DynamicLibrary); });
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, /*is_executable=*/false); });
// Save a loadable HIR dump
- CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); });
- // TODO: Add the metadata to the .so as a non-loadable segment
- //Trans_Link(params.outfile, params.outfile + ".hir", params.outfile + ".o", CodegenOutput::DynamicLibrary);
+ CompilePhaseV("HIR Serialise", [&]() {
+ //auto saved_ext_crates = ::std::move(hir_crate->m_ext_crates);
+ HIR_Serialise(params.outfile + ".hir", *hir_crate);
+ //hir_crate->m_ext_crates = ::std::move(saved_ext_crates);
+ });
+ // Generate a .so
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, CodegenOutput::DynamicLibrary, trans_opt, *hir_crate, items, params.outfile + ".hir"); });
break;
case ::AST::Crate::Type::CDylib:
// Generate a .so/.dll
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, trans_opt, *hir_crate, items, /*is_executable=*/false); });
- // - No metadata file
- //Trans_Link(params.outfile, "", params.outfile + ".o", CodegenOutput::DynamicLibrary);
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, CodegenOutput::DynamicLibrary, trans_opt, *hir_crate, items, ""); });
break;
case ::AST::Crate::Type::ProcMacro: {
// Needs: An executable (the actual macro handler), metadata (for `extern crate foo;`)
- // 1. Generate code for the .o file
- // TODO: Is the .o actually needed for proc macros?
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, /*is_executable=*/false); });
-
- // 2. Generate code for the plugin itself
- TransList items2 = CompilePhase<TransList>("Trans Enumerate", [&]() { return Trans_Enumerate_Main(*hir_crate); });
- CompilePhaseV("Trans Monomorph", [&]() { Trans_Monomorphise_List(*hir_crate, items2); });
- CompilePhaseV("MIR Optimise Inline", [&]() { MIR_OptimiseCrate_Inlining(*hir_crate, items2); });
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + "-plugin", trans_opt, *hir_crate, items2, /*is_executable=*/true); });
-
+ // 1. Generate code for the plugin itself
+ TransList items = CompilePhase<TransList>("Trans Enumerate PM", [&]() { return Trans_Enumerate_Main(*hir_crate); });
+ CompilePhaseV("Trans Auto Impls PM", [&]() { Trans_AutoImpls(*hir_crate, items); });
+ CompilePhaseV("Trans Monomorph PM", [&]() { Trans_Monomorphise_List(*hir_crate, items); });
+ CompilePhaseV("MIR Optimise Inline PM", [&]() { MIR_OptimiseCrate_Inlining(*hir_crate, items); });
// - Save a very basic HIR dump, making sure that there's no lang items in it (e.g. `mrustc-main`)
- hir_crate->m_lang_items.clear();
- CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); });
- //Trans_Link(params.outfile, params.outfile + ".hir", params.outfile + ".o", CodegenOutput::StaticLibrary);
- //Trans_Link(params.outfile+"-plugin", "", params.outfile + "-plugin.o", CodegenOutput::StaticLibrary);
+ CompilePhaseV("HIR Serialise", [&]() {
+ auto saved_lang_items = ::std::move(hir_crate->m_lang_items); hir_crate->m_lang_items.clear();
+ HIR_Serialise(params.outfile + ".hir", *hir_crate);
+ hir_crate->m_lang_items = ::std::move(saved_lang_items);
+ });
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, CodegenOutput::Executable, trans_opt, *hir_crate, items, params.outfile + ".hir"); });
break; }
case ::AST::Crate::Type::Executable:
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, trans_opt, *hir_crate, items, /*is_executable=*/true); });
- //Trans_Link(params.outfile, "", params.outfile + ".o", CodegenOutput::Executable);
+ CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, CodegenOutput::Executable, trans_opt, *hir_crate, items, ""); });
break;
}
}
@@ -961,7 +998,14 @@ ProgramParams::ProgramParams(int argc, char *argv[])
exit(0);
}
else if( strcmp(arg, "--version" ) == 0 ) {
- ::std::cout << "MRustC " << Version_GetString() << ::std::endl;
+ const char* rustc_target = "unknown";
+ switch(gTargetVersion)
+ {
+ case TargetVersion::Rustc1_19: rustc_target = "1.19"; break;
+ case TargetVersion::Rustc1_29: rustc_target = "1.29"; break;
+ }
+ // NOTE: Starts the version with "rustc 1.29.100" so build scripts don't get confused
+ ::std::cout << "rustc " << rustc_target << ".100 (mrustc " << Version_GetString() << ")" << ::std::endl;
::std::cout << "- Build time: " << gsVersion_BuildTime << ::std::endl;
::std::cout << "- Commit: " << gsVersion_GitHash << (gbVersion_GitDirty ? " (dirty tree)" : "") << ::std::endl;
exit(0);
@@ -1024,6 +1068,9 @@ ProgramParams::ProgramParams(int argc, char *argv[])
if( strcmp(type_str, "rlib") == 0 ) {
this->crate_type = ::AST::Crate::Type::RustLib;
}
+ else if( strcmp(type_str, "dylib") == 0 ) {
+ this->crate_type = ::AST::Crate::Type::RustDylib;
+ }
else if( strcmp(type_str, "bin") == 0 ) {
this->crate_type = ::AST::Crate::Type::Executable;
}
@@ -1094,6 +1141,19 @@ ProgramParams::ProgramParams(int argc, char *argv[])
}
}
+
+ if( const auto* a = getenv("MRUSTC_TARGET_VER") )
+ {
+ if( strcmp(a, "1.19") == 0 ) {
+ gTargetVersion = TargetVersion::Rustc1_19;
+ }
+ else if( strcmp(a, "1.29") == 0 ) {
+ gTargetVersion = TargetVersion::Rustc1_29;
+ }
+ else {
+ }
+ }
+
if( const auto* a = getenv("MRUSTC_DUMP") )
{
while( a[0] )
diff --git a/src/mir/check.cpp b/src/mir/check.cpp
index b2d86590..d159c85f 100644
--- a/src/mir/check.cpp
+++ b/src/mir/check.cpp
@@ -19,7 +19,6 @@ namespace {
if( const auto* tep = unsized_ty.m_data.opt_TraitObject() )
{
const auto& trait_path = tep->m_trait;
- const auto& trait = *tep->m_trait.m_trait_ptr;
if( trait_path.m_path.m_path == ::HIR::SimplePath() )
{
@@ -27,8 +26,10 @@ namespace {
}
else
{
- auto vtable_ty_spath = trait_path.m_path.m_path;
- vtable_ty_spath.m_components.back() += "#vtable";
+ const auto& trait = *tep->m_trait.m_trait_ptr;
+
+ const auto& vtable_ty_spath = trait.m_vtable_path;
+ MIR_ASSERT(state, vtable_ty_spath != ::HIR::SimplePath(), "Trait with no vtable - " << trait_path);
const auto& vtable_ref = state.m_resolve.m_crate.get_struct_by_path(state.sp, vtable_ty_spath);
// Copy the param set from the trait in the trait object
::HIR::PathParams vtable_params = trait_path.m_path.m_params.clone();
@@ -115,6 +116,11 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
{
}
+ explicit ValStates(const ValStates& v) = default;
+ ValStates(ValStates&& v) = default;
+ ValStates& operator=(const ValStates& v) = delete;
+ ValStates& operator=(ValStates&& v) = default;
+
void fmt(::std::ostream& os) {
os << "ValStates { ";
switch(ret_state)
@@ -158,12 +164,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
return locals.empty() && args.empty();
}
+ // NOTE: Moves if this state is empty
bool merge(unsigned bb_idx, ValStates& other)
{
DEBUG("bb" << bb_idx << " this=" << FMT_CB(ss,this->fmt(ss);) << ", other=" << FMT_CB(ss,other.fmt(ss);));
if( this->empty() )
{
- *this = other;
+ *this = ValStates(other);
return true;
}
else if( *this == other )
@@ -182,34 +189,38 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
void mark_validity(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv, bool is_valid)
{
- TU_MATCH_DEF( ::MIR::LValue, (lv), (e),
- (
- ),
+ if( !lv.m_wrappers.empty())
+ {
+ return ;
+ }
+ TU_MATCHA( (lv.m_root), (e),
(Return,
ret_state = is_valid ? State::Valid : State::Invalid;
),
(Argument,
- MIR_ASSERT(state, e.idx < this->args.size(), "Argument index out of range");
- DEBUG("arg$" << e.idx << " = " << (is_valid ? "Valid" : "Invalid"));
- this->args[e.idx] = is_valid ? State::Valid : State::Invalid;
+ MIR_ASSERT(state, e < this->args.size(), "Argument index out of range " << lv);
+ DEBUG("arg$" << e << " = " << (is_valid ? "Valid" : "Invalid"));
+ this->args[e] = is_valid ? State::Valid : State::Invalid;
),
(Local,
- MIR_ASSERT(state, e < this->locals.size(), "Local index out of range");
+ MIR_ASSERT(state, e < this->locals.size(), "Local index out of range - " << lv);
DEBUG("_" << e << " = " << (is_valid ? "Valid" : "Invalid"));
this->locals[e] = is_valid ? State::Valid : State::Invalid;
+ ),
+ (Static,
)
)
}
void ensure_valid(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv)
{
- TU_MATCH( ::MIR::LValue, (lv), (e),
+ TU_MATCHA( (lv.m_root), (e),
(Return,
if( this->ret_state != State::Valid )
MIR_BUG(state, "Use of non-valid lvalue - " << lv);
),
(Argument,
- MIR_ASSERT(state, e.idx < this->args.size(), "Arg index out of range");
- if( this->args[e.idx] != State::Valid )
+ MIR_ASSERT(state, e < this->args.size(), "Arg index out of range");
+ if( this->args[e] != State::Valid )
MIR_BUG(state, "Use of non-valid lvalue - " << lv);
),
(Local,
@@ -218,27 +229,22 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
MIR_BUG(state, "Use of non-valid lvalue - " << lv);
),
(Static,
- ),
- (Field,
- ensure_valid(state, *e.val);
- ),
- (Deref,
- ensure_valid(state, *e.val);
- ),
- (Index,
- ensure_valid(state, *e.val);
- ensure_valid(state, *e.idx);
- ),
- (Downcast,
- ensure_valid(state, *e.val);
)
)
+
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( w.is_Index() )
+ {
+ if( this->locals[w.as_Index()] != State::Valid )
+ MIR_BUG(state, "Use of non-valid lvalue - " << ::MIR::LValue::new_Local(w.as_Index()));
+ }
+ }
}
void move_val(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv)
{
ensure_valid(state, lv);
- ::HIR::TypeRef tmp;
- if( ! state.m_resolve.type_is_copy( state.sp, state.get_lvalue_type(tmp, lv) ) )
+ if( ! state.lvalue_is_copy(lv) )
{
mark_validity(state, lv, false);
}
@@ -283,20 +289,29 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
::std::vector<unsigned int> path;
ValStates state;
};
+ // TODO: Remove this? The path is useful, but the cloned states are really expensive
+ // - Option: Keep the paths, but only ever use the pre-set entry state?
::std::vector<ToVisit> to_visit_blocks;
// TODO: Check that all used locals are also set (anywhere at all)
- auto add_to_visit = [&](unsigned int idx, ::std::vector<unsigned int> src_path, auto vs) {
+ auto add_to_visit = [&](unsigned int idx, ::std::vector<unsigned int> src_path, ValStates& vs, bool can_move) {
for(const auto& b : to_visit_blocks)
if( b.bb == idx && b.state == vs)
return ;
if( block_start_states.at(idx) == vs )
return ;
src_path.push_back(idx);
- to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), mv$(vs) } );
+ // TODO: Update the target block, and only visit if we've induced a change
+ to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), (can_move ? mv$(vs) : ValStates(vs)) } );
+ };
+ auto add_to_visit_move = [&](unsigned int idx, ::std::vector<unsigned int> src_path, ValStates vs) {
+ add_to_visit(idx, mv$(src_path), vs, true);
+ };
+ auto add_to_visit_copy = [&](unsigned int idx, ::std::vector<unsigned int> src_path, ValStates& vs) {
+ add_to_visit(idx, mv$(src_path), vs, false);
};
- add_to_visit( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } );
+ add_to_visit_move( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } );
while( to_visit_blocks.size() > 0 )
{
auto block = to_visit_blocks.back().bb;
@@ -310,7 +325,8 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
if( ! block_start_states.at(block).merge(block, val_state) ) {
continue ;
}
- DEBUG("BB" << block << " via [" << path << "]");
+ ASSERT_BUG(Span(), val_state.locals.size() == fcn.locals.size(), "");
+ DEBUG("BB" << block << " via [" << path << "] " << FMT_CB(ss,val_state.fmt(ss);));
// 2. Using the newly merged state, iterate statements checking the usage and updating state.
const auto& bb = fcn.blocks[block];
@@ -341,6 +357,18 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
val_state.mark_validity( state, v.second, true );
break;
case ::MIR::Statement::TAG_Assign:
+ // Destination must be valid
+ for(const auto& w : stmt.as_Assign().dst.m_wrappers)
+ {
+ if( w.is_Deref() ) {
+ // TODO: Check validity of the rest of the wrappers.
+ }
+ if( w.is_Index() )
+ {
+ if( val_state.locals[w.as_Index()] != ValStates::State::Valid )
+ MIR_BUG(state, "Use of non-valid lvalue - " << ::MIR::LValue::new_Local(w.as_Index()));
+ }
+ }
// Check source (and invalidate sources)
TU_MATCH( ::MIR::RValue, (stmt.as_Assign().src), (se),
(Use,
@@ -410,13 +438,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
// 3. Pass new state on to destination blocks
state.set_cur_stmt_term(block);
DEBUG(state << bb.terminator);
- TU_MATCH(::MIR::Terminator, (bb.terminator), (e),
- (Incomplete,
+ TU_MATCH_HDRA( (bb.terminator), { )
+ TU_ARMA(Incomplete, e) {
// Should be impossible here.
- ),
- (Return,
+ }
+ TU_ARMA(Return, e) {
// Check if the return value has been set
- val_state.ensure_valid( state, ::MIR::LValue::make_Return({}) );
+ val_state.ensure_valid( state, ::MIR::LValue::new_Return() );
// Ensure that no other non-Copy values are valid
for(unsigned int i = 0; i < val_state.locals.size(); i ++)
{
@@ -431,51 +459,51 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
// TODO: Error, becuase this has just been leaked
}
}
- ),
- (Diverge,
+ }
+ TU_ARMA(Diverge, e) {
// TODO: Ensure that cleanup has been performed.
- ),
- (Goto,
+ }
+ TU_ARMA(Goto, e) {
// Push block with the new state
- add_to_visit( e, mv$(path), mv$(val_state) );
- ),
- (Panic,
+ add_to_visit_move( e, mv$(path), mv$(val_state) );
+ }
+ TU_ARMA(Panic, e) {
// What should be done here?
- ),
- (If,
+ }
+ TU_ARMA(If, e) {
// Push blocks
val_state.ensure_valid( state, e.cond );
- add_to_visit( e.bb0, path, val_state );
- add_to_visit( e.bb1, mv$(path), mv$(val_state) );
- ),
- (Switch,
+ add_to_visit_copy( e.bb0, path, val_state );
+ add_to_visit_move( e.bb1, mv$(path), mv$(val_state) );
+ }
+ TU_ARMA(Switch, e) {
val_state.ensure_valid( state, e.val );
for(const auto& tgt : e.targets)
{
- add_to_visit( tgt, path, val_state );
+ add_to_visit( tgt, path, val_state, (&tgt == &e.targets.back()) );
+ }
}
- ),
- (SwitchValue,
+ TU_ARMA(SwitchValue, e) {
val_state.ensure_valid( state, e.val );
for(const auto& tgt : e.targets)
{
- add_to_visit( tgt, path, val_state );
+ add_to_visit_copy( tgt, path, val_state );
}
- add_to_visit( e.def_target, path, val_state );
- ),
- (Call,
+ add_to_visit_move( e.def_target, path, mv$(val_state) );
+ }
+ TU_ARMA(Call, e) {
if( e.fcn.is_Value() )
val_state.ensure_valid( state, e.fcn.as_Value() );
for(const auto& arg : e.args)
val_state.move_val( state, arg );
// Push blocks (with return valid only in one)
- add_to_visit(e.panic_block, path, val_state);
+ add_to_visit_copy(e.panic_block, path, val_state);
// TODO: If the function returns !, don't follow the ret_block
val_state.mark_validity( state, e.ret_val, true );
- add_to_visit(e.ret_block, mv$(path), mv$(val_state));
- )
- )
+ add_to_visit_move(e.ret_block, mv$(path), mv$(val_state));
+ }
+ }
}
}
@@ -686,10 +714,12 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
// TODO: Check that the input type is Copy
),
(Borrow,
- // TODO: Check return type
+ ::HIR::TypeRef tmp;
+ check_types( dst_ty, ::HIR::TypeRef::new_borrow(e.type, state.get_lvalue_type(tmp, e.val).clone()) );
),
(Cast,
- // TODO: Check return type
+ // Check return type
+ check_types( dst_ty, e.type );
// TODO: Check suitability of source type (COMPLEX)
),
(BinOp,
@@ -835,33 +865,33 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
state.set_cur_stmt_term(bb_idx);
DEBUG(state << bb.terminator);
- TU_MATCH(::MIR::Terminator, (bb.terminator), (e),
- (Incomplete,
- ),
- (Return,
+ TU_MATCH_HDRA( (bb.terminator), {)
+ TU_ARMA(Incomplete, e) {
+ }
+ TU_ARMA(Return, e) {
// TODO: Check if the function can return (i.e. if its return type isn't an empty type)
- ),
- (Diverge,
- ),
- (Goto,
- ),
- (Panic,
- ),
- (If,
+ }
+ TU_ARMA(Diverge, e) {
+ }
+ TU_ARMA(Goto, e) {
+ }
+ TU_ARMA(Panic, e) {
+ }
+ TU_ARMA(If, e) {
// Check that condition lvalue is a bool
::HIR::TypeRef tmp;
const auto& ty = state.get_lvalue_type(tmp, e.cond);
if( ty != ::HIR::CoreType::Bool ) {
MIR_BUG(state, "Type mismatch in `If` - expected bool, got " << ty);
}
- ),
- (Switch,
+ }
+ TU_ARMA(Switch, e) {
// Check that the condition is an enum
- ),
- (SwitchValue,
+ }
+ TU_ARMA(SwitchValue, e) {
// Check that the condition's type matches the values
- ),
- (Call,
+ }
+ TU_ARMA(Call, e) {
if( e.fcn.is_Value() )
{
::HIR::TypeRef tmp;
@@ -872,8 +902,8 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
}
}
// Typecheck arguments and return value
- )
- )
+ }
+ }
}
}
diff --git a/src/mir/check_full.cpp b/src/mir/check_full.cpp
index 24a4930a..0cc83c6f 100644
--- a/src/mir/check_full.cpp
+++ b/src/mir/check_full.cpp
@@ -446,68 +446,54 @@ namespace
}
const State& get_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const
{
- TU_MATCHA( (lv), (e),
+ const State* state_p = nullptr;
+ TU_MATCHA( (lv.m_root), (e),
(Return,
- return return_value;
+ state_p = &return_value;
),
(Argument,
- return args.at(e.idx);
+ state_p = &args.at(e);
),
(Local,
- return locals.at(e);
+ state_p = &locals.at(e);
),
(Static,
static State state_of_static(true);
return state_of_static;
- ),
- (Field,
- const auto& vs = get_lvalue_state(mir_res, *e.val);
- if( vs.is_composite() )
- {
- const auto& states = this->get_composite(mir_res, vs);
- MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range");
- return states[e.field_index];
- }
- else
- {
- return vs;
+ )
+ )
+
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( state_p->is_composite() ) {
+ break;
}
- ),
- (Deref,
- const auto& vs = get_lvalue_state(mir_res, *e.val);
- if( vs.is_composite() )
- {
+ const auto& vs = *state_p;
+ state_p = nullptr;
+
+ TU_MATCHA( (w), (e),
+ (Field,
+ const auto& states = this->get_composite(mir_res, vs);
+ MIR_ASSERT(mir_res, e < states.size(), "Field index out of range");
+ state_p = &states[e];
+ ),
+ (Deref,
MIR_TODO(mir_res, "Deref with composite state");
- }
- else
- {
- return vs;
- }
- ),
- (Index,
- const auto& vs_v = get_lvalue_state(mir_res, *e.val);
- const auto& vs_i = get_lvalue_state(mir_res, *e.idx);
- MIR_ASSERT(mir_res, !vs_v.is_composite(), "");
- MIR_ASSERT(mir_res, !vs_i.is_composite(), "");
- //return State(vs_v.is_valid() && vs_i.is_valid());
- MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value");
- return vs_v;
- ),
- (Downcast,
- const auto& vs_v = get_lvalue_state(mir_res, *e.val);
- if( vs_v.is_composite() )
- {
- const auto& states = this->get_composite(mir_res, vs_v);
- MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs_v));
- return states[0];
- }
- else
- {
- return vs_v;
- }
+ ),
+ (Index,
+ const auto& vs_i = get_lvalue_state(mir_res, ::MIR::LValue::new_Local(e));
+ MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value");
+ MIR_BUG(mir_res, "Indexing a composite state");
+ ),
+ (Downcast,
+ const auto& states = this->get_composite(mir_res, vs);
+ MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs));
+ state_p = &states[0];
+ )
)
- )
- throw "";
+ assert(state_p);
+ }
+ return *state_p;
}
void clear_state(const ::MIR::TypeResolve& mir_res, State& s) {
@@ -522,42 +508,47 @@ namespace
void set_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv, State new_vs)
{
TRACE_FUNCTION_F(lv << " = " << StateFmt(*this, new_vs) << " (from " << StateFmt(*this, get_lvalue_state(mir_res, lv)) << ")");
- TU_MATCHA( (lv), (e),
+ State* state_p = nullptr;
+ TU_MATCHA( (lv.m_root), (e),
(Return,
- this->clear_state(mir_res, return_value);
- return_value = mv$(new_vs);
+ state_p = &return_value;
),
(Argument,
- auto& slot = args.at(e.idx);
- this->clear_state(mir_res, slot);
- slot = mv$(new_vs);
+ state_p = &args.at(e);
),
(Local,
- auto& slot = locals.at(e);
- this->clear_state(mir_res, slot);
- slot = mv$(new_vs);
+ state_p = &locals.at(e);
),
(Static,
- // Ignore.
- ),
- (Field,
- const auto& cur_vs = get_lvalue_state(mir_res, *e.val);
+ return ;
+ )
+ )
+
+ for(const auto& w : lv.m_wrappers)
+ {
+ auto& cur_vs = *state_p;
+
+ // If this is not a composite, and it matches the new state
if( !cur_vs.is_composite() && cur_vs == new_vs )
{
- // Not a composite, and no state change
+ // Early return
+ return;
}
- else
- {
- ::std::vector<State>* states_p;
+
+ state_p = nullptr;
+ TU_MATCHA( (w), (e),
+ (Field,
+ // Current isn't a composite, we need to change that
if( !cur_vs.is_composite() )
{
::HIR::TypeRef tmp;
- const auto& ty = mir_res.get_lvalue_type(tmp, *e.val);
+ const auto& ty = mir_res.get_lvalue_type(tmp, lv, /*wrapper_skip_count=*/(&lv.m_wrappers.back() - &w));
unsigned int n_fields = 0;
if( const auto* e = ty.m_data.opt_Tuple() )
{
n_fields = e->size();
}
+ // TODO: Fixed-size arrays
else if( ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Struct() )
{
const auto& e = ty.m_data.as_Path().binding.as_Struct();
@@ -573,94 +564,59 @@ namespace
)
)
}
- else {
+ else
+ {
MIR_BUG(mir_res, "Unknown type being accessed with Field - " << ty);
}
- auto new_cur_vs = this->allocate_composite(n_fields, cur_vs);
- set_lvalue_state(mir_res, *e.val, State(new_cur_vs));
- states_p = &this->get_composite(mir_res, new_cur_vs);
- }
- else
- {
- states_p = &this->get_composite(mir_res, cur_vs);
+ cur_vs = State(this->allocate_composite(n_fields, cur_vs));
}
// Get composite state and assign into it
- auto& states = *states_p;
- MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range");
- this->clear_state(mir_res, states[e.field_index]);
- states[e.field_index] = mv$(new_vs);
- }
- ),
- (Deref,
- const auto& cur_vs = get_lvalue_state(mir_res, *e.val);
- if( !cur_vs.is_composite() && cur_vs == new_vs )
- {
- // Not a composite, and no state change
- }
- else
- {
- ::std::vector<State>* states_p;
+ auto& states = this->get_composite(mir_res, cur_vs);
+ MIR_ASSERT(mir_res, e< states.size(), "Field index out of range");
+ state_p = &states[e];
+ ),
+ (Deref,
if( !cur_vs.is_composite() )
{
+ // TODO: Should this check if the type is Box?
//::HIR::TypeRef tmp;
//const auto& ty = mir_res.get_lvalue_type(tmp, *e.val);
- // TODO: Should this check if the type is Box?
- auto new_cur_vs = this->allocate_composite(2, cur_vs);
- set_lvalue_state(mir_res, *e.val, State(new_cur_vs));
- states_p = &this->get_composite(mir_res, new_cur_vs);
- }
- else
- {
- states_p = &this->get_composite(mir_res, cur_vs);
+ cur_vs = State(this->allocate_composite(2, cur_vs));
}
// Get composite state and assign into it
- auto& states = *states_p;
+ auto& states = this->get_composite(mir_res, cur_vs);
MIR_ASSERT(mir_res, states.size() == 2, "Deref with invalid state list size");
- this->clear_state(mir_res, states[1]);
- states[1] = mv$(new_vs);
- }
- ),
- (Index,
- const auto& vs_v = get_lvalue_state(mir_res, *e.val);
- const auto& vs_i = get_lvalue_state(mir_res, *e.idx);
- MIR_ASSERT(mir_res, !vs_v.is_composite(), "");
- MIR_ASSERT(mir_res, !vs_i.is_composite(), "");
+ state_p = &states[1];
+ ),
+ (Index,
+ const auto& vs_i = get_lvalue_state(mir_res, ::MIR::LValue::new_Local(e));
+ MIR_ASSERT(mir_res, !cur_vs.is_composite(), "");
+ MIR_ASSERT(mir_res, !vs_i.is_composite(), "");
- MIR_ASSERT(mir_res, vs_v.is_valid(), "Indexing an invalid value");
- MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalid index");
+ MIR_ASSERT(mir_res, cur_vs.is_valid(), "Indexing an invalid value");
+ MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalid index");
- // NOTE: Ignore
- ),
- (Downcast,
- const auto& cur_vs = get_lvalue_state(mir_res, *e.val);
- if( !cur_vs.is_composite() && cur_vs == new_vs )
- {
- // Not a composite, and no state change
- }
- else
- {
- ::std::vector<State>* states_p;
+ // NOTE: Ignore
+ return ;
+ ),
+ (Downcast,
if( !cur_vs.is_composite() )
{
- auto new_cur_vs = this->allocate_composite(1, cur_vs);
- set_lvalue_state(mir_res, *e.val, State(new_cur_vs));
- states_p = &this->get_composite(mir_res, new_cur_vs);
+ cur_vs = State(this->allocate_composite(1, cur_vs));
}
- else
- {
- states_p = &this->get_composite(mir_res, cur_vs);
- }
-
// Get composite state and assign into it
- auto& states = *states_p;
- MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << *e.val << " - " << this->fmt_state(mir_res, *e.val));
+ auto& states = this->get_composite(mir_res, cur_vs);
+ MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << lv << " - " << StateFmt(*this, cur_vs));
this->clear_state(mir_res, states[0]);
states[0] = mv$(new_vs);
- }
+ )
)
- )
+ assert(state_p);
+ }
+ this->clear_state(mir_res, *state_p);
+ *state_p = mv$(new_vs);
}
};
@@ -939,7 +895,7 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio
(Incomplete,
),
(Return,
- state.ensure_lvalue_valid(mir_res, ::MIR::LValue::make_Return({}));
+ state.ensure_lvalue_valid(mir_res, ::MIR::LValue::new_Return());
if( ENABLE_LEAK_DETECTOR )
{
auto ensure_dropped = [&](const State& s, const ::MIR::LValue& lv) {
@@ -955,10 +911,10 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio
}
};
for(unsigned i = 0; i < state.locals.size(); i ++ ) {
- ensure_dropped(state.locals[i], ::MIR::LValue::make_Local(i));
+ ensure_dropped(state.locals[i], ::MIR::LValue::new_Local(i));
}
for(unsigned i = 0; i < state.args.size(); i ++ ) {
- ensure_dropped(state.args[i], ::MIR::LValue::make_Argument({i}));
+ ensure_dropped(state.args[i], ::MIR::LValue::new_Argument(i));
}
}
),
diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp
index eae24031..6b8bcf79 100644
--- a/src/mir/cleanup.cpp
+++ b/src/mir/cleanup.cpp
@@ -33,7 +33,7 @@ struct MirMutator
::MIR::LValue new_temporary(::HIR::TypeRef ty)
{
- auto rv = ::MIR::LValue::make_Local( static_cast<unsigned int>(m_fcn.locals.size()) );
+ auto rv = ::MIR::LValue::new_Local( static_cast<unsigned int>(m_fcn.locals.size()) );
m_fcn.locals.push_back( mv$(ty) );
return rv;
}
@@ -75,8 +75,7 @@ namespace {
{
const auto& trait = *te.m_trait.m_trait_ptr;
- auto vtable_ty_spath = te.m_trait.m_path.m_path;
- vtable_ty_spath.m_components.back() += "#vtable";
+ const auto& vtable_ty_spath = trait.m_vtable_path;
const auto& vtable_ref = resolve.m_crate.get_struct_by_path(sp, vtable_ty_spath);
// Copy the param set from the trait in the trait object
::HIR::PathParams vtable_params = te.m_trait.m_path.m_params.clone();
@@ -91,8 +90,11 @@ namespace {
}
}
-const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::Path& path, ::HIR::TypeRef& out_ty)
+const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, const ::HIR::Path& path, ::HIR::TypeRef& out_ty)
{
+ const Span& sp = state.sp;
+ const auto& resolve = state.m_resolve;
+ TRACE_FUNCTION_F(path);
TU_MATCHA( (path.m_data), (pe),
(Generic,
const auto& constant = resolve.m_crate.get_constant_by_path(sp, pe.m_path);
@@ -155,6 +157,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
// Obtain `out_ty` by monomorphising the type in the trait.
auto monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &pe.trait.m_params, nullptr);
out_ty = monomorphise_type_with(sp, trait_cdef.m_type, monomorph_cb);
+ resolve.expand_associated_types(sp, out_ty);
if( best_impl )
{
ASSERT_BUG(sp, best_impl->m_constants.find(pe.item) != best_impl->m_constants.end(), "Item '" << pe.item << "' missing in impl for " << path);
@@ -164,13 +167,24 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
else
{
// No impl found at all, use the default in the trait
- return &trait_cdef.m_value_res;
+ if( trait_cdef.m_value_res.is_Defer() )
+ {
+ DEBUG(state << "Found deferred trait constant - " << path);
+ // Return null to force the replacement to not happen (yet)
+ // - Expansion and resolution of this constant happens after/in "Trans Monomorph"
+ return nullptr;
+ }
+ else
+ {
+ DEBUG("- Default " << trait_cdef.m_value_res);
+ return &trait_cdef.m_value_res;
+ }
}
}
),
(UfcsInherent,
const ::HIR::TypeImpl* best_impl = nullptr;
- // TODO: Associated constants (inherent)
+ // Associated constants (inherent)
resolve.m_crate.find_type_impls(*pe.type, [&](const auto& ty)->const auto& { return ty; },
[&](const auto& impl) {
auto it = impl.m_constants.find(pe.item);
@@ -199,9 +213,9 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
if( path == ::HIR::GenericPath() )
- MIR_TODO(state, "Literal of type " << ty << " - " << path << " - " << lit);
- DEBUG("Unknown type " << ty << " - Return BorrowOf");
- return ::MIR::Constant( mv$(path) );
+ MIR_TODO(state, "Literal of type " << ty << " - " << lit);
+ DEBUG("Unknown type " << ty << ", but a path was provided - Return ItemAddr " << path);
+ return ::MIR::Constant::make_ItemAddr( box$(path) );
),
(Tuple,
MIR_ASSERT(state, lit.is_List(), "Non-list literal for Tuple - " << lit);
@@ -315,7 +329,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
}
else
{
- MIR_BUG(state, "Unexpected type - " << ty);
+ MIR_BUG(state, "Unexpected type for literal from " << path << " - " << ty << " (lit = " << lit << ")");
}
),
(Primitive,
@@ -328,6 +342,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
case ::HIR::CoreType::U32:
case ::HIR::CoreType::U16:
case ::HIR::CoreType::U8:
+ MIR_ASSERT(state, lit.is_Integer(), "Literal for " << path << ": " << ty << " not an integer, instead " << lit);
return ::MIR::Constant::make_Uint({ lit.as_Integer(), te });
case ::HIR::CoreType::Isize:
case ::HIR::CoreType::I128:
@@ -335,11 +350,14 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
case ::HIR::CoreType::I32:
case ::HIR::CoreType::I16:
case ::HIR::CoreType::I8:
+ MIR_ASSERT(state, lit.is_Integer(), "Literal for " << path << ": " << ty << " not an integer, instead " << lit);
return ::MIR::Constant::make_Int({ static_cast<int64_t>(lit.as_Integer()), te });
case ::HIR::CoreType::F64:
case ::HIR::CoreType::F32:
+ MIR_ASSERT(state, lit.is_Float(), "Literal for " << path << ": " << ty << " not a float, instead " << lit);
return ::MIR::Constant::make_Float({ lit.as_Float(), te });
case ::HIR::CoreType::Bool:
+ MIR_ASSERT(state, lit.is_Integer(), "Literal for " << path << ": " << ty << " not an integer, instead " << lit);
return ::MIR::Constant::make_Bool({ !!lit.as_Integer() });
case ::HIR::CoreType::Str:
MIR_BUG(state, "Const of type `str` - " << path);
@@ -348,7 +366,6 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
),
(Pointer,
if( lit.is_BorrowPath() || lit.is_BorrowData() ) {
- // TODO:
MIR_TODO(state, "BorrowOf into pointer - " << lit << " into " << ty);
}
else {
@@ -360,7 +377,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
if( const auto* pp = lit.opt_BorrowPath() )
{
const auto& path = *pp;
- auto ptr_val = ::MIR::Constant::make_ItemAddr(path.clone());
+ auto ptr_val = ::MIR::Constant::make_ItemAddr(box$(path.clone()));
// TODO: Get the metadata type (for !Sized wrapper types)
if( te.inner->m_data.is_Slice() )
{
@@ -379,7 +396,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
auto vtable_path = ::HIR::Path(&ty == &tmp ? mv$(tmp) : ty.clone(), tep->m_trait.m_path.clone(), "vtable#");
- auto vtable_val = ::MIR::Param( ::MIR::Constant::make_ItemAddr(mv$(vtable_path)) );
+ auto vtable_val = ::MIR::Param( ::MIR::Constant::make_ItemAddr(box$(vtable_path)) );
return ::MIR::RValue::make_MakeDst({ ::MIR::Param(mv$(ptr_val)), mv$(vtable_val) });
}
@@ -436,6 +453,11 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
else {
MIR_TODO(state, "Const with type " << ty);
}
+ ),
+ (Function,
+ //MIR_TODO(state, "Const function pointer " << lit << " w/ type " << ty);
+ MIR_ASSERT(state, lit.is_BorrowPath(), "");
+ return ::MIR::Constant::make_ItemAddr( box$( lit.as_BorrowPath().clone() ) );
)
)
}
@@ -471,12 +493,13 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
// Allocate a temporary for the vtable pointer itself
auto vtable_lv = mutator.new_temporary( mv$(vtable_ty) );
// - Load the vtable and store it
- auto ptr_lv = ::MIR::LValue::make_Deref({ box$(receiver_lvp.clone()) });
+ auto ptr_lv = ::MIR::LValue::new_Deref( receiver_lvp.clone() );
MIR_Cleanup_LValue(state, mutator, ptr_lv);
- auto vtable_rval = ::MIR::RValue::make_DstMeta({ mv$(*ptr_lv.as_Deref().val) });
+ ptr_lv.m_wrappers.pop_back();
+ auto vtable_rval = ::MIR::RValue::make_DstMeta({ mv$(ptr_lv) });
mutator.push_statement( ::MIR::Statement::make_Assign({ vtable_lv.clone(), mv$(vtable_rval) }) );
- auto fcn_lval = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(vtable_lv) })), vtable_idx });
+ auto fcn_lval = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref( mv$(vtable_lv) ), vtable_idx );
::HIR::TypeRef tmp;
const auto& ty = state.get_lvalue_type(tmp, fcn_lval);
@@ -504,23 +527,23 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
),
(Tuple,
for(unsigned int i = 0; i < se.size(); i ++ ) {
- auto val = (i == se.size() - 1 ? mv$(lv) : lv.clone());
+ auto val = ::MIR::LValue::new_Field( (i == se.size() - 1 ? mv$(lv) : lv.clone()), i );
if( i == str.m_struct_markings.coerce_unsized_index ) {
- vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].ent), ::MIR::LValue::make_Field({ box$(val), i }) ) );
+ vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].ent), mv$(val)) );
}
else {
- vals.push_back( ::MIR::LValue::make_Field({ box$(val), i }) );
+ vals.push_back( mv$(val) );
}
}
),
(Named,
for(unsigned int i = 0; i < se.size(); i ++ ) {
- auto val = (i == se.size() - 1 ? mv$(lv) : lv.clone());
+ auto val = ::MIR::LValue::new_Field( (i == se.size() - 1 ? mv$(lv) : lv.clone()), i );
if( i == str.m_struct_markings.coerce_unsized_index ) {
- vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].second.ent), ::MIR::LValue::make_Field({ box$(val), i }) ) );
+ vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].second.ent), mv$(val) ) );
}
else {
- vals.push_back( ::MIR::LValue::make_Field({ box$(val), i }) );
+ vals.push_back( mv$(val) );
}
}
)
@@ -653,8 +676,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
const auto& trait = *de.m_trait.m_trait_ptr;
// Obtain vtable type `::"path"::to::Trait#vtable`
- auto vtable_ty_spath = trait_path.m_path.m_path;
- vtable_ty_spath.m_components.back() += "#vtable";
+ const auto& vtable_ty_spath = trait.m_vtable_path;
const auto& vtable_ref = state.m_crate.get_struct_by_path(state.sp, vtable_ty_spath);
// Copy the param set from the trait in the trait object
::HIR::PathParams vtable_params = trait_path.m_path.m_params.clone();
@@ -680,7 +702,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
MIR_ASSERT(state, state.m_resolve.type_is_sized(state.sp, src_ty), "Attempting to get vtable for unsized type - " << src_ty);
::HIR::Path vtable { src_ty.clone(), trait_path.m_path.clone(), "vtable#" };
- out_meta_val = ::MIR::Constant::make_ItemAddr(mv$(vtable));
+ out_meta_val = ::MIR::Constant::make_ItemAddr(box$(vtable));
}
}
return true;
@@ -697,7 +719,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
bool source_is_dst = false;
if( MIR_Cleanup_Unsize_GetMetadata(state, mutator, dst_ty_inner, src_ty_inner, ptr_value, meta_value, meta_type, source_is_dst) )
{
- // TODO: There is a case where the source is already a fat pointer. In that case the pointer of the new DST must be the source DST pointer
+ // There is a case where the source is already a fat pointer. In that case the pointer of the new DST must be the source DST pointer
if( source_is_dst )
{
auto ty_unit_ptr = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_unit());
@@ -756,7 +778,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
auto ty_d = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_d, false);
auto ty_s = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_s, false);
- auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i }));
+ auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::new_Field(value.clone(), i));
auto new_lval = mutator.in_temporary( mv$(ty_d), mv$(new_rval) );
ents.push_back( mv$(new_lval) );
@@ -772,7 +794,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
}
else
{
- ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) );
+ ents.push_back( ::MIR::LValue::new_Field(value.clone(), i) );
}
}
),
@@ -785,7 +807,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
auto ty_d = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_d, false);
auto ty_s = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_s, false);
- auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i }));
+ auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::new_Field(value.clone(), i));
auto new_lval = mutator.new_temporary( mv$(ty_d) );
mutator.push_statement( ::MIR::Statement::make_Assign({ new_lval.clone(), mv$(new_rval) }) );
@@ -802,7 +824,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
}
else
{
- ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) );
+ ents.push_back( ::MIR::LValue::new_Field(value.clone(), i) );
}
}
)
@@ -827,7 +849,6 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
if( dte.type == ste.type )
{
- // TODO: Use unsize code above
return MIR_Cleanup_Unsize(state, mutator, dst_ty, *ste.inner, mv$(value));
}
else
@@ -845,7 +866,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, ::MIR::LValue& lval)
{
- TU_MATCHA( (lval), (le),
+ TU_MATCHA( (lval.m_root), (le),
(Return,
),
(Argument,
@@ -853,30 +874,22 @@ void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, ::
(Local,
),
(Static,
- ),
- (Field,
- MIR_Cleanup_LValue(state, mutator, *le.val);
- ),
- (Deref,
- MIR_Cleanup_LValue(state, mutator, *le.val);
- ),
- (Index,
- MIR_Cleanup_LValue(state, mutator, *le.val);
- MIR_Cleanup_LValue(state, mutator, *le.idx);
- ),
- (Downcast,
- MIR_Cleanup_LValue(state, mutator, *le.val);
)
)
- // If this is a deref of Box, unpack and deref the inner pointer
- if( lval.is_Deref() )
+ for(size_t i = 0; i < lval.m_wrappers.size(); i ++)
{
- auto& le = lval.as_Deref();
+ if( !lval.m_wrappers[i].is_Deref() ) {
+ continue ;
+ }
+
+ // If this is a deref of Box, unpack and deref the inner pointer
::HIR::TypeRef tmp;
- const auto& ty = state.get_lvalue_type(tmp, *le.val);
+ const auto& ty = state.get_lvalue_type(tmp, lval, lval.m_wrappers.size() - i);
if( state.m_resolve.is_type_owned_box(ty) )
{
+ unsigned num_injected_fld_zeros = 0;
+
// Handle Box by extracting it to its pointer.
// - Locate (or remember) which field in Box is the pointer, and replace the inner by that field
// > Dumb idea, assume it's always the first field. Keep accessing until located.
@@ -904,11 +917,16 @@ void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, ::
tmp = monomorphise_type(state.sp, str.m_params, te.path.m_data.as_Generic().m_params, *ty_tpl);
typ = &tmp;
- auto new_lval = ::MIR::LValue::make_Field({ mv$(le.val), 0 });
- le.val = box$(new_lval);
+ num_injected_fld_zeros ++;
}
MIR_ASSERT(state, typ->m_data.is_Pointer(), "First non-path field in Box wasn't a pointer - " << *typ);
// We have reached the pointer. Good.
+
+ // Inject all of the field zero accesses (before the deref)
+ while(num_injected_fld_zeros--)
+ {
+ lval.m_wrappers.insert( lval.m_wrappers.begin() + i, ::MIR::LValue::Wrapper::new_Field(0) );
+ }
}
}
}
@@ -938,6 +956,34 @@ void MIR_Cleanup_Param(const ::MIR::TypeResolve& state, MirMutator& mutator, ::M
MIR_Cleanup_Constant(state, mutator, e);
)
)
+
+ // Effectively a copy of the code that handles RValue::Constant below
+ if( p.is_Constant() && p.as_Constant().is_Const() )
+ {
+ const auto& ce = p.as_Constant().as_Const();
+ ::HIR::TypeRef c_ty;
+ const auto* lit_ptr = MIR_Cleanup_GetConstant(state, *ce.p, c_ty);
+ if( lit_ptr && !lit_ptr->is_Defer() )
+ {
+ DEBUG("Replace constant " << *ce.p << " with " << *lit_ptr);
+ auto new_rval = MIR_Cleanup_LiteralToRValue(state, mutator, *lit_ptr, c_ty.clone(), mv$(*ce.p));
+ if( auto* lv = new_rval.opt_Use() ) {
+ p = ::MIR::Param::make_LValue( ::std::move(*lv) );
+ }
+ else if( auto* c = new_rval.opt_Constant() ) {
+ MIR_Cleanup_Constant(state, mutator, *c);
+ p = ::MIR::Param::make_Constant( ::std::move(*c) );
+ }
+ else {
+ auto tmp_lv = mutator.in_temporary( mv$(c_ty), mv$(new_rval) );
+ p = ::MIR::Param::make_LValue( ::std::move(tmp_lv) );
+ }
+ }
+ else
+ {
+ DEBUG("No replacement for constant " << *ce.p);
+ }
+ }
}
void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type)
@@ -1010,9 +1056,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
),
(DstMeta,
// HACK: Ensure that the box Deref conversion fires here.
- auto v = ::MIR::LValue::make_Deref({ box$(re.val) });
- MIR_Cleanup_LValue(state, mutator, v);
- re.val = mv$( *v.as_Deref().val );
+ re.val.m_wrappers.push_back( ::MIR::LValue::Wrapper::new_Deref() );
+ MIR_Cleanup_LValue(state, mutator, re.val);
+ re.val.m_wrappers.pop_back();
// If the type is an array (due to a monomorpised generic?) then replace.
::HIR::TypeRef tmp;
@@ -1033,9 +1079,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
),
(DstPtr,
// HACK: Ensure that the box Deref conversion fires here.
- auto v = ::MIR::LValue::make_Deref({ box$(re.val) });
- MIR_Cleanup_LValue(state, mutator, v);
- re.val = mv$( *v.as_Deref().val );
+ re.val.m_wrappers.push_back( ::MIR::LValue::Wrapper::new_Deref() );
+ MIR_Cleanup_LValue(state, mutator, re.val);
+ re.val.m_wrappers.pop_back();
),
(MakeDst,
MIR_Cleanup_Param(state, mutator, re.ptr_val);
@@ -1066,22 +1112,22 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
auto& se = stmt.as_Assign();
TU_IFLET( ::MIR::RValue, se.src, Constant, e,
- // TODO: Replace `Const` with actual values
+ // Replace `Const` with actual values
TU_IFLET( ::MIR::Constant, e, Const, ce,
// 1. Find the constant
::HIR::TypeRef ty;
- const auto* lit_ptr = MIR_Cleanup_GetConstant(sp, resolve, ce.p, ty);
- if( lit_ptr )
+ const auto* lit_ptr = MIR_Cleanup_GetConstant(state, *ce.p, ty);
+ if( lit_ptr && !lit_ptr->is_Defer() )
{
- DEBUG("Replace constant " << ce.p << " with " << *lit_ptr);
- se.src = MIR_Cleanup_LiteralToRValue(state, mutator, *lit_ptr, mv$(ty), mv$(ce.p));
+ DEBUG("Replace constant " << *ce.p << " with " << *lit_ptr);
+ se.src = MIR_Cleanup_LiteralToRValue(state, mutator, *lit_ptr, mv$(ty), mv$(*ce.p));
if( auto* p = se.src.opt_Constant() ) {
MIR_Cleanup_Constant(state, mutator, *p);
}
}
else
{
- DEBUG("No replacement for constant " << ce.p);
+ DEBUG("No replacement for constant " << *ce.p);
}
)
)
@@ -1198,13 +1244,13 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
e.args.reserve( fcn_ty.m_arg_types.size() );
for(unsigned int i = 0; i < fcn_ty.m_arg_types.size(); i ++)
{
- e.args.push_back( ::MIR::LValue::make_Field({ box$(args_lvalue.clone()), i }) );
+ e.args.push_back( ::MIR::LValue::new_Field(args_lvalue.clone(), i) );
}
// If the trait is Fn/FnMut, dereference the input value.
if( pe.trait.m_path == resolve.m_lang_FnOnce )
e.fcn = mv$(fcn_lvalue);
else
- e.fcn = ::MIR::LValue::make_Deref({ box$(fcn_lvalue) });
+ e.fcn = ::MIR::LValue::new_Deref( mv$(fcn_lvalue) );
}
}
)
diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp
index 90b81d5d..d41bef7c 100644
--- a/src/mir/dump.cpp
+++ b/src/mir/dump.cpp
@@ -176,51 +176,18 @@ namespace {
#undef FMT
}
void fmt_val(::std::ostream& os, const ::MIR::LValue& lval) {
- TU_MATCHA( (lval), (e),
- (Return,
- os << "RETURN";
- ),
- (Argument,
- os << "arg$" << e.idx;
- ),
- (Local,
- os << "_$" << e;
- ),
- (Static,
- os << e;
- ),
- (Field,
- os << "(";
- fmt_val(os, *e.val);
- os << ")." << e.field_index;
- ),
- (Deref,
- os << "*";
- fmt_val(os, *e.val);
- ),
- (Index,
- os << "(";
- fmt_val(os, *e.val);
- os << ")[";
- fmt_val(os, *e.idx);
- os << "]";
- ),
- (Downcast,
- fmt_val(os, *e.val);
- os << " as variant" << e.variant_index;
- )
- )
+ os << lval;
}
void fmt_val(::std::ostream& os, const ::MIR::Constant& e) {
TU_MATCHA( (e), (ce),
(Int,
- os << ce.v;
+ os << ce.v << "_" << ce.t;
),
(Uint,
- os << "0x" << ::std::hex << ce.v << ::std::dec;
+ os << "0x" << ::std::hex << ce.v << ::std::dec << "_" << ce.t;
),
(Float,
- os << ce.v;
+ os << ce.v << "_" << ce.t;
),
(Bool,
os << (ce.v ? "true" : "false");
@@ -244,10 +211,10 @@ namespace {
os << "\"" << ce << "\"";
),
(Const,
- os << ce.p;
+ os << *ce.p;
),
(ItemAddr,
- os << "addr " << ce;
+ os << "addr " << *ce;
)
)
}
diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp
index 5a629233..697f8141 100644
--- a/src/mir/from_hir.cpp
+++ b/src/mir/from_hir.cpp
@@ -18,6 +18,8 @@
#include "operations.hpp"
#include <mir/visit_crate_mir.hpp>
#include <hir/expr_state.hpp>
+#include <trans/target.hpp> // Target_GetSizeAndAlignOf - for `box`
+#include <cctype> // isdigit
namespace {
@@ -50,7 +52,7 @@ namespace {
struct LoopDesc {
ScopeHandle scope;
- ::std::string label;
+ RcString label;
unsigned int cur;
unsigned int next;
::MIR::LValue res_value;
@@ -161,6 +163,7 @@ namespace {
void destructure_from_ex(const Span& sp, const ::HIR::Pattern& pat, ::MIR::LValue lval, int allow_refutable=0) // 1 : yes, 2 : disallow binding
{
+ TRACE_FUNCTION_F(pat << ", allow_refutable=" << allow_refutable);
if( allow_refutable != 3 && pat.m_binding.is_valid() ) {
if( allow_refutable == 2 ) {
BUG(sp, "Binding when not expected");
@@ -173,6 +176,11 @@ namespace {
destructure_from_ex(sp, pat, lval.clone(), 3);
}
+ for(size_t i = 0; i < pat.m_binding.m_implicit_deref_count; i ++)
+ {
+ lval = ::MIR::LValue::new_Deref(mv$(lval));
+ }
+
switch( pat.m_binding.m_type )
{
case ::HIR::PatternBinding::Type::Move:
@@ -206,90 +214,117 @@ namespace {
allow_refutable = 2;
}
- TU_MATCHA( (pat.m_data), (e),
- (Any,
- ),
- (Box,
- destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable);
- ),
- (Ref,
- destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable);
- ),
- (Tuple,
+ for(size_t i = 0; i < pat.m_implicit_deref_count; i ++)
+ {
+ lval = ::MIR::LValue::new_Deref(mv$(lval));
+ }
+
+ TU_MATCH_HDRA( (pat.m_data), {)
+ TU_ARMA(Any, e) {
+ }
+ TU_ARMA(Box, e) {
+ destructure_from_ex(sp, *e.sub, ::MIR::LValue::new_Deref(mv$(lval)), allow_refutable);
+ }
+ TU_ARMA(Ref, e) {
+ destructure_from_ex(sp, *e.sub, ::MIR::LValue::new_Deref(mv$(lval)), allow_refutable);
+ }
+ TU_ARMA(Tuple, e) {
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
{
- destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable);
+ destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable);
}
- ),
- (SplitTuple,
+ }
+ TU_ARMA(SplitTuple, e) {
assert(e.total_size >= e.leading.size() + e.trailing.size());
for(unsigned int i = 0; i < e.leading.size(); i ++ )
{
- destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable);
+ destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable);
}
// TODO: Is there a binding in the middle?
unsigned int ofs = e.total_size - e.trailing.size();
for(unsigned int i = 0; i < e.trailing.size(); i ++ )
{
- destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), ofs+i}), allow_refutable);
+ destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Field(lval.clone(), ofs+i), allow_refutable);
}
- ),
- (StructValue,
+ }
+ TU_ARMA(StructValue, e) {
// Nothing.
- ),
- (StructTuple,
+ }
+ TU_ARMA(StructTuple, e) {
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
{
- destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable);
+ destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable);
}
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, e) {
const auto& str = *e.binding;
- const auto& fields = str.m_data.as_Named();
- for(const auto& fld_pat : e.sub_patterns)
+ if( !e.sub_patterns.empty() )
{
- unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin();
- destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval.clone() ), idx}), allow_refutable);
+ ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct - " << pat);
+ const auto& fields = str.m_data.as_Named();
+ for(const auto& fld_pat : e.sub_patterns)
+ {
+ unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin();
+ destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable);
+ }
+ }
}
- ),
// Refutable
- (Value,
+ TU_ARMA(Value, e) {
ASSERT_BUG(sp, allow_refutable, "Refutable pattern not expected - " << pat);
- ),
- (Range,
+ }
+ TU_ARMA(Range, e) {
ASSERT_BUG(sp, allow_refutable, "Refutable pattern not expected - " << pat);
- ),
- (EnumValue,
+ }
+ TU_ARMA(EnumValue, e) {
const auto& enm = *e.binding_ptr;
if( enm.num_variants() > 1 )
{
ASSERT_BUG(sp, allow_refutable, "Refutable pattern not expected - " << pat);
}
- ),
- (EnumTuple,
+ }
+ TU_ARMA(EnumTuple, e) {
const auto& enm = *e.binding_ptr;
- ASSERT_BUG(sp, enm.num_variants() == 1 || allow_refutable, "Refutable pattern not expected - " << pat);
- auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx });
+ const auto& variants = enm.m_data.as_Data();
+ // TODO: Check that this is the only non-impossible arm
+ if( !allow_refutable )
+ {
+ for(size_t i = 0; i < variants.size(); i ++)
+ {
+ const auto& var_ty = variants[i].type;
+ if( i == e.binding_idx ) {
+ continue;
+ }
+ ::HIR::TypeRef tmp;
+ const auto& ty = (monomorphise_type_needed(var_ty) ? tmp = monomorphise_type_with(sp, var_ty, monomorphise_type_get_cb(sp, nullptr, &e.path.m_params, nullptr)) : var_ty);
+ if( m_builder.resolve().type_is_impossible(sp, ty) ) {
+ continue;
+ }
+ ERROR(sp, E0000, "Variant " << variants[i].name << " not handled");
+ }
+ }
+ auto lval_var = ::MIR::LValue::new_Downcast(mv$(lval), e.binding_idx);
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
{
- destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval_var.clone() ), i}), allow_refutable);
+ destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval_var.clone(), i), allow_refutable);
}
- ),
- (EnumStruct,
+ }
+ TU_ARMA(EnumStruct, e) {
const auto& enm = *e.binding_ptr;
ASSERT_BUG(sp, enm.num_variants() == 1 || allow_refutable, "Refutable pattern not expected - " << pat);
ASSERT_BUG(sp, enm.m_data.is_Data(), "Expected struct variant - " << pat);
const auto& var = enm.m_data.as_Data()[e.binding_idx];;
const auto& str = *var.type.m_data.as_Path().binding.as_Struct();
+ ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct - " << e.path);
const auto& fields = str.m_data.as_Named();
- auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx });
+ auto lval_var = ::MIR::LValue::new_Downcast(mv$(lval), e.binding_idx);
for(const auto& fld_pat : e.sub_patterns)
{
unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin();
- destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval_var.clone() ), idx}), allow_refutable);
+ destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::new_Field(lval_var.clone(), idx), allow_refutable);
}
- ),
- (Slice,
+ }
+ TU_ARMA(Slice, e) {
// These are only refutable if T is [T]
bool ty_is_array = false;
m_builder.with_val_type(sp, lval, [&ty_is_array](const auto& ty){
@@ -301,7 +336,7 @@ namespace {
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++)
{
const auto& subpat = e.sub_patterns[i];
- destructure_from_ex(sp, subpat, ::MIR::LValue::make_Field({ box$(lval.clone()), i }), allow_refutable );
+ destructure_from_ex(sp, subpat, ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable );
}
}
else
@@ -312,11 +347,11 @@ namespace {
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++)
{
const auto& subpat = e.sub_patterns[i];
- destructure_from_ex(sp, subpat, ::MIR::LValue::make_Field({ box$(lval.clone()), i }), allow_refutable );
+ destructure_from_ex(sp, subpat, ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable );
}
}
- ),
- (SplitSlice,
+ }
+ TU_ARMA(SplitSlice, e) {
// These are only refutable if T is [T]
bool ty_is_array = false;
unsigned int array_size = 0;
@@ -340,7 +375,7 @@ namespace {
for(unsigned int i = 0; i < e.leading.size(); i ++)
{
unsigned int idx = 0 + i;
- destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable );
+ destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable );
}
if( e.extra_bind.is_valid() )
{
@@ -349,7 +384,7 @@ namespace {
for(unsigned int i = 0; i < e.trailing.size(); i ++)
{
unsigned int idx = array_size - e.trailing.size() + i;
- destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable );
+ destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable );
}
}
else
@@ -375,13 +410,13 @@ namespace {
::MIR::LValue len_lval;
if( e.extra_bind.is_valid() || e.trailing.size() > 0 )
{
- len_lval = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, lval).clone() }));
+ len_lval = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, lval) }));
}
for(unsigned int i = 0; i < e.leading.size(); i ++)
{
unsigned int idx = i;
- destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable );
+ destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable );
}
if( e.extra_bind.is_valid() )
{
@@ -392,9 +427,10 @@ namespace {
// 2. Obtain pointer to element
::HIR::BorrowType bt = H::get_borrow_type(sp, e.extra_bind);
::MIR::LValue ptr_val = m_builder.lvalue_or_temp(sp,
- ::HIR::TypeRef::new_pointer( bt, inner_type.clone() ),
- ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::make_Field({ box$(lval.clone()), static_cast<unsigned int>(e.leading.size()) }) })
+ ::HIR::TypeRef::new_borrow( bt, inner_type.clone() ),
+ ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::new_Field( lval.clone(), static_cast<unsigned int>(e.leading.size()) ) })
);
+ // TODO: Cast to raw pointer? Or keep as a borrow?
// Construct fat pointer
m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, e.extra_bind.m_slot), ::MIR::RValue::make_MakeDst({ mv$(ptr_val), mv$(len_val) }) );
@@ -407,15 +443,20 @@ namespace {
auto sub_val = ::MIR::Param(::MIR::Constant::make_Uint({ e.trailing.size() - i, ::HIR::CoreType::Usize }));
::MIR::LValue ofs_val = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_BinOp({ len_lval.clone(), ::MIR::eBinOp::SUB, mv$(sub_val) }) );
// Recurse with the indexed value
- destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Index({ box$(lval.clone()), box$(ofs_val) }), allow_refutable);
+ destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Index( lval.clone(), ofs_val.m_root.as_Local() ), allow_refutable);
}
}
}
- )
- )
+ }
+ } // TU_MATCH_HDRA
}
// -- ExprVisitor
+ void visit_node_ptr(::HIR::ExprNodeP& node_p) override
+ {
+ DEBUG(node_p.get());
+ ::HIR::ExprVisitor::visit_node_ptr(node_p);
+ }
void visit(::HIR::ExprNode_Block& node) override
{
TRACE_FUNCTION_F("_Block");
@@ -521,7 +562,7 @@ namespace {
// Outputs can also (sometimes) be rvalues (only for `*m`?)
for(auto& v : node.m_outputs) {
this->visit_node_ptr(v.value);
- if( v.spec[0] != '=' )
+ if( v.spec[0] != '=' && v.spec[0] != '+' ) // TODO: what does '+' mean?
ERROR(node.span(), E0000, "Assembly output specifiers must start with =");
::MIR::LValue lv;
if(v.spec[1] == '*')
@@ -539,7 +580,7 @@ namespace {
TRACE_FUNCTION_F("_Return");
this->visit_node_ptr(node.m_value);
- m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Return({}), m_builder.get_result(node.span()) );
+ m_builder.push_stmt_assign( node.span(), ::MIR::LValue::new_Return(), m_builder.get_result(node.span()) );
m_builder.terminate_scope_early( node.span(), m_builder.fcn_scope() );
m_builder.end_block( ::MIR::Terminator::make_Return({}) );
}
@@ -643,6 +684,11 @@ namespace {
}
target_block = &*it;
}
+ else {
+ if( target_block->label != "" && target_block->label.c_str()[0] == '#' ) {
+ TODO(node.span(), "Break within try block, want to break parent loop instead");
+ }
+ }
if( node.m_continue ) {
ASSERT_BUG(node.span(), !node.m_value, "Continue with a value isn't valid");
@@ -1217,7 +1263,7 @@ namespace {
}
void visit(::HIR::ExprNode_Cast& node) override
{
- TRACE_FUNCTION_F("_Cast");
+ TRACE_FUNCTION_F("_Cast " << node.m_res_type);
this->visit_node_ptr(node.m_value);
const auto& ty_out = node.m_res_type;
@@ -1231,11 +1277,15 @@ namespace {
auto val = m_builder.get_result_in_lvalue(node.m_value->span(), node.m_value->m_res_type);
- TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_out.m_data), (de),
- (
+ TU_MATCH_HDRA( (ty_out.m_data), {)
+ default:
BUG(node.span(), "Invalid cast to " << ty_out << " from " << ty_in);
- ),
- (Pointer,
+ TU_ARMA(Function, de) {
+ // Just trust the previous stages.
+ ASSERT_BUG(node.span(), ty_in.m_data.is_Function(), ty_in);
+ ASSERT_BUG(node.span(), de.m_arg_types == ty_in.m_data.as_Function().m_arg_types, ty_in);
+ }
+ TU_ARMA(Pointer, de) {
if( ty_in.m_data.is_Primitive() ) {
const auto& ie = ty_in.m_data.as_Primitive();
switch(ie)
@@ -1269,8 +1319,8 @@ namespace {
else {
BUG(node.span(), "Cannot cast to pointer from " << ty_in);
}
- ),
- (Primitive,
+ }
+ TU_ARMA(Primitive, de) {
switch(de)
{
case ::HIR::CoreType::Str:
@@ -1337,8 +1387,8 @@ namespace {
}
break;
}
- )
- )
+ }
+ }
auto res = m_builder.new_temporary(node.m_res_type);
m_builder.push_stmt_assign(node.span(), res.clone(), ::MIR::RValue::make_Cast({ mv$(val), node.m_res_type.clone() }));
m_builder.set_result( node.span(), mv$(res) );
@@ -1435,7 +1485,7 @@ namespace {
limit_val = ::MIR::Constant::make_Uint({ e.size_val, ::HIR::CoreType::Usize });
),
(Slice,
- limit_val = ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(node.m_value->span(), value).clone() });
+ limit_val = ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(node.m_value->span(), value) });
)
)
@@ -1469,7 +1519,13 @@ namespace {
m_builder.set_cur_block( arm_continue );
}
- m_builder.set_result( node.span(), ::MIR::LValue::make_Index({ box$(value), box$(index) }) );
+ if( !index.is_Local())
+ {
+ auto local_idx = m_builder.new_temporary(::HIR::CoreType::Usize);
+ m_builder.push_stmt_assign(node.span(), local_idx.clone(), mv$(index));
+ index = mv$(local_idx);
+ }
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Index( mv$(value), index.m_root.as_Local() ) );
}
void visit(::HIR::ExprNode_Deref& node) override
@@ -1481,8 +1537,8 @@ namespace {
this->visit_node_ptr(node.m_value);
auto val = m_builder.get_result_in_lvalue(node.m_value->span(), ty_val);
- TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_val.m_data), (te),
- (
+ TU_MATCH_HDRA( (ty_val.m_data), {)
+ default: {
if( m_builder.is_type_owned_box( ty_val ) )
{
// Box magically derefs.
@@ -1543,20 +1599,31 @@ namespace {
m_builder.set_cur_block(ok_block);
}
- ),
- (Pointer,
+ }
+ TU_ARMA(Pointer, te) {
// Deref on a pointer - TODO: Requires unsafe
- ),
- (Borrow,
+ }
+ TU_ARMA(Borrow, te) {
// Deref on a borrow - Always valid... assuming borrowck is there :)
- )
- )
+ }
+ }
- m_builder.set_result( node.span(), ::MIR::LValue::make_Deref({ box$(val) }) );
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Deref( mv$(val) ) );
}
void visit(::HIR::ExprNode_Emplace& node) override
{
+ switch(gTargetVersion)
+ {
+ case TargetVersion::Rustc1_19:
+ return visit_emplace_119(node);
+ case TargetVersion::Rustc1_29:
+ return visit_emplace_129(node);
+ }
+ throw "BUG: Unhandled target version";
+ }
+ void visit_emplace_119(::HIR::ExprNode_Emplace& node)
+ {
if( node.m_type == ::HIR::ExprNode_Emplace::Type::Noop ) {
return node.m_value->visit(*this);
}
@@ -1652,7 +1719,7 @@ namespace {
// 3. Get the value and assign it into `place_raw`
node.m_value->visit(*this);
auto val = m_builder.get_result(node.span());
- m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Deref({ box$(place_raw.clone()) }), mv$(val) );
+ m_builder.push_stmt_assign( node.span(), ::MIR::LValue::new_Deref(place_raw.clone()), mv$(val), /*drop_destination=*/false );
// 3. Return a call to `finalize`
::HIR::Path finalize_path(::HIR::GenericPath {});
@@ -1689,6 +1756,92 @@ namespace {
m_builder.mark_value_assigned(node.span(), res);
m_builder.set_result( node.span(), mv$(res) );
}
+ void visit_emplace_129(::HIR::ExprNode_Emplace& node)
+ {
+ assert( node.m_type == ::HIR::ExprNode_Emplace::Type::Boxer );
+ const auto& data_ty = node.m_value->m_res_type;
+
+ node.m_value->visit(*this);
+ auto val = m_builder.get_result(node.span());
+
+ const auto& lang_exchange_malloc = m_builder.crate().get_lang_item_path(node.span(), "exchange_malloc");
+ const auto& lang_owned_box = m_builder.crate().get_lang_item_path(node.span(), "owned_box");
+
+ ::HIR::PathParams trait_params_data;
+ trait_params_data.m_types.push_back( data_ty.clone() );
+
+ // 1. Determine the size/alignment of the type
+ ::MIR::Param size_param, align_param;
+ size_t item_size, item_align;
+ if( Target_GetSizeAndAlignOf(node.span(), m_builder.resolve(), data_ty, item_size, item_align) ) {
+ size_param = ::MIR::Constant::make_Int({ static_cast<int64_t>(item_size), ::HIR::CoreType::Usize });
+ align_param = ::MIR::Constant::make_Int({ static_cast<int64_t>(item_align), ::HIR::CoreType::Usize });
+ }
+ else {
+ // Insert calls to "size_of" and "align_of" intrinsics
+ auto size_slot = m_builder.new_temporary( ::HIR::CoreType::Usize );
+ auto size__panic = m_builder.new_bb_unlinked();
+ auto size__ok = m_builder.new_bb_unlinked();
+ m_builder.end_block(::MIR::Terminator::make_Call({
+ size__ok, size__panic,
+ size_slot.clone(), ::MIR::CallTarget::make_Intrinsic({ "size_of", trait_params_data.clone() }),
+ {}
+ }));
+ m_builder.set_cur_block(size__panic); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); // HACK
+ m_builder.set_cur_block(size__ok);
+ auto align_slot = m_builder.new_temporary( ::HIR::CoreType::Usize );
+ auto align__panic = m_builder.new_bb_unlinked();
+ auto align__ok = m_builder.new_bb_unlinked();
+ m_builder.end_block(::MIR::Terminator::make_Call({
+ align__ok, align__panic,
+ align_slot.clone(), ::MIR::CallTarget::make_Intrinsic({ "align_of", trait_params_data.clone() }),
+ {}
+ }));
+ m_builder.set_cur_block(align__panic); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); // HACK
+ m_builder.set_cur_block(align__ok);
+
+ size_param = ::std::move(size_slot);
+ align_param = ::std::move(align_slot);
+ }
+
+ // 2. Call the allocator function and get a pointer
+ // - NOTE: "exchange_malloc" returns a `*mut u8`, need to cast that to the target type
+ auto place_raw_type = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Unique, ::HIR::CoreType::U8);
+ auto place_raw = m_builder.new_temporary( place_raw_type );
+
+ auto place__panic = m_builder.new_bb_unlinked();
+ auto place__ok = m_builder.new_bb_unlinked();
+ m_builder.end_block(::MIR::Terminator::make_Call({
+ place__ok, place__panic,
+ place_raw.clone(), ::HIR::Path(lang_exchange_malloc),
+ make_vec2<::MIR::Param>( ::std::move(size_param), ::std::move(align_param) )
+ }));
+ m_builder.set_cur_block(place__panic); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); // HACK
+ m_builder.set_cur_block(place__ok);
+
+ auto place_type = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Unique, data_ty.clone());
+ auto place = m_builder.new_temporary( place_type );
+ m_builder.push_stmt_assign(node.span(), place.clone(), ::MIR::RValue::make_Cast({ mv$(place_raw), place_type.clone() }));
+ // 3. Do a non-dropping write into the target location (i.e. just a MIR assignment)
+ m_builder.push_stmt_assign(node.span(), ::MIR::LValue::new_Deref(place.clone()), mv$(val), /*drop_destination=*/false);
+ // 4. Convert the pointer into an `owned_box`
+ auto res_type = ::HIR::TypeRef::new_path(::HIR::GenericPath(lang_owned_box, mv$(trait_params_data)), &m_builder.crate().get_struct_by_path(node.span(), lang_owned_box));
+ auto res = m_builder.new_temporary(res_type);
+ auto cast__panic = m_builder.new_bb_unlinked();
+ auto cast__ok = m_builder.new_bb_unlinked();
+ ::HIR::PathParams transmute_params;
+ transmute_params.m_types.push_back( res_type.clone() );
+ transmute_params.m_types.push_back( place_type.clone() );
+ m_builder.end_block(::MIR::Terminator::make_Call({
+ cast__ok, cast__panic,
+ res.clone(), ::MIR::CallTarget::make_Intrinsic({ "transmute", mv$(transmute_params) }),
+ make_vec1( ::MIR::Param( mv$(place) ) )
+ }));
+ m_builder.set_cur_block(cast__panic); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); // HACK
+ m_builder.set_cur_block(cast__ok);
+
+ m_builder.set_result(node.span(), mv$(res));
+ }
void visit(::HIR::ExprNode_TupleVariant& node) override
{
@@ -1810,6 +1963,14 @@ namespace {
mv$(values)
}));
}
+ if( fcn.m_abi == "platform-intrinsic" )
+ {
+ m_builder.end_block(::MIR::Terminator::make_Call({
+ next_block, panic_block,
+ res.clone(), ::MIR::CallTarget::make_Intrinsic({ RcString(FMT("platform:" << gpath.m_path.m_components.back())), gpath.m_params.clone() }),
+ mv$(values)
+ }));
+ }
// rustc has drop_in_place as a lang item, mrustc uses an intrinsic
if( gpath.m_path == m_builder.crate().get_lang_item_path_opt("drop_in_place") )
@@ -1901,29 +2062,29 @@ namespace {
}
void visit(::HIR::ExprNode_Field& node) override
{
- TRACE_FUNCTION_F("_Field");
+ TRACE_FUNCTION_F("_Field \"" << node.m_field << "\"");
this->visit_node_ptr(node.m_value);
auto val = m_builder.get_result_in_lvalue(node.m_value->span(), node.m_value->m_res_type);
const auto& val_ty = node.m_value->m_res_type;
unsigned int idx;
- if( '0' <= node.m_field[0] && node.m_field[0] <= '9' ) {
- ::std::stringstream(node.m_field) >> idx;
- m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) );
+ if( ::std::isdigit(node.m_field.c_str()[0]) ) {
+ ::std::stringstream(node.m_field.c_str()) >> idx;
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Field( mv$(val), idx ) );
}
else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Struct() ) {
const auto& str = **bep;
const auto& fields = str.m_data.as_Named();
idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin();
- m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) );
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Field( mv$(val), idx ) );
}
else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Union() ) {
const auto& unm = **bep;
const auto& fields = unm.m_variants;
idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin();
- m_builder.set_result( node.span(), ::MIR::LValue::make_Downcast({ box$(val), idx }) );
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Downcast( mv$(val), idx ) );
}
else {
BUG(node.span(), "Field access on non-union/struct - " << val_ty);
@@ -2041,7 +2202,7 @@ namespace {
// TODO: Ideally, the creation of the wrapper function would happen somewhere before trans?
auto tmp = m_builder.new_temporary( node.m_res_type );
- m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(node.m_path.clone()) );
+ m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) );
m_builder.set_result( sp, mv$(tmp) );
return ;
}
@@ -2052,11 +2213,11 @@ namespace {
),
(Constant,
auto tmp = m_builder.new_temporary( e.m_type );
- m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_Const({node.m_path.clone()}) );
+ m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_Const({box$(node.m_path.clone())}) );
m_builder.set_result( node.span(), mv$(tmp) );
),
(Static,
- m_builder.set_result( node.span(), ::MIR::LValue::make_Static(node.m_path.clone()) );
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Static(node.m_path.clone()) );
),
(StructConstant,
// TODO: Why is this still a PathValue?
@@ -2101,13 +2262,13 @@ namespace {
fcn_ty_data.m_arg_types.push_back( monomorphise_type_with(sp, arg.second, monomorph_cb) );
}
auto tmp = m_builder.new_temporary( ::HIR::TypeRef( mv$(fcn_ty_data) ) );
- m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(node.m_path.clone()) );
+ m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) );
m_builder.set_result( sp, mv$(tmp) );
),
(StructConstructor,
// TODO: Ideally, the creation of the wrapper function would happen somewhere before this?
auto tmp = m_builder.new_temporary( node.m_res_type );
- m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(node.m_path.clone()) );
+ m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) );
m_builder.set_result( sp, mv$(tmp) );
)
)
@@ -2119,13 +2280,13 @@ namespace {
ASSERT_BUG(sp, it != tr.m_values.end(), "Cannot find trait item for " << node.m_path);
TU_MATCHA( (it->second), (e),
(Constant,
- m_builder.set_result( sp, ::MIR::Constant::make_Const({node.m_path.clone()}) );
+ m_builder.set_result( sp, ::MIR::Constant::make_Const({box$(node.m_path.clone())}) );
),
(Static,
TODO(sp, "Associated statics (non-rustc) - " << node.m_path);
),
(Function,
- m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(node.m_path.clone()) );
+ m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) );
)
)
),
@@ -2141,7 +2302,7 @@ namespace {
{
auto it = impl.m_methods.find(pe.item);
if( it != impl.m_methods.end() ) {
- m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(node.m_path.clone()) );
+ m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) );
return true;
}
}
@@ -2149,7 +2310,7 @@ namespace {
{
auto it = impl.m_constants.find(pe.item);
if( it != impl.m_constants.end() ) {
- m_builder.set_result( sp, ::MIR::Constant::make_Const({node.m_path.clone()}) );
+ m_builder.set_result( sp, ::MIR::Constant::make_Const({box$(node.m_path.clone())}) );
return true;
}
}
@@ -2175,7 +2336,7 @@ namespace {
ASSERT_BUG(sp, str.m_data.is_Named(), "");
const ::HIR::t_struct_fields& fields = str.m_data.as_Named();
- ::MIR::LValue base_val;
+ auto base_val = ::MIR::LValue::new_Return();
if( node.m_base_value )
{
DEBUG("_StructLiteral - base");
@@ -2216,7 +2377,7 @@ namespace {
if( !node.m_base_value) {
ERROR(node.span(), E0000, "Field '" << fields[i].first << "' not specified");
}
- values[i] = ::MIR::LValue::make_Field({ box$( base_val.clone() ), i });
+ values[i] = ::MIR::LValue::new_Field( base_val.clone(), i );
}
else {
// Partial move support will handle dropping the rest?
@@ -2233,13 +2394,18 @@ namespace {
{
TRACE_FUNCTION_F("_StructLiteral");
- TU_MATCH(::HIR::TypeRef::TypePathBinding, (node.m_res_type.m_data.as_Path().binding), (e),
- (Unbound, ),
- (Opaque, ),
- (Enum,
- auto enum_path = node.m_path.clone();
+ ASSERT_BUG(node.span(), node.m_path.m_data.is_Generic(), "_StructLiteral with non-Generic path - " << node.m_path);
+ const auto& ty_path = node.m_path.m_data.as_Generic();
+
+ TU_MATCH_HDRA( (node.m_res_type.m_data.as_Path().binding), {)
+ TU_ARMA(Unbound, _e) {
+ }
+ TU_ARMA(Opaque, _e) {
+ }
+ TU_ARMA(Enum, e) {
+ auto enum_path = ty_path.clone();
enum_path.m_path.m_components.pop_back();
- const auto& var_name = node.m_path.m_path.m_components.back();
+ const auto& var_name = ty_path.m_path.m_components.back();
const auto& enm = *e;
size_t idx = enm.find_variant(var_name);
@@ -2249,7 +2415,7 @@ namespace {
const auto& str = *var_ty.m_data.as_Path().binding.as_Struct();
// Take advantage of the identical generics to cheaply clone/monomorph the path.
- ::HIR::GenericPath struct_path = node.m_path.clone();
+ ::HIR::GenericPath struct_path = ty_path.clone();
struct_path.m_path = var_ty.m_data.as_Path().path.m_data.as_Generic().m_path;
this->visit_sl_inner(node, str, struct_path);
@@ -2264,22 +2430,25 @@ namespace {
static_cast<unsigned>(idx),
mv$(v)
}) );
- ),
- (Union,
+ }
+ TU_ARMA(Union, e) {
BUG(node.span(), "_StructLiteral Union isn't valid?");
- ),
- (Struct,
+ }
+ TU_ARMA(ExternType, e) {
+ BUG(node.span(), "_StructLiteral ExternType isn't valid?");
+ }
+ TU_ARMA(Struct, e) {
if(e->m_data.is_Unit()) {
m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({
- node.m_path.clone(),
+ ty_path.clone(),
{}
}) );
return ;
}
- this->visit_sl_inner(node, *e, node.m_path);
- )
- )
+ this->visit_sl_inner(node, *e, ty_path);
+ }
+ }
}
void visit(::HIR::ExprNode_UnionLiteral& node) override
{
@@ -2391,7 +2560,7 @@ namespace {
else
{
ev.define_vars_from(ptr->span(), arg.first);
- ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i}));
+ ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::new_Argument(i));
}
i ++;
}
@@ -2402,8 +2571,9 @@ namespace {
}
// NOTE: Can't clean up yet, as consteval isn't done
- //MIR_Cleanup(resolve, path, fcn, args, ptr->m_res_type);
- MIR_Validate(resolve, path, fcn, args, ptr->m_res_type);
+ //MIR_Cleanup(resolve, path, fcn, args, ret_ty);
+ //DEBUG("MIR Dump:" << ::std::endl << FMT_CB(ss, MIR_Dump_Fcn(ss, fcn, 1);));
+ MIR_Validate(resolve, path, fcn, args, ret_ty);
if( getenv("MRUSTC_VALIDATE_FULL_EARLY") ) {
MIR_Validate_Full(resolve, path, fcn, args, ptr->m_res_type);
diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp
index 0dcbd65b..c29d6283 100644
--- a/src/mir/from_hir.hpp
+++ b/src/mir/from_hir.hpp
@@ -70,8 +70,8 @@ TAGGED_UNION_EX(VarState, (), Invalid, (
(), (),
(
VarState clone() const;
- bool operator==(VarState& x) const;
- bool operator!=(VarState& x) const { return !(*this == x); }
+ bool operator==(const VarState& x) const;
+ bool operator!=(const VarState& x) const { return !(*this == x); }
)
);
extern ::std::ostream& operator<<(::std::ostream& os, const VarState& x);
@@ -110,7 +110,7 @@ TAGGED_UNION(ScopeType, Owning,
}),
// State which should end up with no mutation of variable states
(Freeze, struct {
- //::std::map<unsigned int,VarState> changed_slots;
+ ::std::map<unsigned int,VarState> changed_slots;
//::std::map<unsigned int,VarState> changed_args;
})
);
@@ -188,13 +188,10 @@ public:
// - Values
::MIR::LValue get_variable(const Span& sp, unsigned idx) const {
- // DIASBLED: State tracking doesn't support arguments in loops/splits
-#if 1
auto it = m_var_arg_mappings.find(idx);
if(it != m_var_arg_mappings.end())
- return ::MIR::LValue::make_Argument({ it->second });
-#endif
- return ::MIR::LValue::make_Local( idx );
+ return ::MIR::LValue::new_Argument(it->second);
+ return ::MIR::LValue::new_Local(idx);
}
::MIR::LValue new_temporary(const ::HIR::TypeRef& ty);
::MIR::LValue lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val);
@@ -224,7 +221,7 @@ public:
// - Statements
// Push an assignment. NOTE: This also marks the rvalue as moved
- void push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val);
+ void push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val, bool drop_destination=true);
// Push a drop (likely only used by scope cleanup)
void push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int drop_flag=~0u);
// Push a shallow drop (for Box)
@@ -296,8 +293,7 @@ private:
const VarState& get_slot_state(const Span& sp, unsigned int idx, SlotType type, unsigned int skip_count=0) const;
VarState& get_slot_state_mut(const Span& sp, unsigned int idx, SlotType type);
- const VarState& get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count=0);
- VarState& get_val_state_mut(const Span& sp, const ::MIR::LValue& lv);
+ VarState* get_val_state_mut_p(const Span& sp, const ::MIR::LValue& lv, bool expect_valid=false);
void terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_loop);
@@ -306,11 +302,11 @@ private:
void complete_scope(ScopeDef& sd);
public:
- void with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb) const;
+ void with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb, const ::MIR::LValue::Wrapper* stop_wrapper=nullptr) const;
bool lvalue_is_copy(const Span& sp, const ::MIR::LValue& lv) const;
// Obtain the base fat poiner for a dst reference. Errors if it wasn't via a fat pointer
- const ::MIR::LValue& get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const;
+ ::MIR::LValue get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const;
};
class MirConverter:
diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp
index b8fabdc0..536842b7 100644
--- a/src/mir/from_hir_match.cpp
+++ b/src/mir/from_hir_match.cpp
@@ -395,6 +395,8 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod
else
{
ac.has_condition = false;
+ ac.cond_start = ~0u;
+ ac.cond_false = ~0u;
}
// Code
@@ -802,6 +804,9 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal
)
)
),
+ (ExternType,
+ TODO(sp, "Match extern type");
+ ),
(Union,
TODO(sp, "Match union");
),
@@ -886,9 +891,10 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal
)
)
}
-void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty)
+void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& top_ty)
{
- TRACE_FUNCTION_F("pat="<<pat<<", ty="<<ty<<", m_field_path=[" << m_field_path << "]");
+ static ::HIR::Pattern empty_pattern;
+ TRACE_FUNCTION_F("pat="<<pat<<", ty="<<top_ty<<", m_field_path=[" << m_field_path << "]");
struct H {
static uint64_t get_pattern_value_int(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::Pattern::Value& val) {
TU_MATCH_DEF( ::HIR::Pattern::Value, (val), (e),
@@ -922,6 +928,16 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
}
};
+ const auto* ty_p = &top_ty;
+ for(size_t i = 0; i < pat.m_implicit_deref_count; i ++)
+ {
+ if( !ty_p->m_data.is_Borrow() )
+ BUG(sp, "Deref step " << i << "/" << pat.m_implicit_deref_count << " hit a non-borrow " << *ty_p << " from " << top_ty);
+ ty_p = &*ty_p->m_data.as_Borrow().inner;
+ m_field_path.push_back( FIELD_DEREF );
+ }
+ const auto& ty = *ty_p;
+
// TODO: Outer handling for Value::Named patterns
// - Convert them into either a pattern, or just a variant of this function that operates on ::HIR::Literal
// > It does need a way of handling unknown-value constants (e.g. <GenericT as Foo>::CONST)
@@ -931,6 +947,10 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
if( pve.binding )
{
this->append_from_lit(sp, pve.binding->m_value_res, ty);
+ for(size_t i = 0; i < pat.m_implicit_deref_count; i ++)
+ {
+ m_field_path.pop_back();
+ }
return ;
}
else
@@ -940,20 +960,23 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
)
)
- TU_MATCHA( (ty.m_data), (e),
- (Infer, BUG(sp, "Ivar for in match type"); ),
- (Diverge,
+ TU_MATCH_HDR( (ty.m_data), {)
+ TU_ARM(ty.m_data, Infer, e) {
+ BUG(sp, "Ivar for in match type");
+ }
+ TU_ARM(ty.m_data, Diverge, e) {
// Since ! can never exist, mark this arm as impossible.
// TODO: Marking as impossible (and not emitting) leads to exhuaustiveness failure.
//this->m_is_impossible = true;
- ),
- (Primitive,
- TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe),
- ( BUG(sp, "Matching primitive with invalid pattern - " << pat); ),
- (Any,
+ }
+ TU_ARM(ty.m_data, Primitive, e) {
+ TU_MATCH_HDR( (pat.m_data), {)
+ default:
+ BUG(sp, "Matching primitive with invalid pattern - " << pat);
+ TU_ARM(pat.m_data, Any, pe) {
this->push_rule( PatternRule::make_Any({}) );
- ),
- (Range,
+ }
+ TU_ARM(pat.m_data, Range, pe) {
switch(e)
{
case ::HIR::CoreType::F32:
@@ -994,8 +1017,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
BUG(sp, "Hit match over `str` - must be `&str`");
break;
}
- ),
- (Value,
+ }
+ TU_ARM(pat.m_data, Value, pe) {
switch(e)
{
case ::HIR::CoreType::F32:
@@ -1035,16 +1058,16 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
BUG(sp, "Hit match over `str` - must be `&str`");
break;
}
- )
- )
- ),
- (Tuple,
+ }
+ }
+ }
+ TU_ARM(ty.m_data, Tuple, e) {
m_field_path.push_back(0);
TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe),
( BUG(sp, "Matching tuple with invalid pattern - " << pat); ),
(Any,
for(const auto& sty : e) {
- this->append_from(sp, pat, sty);
+ this->append_from(sp, empty_pattern, sty);
m_field_path.back() ++;
}
),
@@ -1070,22 +1093,22 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
)
)
m_field_path.pop_back();
- ),
- (Path,
+ }
+ TU_ARM(ty.m_data, Path, e) {
// This is either a struct destructure or an enum
- TU_MATCHA( (e.binding), (pbe),
- (Unbound,
+ TU_MATCH_HDRA( (e.binding), {)
+ TU_ARMA(Unbound, pbe) {
BUG(sp, "Encounterd unbound path - " << e.path);
- ),
- (Opaque,
+ }
+ TU_ARMA(Opaque, be) {
TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe),
( BUG(sp, "Matching opaque type with invalid pattern - " << pat); ),
(Any,
this->push_rule( PatternRule::make_Any({}) );
)
)
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, pbe) {
auto monomorph = [&](const auto& ty) {
auto rv = monomorphise_type(sp, pbe->m_params, e.path.m_data.as_Generic().m_params, ty);
this->m_resolve.expand_associated_types(sp, rv);
@@ -1101,7 +1124,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
(Any,
// _ on a box, recurse into the box type.
m_field_path.push_back(FIELD_DEREF);
- this->append_from(sp, pat, inner_ty);
+ this->append_from(sp, empty_pattern, inner_ty);
m_field_path.pop_back();
),
(Box,
@@ -1132,12 +1155,12 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe),
( BUG(sp, "Match not allowed, " << ty << " with " << pat); ),
(Any,
- // - Recurse into type and use the same pattern again
+ // - Recurse into type using an empty pattern
for(const auto& fld : sd)
{
::HIR::TypeRef tmp;
const auto& sty_mono = (monomorphise_type_needed(fld.ent) ? tmp = monomorph(fld.ent) : fld.ent);
- this->append_from(sp, pat, sty_mono);
+ this->append_from(sp, empty_pattern, sty_mono);
m_field_path.back() ++;
}
),
@@ -1166,7 +1189,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
{
::HIR::TypeRef tmp;
const auto& sty_mono = (monomorphise_type_needed(fld.second.ent) ? tmp = monomorph(fld.second.ent) : fld.second.ent);
- this->append_from(sp, pat, sty_mono);
+ this->append_from(sp, empty_pattern, sty_mono);
m_field_path.back() ++;
}
m_field_path.pop_back();
@@ -1182,8 +1205,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
auto it = ::std::find_if( pe.sub_patterns.begin(), pe.sub_patterns.end(), [&](const auto& x){ return x.first == fld.first; } );
if( it == pe.sub_patterns.end() )
{
- ::HIR::Pattern any_pat {};
- this->append_from(sp, any_pat, sty_mono);
+ this->append_from(sp, empty_pattern, sty_mono);
}
else
{
@@ -1196,11 +1218,24 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
)
)
)
- ),
- (Union,
- TODO(sp, "Match over union - " << ty);
- ),
- (Enum,
+ }
+ TU_ARMA(Union, pbe) {
+ TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe),
+ ( TODO(sp, "Match over union - " << ty << " with " << pat); ),
+ (Any,
+ this->push_rule( PatternRule::make_Any({}) );
+ )
+ )
+ }
+ TU_ARMA(ExternType, pbe) {
+ TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe),
+ ( BUG(sp, "Matching extern type with invalid pattern - " << pat); ),
+ (Any,
+ this->push_rule( PatternRule::make_Any({}) );
+ )
+ )
+ }
+ TU_ARMA(Enum, pbe) {
auto monomorph = [&](const auto& ty) {
auto rv = monomorphise_type(sp, pbe->m_params, e.path.m_data.as_Generic().m_params, ty);
this->m_resolve.expand_associated_types(sp, rv);
@@ -1287,10 +1322,10 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
this->push_rule( PatternRule::make_Variant({ pe.binding_idx, mv$(sub_builder.m_rules) }) );
)
)
- )
- )
- ),
- (Generic,
+ }
+ }
+ }
+ TU_ARM(ty.m_data, Generic, e) {
// Generics don't destructure, so the only valid pattern is `_`
TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe),
( BUG(sp, "Match not allowed, " << ty << " with " << pat); ),
@@ -1298,29 +1333,29 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
this->push_rule( PatternRule::make_Any({}) );
)
)
- ),
- (TraitObject,
+ }
+ TU_ARM(ty.m_data, TraitObject, e) {
if( pat.m_data.is_Any() ) {
}
else {
ERROR(sp, E0000, "Attempting to match over a trait object");
}
- ),
- (ErasedType,
+ }
+ TU_ARM(ty.m_data, ErasedType, e) {
if( pat.m_data.is_Any() ) {
}
else {
ERROR(sp, E0000, "Attempting to match over an erased type");
}
- ),
- (Array,
+ }
+ TU_ARM(ty.m_data, Array, e) {
// Sequential match just like tuples.
m_field_path.push_back(0);
TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe),
( BUG(sp, "Matching array with invalid pattern - " << pat); ),
(Any,
for(unsigned int i = 0; i < e.size_val; i ++) {
- this->append_from(sp, pat, *e.inner);
+ this->append_from(sp, empty_pattern, *e.inner);
m_field_path.back() ++;
}
),
@@ -1336,8 +1371,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
)
)
m_field_path.pop_back();
- ),
- (Slice,
+ }
+ TU_ARM(ty.m_data, Slice, e) {
TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe),
(
BUG(sp, "Matching over [T] with invalid pattern - " << pat);
@@ -1393,18 +1428,19 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
}) );
)
)
- ),
- (Borrow,
+ }
+ TU_ARM(ty.m_data, Borrow, e) {
m_field_path.push_back( FIELD_DEREF );
- TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe),
- ( BUG(sp, "Matching borrow invalid pattern - " << pat); ),
- (Any,
- this->append_from( sp, pat, *e.inner );
- ),
- (Ref,
+ TU_MATCH_HDR( (pat.m_data), {)
+ default:
+ BUG(sp, "Matching borrow invalid pattern - " << ty << " with " << pat);
+ TU_ARM(pat.m_data, Any, pe) {
+ this->append_from( sp, empty_pattern, *e.inner );
+ }
+ TU_ARM(pat.m_data, Ref, pe) {
this->append_from( sp, *pe.sub, *e.inner );
- ),
- (Value,
+ }
+ TU_ARM(pat.m_data, Value, pe) {
// TODO: Check type?
if( pe.val.is_String() ) {
const auto& s = pe.val.as_String();
@@ -1423,32 +1459,36 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa
else {
BUG(sp, "Matching borrow invalid pattern - " << pat);
}
- )
- )
+ }
+ }
m_field_path.pop_back();
- ),
- (Pointer,
+ }
+ TU_ARM(ty.m_data, Pointer, e) {
if( pat.m_data.is_Any() ) {
}
else {
ERROR(sp, E0000, "Attempting to match over a pointer");
}
- ),
- (Function,
+ }
+ TU_ARM(ty.m_data, Function, e) {
if( pat.m_data.is_Any() ) {
}
else {
ERROR(sp, E0000, "Attempting to match over a functon pointer");
}
- ),
- (Closure,
+ }
+ TU_ARM(ty.m_data, Closure, e) {
if( pat.m_data.is_Any() ) {
}
else {
ERROR(sp, E0000, "Attempting to match over a closure");
}
- )
- )
+ }
+ }
+ for(size_t i = 0; i < pat.m_implicit_deref_count; i ++)
+ {
+ m_field_path.pop_back();
+ }
}
namespace {
@@ -1456,7 +1496,7 @@ namespace {
Ordering ord_rule_compatible(const PatternRule& a, const PatternRule& b)
{
if(a.tag() != b.tag())
- return ::ord( (unsigned)a.tag(), b.tag() );
+ return ::ord( (unsigned)a.tag(), (unsigned)b.tag() );
TU_MATCHA( (a, b), (ae, be),
(Any,
@@ -1699,13 +1739,13 @@ namespace {
),
(Tuple,
ASSERT_BUG(sp, idx < e.size(), "Tuple index out of range");
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
cur_ty = &e[idx];
),
(Path,
if( idx == FIELD_DEREF ) {
// TODO: Check that the path is Box
- lval = ::MIR::LValue::make_Deref({ box$(lval) });
+ lval = ::MIR::LValue::new_Deref( mv$(lval) );
cur_ty = &e.path.m_data.as_Generic().m_params.m_types.at(0);
break;
}
@@ -1716,6 +1756,9 @@ namespace {
(Opaque,
BUG(sp, "Destructuring an opaque type - " << *cur_ty);
),
+ (ExternType,
+ BUG(sp, "Destructuring an extern type - " << *cur_ty);
+ ),
(Struct,
// TODO: Should this do a call to expand_associated_types?
auto monomorph = [&](const auto& ty) {
@@ -1737,7 +1780,7 @@ namespace {
else {
cur_ty = &fld.ent;
}
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
),
(Named,
assert( idx < fields.size() );
@@ -1749,7 +1792,7 @@ namespace {
else {
cur_ty = &fld.ent;
}
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
)
)
),
@@ -1768,7 +1811,7 @@ namespace {
else {
cur_ty = &fld.second.ent;
}
- lval = ::MIR::LValue::make_Downcast({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Downcast(mv$(lval), idx);
),
(Enum,
auto monomorph_to_ptr = [&](const auto& ty)->const auto* {
@@ -1788,7 +1831,7 @@ namespace {
const auto& var = variants[idx];
cur_ty = monomorph_to_ptr(var.type);
- lval = ::MIR::LValue::make_Downcast({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Downcast(mv$(lval), idx);
)
)
),
@@ -1805,7 +1848,7 @@ namespace {
assert(idx < e.size_val);
cur_ty = &*e.inner;
if( idx < FIELD_INDEX_MAX )
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
else {
idx -= FIELD_INDEX_MAX;
idx = FIELD_INDEX_MAX - idx;
@@ -1815,16 +1858,16 @@ namespace {
(Slice,
cur_ty = &*e.inner;
if( idx < FIELD_INDEX_MAX )
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
else {
idx -= FIELD_INDEX_MAX;
idx = FIELD_INDEX_MAX - idx;
// 1. Create an LValue containing the size of this slice subtract `idx`
- auto len_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, lval).clone() }));
+ auto len_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, lval) }));
auto sub_val = ::MIR::Param(::MIR::Constant::make_Uint({ idx, ::HIR::CoreType::Usize }));
auto ofs_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_BinOp({ mv$(len_lval), ::MIR::eBinOp::SUB, mv$(sub_val) }) );
// 2. Return _Index with that value
- lval = ::MIR::LValue::make_Index({ box$(lval), box$(ofs_val) });
+ lval = ::MIR::LValue::new_Index(mv$(lval), ofs_val.as_Local());
}
),
(Borrow,
@@ -1838,7 +1881,7 @@ namespace {
cur_ty = &*e.inner;
}
DEBUG(i << " " << *cur_ty);
- lval = ::MIR::LValue::make_Deref({ box$(lval) });
+ lval = ::MIR::LValue::new_Deref(mv$(lval));
),
(Pointer,
ERROR(sp, E0000, "Attempting to match over a pointer");
@@ -1942,14 +1985,14 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
DEBUG("ty = " << ity << ", val = " << val);
const auto& ty = ity;
- TU_MATCHA( (ty.m_data), (te),
- (Infer,
+ TU_MATCH_HDRA( (ty.m_data), {)
+ TU_ARMA(Infer, _te) {
BUG(sp, "Hit _ in type - " << ty);
- ),
- (Diverge,
+ }
+ TU_ARMA(Diverge, _te) {
BUG(sp, "Matching over !");
- ),
- (Primitive,
+ }
+ TU_ARMA(Primitive, te) {
switch(te)
{
case ::HIR::CoreType::Bool: {
@@ -2116,17 +2159,20 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
case ::HIR::CoreType::Str: {
ASSERT_BUG(sp, rule.is_Value() && rule.as_Value().is_StaticString(), "");
const auto& v = rule.as_Value();
+ ASSERT_BUG(sp, val.is_Deref(), "");
+ val.m_wrappers.pop_back();
+ auto str_val = mv$(val);
auto succ_bb = builder.new_bb_unlinked();
auto test_val = ::MIR::Param(::MIR::Constant( v.as_StaticString() ));
- auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(*val.as_Deref().val), ::MIR::eBinOp::EQ, mv$(test_val) }));
+ auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(str_val), ::MIR::eBinOp::EQ, mv$(test_val) }));
builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) );
builder.set_cur_block(succ_bb);
} break;
}
- ),
- (Path,
+ }
+ TU_ARMA(Path, te) {
TU_MATCHA( (te.binding), (pbe),
(Unbound,
BUG(sp, "Encounterd unbound path - " << te.path);
@@ -2151,6 +2197,9 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
(Union,
TODO(sp, "Match over Union");
),
+ (ExternType,
+ TODO(sp, "Match over ExternType");
+ ),
(Enum,
auto monomorph = [&](const auto& ty) {
auto rv = monomorphise_type(sp, pbe->m_params, te.path.m_data.as_Generic().m_params, ty);
@@ -2182,26 +2231,26 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
// Recurse with the new ruleset
MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp,
re.sub_rules.data(), re.sub_rules.size(),
- var_ty_m, ::MIR::LValue::make_Downcast({ box$(val.clone()), var_idx }), rule.field_path.size()+1,
+ var_ty_m, ::MIR::LValue::new_Downcast(val.clone(), var_idx), rule.field_path.size()+1,
fail_bb
);
}
) // TypePathBinding::Enum
)
- ), // Type::Data::Path
- (Generic,
+ } // Type::Data::Path
+ TU_ARMA(Generic, _te) {
BUG(sp, "Attempting to match a generic");
- ),
- (TraitObject,
+ }
+ TU_ARMA(TraitObject, te) {
BUG(sp, "Attempting to match a trait object");
- ),
- (ErasedType,
+ }
+ TU_ARMA(ErasedType, te) {
BUG(sp, "Attempting to match an erased type");
- ),
- (Array,
+ }
+ TU_ARMA(Array, te) {
TODO(sp, "Match directly on array?");
- ),
- (Slice,
+ }
+ TU_ARMA(Slice, te) {
ASSERT_BUG(sp, rule.is_Slice() || rule.is_SplitSlice() || (rule.is_Value() && rule.as_Value().is_Bytes()), "Can only match slice with Bytes or Slice rules - " << rule);
if( rule.is_Value() ) {
ASSERT_BUG(sp, *te.inner == ::HIR::CoreType::U8, "Bytes pattern on non-&[u8]");
@@ -2210,7 +2259,8 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
auto succ_bb = builder.new_bb_unlinked();
- auto inner_val = val.as_Deref().val->clone();
+ ASSERT_BUG(sp, val.is_Deref(), "Slice pattern on non-Deref - " << val);
+ auto inner_val = val.clone_unwrapped();
auto slice_rval = ::MIR::RValue::make_MakeDst({ mv$(cloned_val), mv$(size_val) });
auto test_lval = builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone()), mv$(slice_rval));
@@ -2223,7 +2273,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
// Compare length
auto test_val = ::MIR::Param( ::MIR::Constant::make_Uint({ re.len, ::HIR::CoreType::Usize }) );
- auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val).clone() }));
+ auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val) }));
auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::EQ, mv$(test_val) }));
auto len_succ_bb = builder.new_bb_unlinked();
@@ -2242,7 +2292,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
// Compare length
auto test_val = ::MIR::Param( ::MIR::Constant::make_Uint({ re.min_len, ::HIR::CoreType::Usize}) );
- auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val).clone() }));
+ auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val) }));
auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::LT, mv$(test_val) }));
auto len_succ_bb = builder.new_bb_unlinked();
@@ -2263,23 +2313,23 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
else {
BUG(sp, "Invalid rule type for slice - " << rule);
}
- ),
- (Tuple,
+ } // Type::Data::Array
+ TU_ARMA(Tuple, te) {
TODO(sp, "Match directly on tuple?");
- ),
- (Borrow,
+ }
+ TU_ARMA(Borrow, te) {
TODO(sp, "Match directly on borrow?");
- ), // Type::Data::Borrow
- (Pointer,
+ } // Type::Data::Borrow
+ TU_ARMA(Pointer, te) {
BUG(sp, "Attempting to match a pointer - " << rule << " against " << ty);
- ),
- (Function,
+ }
+ TU_ARMA(Function, te) {
BUG(sp, "Attempting to match a function pointer - " << rule << " against " << ty);
- ),
- (Closure,
+ }
+ TU_ARMA(Closure, te) {
BUG(sp, "Attempting to match a closure");
- )
- )
+ }
+ }
}
return 0;
}
@@ -2780,37 +2830,37 @@ void MatchGenGrouped::gen_dispatch(const ::std::vector<t_rules_subset>& rules, s
// Matching over a path can only happen with an enum.
// TODO: What about `box` destructures?
// - They're handled via hidden derefs
- if( !te.binding.is_Enum() ) {
- TU_MATCHA( (te.binding), (pbe),
- (Unbound,
- BUG(sp, "Encounterd unbound path - " << te.path);
- ),
- (Opaque,
- BUG(sp, "Attempting to match over opaque type - " << ty);
- ),
- (Struct,
- const auto& str_data = pbe->m_data;
- TU_MATCHA( (str_data), (sd),
- (Unit,
- BUG(sp, "Attempting to match over unit type - " << ty);
- ),
- (Tuple,
- TODO(sp, "Matching on tuple-like struct?");
- ),
- (Named,
- TODO(sp, "Matching on struct?");
- )
- )
+ TU_MATCH_HDR( (te.binding), { )
+ TU_ARM(te.binding, Unbound, pbe) {
+ BUG(sp, "Encounterd unbound path - " << te.path);
+ }
+ TU_ARM(te.binding, Opaque, pbe) {
+ BUG(sp, "Attempting to match over opaque type - " << ty);
+ }
+ TU_ARM(te.binding, Struct, pbe) {
+ const auto& str_data = pbe->m_data;
+ TU_MATCHA( (str_data), (sd),
+ (Unit,
+ BUG(sp, "Attempting to match over unit type - " << ty);
),
- (Union,
- TODO(sp, "Match over Union");
+ (Tuple,
+ TODO(sp, "Matching on tuple-like struct?");
),
- (Enum,
+ (Named,
+ TODO(sp, "Matching on struct? - " << ty);
)
)
+ }
+ TU_ARM(te.binding, Union, pbe) {
+ TODO(sp, "Match over Union");
+ }
+ TU_ARM(te.binding, ExternType, pbe) {
+ TODO(sp, "Match over ExternType - " << ty);
+ }
+ TU_ARM(te.binding, Enum, pbe) {
+ this->gen_dispatch__enum(mv$(ty), mv$(val), rules, ofs, arm_targets, def_blk);
+ }
}
-
- this->gen_dispatch__enum(mv$(ty), mv$(val), rules, ofs, arm_targets, def_blk);
),
(Generic,
BUG(sp, "Attempting to match a generic");
@@ -2996,10 +3046,10 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v
}
m_builder.end_block( ::MIR::Terminator::make_Goto(def_blk) );
} break;
- case ::HIR::CoreType::Str:
+ case ::HIR::CoreType::Str: {
// Remove the deref on the &str
- auto oval = mv$(val);
- auto val = mv$(*oval.as_Deref().val);
+ ASSERT_BUG(sp, !val.m_wrappers.empty() && val.m_wrappers.back().is_Deref(), "&str match on non-Deref lvalue - " << val);
+ val.m_wrappers.pop_back();
::std::vector< ::MIR::BasicBlockId> targets;
::std::vector< ::std::string> values;
@@ -3023,7 +3073,7 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v
m_builder.end_block( ::MIR::Terminator::make_SwitchValue({
mv$(val), def_blk, mv$(targets), ::MIR::SwitchValues(mv$(values))
}) );
- break;
+ } break;
}
}
@@ -3061,7 +3111,7 @@ void MatchGenGrouped::gen_dispatch__enum(::HIR::TypeRef ty, ::MIR::LValue val, c
void MatchGenGrouped::gen_dispatch__slice(::HIR::TypeRef ty, ::MIR::LValue val, const ::std::vector<t_rules_subset>& rules, size_t ofs, const ::std::vector<::MIR::BasicBlockId>& arm_targets, ::MIR::BasicBlockId def_blk)
{
- auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val).clone() }));
+ auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val) }));
// TODO: Re-sort the rules list to interleve Constant::Bytes and Slice
@@ -3123,8 +3173,8 @@ void MatchGenGrouped::gen_dispatch__slice(::HIR::TypeRef ty, ::MIR::LValue val,
m_builder.set_cur_block(succ_blk);
// TODO: What if `val` isn't a Deref?
- ASSERT_BUG(sp, val.is_Deref(), "TODO: Handle non-Deref matches of byte strings");
- cmp_lval_eq = this->push_compare( val.as_Deref().val->clone(), ::MIR::eBinOp::EQ, mv$(cmp_slice_val) );
+ ASSERT_BUG(sp, !val.m_wrappers.empty() && val.m_wrappers.back().is_Deref(), "TODO: Handle non-Deref matches of byte strings - " << val);
+ cmp_lval_eq = this->push_compare( val.clone_unwrapped(), ::MIR::eBinOp::EQ, mv$(cmp_slice_val) );
m_builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval_eq), arm_targets[tgt_ofs], def_blk }) );
m_builder.set_cur_block(next_cmp_blk);
@@ -3234,7 +3284,7 @@ void MatchGenGrouped::gen_dispatch_splitslice(const field_path_t& field_path, co
ASSERT_BUG(sp, ty.m_data.is_Slice(), "SplitSlice pattern on non-slice - " << ty);
// Obtain slice length
- auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val).clone() }));
+ auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val) }));
// 1. Check that length is sufficient for the pattern to be used
// `IF len < min_len : def_blk, next
diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp
index 38380fed..6f0ef891 100644
--- a/src/mir/helpers.cpp
+++ b/src/mir/helpers.cpp
@@ -12,9 +12,12 @@
#include <mir/mir.hpp>
#include <algorithm> // ::std::find
-void ::MIR::TypeResolve::fmt_pos(::std::ostream& os) const
+void ::MIR::TypeResolve::fmt_pos(::std::ostream& os, bool include_path/*=false*/) const
{
- os << this->m_path << " BB" << this->bb_idx << "/";
+ if( include_path ) {
+ os << this->m_path << " ";
+ }
+ os << "BB" << this->bb_idx << "/";
if( this->stmt_idx == STMT_TERM ) {
os << "TERM";
}
@@ -27,7 +30,7 @@ void ::MIR::TypeResolve::print_msg(const char* tag, ::std::function<void(::std::
{
auto& os = ::std::cerr;
os << "MIR " << tag << ": ";
- fmt_pos(os);
+ fmt_pos(os, true);
cb(os);
os << ::std::endl;
abort();
@@ -67,25 +70,39 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_static_type(::HIR::TypeRef& tmp, c
)
throw "";
}
-const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val) const
+const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val, unsigned wrapper_skip_count/*=0*/) const
{
- TU_MATCH(::MIR::LValue, (val), (e),
+ const ::HIR::TypeRef* rv = nullptr;
+ TU_MATCHA( (val.m_root), (e),
(Return,
- return m_ret_type;
+ rv = &m_ret_type;
),
(Argument,
- MIR_ASSERT(*this, e.idx < m_args.size(), "Argument " << val << " out of range (" << m_args.size() << ")");
- return m_args.at(e.idx).second;
+ MIR_ASSERT(*this, e < m_args.size(), "Argument " << val << " out of range (" << m_args.size() << ")");
+ rv = &m_args.at(e).second;
),
(Local,
MIR_ASSERT(*this, e < m_fcn.locals.size(), "Local " << val << " out of range (" << m_fcn.locals.size() << ")");
- return m_fcn.locals.at(e);
+ rv = &m_fcn.locals.at(e);
),
(Static,
- return get_static_type(tmp, e);
- ),
- (Field,
- const auto& ty = this->get_lvalue_type(tmp, *e.val);
+ rv = &get_static_type(tmp, e);
+ )
+ )
+ assert(wrapper_skip_count <= val.m_wrappers.size());
+ const auto* stop_wrapper = &val.m_wrappers[ val.m_wrappers.size() - wrapper_skip_count ];
+ for(const auto& w : val.m_wrappers)
+ {
+ if( &w == stop_wrapper )
+ break;
+ rv = &this->get_unwrapped_type(tmp, w, *rv);
+ }
+ return *rv;
+}
+const ::HIR::TypeRef& ::MIR::TypeResolve::get_unwrapped_type(::HIR::TypeRef& tmp, const ::MIR::LValue::Wrapper& w, const ::HIR::TypeRef& ty) const
+{
+ TU_MATCH_HDRA( (w), {)
+ TU_ARMA(Field, field_index) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
MIR_BUG(*this, "Field access on unexpected type - " << ty);
@@ -98,14 +115,14 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
return *te.inner;
),
(Tuple,
- MIR_ASSERT(*this, e.field_index < te.size(), "Field index out of range in tuple " << e.field_index << " >= " << te.size());
- return te[e.field_index];
+ MIR_ASSERT(*this, field_index < te.size(), "Field index out of range in tuple " << field_index << " >= " << te.size());
+ return te[field_index];
),
(Path,
if( const auto* tep = te.binding.opt_Struct() )
{
const auto& str = **tep;
- auto monomorph = [&](const auto& ty)->const auto& {
+ auto maybe_monomorph = [&](const auto& ty)->const auto& {
if( monomorphise_type_needed(ty) ) {
tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, ty);
m_resolve.expand_associated_types(sp, tmp);
@@ -120,12 +137,12 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
MIR_BUG(*this, "Field on unit-like struct - " << ty);
),
(Tuple,
- MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in tuple-struct " << te.path);
- return monomorph(se[e.field_index].ent);
+ MIR_ASSERT(*this, field_index < se.size(), "Field index out of range in tuple-struct " << te.path);
+ return maybe_monomorph(se[field_index].ent);
),
(Named,
- MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in struct " << te.path);
- return monomorph(se[e.field_index].second.ent);
+ MIR_ASSERT(*this, field_index < se.size(), "Field index out of range in struct " << te.path);
+ return maybe_monomorph(se[field_index].second.ent);
)
)
}
@@ -142,8 +159,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
return t;
}
};
- MIR_ASSERT(*this, e.field_index < unm.m_variants.size(), "Field index out of range for union");
- return maybe_monomorph(unm.m_variants.at(e.field_index).second.ent);
+ MIR_ASSERT(*this, field_index < unm.m_variants.size(), "Field index out of range for union");
+ return maybe_monomorph(unm.m_variants.at(field_index).second.ent);
}
else
{
@@ -151,9 +168,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
}
)
)
- ),
- (Deref,
- const auto& ty = this->get_lvalue_type(tmp, *e.val);
+ }
+ TU_ARMA(Deref, _e) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
MIR_BUG(*this, "Deref on unexpected type - " << ty);
@@ -174,9 +190,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
return *te.inner;
)
)
- ),
- (Index,
- const auto& ty = this->get_lvalue_type(tmp, *e.val);
+ }
+ TU_ARMA(Index, index_local) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
MIR_BUG(*this, "Index on unexpected type - " << ty);
@@ -188,9 +203,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
return *te.inner;
)
)
- ),
- (Downcast,
- const auto& ty = this->get_lvalue_type(tmp, *e.val);
+ }
+ TU_ARMA(Downcast, variant_index) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
MIR_BUG(*this, "Downcast on unexpected type - " << ty);
@@ -202,8 +216,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
const auto& enm = *te.binding.as_Enum();
MIR_ASSERT(*this, enm.m_data.is_Data(), "Downcast on non-data enum - " << ty);
const auto& variants = enm.m_data.as_Data();
- MIR_ASSERT(*this, e.variant_index < variants.size(), "Variant index out of range for " << ty);
- const auto& variant = variants[e.variant_index];
+ MIR_ASSERT(*this, variant_index < variants.size(), "Variant index out of range for " << ty);
+ const auto& variant = variants[variant_index];
const auto& var_ty = variant.type;
if( monomorphise_type_needed(var_ty) ) {
@@ -218,12 +232,13 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
else
{
const auto& unm = *te.binding.as_Union();
- MIR_ASSERT(*this, e.variant_index < unm.m_variants.size(), "Variant index out of range");
- const auto& variant = unm.m_variants[e.variant_index];
+ MIR_ASSERT(*this, variant_index < unm.m_variants.size(), "Variant index out of range");
+ const auto& variant = unm.m_variants[variant_index];
const auto& var_ty = variant.second.ent;
+ //return m_resolve.maybe_monomorph(sp, tmp, unm.m_params, te.path.m_data.as_Generic().m_params, var_ty);
if( monomorphise_type_needed(var_ty) ) {
- tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, variant.second.ent);
+ tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, var_ty);
m_resolve.expand_associated_types(sp, tmp);
return tmp;
}
@@ -233,8 +248,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
}
)
)
- )
- )
+ }
+ }
throw "";
}
const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, const ::MIR::Param& val) const
@@ -270,7 +285,7 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons
),
(Const,
MonomorphState p;
- auto v = m_resolve.get_value(this->sp, e.p, p, /*signature_only=*/true);
+ auto v = m_resolve.get_value(this->sp, *e.p, p, /*signature_only=*/true);
if( const auto* ve = v.opt_Constant() ) {
const auto& ty = (*ve)->m_type;
if( monomorphise_type_needed(ty) ) {
@@ -282,12 +297,12 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons
return ty.clone();
}
else {
- MIR_BUG(*this, "get_const_type - Not a constant " << e.p);
+ MIR_BUG(*this, "get_const_type - Not a constant " << *e.p);
}
),
(ItemAddr,
MonomorphState p;
- auto v = m_resolve.get_value(this->sp, e, p, /*signature_only=*/true);
+ auto v = m_resolve.get_value(this->sp, *e, p, /*signature_only=*/true);
TU_MATCHA( (v), (ve),
(NotFound,
MIR_BUG(*this, "get_const_type - ItemAddr points to unknown value - " << c);
@@ -325,7 +340,7 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons
::HIR::FunctionType ft;
ft.is_unsafe = false;
ft.m_abi = ABI_RUST;
- auto enum_path = e.clone();
+ auto enum_path = e->clone();
enum_path.m_data.as_Generic().m_path.m_components.pop_back();
ft.m_rettype = box$( ::HIR::TypeRef::new_path(mv$(enum_path), ve.e) );
ft.m_arg_types.reserve(str_data.size());
@@ -348,7 +363,7 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons
::HIR::FunctionType ft;
ft.is_unsafe = false;
ft.m_abi = ABI_RUST;
- ft.m_rettype = box$( ::HIR::TypeRef::new_path( ::HIR::GenericPath(*ve.p, e.m_data.as_Generic().m_params.clone()), &str) );
+ ft.m_rettype = box$( ::HIR::TypeRef::new_path( ::HIR::GenericPath(*ve.p, e->m_data.as_Generic().m_params.clone()), &str) );
ft.m_arg_types.reserve(str_data.size());
for(const auto& fld : str_data)
ft.m_arg_types.push_back( p.monomorph(this->sp, fld.ent) );
@@ -383,6 +398,15 @@ namespace visit {
{
if( cb(lv, u) )
return true;
+#if 1
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( w.is_Index() )
+ {
+ cb(LValue::new_Local(w.as_Index()), ValUsage::Read);
+ }
+ }
+#else
TU_MATCHA( (lv), (e),
(Return,
),
@@ -408,6 +432,7 @@ namespace visit {
return visit_mir_lvalue(*e.val, u, cb);
)
)
+#endif
return false;
}
@@ -625,32 +650,15 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c
{
auto assigned_lvalue = [&](size_t bb_idx, size_t stmt_idx, const ::MIR::LValue& lv) {
// NOTE: Fills the first statement after running, just to ensure that any assigned value has _a_ lifetime
- if( const auto* de = lv.opt_Local() )
+ if( lv.m_root.is_Local() )
{
- if( !mask || mask->at(*de) )
+ auto de = lv.m_root.as_Local();
+ if( !mask || mask->at(de) )
{
- MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]);
- slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx);
+ MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[de]);
+ slot_lifetimes[de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx);
}
}
- else
- {
- // Not a direct assignment of a slot. But check if a slot is mutated as part of this.
- ::MIR::visit::visit_mir_lvalue(lv, ValUsage::Write, [&](const auto& ilv, ValUsage vu) {
- if( const auto* de = ilv.opt_Local() )
- {
- if( vu == ValUsage::Write )
- {
- if( !mask || mask->at(*de) )
- {
- MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]);
- slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx);
- }
- }
- }
- return false;
- });
- }
};
const auto& bb = fcn.blocks[bb_idx];
@@ -673,11 +681,12 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c
else if( const auto* se = stmt.opt_Drop() )
{
// HACK: Mark values as valid wherever there's a drop (prevents confusion by simple validator)
- if( const auto* de = se->slot.opt_Local() )
+ if( se->slot.m_wrappers.empty() && se->slot.m_root.is_Local() )
{
- if( !mask || mask->at(*de) )
+ auto de = se->slot.m_root.as_Local();
+ if( !mask || mask->at(de) )
{
- slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx);
+ slot_lifetimes[de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx);
}
}
}
diff --git a/src/mir/helpers.hpp b/src/mir/helpers.hpp
index 58eee9b9..0296a1c4 100644
--- a/src/mir/helpers.hpp
+++ b/src/mir/helpers.hpp
@@ -104,7 +104,7 @@ public:
}
unsigned int get_cur_stmt_ofs() const;
- void fmt_pos(::std::ostream& os) const;
+ void fmt_pos(::std::ostream& os, bool include_path=false) const;
void print_bug(::std::function<void(::std::ostream& os)> cb) const {
print_msg("ERROR", cb);
}
@@ -116,7 +116,14 @@ public:
const ::MIR::BasicBlock& get_block(::MIR::BasicBlockId id) const;
const ::HIR::TypeRef& get_static_type(::HIR::TypeRef& tmp, const ::HIR::Path& path) const;
- const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val) const;
+ const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val, unsigned wrapper_skip_count=0) const;
+ const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue::CRef& val) const {
+ return get_lvalue_type(tmp, val.lv(), val.lv().m_wrappers.size() - val.wrapper_count());
+ }
+ const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue::MRef& val) const {
+ return get_lvalue_type(tmp, val.lv(), val.lv().m_wrappers.size() - val.wrapper_count());
+ }
+ const ::HIR::TypeRef& get_unwrapped_type(::HIR::TypeRef& tmp, const ::MIR::LValue::Wrapper& w, const ::HIR::TypeRef& ty) const;
const ::HIR::TypeRef& get_param_type(::HIR::TypeRef& tmp, const ::MIR::Param& val) const;
::HIR::TypeRef get_const_type(const ::MIR::Constant& c) const;
diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp
index 840db1ac..a0def040 100644
--- a/src/mir/mir.cpp
+++ b/src/mir/mir.cpp
@@ -6,6 +6,7 @@
* - MIR (Middle Intermediate Representation) definitions
*/
#include <mir/mir.hpp>
+#include <algorithm> // std::min
namespace MIR {
::std::ostream& operator<<(::std::ostream& os, const Constant& v) {
@@ -44,10 +45,10 @@ namespace MIR {
os << "\"" << FmtEscaped(e) << "\"";
),
(Const,
- os << e.p;
+ os << *e.p;
),
(ItemAddr,
- os << "&" << e;
+ os << "&" << *e;
)
)
return os;
@@ -55,7 +56,7 @@ namespace MIR {
::Ordering Constant::ord(const Constant& b) const
{
if( this->tag() != b.tag() )
- return ::ord( static_cast<unsigned int>(this->tag()), b.tag() );
+ return ::ord( static_cast<unsigned int>(this->tag()), static_cast<unsigned int>(b.tag()) );
TU_MATCHA( (*this,b), (ae,be),
(Int,
if( ae.v != be.v )
@@ -82,128 +83,95 @@ namespace MIR {
return ::ord(ae, be);
),
(Const,
- return ::ord(ae.p, be.p);
+ return ::ord(*ae.p, *be.p);
),
(ItemAddr,
- return ::ord(ae, be);
+ return ::ord(*ae, *be);
)
)
throw "";
}
- ::std::ostream& operator<<(::std::ostream& os, const LValue& x)
+ void LValue::RefCommon::fmt(::std::ostream& os) const
{
- TU_MATCHA( (x), (e),
+ TU_MATCHA( (m_lv->m_root), (e),
(Return,
- os << "Return";
+ os << "retval";
),
(Argument,
- os << "Argument(" << e.idx << ")";
+ os << "a" << e;
),
(Local,
- os << "Local(" << e << ")";
+ os << "_" << e;
),
(Static,
- os << "Static(" << e << ")";
- ),
- (Field,
- os << "Field(" << e.field_index << ", " << *e.val << ")";
- ),
- (Deref,
- os << "Deref(" << *e.val << ")";
- ),
- (Index,
- os << "Index(" << *e.val << ", " << *e.idx << ")";
- ),
- (Downcast,
- os << "Downcast(" << e.variant_index << ", " << *e.val << ")";
+ os << "(" << e << ")";
)
)
+ for(size_t i = 0; i < m_wrapper_count; i ++)
+ {
+ const LValue::Wrapper& w = m_lv->m_wrappers.at(i);
+ TU_MATCHA( (w), (e),
+ (Field,
+ os << "." << e;
+ ),
+ (Deref,
+ os << "*";
+ ),
+ (Index,
+ os << "[_" << e << "]";
+ ),
+ (Downcast,
+ os << "#" << e;
+ )
+ )
+ }
+ }
+
+ ::std::ostream& operator<<(::std::ostream& os, const LValue& x)
+ {
+ LValue::CRef(x).fmt(os);
return os;
}
- bool operator<(const LValue& a, const LValue& b)
+
+ Ordering LValue::Storage::ord(const LValue::Storage& x) const
{
- if( a.tag() != b.tag() )
- return a.tag() < b.tag();
- TU_MATCHA( (a, b), (ea, eb),
- (Return,
- return false;
- ),
- (Argument,
- return ea.idx < eb.idx;
- ),
- (Local,
- return ea < eb;
- ),
- (Static,
- return ea < eb;
- ),
- (Field,
- if( *ea.val != *eb.val )
- return *ea.val < *eb.val;
- if( ea.field_index != eb.field_index )
- return ea.field_index < eb.field_index;
- return true;
- ),
- (Deref,
- return *ea.val < *eb.val;
- ),
- (Index,
- if( *ea.val != *eb.val )
- return *ea.val < *eb.val;
- return *ea.idx < *eb.idx;
- ),
- (Downcast,
- if( *ea.val != *eb.val )
- return *ea.val < *eb.val;
- return ea.variant_index < eb.variant_index;
- )
- )
- throw "";
+ if( x.is_Static() )
+ {
+ if( this->is_Static() )
+ return this->as_Static().ord( x.as_Static() );
+ else
+ return OrdLess;
+ }
+ else
+ {
+ if( this->is_Static() )
+ return OrdGreater;
+ }
+
+ return ::ord(this->val, x.val);
}
- bool operator==(const LValue& a, const LValue& b)
+ Ordering LValue::ord(const LValue& x) const
{
- if( a.tag() != b.tag() )
- return false;
- TU_MATCHA( (a, b), (ea, eb),
- (Return,
- return true;
- ),
- (Argument,
- return ea.idx == eb.idx;
- ),
- (Local,
- return ea == eb;
- ),
- (Static,
- return ea == eb;
- ),
- (Field,
- if( *ea.val != *eb.val )
- return false;
- if( ea.field_index != eb.field_index )
- return false;
- return true;
- ),
- (Deref,
- return *ea.val == *eb.val;
- ),
- (Index,
- if( *ea.val != *eb.val )
- return false;
- if( *ea.idx != *eb.idx )
- return false;
- return true;
- ),
- (Downcast,
- if( *ea.val != *eb.val )
- return false;
- if( ea.variant_index != eb.variant_index )
- return false;
- return true;
- )
- )
- throw "";
+ auto rv = m_root.ord(x.m_root);
+ if( rv != OrdEqual )
+ return rv;
+ return ::ord(m_wrappers, x.m_wrappers);
+ }
+ Ordering LValue::RefCommon::ord(const LValue::RefCommon& x) const
+ {
+ Ordering rv;
+ //TRACE_FUNCTION_FR(FMT_CB(ss, this->fmt(ss); ss << " ? "; x.fmt(ss);), rv);
+ rv = m_lv->m_root.ord(x.m_lv->m_root);
+ if( rv != OrdEqual )
+ return rv;
+ for(size_t i = 0; i < ::std::min(m_wrapper_count, x.m_wrapper_count); i ++)
+ {
+ rv = m_lv->m_wrappers[i].ord(x.m_lv->m_wrappers[i]);
+ if( rv != OrdEqual )
+ return rv;
+ }
+ return (rv = ::ord(m_wrapper_count, x.m_wrapper_count));
}
::std::ostream& operator<<(::std::ostream& os, const Param& x)
@@ -537,30 +505,14 @@ namespace MIR {
}
}
-::MIR::LValue MIR::LValue::clone() const
+::MIR::LValue::Storage MIR::LValue::Storage::clone() const
{
- TU_MATCHA( (*this), (e),
- (Return, return LValue(e); ),
- (Argument, return LValue(e); ),
- (Local, return LValue(e); ),
- (Static, return LValue(e.clone()); ),
- (Field, return LValue::make_Field({
- box$( e.val->clone() ),
- e.field_index
- }); ),
- (Deref, return LValue::make_Deref({
- box$( e.val->clone() )
- }); ),
- (Index, return LValue::make_Index({
- box$( e.val->clone() ),
- box$( e.idx->clone() )
- }); ),
- (Downcast, return LValue::make_Downcast({
- box$( e.val->clone() ),
- e.variant_index
- }); )
- )
- throw "";
+ if( is_Static() ) {
+ return new_Static(as_Static().clone());
+ }
+ else {
+ return Storage(this->val);
+ }
}
::MIR::Constant MIR::Constant::clone() const
{
@@ -571,8 +523,8 @@ namespace MIR {
(Bool, return ::MIR::Constant(e2); ),
(Bytes, return ::MIR::Constant(e2); ),
(StaticString, return ::MIR::Constant(e2); ),
- (Const, return ::MIR::Constant::make_Const({e2.p.clone()}); ),
- (ItemAddr, return ::MIR::Constant(e2.clone()); )
+ (Const, return ::MIR::Constant::make_Const({box$(e2.p->clone())}); ),
+ (ItemAddr, return ::MIR::Constant(box$(e2->clone())); )
)
throw "";
}
diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp
index 31eb9cd7..99698134 100644
--- a/src/mir/mir.hpp
+++ b/src/mir/mir.hpp
@@ -12,49 +12,395 @@
#include <memory> // std::unique_ptr
#include <hir/type.hpp>
+class MonomorphState;
+
namespace MIR {
typedef unsigned int RegionId;
typedef unsigned int BasicBlockId;
-// "LVALUE" - Assignable values
-TAGGED_UNION_EX(LValue, (), Return, (
- // Function return
- (Return, struct{}),
- // Function argument (input)
- (Argument, struct { unsigned int idx; }),
- // Variable/Temporary
- (Local, unsigned int),
- // `static` or `static mut`
- (Static, ::HIR::Path),
- // Field access (tuple, struct, tuple struct, enum field, ...)
- // NOTE: Also used to index an array/slice by a compile-time known index (e.g. in destructuring)
- (Field, struct {
- ::std::unique_ptr<LValue> val;
- unsigned int field_index;
- }),
- // Dereference a value
- (Deref, struct {
- ::std::unique_ptr<LValue> val;
- }),
- // Index an array or slice (typeof(val) == [T; n] or [T])
- // NOTE: This is not bounds checked!
- (Index, struct {
- ::std::unique_ptr<LValue> val;
- ::std::unique_ptr<LValue> idx;
- }),
- // Interpret an enum as a particular variant
- (Downcast, struct {
- ::std::unique_ptr<LValue> val;
- unsigned int variant_index;
- })
- ), (),(), (
- LValue clone() const;
- )
- );
+// Store LValues as:
+// - A packed root value (one word, using the low bits as an enum descriminator)
+// - A list of (inner to outer) wrappers
+struct LValue
+{
+ class Storage
+ {
+ public:
+ const static uintptr_t MAX_ARG = (1 << 30) - 1; // max value of 30 bits
+ private:
+
+ uintptr_t val;
+
+ Storage(uintptr_t v): val(v) {}
+ public:
+ Storage(const Storage&) = delete;
+ Storage& operator=(const Storage&) = delete;
+ Storage(Storage&& x)
+ :val(x.val)
+ {
+ x.val = 0;
+ }
+ Storage& operator=(Storage&& x)
+ {
+ this->~Storage();
+ this->val = x.val;
+ x.val = 0;
+ return *this;
+ }
+ ~Storage()
+ {
+ if( is_Static() ) {
+ delete reinterpret_cast<::HIR::Path*>(val & ~3ull);
+ val = 0;
+ }
+ }
+
+ static Storage new_Return() { return Storage(0 << 2); }
+ static Storage new_Argument(unsigned idx) { assert(idx < MAX_ARG); return Storage((idx+1) << 2); }
+ static Storage new_Local(unsigned idx) { assert(idx <= MAX_ARG); return Storage((idx << 2) | 1); }
+ static Storage new_Static(::HIR::Path p) {
+ ::HIR::Path* ptr = new ::HIR::Path(::std::move(p));
+ return Storage(reinterpret_cast<uintptr_t>(ptr) | 2);
+ }
+
+ Storage clone() const;
+
+ uintptr_t get_inner() const {
+ assert(!is_Static());
+ return val;
+ }
+ static Storage from_inner(uintptr_t v) {
+ assert( (v & 3) < 2 );
+ return Storage(v);
+ }
+
+ enum Tag {
+ TAG_Argument,
+ TAG_Local,
+ TAG_Static,
+ TAG_Return,
+ TAGDEAD,
+ };
+ Tag tag() const {
+ if(val == 0)
+ return TAG_Return;
+ return static_cast<Tag>(val & 3);
+ }
+
+ bool is_Return() const { return val == 0; }
+ bool is_Argument() const { return val != 0 && (val & 3) == 0; }
+ bool is_Local() const { return (val & 3) == 1; }
+ bool is_Static() const { return (val & 3) == 2; }
+
+ const char as_Return () const { assert(is_Return()); return 0; }
+ const unsigned as_Argument() const { assert(is_Argument()); return (val >> 2) - 1; }
+ const unsigned as_Local () const { assert(is_Local()); return val >> 2; }
+
+ const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast<const ::HIR::Path*>(val & ~3llu); }
+ ::HIR::Path& as_Static() { assert(is_Static()); return *reinterpret_cast< ::HIR::Path*>(val & ~3llu); }
+
+ Ordering ord(const Storage& x) const;
+ bool operator==(const Storage& x) const { return this->ord(x) == OrdEqual; }
+ bool operator!=(const Storage& x) const { return this->ord(x) != OrdEqual; }
+ };
+ class Wrapper
+ {
+ uint32_t val;
+ Wrapper(uint32_t v): val(v) {}
+ public:
+ static Wrapper new_Deref() { return Wrapper( 0 ); }
+ static Wrapper new_Field (unsigned idx) { return Wrapper( (idx << 2) | 1 ); }
+ static Wrapper new_Downcast(unsigned idx) { return Wrapper( (idx << 2) | 2 ); }
+ static Wrapper new_Index (unsigned idx) { if(idx == ~0u) idx = Storage::MAX_ARG; return Wrapper( (idx << 2) | 3 ); }
+
+ uint32_t get_inner() const { return val; }
+ static Wrapper from_inner(uint32_t v) {
+ return Wrapper(v);
+ }
+
+ enum Tag {
+ TAG_Deref,
+ TAG_Field,
+ TAG_Downcast,
+ TAG_Index,
+ TAGDEAD,
+ };
+ Tag tag() const {
+ return static_cast<Tag>(val & 3);
+ }
+
+ bool is_Deref () const { return (val & 3) == 0; }
+ // Stores the field index
+ bool is_Field () const { return (val & 3) == 1; }
+ // Stores the variant index
+ bool is_Downcast() const { return (val & 3) == 2; }
+ // Stores a Local index
+ bool is_Index () const { return (val & 3) == 3; }
+
+ const char as_Deref () const { assert(is_Deref()); return 0; }
+ const unsigned as_Field () const { assert(is_Field()); return (val >> 2); }
+ const unsigned as_Downcast() const { assert(is_Downcast()); return (val >> 2); }
+ // TODO: Should this return a LValue?
+ const unsigned as_Index () const { assert(is_Index()); unsigned rv = (val >> 2); return rv; }
+
+ void inc_Field () { assert(is_Field ()); *this = Wrapper::new_Field (as_Field () + 1); }
+ void inc_Downcast() { assert(is_Downcast()); *this = Wrapper::new_Downcast(as_Downcast() + 1); }
+
+ Ordering ord(const Wrapper& x) const { return ::ord(val, x.val); }
+ };
+
+ Storage m_root;
+ ::std::vector<Wrapper> m_wrappers;
+
+ LValue()
+ :m_root( Storage::new_Return() )
+ {
+ }
+ LValue(Storage root, ::std::vector<Wrapper> wrappers)
+ :m_root( ::std::move(root) )
+ ,m_wrappers( ::std::move(wrappers) )
+ {
+ }
+
+ static LValue new_Return () { return LValue(Storage::new_Return(), {}); }
+ static LValue new_Argument(unsigned idx ) { return LValue(Storage::new_Argument(idx), {}); }
+ static LValue new_Local (unsigned idx ) { return LValue(Storage::new_Local(idx), {}); }
+ static LValue new_Static (::HIR::Path p) { return LValue(Storage::new_Static(::std::move(p)), {}); }
+
+ static LValue new_Deref(LValue lv) { lv.m_wrappers.push_back(Wrapper::new_Deref()); return lv; }
+ static LValue new_Field(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Field(idx)); return lv; }
+ static LValue new_Downcast(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Downcast(idx)); return lv; }
+ static LValue new_Index(LValue lv, unsigned local_idx) { lv.m_wrappers.push_back(Wrapper::new_Index(local_idx)); return lv; }
+
+ bool is_Return() const { return m_wrappers.empty() && m_root.is_Return(); }
+ bool is_Local () const { return m_wrappers.empty() && m_root.is_Local(); }
+ const unsigned as_Local() const { assert(m_wrappers.empty()); return m_root.as_Local(); }
+
+ bool is_Deref () const { return m_wrappers.size() > 0 && m_wrappers.back().is_Deref(); }
+ bool is_Field () const { return m_wrappers.size() > 0 && m_wrappers.back().is_Field(); }
+ bool is_Downcast() const { return m_wrappers.size() > 0 && m_wrappers.back().is_Downcast(); }
+ const unsigned as_Field() const { assert(!m_wrappers.empty()); return m_wrappers.back().as_Field(); }
+
+ void inc_Field () { assert(m_wrappers.size() > 0); m_wrappers.back().inc_Field (); }
+ void inc_Downcast() { assert(m_wrappers.size() > 0); m_wrappers.back().inc_Downcast(); }
+
+ Ordering ord(const LValue& x) const;
+
+ LValue monomorphise(const MonomorphState& ms, unsigned local_offset=0);
+ //LValue monomorphise(const TransParams& ms, unsigned local_offset=0);
+ LValue clone() const {
+ return LValue(m_root.clone(), m_wrappers);
+ }
+ LValue clone_wrapped(::std::vector<Wrapper> wrappers) const {
+ if( this->m_wrappers.empty() ) {
+ return LValue(m_root.clone(), ::std::move(wrappers));
+ }
+ else {
+ return clone_wrapped(wrappers.begin(), wrappers.end());
+ }
+ }
+ template<typename It>
+ LValue clone_wrapped(It begin_it, It end_it) const {
+ ::std::vector<Wrapper> wrappers;
+ wrappers.reserve(m_wrappers.size() + ::std::distance(begin_it, end_it));
+ wrappers.insert(wrappers.end(), m_wrappers.begin(), m_wrappers.end());
+ wrappers.insert(wrappers.end(), begin_it, end_it);
+ return LValue(m_root.clone(), ::std::move(wrappers));
+ }
+
+ LValue clone_unwrapped(unsigned count=1) const {
+ assert(count > 0);
+ assert(count <= m_wrappers.size());
+ return LValue(m_root.clone(), ::std::vector<Wrapper>(m_wrappers.begin(), m_wrappers.end() - count));
+ }
+
+ /// Helper class that represents a LValue unwrapped to a certain degree
+ class RefCommon
+ {
+ protected:
+ const LValue* m_lv;
+ size_t m_wrapper_count;
+
+ RefCommon(const LValue& lv, size_t wrapper_count)
+ :m_lv(&lv)
+ ,m_wrapper_count(wrapper_count)
+ {
+ assert(wrapper_count <= lv.m_wrappers.size());
+ }
+
+ public:
+ LValue clone() const {
+ return ::MIR::LValue( m_lv->m_root.clone(), ::std::vector<Wrapper>(m_lv->m_wrappers.begin(), m_lv->m_wrappers.begin() + m_wrapper_count) );
+ }
+
+ const LValue& lv() const { return *m_lv; }
+ size_t wrapper_count() const { return m_wrapper_count; }
+
+ /// Unwrap one level, returning false if already at the root
+ bool try_unwrap() {
+ if( m_wrapper_count == 0 ) {
+ return false;
+ }
+ else {
+ m_wrapper_count --;
+ return true;
+ }
+ }
+
+ enum Tag {
+ TAGDEAD,
+ TAG_Return,
+ TAG_Argument,
+ TAG_Local,
+ TAG_Static,
+ TAG_Deref,
+ TAG_Field,
+ TAG_Downcast,
+ TAG_Index,
+ };
+ Tag tag() const {
+ if( m_wrapper_count == 0 )
+ {
+ switch(m_lv->m_root.tag())
+ {
+ case Storage::TAGDEAD: return TAGDEAD;
+ case Storage::TAG_Return: return TAG_Return;
+ case Storage::TAG_Argument: return TAG_Argument;
+ case Storage::TAG_Local: return TAG_Local;
+ case Storage::TAG_Static: return TAG_Static;
+ }
+ }
+ else
+ {
+ switch(m_lv->m_wrappers[m_wrapper_count-1].tag())
+ {
+ case Wrapper::TAGDEAD: return TAGDEAD;
+ case Wrapper::TAG_Deref: return TAG_Deref;
+ case Wrapper::TAG_Field: return TAG_Field;
+ case Wrapper::TAG_Downcast: return TAG_Downcast;
+ case Wrapper::TAG_Index: return TAG_Index;
+ }
+ }
+ return TAGDEAD;
+ }
+
+ bool is_Local () const { return m_wrapper_count == 0 && m_lv->m_root.is_Local (); }
+ bool is_Return () const { return m_wrapper_count == 0 && m_lv->m_root.is_Return (); }
+ bool is_Argument() const { return m_wrapper_count == 0 && m_lv->m_root.is_Argument(); }
+ bool is_Static () const { return m_wrapper_count == 0 && m_lv->m_root.is_Static (); }
+ bool is_Deref () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Deref (); }
+ bool is_Field () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Field (); }
+ bool is_Downcast() const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Downcast(); }
+ bool is_Index () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Index (); }
+
+ const unsigned as_Local () const { assert(is_Local ()); return m_lv->m_root.as_Local (); }
+ const char as_Return () const { assert(is_Return ()); return m_lv->m_root.as_Return (); }
+ const unsigned as_Argument() const { assert(is_Argument()); return m_lv->m_root.as_Argument(); }
+ const HIR::Path& as_Static () const { assert(is_Static ()); return m_lv->m_root.as_Static (); }
+ const char as_Deref () const { assert(is_Deref ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Deref (); }
+ const unsigned as_Field () const { assert(is_Field ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Field (); }
+ const unsigned as_Downcast() const { assert(is_Downcast()); return m_lv->m_wrappers[m_wrapper_count-1].as_Downcast(); }
+ const unsigned as_Index () const { assert(is_Index ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Index (); }
+
+ void fmt(::std::ostream& os) const;
+ Ordering ord(const RefCommon& b) const;
+ };
+
+ class CRef: public RefCommon
+ {
+ public:
+ CRef(const LValue& lv)
+ :RefCommon(lv, lv.m_wrappers.size())
+ {
+ }
+ CRef(const LValue& lv, size_t wc)
+ :RefCommon(lv, wc)
+ {
+ }
+
+ /// Unwrap one level
+ const CRef inner_ref() const {
+ assert(m_wrapper_count > 0);
+ auto rv = *this;
+ rv.m_wrapper_count--;
+ return rv;
+ }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const CRef& x) {
+ x.fmt(os);
+ return os;
+ }
+
+ bool operator<(const CRef& b) const {
+ return this->ord(b) == OrdLess;
+ }
+ bool operator==(const CRef& b) const {
+ return this->ord(b) == OrdEqual;
+ }
+ };
+ class MRef: public RefCommon
+ {
+ public:
+ MRef(LValue& lv)
+ :RefCommon(lv, lv.m_wrappers.size())
+ {
+ }
+
+ operator CRef() const {
+ return CRef(*m_lv, m_wrapper_count);
+ }
+
+ MRef inner_ref() {
+ assert(m_wrapper_count > 0);
+ auto rv = *this;
+ rv.m_wrapper_count--;
+ return rv;
+ }
+ void replace(LValue x) {
+ auto& mut_lv = const_cast<LValue&>(*m_lv);
+ // Shortcut: No wrappers on source/destination (just assign the slot/root)
+ if( m_wrapper_count == 0 && x.m_wrappers.empty() ) {
+ mut_lv.m_root = ::std::move(x.m_root);
+ return ;
+ }
+ // If there's wrappers on this value (assigning over inner portion)
+ if( m_wrapper_count < m_lv->m_wrappers.size() ) {
+ // Add those wrappers to the end of the new value
+ x.m_wrappers.insert(x.m_wrappers.end(), m_lv->m_wrappers.begin() + m_wrapper_count, m_lv->m_wrappers.end());
+ }
+ // Overwrite
+ mut_lv = ::std::move(x);
+ }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const MRef& x) {
+ x.fmt(os);
+ return os;
+ }
+ };
+
+ Ordering ord(const LValue::CRef& x) const;
+ Ordering ord(const LValue::MRef& x) const;
+};
extern ::std::ostream& operator<<(::std::ostream& os, const LValue& x);
-extern bool operator<(const LValue& a, const LValue& b);
-extern bool operator==(const LValue& a, const LValue& b);
+static inline bool operator<(const LValue& a, const LValue::CRef& b) {
+ return a.ord(b) == OrdLess;
+}
+static inline bool operator<(const LValue& a, const LValue::MRef& b) {
+ return a.ord(b) == OrdLess;
+}
+static inline bool operator<(const LValue::CRef& a, const LValue& b) {
+ return b.ord(a) == OrdGreater;
+}
+static inline bool operator<(const LValue::MRef& a, const LValue& b) {
+ return b.ord(a) == OrdGreater;
+}
+static inline bool operator<(const LValue& a, const LValue& b) {
+ return a.ord(b) == OrdLess;
+}
+static inline bool operator==(const LValue& a, const LValue& b) {
+ return a.ord(b) == OrdEqual;
+}
static inline bool operator!=(const LValue& a, const LValue& b) {
return !(a == b);
}
@@ -103,8 +449,10 @@ TAGGED_UNION_EX(Constant, (), Int, (
}),
(Bytes, ::std::vector< ::std::uint8_t>), // Byte string
(StaticString, ::std::string), // String
- (Const, struct { ::HIR::Path p; }), // `const`
- (ItemAddr, ::HIR::Path) // address of a value
+ // NOTE: These are behind pointers to save inline space (HIR::Path is ~11
+ // words, compared to 4 for MIR::Constant without it)
+ (Const, struct { ::std::unique_ptr<::HIR::Path> p; }), // `const`
+ (ItemAddr, ::std::unique_ptr<::HIR::Path>) // address of a value
), (), (), (
friend ::std::ostream& operator<<(::std::ostream& os, const Constant& v);
::Ordering ord(const Constant& b) const;
@@ -120,7 +468,7 @@ TAGGED_UNION_EX(Constant, (), Int, (
/// Parameter - A value used when a rvalue just reads (doesn't require a lvalue)
/// Can be either a lvalue (memory address), or a constant
-TAGGED_UNION_EX(Param, (), LValue, (
+TAGGED_UNION_EX(Param, (), Constant, (
(LValue, LValue),
(Constant, Constant)
), (), (), (
@@ -133,7 +481,7 @@ TAGGED_UNION_EX(Param, (), LValue, (
)
);
-TAGGED_UNION_EX(RValue, (), Use, (
+TAGGED_UNION_EX(RValue, (), Tuple, (
(Use, LValue),
(Constant, Constant),
(SizedArray, struct {
@@ -207,7 +555,7 @@ TAGGED_UNION(CallTarget, Intrinsic,
(Value, LValue),
(Path, ::HIR::Path),
(Intrinsic, struct {
- ::std::string name;
+ RcString name;
::HIR::PathParams params;
})
);
@@ -255,7 +603,7 @@ enum class eDropKind {
SHALLOW,
DEEP,
};
-TAGGED_UNION(Statement, Assign,
+TAGGED_UNION(Statement, Asm,
// Value assigment
(Assign, struct {
LValue dst;
@@ -298,14 +646,30 @@ struct BasicBlock
};
+struct EnumCache; // Defined in trans/enumerate.cpp
+class EnumCachePtr
+{
+ const EnumCache* p;
+public:
+ EnumCachePtr(const EnumCache* p=nullptr): p(p) {}
+ ~EnumCachePtr();
+ EnumCachePtr(EnumCachePtr&& x): p(x.p) { x.p = nullptr; }
+ EnumCachePtr& operator=(EnumCachePtr&& x) { this->~EnumCachePtr(); p = x.p; x.p = nullptr; return *this; }
+ operator bool() { return p != nullptr; }
+ const EnumCache& operator*() const { return *p; }
+ const EnumCache* operator->() const { return p; }
+};
class Function
{
public:
::std::vector< ::HIR::TypeRef> locals;
- //::std::vector< ::std::string> local_names;
+ //::std::vector< RcString> local_names;
::std::vector<bool> drop_flags;
::std::vector<BasicBlock> blocks;
+
+ // Cache filled/used by enumerate
+ mutable EnumCachePtr trans_enum_state;
};
};
diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp
index 3e14ce66..96833609 100644
--- a/src/mir/mir_builder.cpp
+++ b/src/mir/mir_builder.cpp
@@ -68,7 +68,7 @@ MirBuilder::~MirBuilder()
{
if( has_result() )
{
- push_stmt_assign( sp, ::MIR::LValue::make_Return({}), get_result(sp) );
+ push_stmt_assign( sp, ::MIR::LValue::new_Return(), get_result(sp) );
}
terminate_scope_early(sp, fcn_scope());
@@ -176,7 +176,7 @@ void MirBuilder::define_variable(unsigned int idx)
auto& tmp_scope = top_scope->data.as_Owning();
assert(tmp_scope.is_temporary);
tmp_scope.slots.push_back( rv );
- return ::MIR::LValue::make_Local(rv);
+ return ::MIR::LValue::new_Local(rv);
}
::MIR::LValue MirBuilder::lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val)
{
@@ -258,12 +258,10 @@ void MirBuilder::set_result(const Span& sp, ::MIR::RValue val)
m_result_valid = true;
}
-void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val)
+void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val, bool drop_destination/*=true*/)
{
DEBUG(dst << " = " << val);
ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block");
- ASSERT_BUG(sp, dst.tag() != ::MIR::LValue::TAGDEAD, "");
- ASSERT_BUG(sp, val.tag() != ::MIR::RValue::TAGDEAD, "");
auto moved_param = [&](const ::MIR::Param& p) {
if(const auto* e = p.opt_LValue()) {
@@ -340,13 +338,15 @@ void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RVal
)
// Drop target if populated
- mark_value_assigned(sp, dst);
+ if( drop_destination )
+ {
+ mark_value_assigned(sp, dst);
+ }
this->push_stmt( sp, ::MIR::Statement::make_Assign({ mv$(dst), mv$(val) }) );
}
void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/)
{
ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block");
- ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, "");
if( lvalue_is_copy(sp, val) ) {
// Don't emit a drop for Copy values
@@ -358,7 +358,6 @@ void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int
void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/)
{
ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block");
- ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, "");
// TODO: Ensure that the type is a Box?
@@ -396,21 +395,12 @@ void MirBuilder::push_stmt(const Span& sp, ::MIR::Statement stmt)
void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst)
{
- VarState* state_p = nullptr;
- TU_MATCH_DEF(::MIR::LValue, (dst), (e),
- (
- ),
- (Return,
- // Don't drop.
- // No state tracking for the return value
- ),
- (Argument,
- state_p = &get_slot_state_mut(sp, e.idx, SlotType::Argument);
- ),
- (Local,
- state_p = &get_slot_state_mut(sp, e, SlotType::Local);
- )
- )
+ if( dst.m_root.is_Return() )
+ {
+ ASSERT_BUG(sp, dst.m_wrappers.empty(), "Assignment to a component of the return value should be impossible.");
+ return ;
+ }
+ VarState* state_p = get_val_state_mut_p(sp, dst, /*expect_valid=*/true);
if( state_p )
{
@@ -420,41 +410,28 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst)
drop_value_from_state(sp, *state_p, dst.clone());
*state_p = VarState::make_Valid({});
}
+ else
+ {
+ // Assigning into non-tracked locations still causes a drop
+ drop_value_from_state(sp, VarState::make_Valid({}), dst.clone());
+ }
}
void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above/*=false*/)
{
TRACE_FUNCTION_F(val);
- TU_MATCH_DEF(::MIR::LValue, (val), (e),
- (
+ for(const auto& w : val.m_wrappers)
+ {
+ if( w.is_Index() ) {
+ // Raise index temporary
+ raise_temporaries(sp, ::MIR::LValue::new_Local(w.as_Index()), scope, to_above);
+ }
+ }
+ if( !val.m_root.is_Local() ) {
// No raising of these source values?
return ;
- ),
- // TODO: This may not be correct, because it can change the drop points and ordering
- // HACK: Working around cases where values are dropped while the result is not yet used.
- (Index,
- raise_temporaries(sp, *e.val, scope, to_above);
- raise_temporaries(sp, *e.idx, scope, to_above);
- return ;
- ),
- (Deref,
- raise_temporaries(sp, *e.val, scope, to_above);
- return ;
- ),
- (Field,
- raise_temporaries(sp, *e.val, scope, to_above);
- return ;
- ),
- (Downcast,
- raise_temporaries(sp, *e.val, scope, to_above);
- return ;
- ),
- // Actual value types
- (Local,
- )
- )
- ASSERT_BUG(sp, val.is_Local(), "Hit value raising code with non-variable value - " << val);
- const auto idx = val.as_Local();
+ }
+ const auto idx = val.m_root.as_Local();
bool is_temp = (idx >= m_first_temp_idx);
/*
if( !is_temp ) {
@@ -827,13 +804,12 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle
}
auto& src_scope_def = m_scopes.at(source.idx);
-#if 1
ASSERT_BUG(sp, src_scope_def.data.is_Owning(), "Rasising scopes can only be done on temporaries (source)");
ASSERT_BUG(sp, src_scope_def.data.as_Owning().is_temporary, "Rasising scopes can only be done on temporaries (source)");
auto& src_list = src_scope_def.data.as_Owning().slots;
for(auto idx : src_list)
{
- DEBUG("> Raising " << ::MIR::LValue::make_Local(idx));
+ DEBUG("> Raising " << ::MIR::LValue::new_Local(idx));
assert(idx >= m_first_temp_idx);
}
@@ -904,13 +880,6 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle
// Move all defined variables from one to the other
auto& tgt_list = tgt_scope_def.data.as_Owning().slots;
tgt_list.insert( tgt_list.end(), src_list.begin(), src_list.end() );
-#else
- auto list = src_scope_def.data.as_Temporaries().temporaries;
- for(auto idx : list)
- {
- this->raise_temporaries(sp, ::MIR::LValue::make_Temporary({ idx }), target);
- }
-#endif
// Scope completed
m_scope_stack.pop_back();
@@ -973,7 +942,7 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope,
for(size_t i = 0; i < m_arg_states.size(); i ++)
{
const auto& state = get_slot_state(sp, i, SlotType::Argument);
- this->drop_value_from_state(sp, state, ::MIR::LValue::make_Argument({ static_cast<unsigned>(i) }));
+ this->drop_value_from_state(sp, state, ::MIR::LValue::new_Argument(static_cast<unsigned>(i)));
}
}
}
@@ -1054,7 +1023,7 @@ namespace
});
if( is_box )
{
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state);
}
else
{
@@ -1080,13 +1049,13 @@ namespace
if( is_enum ) {
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
- merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)), ose.inner_states[i], nse.inner_states[i]);
}
}
else {
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
- merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]);
}
}
} return;
@@ -1162,7 +1131,7 @@ namespace
});
if( is_box ) {
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state);
}
else {
BUG(sp, "MovedOut on non-Box");
@@ -1186,19 +1155,19 @@ namespace
}
auto& ose = old_state.as_Partial();
if( is_enum ) {
- auto ilv = ::MIR::LValue::make_Downcast({ box$(lv.clone()), 0 });
+ auto ilv = ::MIR::LValue::new_Downcast(lv.clone(), 0);
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
merge_state(sp, builder, ilv, ose.inner_states[i], nse.inner_states[i]);
- ilv.as_Downcast().variant_index ++;
+ ilv.inc_Downcast();
}
}
else {
- auto ilv = ::MIR::LValue::make_Field({ box$(lv.clone()), 0 });
+ auto ilv = ::MIR::LValue::new_Field(lv.clone(), 0);
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
merge_state(sp, builder, ilv, ose.inner_states[i], nse.inner_states[i]);
- ilv.as_Field().field_index ++;
+ ilv.inc_Field();
}
}
} return;
@@ -1262,13 +1231,13 @@ namespace
if( is_enum ) {
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
- merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)), ose.inner_states[i], nse.inner_states[i]);
}
}
else {
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
- merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]);
}
}
return; }
@@ -1303,7 +1272,7 @@ namespace
builder.push_stmt_set_dropflag_val(sp, ose.outer_flag, is_valid);
}
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, new_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, new_state);
return ; }
case VarState::TAG_Optional: {
const auto& nse = new_state.as_Optional();
@@ -1328,7 +1297,7 @@ namespace
builder.push_stmt_set_dropflag_other(sp, ose.outer_flag, nse);
builder.push_stmt_set_dropflag_default(sp, nse);
}
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, new_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, new_state);
return; }
case VarState::TAG_MovedOut: {
const auto& nse = new_state.as_MovedOut();
@@ -1336,7 +1305,7 @@ namespace
{
TODO(sp, "Handle mismatched flags in MovedOut");
}
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state);
return; }
case VarState::TAG_Partial:
BUG(sp, "MovedOut->Partial not valid");
@@ -1360,13 +1329,13 @@ namespace
if( is_enum ) {
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
- merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }), ose.inner_states[i], new_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)), ose.inner_states[i], new_state);
}
}
else {
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
- merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], new_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], new_state);
}
}
return ;
@@ -1378,13 +1347,13 @@ namespace
if( is_enum ) {
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
- merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)), ose.inner_states[i], nse.inner_states[i]);
}
}
else {
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
- merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]);
}
}
} return ;
@@ -1413,8 +1382,8 @@ void MirBuilder::terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_l
merge_state(sp, *this, val_cb(idx), old_state, get_slot_state(sp, idx, type));
}
};
- merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::make_Local, SlotType::Local);
- merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::make_Argument({v}); }, SlotType::Argument);
+ merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::new_Local, SlotType::Local);
+ merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::new_Argument(v); }, SlotType::Argument);
}
else
{
@@ -1469,7 +1438,7 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r
auto it = states.find(idx);
const auto& src_state = (it != states.end() ? it->second : get_slot_state(sp, idx, type, 1));
- auto lv = (type == SlotType::Local ? ::MIR::LValue::make_Local(idx) : ::MIR::LValue::make_Argument({idx}));
+ auto lv = (type == SlotType::Local ? ::MIR::LValue::new_Local(idx) : ::MIR::LValue::new_Argument(idx));
merge_state(sp, *this, mv$(lv), out_state, src_state);
}
};
@@ -1548,7 +1517,6 @@ void MirBuilder::complete_scope(ScopeDef& sd)
(Split,
),
(Freeze,
- //DEBUG("Freeze");
)
)
@@ -1560,7 +1528,7 @@ void MirBuilder::complete_scope(ScopeDef& sd)
auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Local);
if( vs != ent.second )
{
- DEBUG(::MIR::LValue::make_Local(ent.first) << " " << vs << " => " << ent.second);
+ DEBUG(::MIR::LValue::new_Local(ent.first) << " " << vs << " => " << ent.second);
vs = ::std::move(ent.second);
}
}
@@ -1569,7 +1537,7 @@ void MirBuilder::complete_scope(ScopeDef& sd)
auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Argument);
if( vs != ent.second )
{
- DEBUG(::MIR::LValue::make_Argument({ent.first}) << " " << vs << " => " << ent.second);
+ DEBUG(::MIR::LValue::new_Argument(ent.first) << " " << vs << " => " << ent.second);
vs = ::std::move(ent.second);
}
}
@@ -1601,26 +1569,50 @@ void MirBuilder::complete_scope(ScopeDef& sd)
ASSERT_BUG(sd.span, e.end_state_valid, "");
H::apply_end_state(sd.span, *this, e.end_state);
}
+ else if( const auto* e = sd.data.opt_Freeze() )
+ {
+ TRACE_FUNCTION_F("Freeze");
+ for(auto& ent : e->changed_slots)
+ {
+ auto& vs = this->get_slot_state_mut(sd.span, ent.first, SlotType::Local);
+ auto lv = ::MIR::LValue::new_Local(ent.first);
+ DEBUG(lv << " " << vs << " => " << ent.second);
+ if( vs != ent.second )
+ {
+ if( vs.is_Valid() ) {
+ ERROR(sd.span, E0000, "Value went from " << vs << " => " << ent.second << " over freeze");
+ }
+ else if( !this->lvalue_is_copy(sd.span, lv) ) {
+ ERROR(sd.span, E0000, "Non-Copy value went from " << vs << " => " << ent.second << " over freeze");
+ }
+ else {
+ // It's a Copy value, and it wasn't originally fully Valid - allowable
+ }
+ }
+ }
+ }
}
-void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb) const
+void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb, const ::MIR::LValue::Wrapper* stop_wrapper/*=nullptr*/) const
{
- TU_MATCH(::MIR::LValue, (val), (e),
+ ::HIR::TypeRef tmp;
+ const ::HIR::TypeRef* ty_p = nullptr;
+ TU_MATCHA( (val.m_root), (e),
(Return,
TODO(sp, "Return");
),
(Argument,
- cb( m_args.at(e.idx).second );
+ ty_p = &m_args.at(e).second;
),
(Local,
- cb( m_output.locals.at(e) );
+ ty_p = &m_output.locals.at(e);
),
(Static,
TU_MATCHA( (e.m_data), (pe),
(Generic,
ASSERT_BUG(sp, pe.m_params.m_types.empty(), "Path params on static");
const auto& s = m_resolve.m_crate.get_static_by_path(sp, pe.m_path);
- cb( s.m_type );
+ ty_p = &s.m_type;
),
(UfcsKnown,
TODO(sp, "Static - UfcsKnown - " << e);
@@ -1632,68 +1624,65 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
TODO(sp, "Static - UfcsInherent - " << e);
)
)
- ),
- (Field,
- with_val_type(sp, *e.val, [&](const auto& ty){
+ )
+ )
+ assert(ty_p);
+ for(const auto& w : val.m_wrappers)
+ {
+ if( &w == stop_wrapper )
+ {
+ stop_wrapper = nullptr; // Reset so the below bugcheck can work
+ break;
+ }
+ const auto& ty = *ty_p;
+ ty_p = nullptr;
+ auto maybe_monomorph = [&](const ::HIR::GenericParams& params_def, const ::HIR::Path& p, const ::HIR::TypeRef& t)->const ::HIR::TypeRef& {
+ if( monomorphise_type_needed(t) ) {
+ tmp = monomorphise_type(sp, params_def, p.m_data.as_Generic().m_params, t);
+ m_resolve.expand_associated_types(sp, tmp);
+ return tmp;
+ }
+ else {
+ return t;
+ }
+ };
+ TU_MATCH_HDRA( (w), {)
+ TU_ARMA(Field, field_index) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
BUG(sp, "Field access on unexpected type - " << ty);
),
(Array,
- cb( *te.inner );
+ ty_p = &*te.inner;
),
(Slice,
- cb( *te.inner );
+ ty_p = &*te.inner;
),
(Path,
- ::HIR::TypeRef tmp;
if( const auto* tep = te.binding.opt_Struct() )
{
const auto& str = **tep;
- auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& {
- if( monomorphise_type_needed(t) ) {
- tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, t);
- m_resolve.expand_associated_types(sp, tmp);
- return tmp;
- }
- else {
- return t;
- }
- };
TU_MATCHA( (str.m_data), (se),
(Unit,
BUG(sp, "Field on unit-like struct - " << ty);
),
(Tuple,
- ASSERT_BUG(sp, e.field_index < se.size(),
- "Field index out of range in tuple-struct " << ty << " - " << e.field_index << " > " << se.size());
- const auto& fld = se[e.field_index];
- cb( maybe_monomorph(fld.ent) );
+ ASSERT_BUG(sp, field_index < se.size(),
+ "Field index out of range in tuple-struct " << ty << " - " << field_index << " > " << se.size());
+ const auto& fld = se[field_index];
+ ty_p = &maybe_monomorph(str.m_params, te.path, fld.ent);
),
(Named,
- ASSERT_BUG(sp, e.field_index < se.size(),
- "Field index out of range in struct " << ty << " - " << e.field_index << " > " << se.size());
- const auto& fld = se[e.field_index].second;
- cb( maybe_monomorph(fld.ent) );
+ ASSERT_BUG(sp, field_index < se.size(),
+ "Field index out of range in struct " << ty << " - " << field_index << " > " << se.size());
+ const auto& fld = se[field_index].second;
+ ty_p = &maybe_monomorph(str.m_params, te.path, fld.ent);
)
)
}
- else if( const auto* tep = te.binding.opt_Union() )
+ else if( /*const auto* tep =*/ te.binding.opt_Union() )
{
BUG(sp, "Field access on a union isn't valid, use Downcast instead - " << ty);
- const auto& unm = **tep;
- auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& {
- if( monomorphise_type_needed(t) ) {
- tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, t);
- m_resolve.expand_associated_types(sp, tmp);
- return tmp;
- }
- else {
- return t;
- }
- };
- ASSERT_BUG(sp, e.field_index < unm.m_variants.size(), "Field index out of range for union");
- cb( maybe_monomorph(unm.m_variants.at(e.field_index).second.ent) );
}
else
{
@@ -1701,14 +1690,12 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
}
),
(Tuple,
- ASSERT_BUG(sp, e.field_index < te.size(), "Field index out of range in tuple " << e.field_index << " >= " << te.size());
- cb( te[e.field_index] );
+ ASSERT_BUG(sp, field_index < te.size(), "Field index out of range in tuple " << field_index << " >= " << te.size());
+ ty_p = &te[field_index];
)
)
- });
- ),
- (Deref,
- with_val_type(sp, *e.val, [&](const auto& ty){
+ }
+ TU_ARMA(Deref, _e) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
BUG(sp, "Deref on unexpected type - " << ty);
@@ -1716,38 +1703,34 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
(Path,
if( const auto* inner_ptr = this->is_type_owned_box(ty) )
{
- cb( *inner_ptr );
+ ty_p = &*inner_ptr;
}
else {
BUG(sp, "Deref on unexpected type - " << ty);
}
),
(Pointer,
- cb(*te.inner);
+ ty_p = &*te.inner;
),
(Borrow,
- cb(*te.inner);
+ ty_p = &*te.inner;
)
)
- });
- ),
- (Index,
- with_val_type(sp, *e.val, [&](const auto& ty){
+ }
+ TU_ARMA(Index, _index_val) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
BUG(sp, "Index on unexpected type - " << ty);
),
(Slice,
- cb(*te.inner);
+ ty_p = &*te.inner;
),
(Array,
- cb(*te.inner);
+ ty_p = &*te.inner;
)
)
- });
- ),
- (Downcast,
- with_val_type(sp, *e.val, [&](const auto& ty){
+ }
+ TU_ARMA(Downcast, variant_index) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
BUG(sp, "Downcast on unexpected type - " << ty);
@@ -1758,33 +1741,19 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
const auto& enm = **pbe;
ASSERT_BUG(sp, enm.m_data.is_Data(), "Downcast on non-data enum");
const auto& variants = enm.m_data.as_Data();
- ASSERT_BUG(sp, e.variant_index < variants.size(), "Variant index out of range");
- const auto& variant = variants[e.variant_index];
+ ASSERT_BUG(sp, variant_index < variants.size(), "Variant index out of range");
+ const auto& variant = variants[variant_index];
- if( monomorphise_type_needed(variant.type) ) {
- auto tmp = monomorphise_type(sp, enm.m_params, te.path.m_data.as_Generic().m_params, variant.type);
- m_resolve.expand_associated_types(sp, tmp);
- cb(tmp);
- }
- else {
- cb(variant.type);
- }
+ ty_p = &maybe_monomorph(enm.m_params, te.path, variant.type);
}
else if( const auto* pbe = te.binding.opt_Union() )
{
const auto& unm = **pbe;
- ASSERT_BUG(sp, e.variant_index < unm.m_variants.size(), "Variant index out of range");
- const auto& variant = unm.m_variants.at(e.variant_index);
+ ASSERT_BUG(sp, variant_index < unm.m_variants.size(), "Variant index out of range");
+ const auto& variant = unm.m_variants.at(variant_index);
const auto& fld = variant.second;
- if( monomorphise_type_needed(fld.ent) ) {
- auto sty = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, fld.ent);
- m_resolve.expand_associated_types(sp, sty);
- cb(sty);
- }
- else {
- cb(fld.ent);
- }
+ ty_p = &maybe_monomorph(unm.m_params, te.path, fld.ent);
}
else
{
@@ -1792,9 +1761,12 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
}
)
)
- });
- )
- )
+ }
+ }
+ assert(ty_p);
+ }
+ ASSERT_BUG(sp, !stop_wrapper, "A stop wrapper was passed, but not found");
+ cb(*ty_p);
}
bool MirBuilder::lvalue_is_copy(const Span& sp, const ::MIR::LValue& val) const
@@ -1913,20 +1885,38 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotT
}
}
}
- else if( scope_def.data.is_Freeze() )
+ // Freeze is used for `match` guards
+ // - These are only allowed to modify the (known `bool`) condition variable
+ // TODO: Some guards have more complex pieces of code, with self-contained scopes, allowable?
+ // - Those should already have defined their own scope?
+ // - OR, allow mutations here but ONLY if it's of a Copy type, and force it uninit at the end of the scope
+ else if( auto* e = scope_def.data.opt_Freeze() )
{
+ // If modified variable is the guard's result variable, allow it.
+ if( type != SlotType::Local ) {
+ DEBUG("Mutating state of arg" << idx);
+ ERROR(sp, E0000, "Attempting to move/initialise a value where not allowed");
+ }
if( type == SlotType::Local && idx == m_if_cond_lval.as_Local() )
{
+ // The guard condition variable is allowed to be mutated, and falls through to the upper scope
}
else
{
- // NOTE: This is only used in match conditions
- DEBUG("Mutating state of ?" << idx);
- ERROR(sp, E0000, "Attempting to move/initialise a value where not allowed");
+ DEBUG("Mutating state of local" << idx);
+ auto& states = e->changed_slots;
+ if( states.count(idx) == 0 )
+ {
+ auto state = get_slot_state(sp, idx, type).clone();
+ states.insert(::std::make_pair( idx, mv$(state) ));
+ }
+ ret = &states[idx];
+ break; // Stop searching
}
}
else
{
+ // Unknown scope type?
}
}
if( ret )
@@ -1953,165 +1943,171 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotT
}
}
-const VarState& MirBuilder::get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count)
-{
- TODO(sp, "");
-}
-VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv)
+VarState* MirBuilder::get_val_state_mut_p(const Span& sp, const ::MIR::LValue& lv, bool expect_valid/*=false*/)
{
TRACE_FUNCTION_F(lv);
- TU_MATCHA( (lv), (e),
+ VarState* vs;
+ TU_MATCHA( (lv.m_root), (e),
(Return,
BUG(sp, "Move of return value");
- return get_slot_state_mut(sp, ~0u, SlotType::Local);
+ vs = &get_slot_state_mut(sp, ~0u, SlotType::Local);
),
(Argument,
- return get_slot_state_mut(sp, e.idx, SlotType::Argument);
+ vs = &get_slot_state_mut(sp, e, SlotType::Argument);
),
(Local,
- return get_slot_state_mut(sp, e, SlotType::Local);
+ vs = &get_slot_state_mut(sp, e, SlotType::Local);
),
(Static,
- BUG(sp, "Attempting to mutate state of a static");
- ),
- (Field,
- auto& ivs = get_val_state_mut(sp, *e.val);
- VarState tpl;
- TU_MATCHA( (ivs), (ivse),
- (Invalid,
- //BUG(sp, "Mutating inner state of an invalidated composite - " << lv);
- tpl = VarState::make_Valid({});
- ),
- (MovedOut,
- BUG(sp, "Field on value with MovedOut state - " << lv);
- ),
- (Partial,
- ),
- (Optional,
- tpl = ivs.clone();
- ),
- (Valid,
- tpl = VarState::make_Valid({});
- )
+ return nullptr;
+ //BUG(sp, "Attempting to mutate state of a static");
)
- if( !ivs.is_Partial() )
- {
- size_t n_flds = 0;
- with_val_type(sp, *e.val, [&](const auto& ty) {
- DEBUG("ty = " << ty);
- if(const auto* e = ty.m_data.opt_Path()) {
- ASSERT_BUG(sp, e->binding.is_Struct(), "");
- const auto& str = *e->binding.as_Struct();
- TU_MATCHA( (str.m_data), (se),
- (Unit,
- BUG(sp, "Field access of unit-like struct");
- ),
- (Tuple,
- n_flds = se.size();
- ),
- (Named,
- n_flds = se.size();
- )
- )
- }
- else if(const auto* e = ty.m_data.opt_Tuple()) {
- n_flds = e->size();
- }
- else if(const auto* e = ty.m_data.opt_Array()) {
- n_flds = e->size_val;
- }
- else {
- TODO(sp, "Determine field count for " << ty);
- }
- });
- ::std::vector<VarState> inner_vs; inner_vs.reserve(n_flds);
- for(size_t i = 0; i < n_flds; i++)
- inner_vs.push_back( tpl.clone() );
- ivs = VarState::make_Partial({ mv$(inner_vs) });
- }
- return ivs.as_Partial().inner_states.at(e.field_index);
- ),
- (Deref,
- // HACK: If the dereferenced type is a Box ("owned_box") then hack in move and shallow drop
- bool is_box = false;
- if( this->m_lang_Box )
- {
- with_val_type(sp, *e.val, [&](const auto& ty){
- DEBUG("ty = " << ty);
- is_box = this->is_type_owned_box(ty);
- });
- }
+ )
+ if( expect_valid && vs->is_Valid() )
+ {
+ return nullptr;
+ }
- if( is_box )
- {
- auto& ivs = get_val_state_mut(sp, *e.val);
- if( ! ivs.is_MovedOut() )
+ for(const auto& w : lv.m_wrappers)
+ {
+ auto& ivs = *vs;
+ vs = nullptr;
+ TU_MATCH_HDRA( (w), { )
+ TU_ARMA(Field, field_index) {
+ VarState tpl;
+ TU_MATCHA( (ivs), (ivse),
+ (Invalid,
+ //BUG(sp, "Mutating inner state of an invalidated composite - " << lv);
+ tpl = VarState::make_Valid({});
+ ),
+ (MovedOut,
+ BUG(sp, "Field on value with MovedOut state - " << lv);
+ ),
+ (Partial,
+ ),
+ (Optional,
+ tpl = ivs.clone();
+ ),
+ (Valid,
+ tpl = VarState::make_Valid({});
+ )
+ )
+ if( !ivs.is_Partial() )
{
- ::std::vector<VarState> inner;
- inner.push_back(VarState::make_Valid({}));
- unsigned int drop_flag = (ivs.is_Optional() ? ivs.as_Optional() : ~0u);
- ivs = VarState::make_MovedOut({ box$(VarState::make_Valid({})), drop_flag });
+ size_t n_flds = 0;
+ with_val_type(sp, lv, [&](const auto& ty) {
+ DEBUG("ty = " << ty);
+ if(const auto* e = ty.m_data.opt_Path()) {
+ ASSERT_BUG(sp, e->binding.is_Struct(), "");
+ const auto& str = *e->binding.as_Struct();
+ TU_MATCHA( (str.m_data), (se),
+ (Unit,
+ BUG(sp, "Field access of unit-like struct");
+ ),
+ (Tuple,
+ n_flds = se.size();
+ ),
+ (Named,
+ n_flds = se.size();
+ )
+ )
+ }
+ else if(const auto* e = ty.m_data.opt_Tuple()) {
+ n_flds = e->size();
+ }
+ else if(const auto* e = ty.m_data.opt_Array()) {
+ n_flds = e->size_val;
+ }
+ else {
+ TODO(sp, "Determine field count for " << ty);
+ }
+ }, &w);
+ ::std::vector<VarState> inner_vs; inner_vs.reserve(n_flds);
+ for(size_t i = 0; i < n_flds; i++)
+ inner_vs.push_back( tpl.clone() );
+ ivs = VarState::make_Partial({ mv$(inner_vs) });
+ }
+ vs = &ivs.as_Partial().inner_states.at(field_index);
+ }
+ TU_ARMA(Deref, _e) {
+ // HACK: If the dereferenced type is a Box ("owned_box") then hack in move and shallow drop
+ bool is_box = false;
+ if( this->m_lang_Box )
+ {
+ with_val_type(sp, lv, [&](const auto& ty){
+ DEBUG("ty = " << ty);
+ is_box = this->is_type_owned_box(ty);
+ }, &w);
}
- return *ivs.as_MovedOut().inner_state;
- }
- else
- {
- BUG(sp, "Move out of deref with non-Copy values - &move? - " << lv << " : " << FMT_CB(ss, this->with_val_type(sp, lv, [&](const auto& ty){ss<<ty;});) );
- }
- ),
- (Index,
- BUG(sp, "Move out of index with non-Copy values - Partial move?");
- ),
- (Downcast,
- // TODO: What if the inner is Copy? What if the inner is a hidden pointer?
- auto& ivs = get_val_state_mut(sp, *e.val);
- //static VarState ivs; ivs = VarState::make_Valid({});
- if( !ivs.is_Partial() )
- {
- ASSERT_BUG(sp, !ivs.is_MovedOut(), "Downcast of a MovedOut value");
-
- size_t var_count = 0;
- with_val_type(sp, *e.val, [&](const auto& ty){
- DEBUG("ty = " << ty);
- ASSERT_BUG(sp, ty.m_data.is_Path(), "Downcast on non-Path type - " << ty);
- const auto& pb = ty.m_data.as_Path().binding;
- // TODO: What about unions?
- // - Iirc, you can't move out of them so they will never have state mutated
- if( pb.is_Enum() )
- {
- const auto& enm = *pb.as_Enum();
- var_count = enm.num_variants();
- }
- else if( const auto* pbe = pb.opt_Union() )
+
+ if( is_box )
+ {
+ if( ! ivs.is_MovedOut() )
{
- const auto& unm = **pbe;
- var_count = unm.m_variants.size();
+ ::std::vector<VarState> inner;
+ inner.push_back(VarState::make_Valid({}));
+ unsigned int drop_flag = (ivs.is_Optional() ? ivs.as_Optional() : ~0u);
+ ivs = VarState::make_MovedOut({ box$(VarState::make_Valid({})), drop_flag });
}
- else
+ vs = &*ivs.as_MovedOut().inner_state;
+ }
+ else
+ {
+ return nullptr;
+ }
+ }
+ TU_ARMA(Index, e) {
+ return nullptr;
+ }
+ TU_ARMA(Downcast, variant_index) {
+ if( !ivs.is_Partial() )
+ {
+ ASSERT_BUG(sp, !ivs.is_MovedOut(), "Downcast of a MovedOut value");
+
+ size_t var_count = 0;
+ with_val_type(sp, lv, [&](const auto& ty){
+ DEBUG("ty = " << ty);
+ ASSERT_BUG(sp, ty.m_data.is_Path(), "Downcast on non-Path type - " << ty);
+ const auto& pb = ty.m_data.as_Path().binding;
+ // TODO: What about unions?
+ // - Iirc, you can't move out of them so they will never have state mutated
+ if( pb.is_Enum() )
+ {
+ const auto& enm = *pb.as_Enum();
+ var_count = enm.num_variants();
+ }
+ else if( const auto* pbe = pb.opt_Union() )
+ {
+ const auto& unm = **pbe;
+ var_count = unm.m_variants.size();
+ }
+ else
+ {
+ BUG(sp, "Downcast on non-Enum/Union - " << ty);
+ }
+ }, &w);
+
+ ::std::vector<VarState> inner;
+ for(size_t i = 0; i < var_count; i ++)
{
- BUG(sp, "Downcast on non-Enum/Union - " << ty);
+ inner.push_back( VarState::make_Invalid(InvalidType::Uninit) );
}
- });
+ inner[variant_index] = mv$(ivs);
+ ivs = VarState::make_Partial({ mv$(inner) });
+ }
- ::std::vector<VarState> inner;
- for(size_t i = 0; i < var_count; i ++)
- {
- inner.push_back( VarState::make_Invalid(InvalidType::Uninit) );
+ vs = &ivs.as_Partial().inner_states.at(variant_index);
}
- inner[e.variant_index] = mv$(ivs);
- ivs = VarState::make_Partial({ mv$(inner) });
}
-
- return ivs.as_Partial().inner_states.at(e.variant_index);
- )
- )
- BUG(sp, "Fell off send of get_val_state_mut");
+ assert(vs);
+ }
+ return vs;
}
-
void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR::LValue lv)
{
+ TRACE_FUNCTION_F(lv << " " << vs);
TU_MATCHA( (vs), (vse),
(Invalid,
),
@@ -2125,7 +2121,7 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR
});
if( is_box )
{
- drop_value_from_state(sp, *vse.inner_state, ::MIR::LValue::make_Deref({ box$(lv.clone()) }));
+ drop_value_from_state(sp, *vse.inner_state, ::MIR::LValue::new_Deref(lv.clone()));
push_stmt_drop_shallow(sp, mv$(lv), vse.outer_flag);
}
else
@@ -2145,7 +2141,7 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR
DEBUG("TODO: Switch based on enum value");
//for(size_t i = 0; i < vse.inner_states.size(); i ++)
//{
- // drop_value_from_state(sp, vse.inner_states[i], ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }));
+ // drop_value_from_state(sp, vse.inner_states[i], ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)));
//}
}
else if( is_union )
@@ -2156,7 +2152,7 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR
{
for(size_t i = 0; i < vse.inner_states.size(); i ++)
{
- drop_value_from_state(sp, vse.inner_states[i], ::MIR::LValue::make_Field({ box$(lv.clone()), static_cast<unsigned int>(i) }));
+ drop_value_from_state(sp, vse.inner_states[i], ::MIR::LValue::new_Field(lv.clone(), static_cast<unsigned int>(i)));
}
}
),
@@ -2174,7 +2170,7 @@ void MirBuilder::drop_scope_values(const ScopeDef& sd)
{
const auto& vs = get_slot_state(sd.span, idx, SlotType::Local);
DEBUG("slot" << idx << " - " << vs);
- drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Local(idx) );
+ drop_value_from_state( sd.span, vs, ::MIR::LValue::new_Local(idx) );
}
),
(Split,
@@ -2192,24 +2188,28 @@ void MirBuilder::drop_scope_values(const ScopeDef& sd)
void MirBuilder::moved_lvalue(const Span& sp, const ::MIR::LValue& lv)
{
if( !lvalue_is_copy(sp, lv) ) {
- auto& vs = get_val_state_mut(sp, lv);
+ auto* vs_p = get_val_state_mut_p(sp, lv);
+ if( !vs_p ) {
+ ERROR(sp, E0000, "Attempting to move out of invalid slot - " << lv);
+ }
+ auto& vs = *vs_p;
// TODO: If the current state is Optional, set the drop flag to 0
vs = VarState::make_Invalid(InvalidType::Moved);
}
}
-const ::MIR::LValue& MirBuilder::get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const
+::MIR::LValue MirBuilder::get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const
{
// Undo field accesses
- const auto* lvp = &lv;
- while(lvp->is_Field())
- lvp = &*lvp->as_Field().val;
+ size_t count = 0;
+ while( count < lv.m_wrappers.size() && lv.m_wrappers[ lv.m_wrappers.size()-1 - count ].is_Field() )
+ count ++;
// TODO: Enum variants?
- ASSERT_BUG(sp, lvp->is_Deref(), "Access of an unsized field without a dereference - " << lv);
+ ASSERT_BUG(sp, count < lv.m_wrappers.size() && lv.m_wrappers[ lv.m_wrappers.size()-1 - count ].is_Deref(), "Access of an unsized field without a dereference - " << lv);
- return *lvp->as_Deref().val;
+ return lv.clone_unwrapped(count+1);
}
// --------------------------------------------------------------------
@@ -2253,7 +2253,7 @@ VarState VarState::clone() const
)
throw "";
}
-bool VarState::operator==(VarState& x) const
+bool VarState::operator==(const VarState& x) const
{
if( this->tag() != x.tag() )
return false;
diff --git a/src/mir/mir_ptr.hpp b/src/mir/mir_ptr.hpp
index 9133dd44..27dd6b22 100644
--- a/src/mir/mir_ptr.hpp
+++ b/src/mir/mir_ptr.hpp
@@ -7,7 +7,6 @@
*/
#pragma once
-
namespace MIR {
class Function;
@@ -32,10 +31,10 @@ public:
void reset();
- ::MIR::Function* operator->() { return ptr; }
- ::MIR::Function& operator*() { return *ptr; }
- const ::MIR::Function* operator->() const { return ptr; }
- const ::MIR::Function& operator*() const { return *ptr; }
+ ::MIR::Function* operator->() { if(!ptr) throw ""; return ptr; }
+ const ::MIR::Function* operator->() const { if(!ptr) throw ""; return ptr; }
+ ::MIR::Function& operator*() { if(!ptr) throw ""; return *ptr; }
+ const ::MIR::Function& operator*() const { if(!ptr) throw ""; return *ptr; }
operator bool() const { return ptr != nullptr; }
};
diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp
index 80bca08d..04ba8470 100644
--- a/src/mir/optimise.cpp
+++ b/src/mir/optimise.cpp
@@ -191,7 +191,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
#endif
// >> Move common statements (assignments) across gotos.
- change_happened |= MIR_Optimise_CommonStatements(state, fcn);
+ //change_happened |= MIR_Optimise_CommonStatements(state, fcn);
// >> Combine Duplicate Blocks
change_happened |= MIR_Optimise_UnifyBlocks(state, fcn);
@@ -305,49 +305,78 @@ namespace {
Borrow, // Any borrow
};
- bool visit_mir_lvalue_mut(::MIR::LValue& lv, ValUsage u, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
+ bool visit_mir_lvalues_inner(const ::MIR::LValue& lv, ValUsage u, ::std::function<bool(const ::MIR::LValue& , ValUsage)> cb)
{
- //TRACE_FUNCTION_F(lv);
- if( cb(lv, u) )
- return true;
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Argument,
- ),
- (Local,
- ),
- (Static,
- ),
- (Field,
- // HACK: If "moving", use a "Read" value usage (covers some quirks)
- return visit_mir_lvalue_mut(*e.val, u == ValUsage::Move ? ValUsage::Read : u, cb);
- ),
- (Deref,
- return visit_mir_lvalue_mut(*e.val, u == ValUsage::Borrow ? u : ValUsage::Read, cb);
- ),
- (Index,
- bool rv = false;
- rv |= visit_mir_lvalue_mut(*e.val, u, cb);
- rv |= visit_mir_lvalue_mut(*e.idx, ValUsage::Read, cb);
- return rv;
- ),
- (Downcast,
- return visit_mir_lvalue_mut(*e.val, u, cb);
- )
- )
+ for(const auto& w : lv.m_wrappers)
+ {
+ if(w.is_Index())
+ {
+ if( cb(::MIR::LValue::new_Local(w.as_Index()), ValUsage::Read) )
+ return true;
+ }
+ else if(w.is_Deref())
+ {
+ //u = ValUsage::Read;
+ }
+ }
+ return cb(lv, u);
+ }
+ bool visit_mir_lvalue_mut(::MIR::LValue& lv, ValUsage u, ::std::function<bool(::MIR::LValue::MRef& , ValUsage)> cb)
+ {
+ auto lvr = ::MIR::LValue::MRef(lv);
+ do
+ {
+ if( cb(lvr, u) )
+ return true;
+ // TODO: Use a TU_MATCH?
+ if( lvr.is_Index() )
+ {
+ auto ilv = ::MIR::LValue::new_Local(lvr.as_Index());
+ auto ilv_r = ::MIR::LValue::MRef(ilv);
+ bool rv = cb(ilv_r, ValUsage::Read);
+ assert(ilv.is_Local() && ilv.as_Local() == lvr.as_Index());
+ if( rv )
+ return true;
+ }
+ else if( lvr.is_Field() )
+ {
+ // HACK: If "moving", use a "Read" value usage (covers some quirks)
+ if( u == ValUsage::Move ) {
+ u = ValUsage::Read;
+ }
+ }
+ else if( lvr.is_Deref() )
+ {
+ // TODO: Is this right?
+ if( u == ValUsage::Borrow ) {
+ u = ValUsage::Read;
+ }
+ }
+ else
+ {
+ // No change
+ }
+ } while( lvr.try_unwrap() );
return false;
}
- bool visit_mir_lvalue(const ::MIR::LValue& lv, ValUsage u, ::std::function<bool(const ::MIR::LValue& , ValUsage)> cb)
+ bool visit_mir_lvalue(const ::MIR::LValue& lv, ValUsage u, ::std::function<bool(const ::MIR::LValue::CRef& , ValUsage)> cb)
{
return visit_mir_lvalue_mut( const_cast<::MIR::LValue&>(lv), u, [&](auto& v, auto u) { return cb(v,u); } );
}
+ bool visit_mir_lvalue_raw_mut(::MIR::LValue& lv, ValUsage u, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
+ {
+ return cb(lv, u);
+ }
+ bool visit_mir_lvalue_raw(const ::MIR::LValue& lv, ValUsage u, ::std::function<bool(const ::MIR::LValue& , ValUsage)> cb)
+ {
+ return cb(lv, u);
+ }
bool visit_mir_lvalue_mut(::MIR::Param& p, ValUsage u, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
{
if( auto* e = p.opt_LValue() )
{
- return visit_mir_lvalue_mut(*e, u, cb);
+ return visit_mir_lvalue_raw_mut(*e, u, cb);
}
else
{
@@ -358,7 +387,7 @@ namespace {
{
if( const auto* e = p.opt_LValue() )
{
- return visit_mir_lvalue(*e, u, cb);
+ return visit_mir_lvalue_raw(*e, u, cb);
}
else
{
@@ -371,7 +400,7 @@ namespace {
bool rv = false;
TU_MATCHA( (rval), (se),
(Use,
- rv |= visit_mir_lvalue_mut(se, ValUsage::Move, cb); // Can move
+ rv |= visit_mir_lvalue_raw_mut(se, ValUsage::Move, cb); // Can move
),
(Constant,
),
@@ -379,23 +408,23 @@ namespace {
rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb); // Has to be Read
),
(Borrow,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Borrow, cb);
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Borrow, cb);
),
(Cast,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb); // Also has to be read
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Read, cb); // Also has to be read
),
(BinOp,
rv |= visit_mir_lvalue_mut(se.val_l, ValUsage::Read, cb); // Same
rv |= visit_mir_lvalue_mut(se.val_r, ValUsage::Read, cb);
),
(UniOp,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Read, cb);
),
(DstMeta,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb); // Reads
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Read, cb); // Reads
),
(DstPtr,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Read, cb);
),
(MakeDst,
rv |= visit_mir_lvalue_mut(se.ptr_val, ValUsage::Move, cb);
@@ -430,19 +459,19 @@ namespace {
TU_MATCHA( (stmt), (e),
(Assign,
rv |= visit_mir_lvalues_mut(e.src, cb);
- rv |= visit_mir_lvalue_mut(e.dst, ValUsage::Write, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.dst, ValUsage::Write, cb);
),
(Asm,
for(auto& v : e.inputs)
- rv |= visit_mir_lvalue_mut(v.second, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(v.second, ValUsage::Read, cb);
for(auto& v : e.outputs)
- rv |= visit_mir_lvalue_mut(v.second, ValUsage::Write, cb);
+ rv |= visit_mir_lvalue_raw_mut(v.second, ValUsage::Write, cb);
),
(SetDropFlag,
),
(Drop,
// Well, it mutates...
- rv |= visit_mir_lvalue_mut(e.slot, ValUsage::Write, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.slot, ValUsage::Write, cb);
),
(ScopeEnd,
)
@@ -454,8 +483,9 @@ namespace {
return visit_mir_lvalues_mut(const_cast<::MIR::Statement&>(stmt), [&](auto& lv, auto im){ return cb(lv, im); });
}
- void visit_mir_lvalues_mut(::MIR::Terminator& term, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
+ bool visit_mir_lvalues_mut(::MIR::Terminator& term, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
{
+ bool rv = false;
TU_MATCHA( (term), (e),
(Incomplete,
),
@@ -468,27 +498,28 @@ namespace {
(Panic,
),
(If,
- visit_mir_lvalue_mut(e.cond, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.cond, ValUsage::Read, cb);
),
(Switch,
- visit_mir_lvalue_mut(e.val, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.val, ValUsage::Read, cb);
),
(SwitchValue,
- visit_mir_lvalue_mut(e.val, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.val, ValUsage::Read, cb);
),
(Call,
if( e.fcn.is_Value() ) {
- visit_mir_lvalue_mut(e.fcn.as_Value(), ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.fcn.as_Value(), ValUsage::Read, cb);
}
for(auto& v : e.args)
- visit_mir_lvalue_mut(v, ValUsage::Move, cb);
- visit_mir_lvalue_mut(e.ret_val, ValUsage::Write, cb);
+ rv |= visit_mir_lvalue_mut(v, ValUsage::Move, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.ret_val, ValUsage::Write, cb);
)
)
+ return rv;
}
- void visit_mir_lvalues(const ::MIR::Terminator& term, ::std::function<bool(const ::MIR::LValue& , ValUsage)> cb)
+ bool visit_mir_lvalues(const ::MIR::Terminator& term, ::std::function<bool(const ::MIR::LValue& , ValUsage)> cb)
{
- visit_mir_lvalues_mut(const_cast<::MIR::Terminator&>(term), [&](auto& lv, auto im){ return cb(lv, im); });
+ return visit_mir_lvalues_mut(const_cast<::MIR::Terminator&>(term), [&](auto& lv, auto im){ return cb(lv, im); });
}
void visit_mir_lvalues_mut(::MIR::TypeResolve& state, ::MIR::Function& fcn, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
@@ -733,32 +764,6 @@ namespace {
void visit_blocks(::MIR::TypeResolve& state, const ::MIR::Function& fcn, ::std::function<void(::MIR::BasicBlockId, const ::MIR::BasicBlock&)> cb) {
visit_blocks_mut(state, const_cast<::MIR::Function&>(fcn), [cb](auto id, auto& blk){ cb(id, blk); });
}
-
- bool statement_invalidates_lvalue(const ::MIR::Statement& stmt, const ::MIR::LValue& lv)
- {
- return visit_mir_lvalues(stmt, [&](const auto& v, auto vu) {
- if( v == lv ) {
- return vu != ValUsage::Read;
- }
- return false;
- });
- }
- bool terminator_invalidates_lvalue(const ::MIR::Terminator& term, const ::MIR::LValue& lv)
- {
- if( const auto* e = term.opt_Call() )
- {
- return visit_mir_lvalue(e->ret_val, ValUsage::Write, [&](const auto& v, auto vu) {
- if( v == lv ) {
- return vu != ValUsage::Read;
- }
- return false;
- });
- }
- else
- {
- return false;
- }
- }
}
@@ -859,12 +864,31 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
{
bool inline_happened = false;
TRACE_FUNCTION_FR("", inline_happened);
+ struct InlineEvent {
+ ::HIR::Path path;
+ ::std::vector<size_t> bb_list;
+ InlineEvent(::HIR::Path p)
+ :path(::std::move(p))
+ {
+ }
+ bool has_bb(size_t i) const {
+ return ::std::find(this->bb_list.begin(), this->bb_list.end(), i) != this->bb_list.end();
+ }
+ void add_range(size_t start, size_t count) {
+ for(size_t j = 0; j < count; j++)
+ {
+ this->bb_list.push_back(start + j);
+ }
+ }
+ };
+ ::std::vector<InlineEvent> inlined_functions;
struct H
{
static bool can_inline(const ::HIR::Path& path, const ::MIR::Function& fcn, bool minimal)
{
// TODO: If the function is marked as `inline(always)`, then inline it regardless of the contents
+ // TODO: Take a monomorph helper so recursion can be detected
if( minimal ) {
return false;
@@ -888,6 +912,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
return false;
// Detect and avoid simple recursion.
// - This won't detect mutual recursion - that also needs prevention.
+ // TODO: This is the pre-monomorph path, but we're comparing with the post-monomorph path
if( blk0_te.fcn.is_Path() && blk0_te.fcn.as_Path() == path )
return false;
return true;
@@ -907,6 +932,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
// Recursion, don't inline.
if( te.fcn.is_Path() && te.fcn.as_Path() == path )
return false;
+ // HACK: Only allow if the wrapped function is an intrinsic
+ // - Works around the TODO about monomorphed paths above
+ if(!te.fcn.is_Intrinsic())
+ return false;
}
}
return true;
@@ -1139,42 +1168,34 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
::MIR::LValue clone_lval(const ::MIR::LValue& src) const
{
- TU_MATCHA( (src), (se),
+ auto wrappers = src.m_wrappers;
+ for(auto& w : wrappers)
+ {
+ if( w.is_Index() ) {
+ w = ::MIR::LValue::Wrapper::new_Index( this->var_base + w.as_Index() );
+ }
+ }
+ TU_MATCHA( (src.m_root), (se),
(Return,
- return this->retval.clone();
+ return this->retval.clone_wrapped( mv$(wrappers) );
),
(Argument,
- const auto& arg = this->te.args.at(se.idx);
- if( this->copy_args[se.idx] != ~0u )
+ const auto& arg = this->te.args.at(se);
+ if( this->copy_args[se] != ~0u )
{
- return ::MIR::LValue::make_Local(this->copy_args[se.idx]);
+ return ::MIR::LValue( ::MIR::LValue::Storage::new_Local(this->copy_args[se]), mv$(wrappers) );
}
else
{
assert( !arg.is_Constant() ); // Should have been handled in the above
- return arg.as_LValue().clone();
+ return arg.as_LValue().clone_wrapped( mv$(wrappers) );
}
),
(Local,
- return ::MIR::LValue::make_Local(this->var_base + se);
+ return ::MIR::LValue( ::MIR::LValue::Storage::new_Local(this->var_base + se), mv$(wrappers) );
),
(Static,
- return this->monomorph( se );
- ),
- (Deref,
- return ::MIR::LValue::make_Deref({ box$(this->clone_lval(*se.val)) });
- ),
- (Field,
- return ::MIR::LValue::make_Field({ box$(this->clone_lval(*se.val)), se.field_index });
- ),
- (Index,
- return ::MIR::LValue::make_Index({
- box$(this->clone_lval(*se.val)),
- box$(this->clone_lval(*se.idx))
- });
- ),
- (Downcast,
- return ::MIR::LValue::make_Downcast({ box$(this->clone_lval(*se.val)), se.variant_index });
+ return ::MIR::LValue( ::MIR::LValue::Storage::new_Static(this->monomorph(se)), mv$(wrappers) );
)
)
throw "";
@@ -1189,10 +1210,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
(Bytes, return ::MIR::Constant(ce);),
(StaticString, return ::MIR::Constant(ce);),
(Const,
- return ::MIR::Constant::make_Const({ this->monomorph(ce.p) });
+ return ::MIR::Constant::make_Const({ box$(this->monomorph(*ce.p)) });
),
(ItemAddr,
- return ::MIR::Constant::make_ItemAddr(this->monomorph(ce));
+ return ::MIR::Constant::make_ItemAddr(box$(this->monomorph(*ce)));
)
)
throw "";
@@ -1272,6 +1293,15 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
if( ! te->fcn.is_Path() )
continue ;
const auto& path = te->fcn.as_Path();
+ DEBUG(state << fcn.blocks[i].terminator);
+
+ for(const auto& e : inlined_functions)
+ {
+ if( path == e.path && e.has_bb(i) )
+ {
+ MIR_BUG(state, "Recursive inline of " << path);
+ }
+ }
Cloner cloner { state.sp, state.m_resolve, *te };
const auto* called_mir = get_called_mir(state, list, path, cloner.params);
@@ -1292,12 +1322,11 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
DEBUG("Can't inline " << path);
continue ;
}
- DEBUG(state << fcn.blocks[i].terminator);
TRACE_FUNCTION_F("Inline " << path);
// Allocate a temporary for the return value
{
- cloner.retval = ::MIR::LValue::make_Local( fcn.locals.size() );
+ cloner.retval = ::MIR::LValue::new_Local( fcn.locals.size() );
DEBUG("- Storing return value in " << cloner.retval);
::HIR::TypeRef tmp_ty;
fcn.locals.push_back( state.get_lvalue_type(tmp_ty, te->ret_val).clone() );
@@ -1341,7 +1370,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
{
::HIR::TypeRef tmp;
auto ty = val.is_Constant() ? state.get_const_type(val.as_Constant()) : state.get_lvalue_type(tmp, val.as_LValue()).clone();
- auto lv = ::MIR::LValue::make_Local( static_cast<unsigned>(fcn.locals.size()) );
+ auto lv = ::MIR::LValue::new_Local( static_cast<unsigned>(fcn.locals.size()) );
fcn.locals.push_back( mv$(ty) );
auto rval = val.is_Constant() ? ::MIR::RValue(mv$(val.as_Constant())) : ::MIR::RValue( mv$(val.as_LValue()) );
auto stmt = ::MIR::Statement::make_Assign({ mv$(lv), mv$(rval) });
@@ -1350,6 +1379,17 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
}
cloner.const_assignments.clear();
+ // Record the inline event
+ for(auto& e : inlined_functions)
+ {
+ if( e.has_bb(i) )
+ {
+ e.add_range(cloner.bb_base, new_blocks.size());
+ }
+ }
+ inlined_functions.push_back(InlineEvent(path.clone()));
+ inlined_functions.back().add_range(cloner.bb_base, new_blocks.size());
+
// Apply
DEBUG("- Append new blocks");
fcn.blocks.reserve( fcn.blocks.size() + new_blocks.size() );
@@ -1359,11 +1399,670 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
}
fcn.blocks[i].terminator = ::MIR::Terminator::make_Goto( cloner.bb_base );
inline_happened = true;
+
+ // TODO: Store the inlined path along with the start and end BBs, and then use that to detect recursive
+ // inlining
+ // - Recursive inlining should be an immediate panic.
}
}
return inline_happened;
}
+namespace {
+ struct StmtRef {
+ unsigned bb_idx;
+ unsigned stmt_idx;
+ StmtRef(): bb_idx(~0u), stmt_idx(0) {}
+ StmtRef(unsigned b, unsigned s): bb_idx(b), stmt_idx(s) {}
+ };
+ ::std::ostream& operator<<(::std::ostream& os, const StmtRef& x) {
+ return os << "BB" << x.bb_idx << "/" << x.stmt_idx;
+ }
+
+ // Iterates the path between two positions, NOT visiting entry specified by `end`
+ enum class IterPathRes {
+ Abort,
+ EarlyTrue,
+ Complete,
+ };
+ IterPathRes iter_path(
+ const ::MIR::Function& fcn, const StmtRef& start, const StmtRef& end,
+ ::std::function<bool(StmtRef, const ::MIR::Statement&)> cb_stmt,
+ ::std::function<bool(StmtRef, const ::MIR::Terminator&)> cb_term
+ )
+ {
+ if( start.bb_idx == end.bb_idx ) {
+ assert(start.stmt_idx <= end.stmt_idx);
+ }
+
+ auto visted_bbs = ::std::set<unsigned>();
+ // Loop while not equal (either not in the right block, or before the statement) to the end point
+ for(auto ref = start; ref.bb_idx != end.bb_idx || ref.stmt_idx < end.stmt_idx; )
+ {
+ const auto& bb = fcn.blocks.at(ref.bb_idx);
+ if( ref.stmt_idx < bb.statements.size() )
+ {
+ DEBUG(ref << " " << bb.statements.at(ref.stmt_idx));
+ if( cb_stmt(ref, bb.statements.at(ref.stmt_idx)) )
+ {
+ return IterPathRes::EarlyTrue;
+ }
+
+ ref.stmt_idx ++;
+ }
+ else
+ {
+ DEBUG(ref << " " << bb.terminator);
+ if( cb_term(ref, bb.terminator) )
+ {
+ return IterPathRes::EarlyTrue;
+ }
+
+ // If this is the end point, break out before checking the terminator for looping
+ if( ref.bb_idx == end.bb_idx )
+ {
+ // ^ don't need to check the statment index, this is the last "statement"
+ break;
+ }
+
+ // If this terminator is a Goto, follow it (tracking for loops)
+ if( const auto* te = bb.terminator.opt_Goto() )
+ {
+ // Possibly loop into the next block
+ if( !visted_bbs.insert(*te).second ) {
+ return IterPathRes::Abort;
+ }
+ ref.stmt_idx = 0;
+ ref.bb_idx = *te;
+ }
+ // If it's a call, check that the target block ends with Diverge, and iterate that in-place
+ // - Then follow the success path as usual
+ else if( const auto* te = bb.terminator.opt_Call() )
+ {
+ // Check the panic arm (should just be a list of destructor calls follwed by a Diverge terminator)
+ const auto& panic_bb = fcn.blocks[te->panic_block];
+ ASSERT_BUG(Span(), panic_bb.terminator.is_Diverge(), "Panic arm of call does not end with Diverge");
+ if( !panic_bb.statements.empty() )
+ {
+ TODO(Span(), "Visit call panic block");
+ }
+ // Possibly loop into the next block
+ if( !visted_bbs.insert(te->ret_block).second ) {
+ return IterPathRes::Abort;
+ }
+ ref.stmt_idx = 0;
+ ref.bb_idx = te->ret_block;
+ }
+ else
+ {
+ return IterPathRes::Abort;
+ }
+ }
+ }
+ return IterPathRes::Complete;
+ }
+
+ ::std::function<bool(const ::MIR::LValue& , ValUsage)> check_invalidates_lvalue_cb(const ::MIR::LValue& val, bool also_read=false)
+ {
+ bool has_index = ::std::any_of(val.m_wrappers.begin(), val.m_wrappers.end(), [](const auto& w){ return w.is_Index(); });
+ // Value is invalidated if it's used with ValUsage::Write or ValUsage::Borrow
+ // - Same applies to any component of the lvalue
+ return [&val,has_index,also_read](const ::MIR::LValue& lv, ValUsage vu) {
+ switch(vu)
+ {
+ case ValUsage::Move: // A move can invalidate
+ // - Ideally this would check if it DOES invalidate
+ case ValUsage::Write:
+ case ValUsage::Borrow:
+ // (Possibly) mutating use, check if it impacts the root or one of the indexes
+ if( lv.m_root == val.m_root ) {
+ return true;
+ }
+ if( has_index && lv.m_root.is_Local() )
+ {
+ for(const auto& w : val.m_wrappers)
+ {
+ if( w.is_Index() )
+ {
+ if( w.as_Index() == lv.m_root.as_Local() )
+ {
+ return true;
+ }
+ }
+ }
+ }
+ break;
+ case ValUsage::Read:
+ if( also_read )
+ return true;
+ break;
+ }
+ return false;
+ };
+ }
+ bool check_invalidates_lvalue(const ::MIR::Statement& stmt, const ::MIR::LValue& val, bool also_read=false)
+ {
+ return visit_mir_lvalues(stmt, check_invalidates_lvalue_cb(val, also_read));
+ }
+ bool check_invalidates_lvalue(const ::MIR::Terminator& term, const ::MIR::LValue& val, bool also_read=false)
+ {
+ return visit_mir_lvalues(term, check_invalidates_lvalue_cb(val, also_read));
+ }
+}
+
+bool MIR_Optimise_DeTemporary_SingleSetAndUse(::MIR::TypeResolve& state, ::MIR::Function& fcn)
+{
+ bool changed = false;
+ TRACE_FUNCTION_FR("", changed);
+
+ // Find all single-use/single-write locals
+ // - IF the usage is a RValue::Use, AND the usage destination is not invalidated between set/use
+ // - Replace initialisation destination with usage destination (delete usage statement)
+ // - IF the source a Use/Constant, AND is not invalidated between set/use
+ // - Replace usage with the original source
+ struct LocalUsage {
+ unsigned n_write;
+ unsigned n_read;
+ unsigned n_borrow;
+ StmtRef set_loc;
+ StmtRef use_loc;
+ LocalUsage():
+ n_write(0),
+ n_read(0),
+ n_borrow(0)
+ {
+ }
+ };
+ auto usage_info = ::std::vector<LocalUsage>(fcn.locals.size());
+ for(const auto& bb : fcn.blocks)
+ {
+ StmtRef cur_loc;
+ auto visit_cb = [&](const ::MIR::LValue& lv, auto vu) {
+ if( !lv.m_wrappers.empty() ) {
+ vu = ValUsage::Read;
+ }
+ for(const auto& w : lv.m_wrappers)
+ {
+ if(w.is_Index())
+ {
+ auto& slot = usage_info[w.as_Index()];
+ slot.n_read += 1;
+ slot.use_loc = cur_loc;
+ //DEBUG(lv << " index use");
+ }
+ }
+ if( lv.m_root.is_Local() )
+ {
+ auto& slot = usage_info[lv.m_root.as_Local()];
+ switch(vu)
+ {
+ case ValUsage::Write:
+ slot.n_write += 1;
+ slot.set_loc = cur_loc;
+ //DEBUG(lv << " set");
+ break;
+ case ValUsage::Move:
+ slot.n_read += 1;
+ slot.use_loc = cur_loc;
+ //DEBUG(lv << " use");
+ break;
+ case ValUsage::Read:
+ case ValUsage::Borrow:
+ slot.n_borrow += 1;
+ //DEBUG(lv << " borrow");
+ break;
+ }
+ }
+ return false;
+ };
+ for(const auto& stmt : bb.statements)
+ {
+ cur_loc = StmtRef(&bb - &fcn.blocks.front(), &stmt - &bb.statements.front());
+ //DEBUG(cur_loc << ":" << stmt);
+ visit_mir_lvalues(stmt, visit_cb);
+ }
+ cur_loc = StmtRef(&bb - &fcn.blocks.front(), bb.statements.size());
+ //DEBUG(cur_loc << ":" << bb.terminator);
+ visit_mir_lvalues(bb.terminator, visit_cb);
+ }
+
+ for(size_t var_idx = 0; var_idx < fcn.locals.size(); var_idx ++)
+ {
+ const auto& slot = usage_info[var_idx];
+ auto this_var = ::MIR::LValue::new_Local(var_idx);
+ //ASSERT_BUG(Span(), slot.n_write > 0, "Variable " << var_idx << " not written?");
+ if( slot.n_write == 1 && slot.n_read == 1 && slot.n_borrow == 0 )
+ {
+ // Single-use variable, now check how we can eliminate it
+ DEBUG("Single-use: _" << var_idx << " - Set " << slot.set_loc << ", Use " << slot.use_loc);
+
+ auto& use_bb = fcn.blocks[slot.use_loc.bb_idx];
+ auto& set_bb = fcn.blocks[slot.set_loc.bb_idx];
+ // If usage is direct assignment of the original value.
+ // - In this case, we can move the usage upwards
+ if( slot.use_loc.stmt_idx < use_bb.statements.size() && TU_TEST2(use_bb.statements[slot.use_loc.stmt_idx], Assign, .src, Use, == this_var) )
+ {
+ // Move the usage up to original assignment (if destination isn't invalidated)
+ const auto& dst = use_bb.statements[slot.use_loc.stmt_idx].as_Assign().dst;
+
+ // TODO: If the destination slot was ever borrowed mutably, don't move.
+ // - Maybe, if there's a drop skip? (as the drop could be &mut to the target value)
+
+ // - Iterate the path(s) between the two statements to check if the destination would be invalidated
+ // > The iterate function doesn't (yet) support following BB chains, so assume invalidated if over a jump.
+ bool invalidated = IterPathRes::Complete != iter_path(fcn, slot.set_loc, slot.use_loc,
+ [&](auto loc, const auto& stmt)->bool{ return stmt.is_Drop() || check_invalidates_lvalue(stmt, dst, /*also_read=*/true); },
+ [&](auto loc, const auto& term)->bool{ return check_invalidates_lvalue(term, dst, /*also_read=*/true); }
+ );
+ if( !invalidated )
+ {
+ // destination not dependent on any statements between the two, move.
+ if( slot.set_loc.stmt_idx < set_bb.statements.size() )
+ {
+ auto& set_stmt = set_bb.statements[slot.set_loc.stmt_idx];
+ TU_MATCH_HDRA( (set_stmt), {)
+ TU_ARMA(Assign, se) {
+ MIR_ASSERT(state, se.dst == ::MIR::LValue::new_Local(var_idx), "");
+ DEBUG("Move destination " << dst << " from " << use_bb.statements[slot.use_loc.stmt_idx] << " to " << set_stmt);
+ se.dst = dst.clone();
+ use_bb.statements[slot.use_loc.stmt_idx] = ::MIR::Statement();
+ changed = true;
+ }
+ TU_ARMA(Asm, se) {
+ // Initialised from an ASM statement, find the variable in the output parameters
+ }
+ break;
+ default:
+ MIR_BUG(state, "Impossibility: Value set in " << set_stmt);
+ }
+ }
+ else
+ {
+ auto& set_term = set_bb.terminator;
+ MIR_ASSERT(state, set_term.is_Call(), "Impossibility: Value set using non-call");
+ auto& te = set_term.as_Call();
+ DEBUG("Move destination " << dst << " from " << use_bb.statements[slot.use_loc.stmt_idx] << " to " << set_term);
+ te.ret_val = dst.clone();
+ use_bb.statements[slot.use_loc.stmt_idx] = ::MIR::Statement();
+ changed = true;
+ }
+ }
+ else
+ {
+ DEBUG("Destination invalidated");
+ }
+ continue ;
+ }
+ // Can't move up, can we move down?
+ // - If the source is an Assign(Use) then we can move down
+ if( slot.set_loc.stmt_idx < set_bb.statements.size() && TU_TEST1(set_bb.statements[slot.set_loc.stmt_idx], Assign, .src.is_Use()) )
+ {
+ auto& set_stmt = set_bb.statements[slot.set_loc.stmt_idx];
+ const auto& src = set_stmt.as_Assign().src.as_Use();
+
+ // Check if the source of initial assignment is invalidated in the meantime.
+ // - TODO: We don't want to check the set statement, just all others after it
+ bool invalidated = IterPathRes::Complete != iter_path(fcn, slot.set_loc, slot.use_loc,
+ [&](auto loc, const auto& stmt)->bool{ return check_invalidates_lvalue(stmt, src); },
+ [&](auto loc, const auto& term)->bool{ return check_invalidates_lvalue(term, src); }
+ );
+ if( !invalidated )
+ {
+ // Update the usage site and replace.
+ auto replace_cb = [&](::MIR::LValue& slot, ValUsage vu)->bool {
+ if( slot.m_root == this_var.m_root )
+ {
+ if( src.m_wrappers.empty() ) {
+ slot.m_root = src.m_root.clone();
+ }
+ else if( slot.m_wrappers.empty() ) {
+ slot = src.clone();
+ }
+ else {
+ MIR_TODO(state, "Replace inner of " << slot << " with " << src);
+ }
+ return true;
+ }
+ return false;
+ };
+ if( slot.use_loc.stmt_idx < use_bb.statements.size() )
+ {
+ auto& use_stmt = use_bb.statements[slot.use_loc.stmt_idx];
+ DEBUG("Replace " << this_var << " with " << src << " in " << use_stmt);
+ bool found = visit_mir_lvalues_mut(use_stmt, replace_cb);
+ if( !found )
+ {
+ DEBUG("Can't find use of " << this_var << " in " << use_stmt);
+ }
+ else
+ {
+ set_stmt = ::MIR::Statement();
+ changed = true;
+ }
+ }
+ else
+ {
+ auto& use_term = use_bb.terminator;
+ DEBUG("Replace " << this_var << " with " << src << " in " << use_term);
+ bool found = visit_mir_lvalues_mut(use_term, replace_cb);
+ if( !found )
+ {
+ DEBUG("Can't find use of " << this_var << " in " << use_term);
+ }
+ else
+ {
+ set_stmt = ::MIR::Statement();
+ changed = true;
+ }
+ }
+ }
+ else
+ {
+ DEBUG("Source invalidated");
+ }
+ continue;
+ }
+
+ // TODO: If the source is a Borrow and the use is a Deref, then propagate forwards
+ // - This would be a simpler version of a var more compliciated algorithm
+
+ DEBUG("Can't replace:");
+ if( slot.set_loc.stmt_idx < set_bb.statements.size() )
+ {
+ DEBUG("Set: " << set_bb.statements[slot.set_loc.stmt_idx]);
+ }
+ else
+ {
+ DEBUG("Set: " << set_bb.terminator);
+ }
+ if( slot.use_loc.stmt_idx < use_bb.statements.size() )
+ {
+ DEBUG("Use: " << use_bb.statements[slot.use_loc.stmt_idx]);
+ }
+ else
+ {
+ DEBUG("Use: " << use_bb.terminator);
+ }
+ }
+ }
+
+ return changed;
+}
+
+// Remove useless borrows (locals assigned with a borrow, and never used by value)
+// ```
+// _$1 = & _$0;
+// (*_$1).1 = 0x0;
+// ```
+bool MIR_Optimise_DeTemporary_Borrows(::MIR::TypeResolve& state, ::MIR::Function& fcn)
+{
+ bool changed = false;
+#if 1
+ TRACE_FUNCTION_FR("", changed);
+
+ // Find all single-assign borrows that are only ever used via Deref
+ // - Direct drop is ignored for this purpose
+ struct LocalUsage {
+ unsigned n_write;
+ unsigned n_other_read;
+ unsigned n_deref_read;
+ StmtRef set_loc;
+ ::std::vector<StmtRef> drop_locs;
+ LocalUsage():
+ n_write(0),
+ n_other_read(0),
+ n_deref_read(0)
+ {
+ }
+ };
+ auto usage_info = ::std::vector<LocalUsage>(fcn.locals.size());
+ for(const auto& bb : fcn.blocks)
+ {
+ StmtRef cur_loc;
+ auto visit_cb = [&](const ::MIR::LValue& lv, auto vu) {
+ if( lv.m_root.is_Local() )
+ {
+ auto& slot = usage_info[lv.m_root.as_Local()];
+ // NOTE: This pass doesn't care about indexing, as we're looking for values that are borrows (which aren't valid indexes)
+ // > Inner-most wrapper is Deref - it's a deref of this variable
+ if( !lv.m_wrappers.empty() && lv.m_wrappers.front().is_Deref() ) {
+ slot.n_deref_read ++;
+ if( fcn.locals[lv.m_root.as_Local()].m_data.is_Borrow() ) {
+ DEBUG(lv << " deref use " << cur_loc);
+ }
+ }
+ // > Write with no wrappers - Assignment
+ else if( lv.m_wrappers.empty() && vu == ValUsage::Write ) {
+ slot.n_write ++;
+ slot.set_loc = cur_loc;
+ //DEBUG(lv << " set");
+ }
+ // Anything else, count as a read
+ else {
+ slot.n_other_read ++;
+ }
+ }
+ return false;
+ };
+ for(const auto& stmt : bb.statements)
+ {
+ cur_loc = StmtRef(&bb - &fcn.blocks.front(), &stmt - &bb.statements.front());
+
+ // If the statement is a drop of a local, then don't count that as a read
+ // - But do record the location of the drop, so it can be deleted later on?
+ if( stmt.is_Drop() )
+ {
+ const auto& drop_lv = stmt.as_Drop().slot;
+ if( drop_lv.m_root.is_Local() && drop_lv.m_wrappers.empty() )
+ {
+ auto& slot = usage_info[drop_lv.m_root.as_Local()];
+ slot.drop_locs.push_back(cur_loc);
+ continue ;
+ }
+ }
+
+ //DEBUG(cur_loc << ":" << stmt);
+ visit_mir_lvalues(stmt, visit_cb);
+ }
+ cur_loc = StmtRef(&bb - &fcn.blocks.front(), bb.statements.size());
+ //DEBUG(cur_loc << ":" << bb.terminator);
+ visit_mir_lvalues(bb.terminator, visit_cb);
+ }
+
+ // Look single-write/deref-only locals assigned with `_0 = Borrow`
+ for(size_t var_idx = 0; var_idx < fcn.locals.size(); var_idx ++)
+ {
+ const auto& slot = usage_info[var_idx];
+ auto this_var = ::MIR::LValue::new_Local(var_idx);
+
+ // This rule only applies to single-write variables, with no use other than via derefs
+ if( !(slot.n_write == 1 && slot.n_other_read == 0) )
+ {
+ //DEBUG(this_var << " - Multi-assign, or use-by-value");
+ continue ;
+ }
+ if( slot.n_deref_read == 0 )
+ {
+ //DEBUG(this_var << " - Not used");
+ continue ;
+ }
+
+ // Check that the source was a borrow statement
+ auto& src_bb = fcn.blocks[slot.set_loc.bb_idx];
+ if( !(slot.set_loc.stmt_idx < src_bb.statements.size() && TU_TEST1(src_bb.statements[slot.set_loc.stmt_idx], Assign, .src.is_Borrow())) )
+ {
+ DEBUG(this_var << " - Source is not a borrow op");
+ continue;
+ }
+ const auto& src_lv = src_bb.statements[slot.set_loc.stmt_idx].as_Assign().src.as_Borrow().val;
+ // Check that the borrow isn't too complex
+ // TODO: If there's only one use, then no complexity limit?
+ if( src_lv.m_wrappers.size() >= 2 )
+ {
+ DEBUG(this_var << " - Source is too complex - " << src_lv);
+ continue;
+ }
+ if( slot.n_deref_read > 1 && fcn.locals[var_idx].m_data.as_Borrow().type != ::HIR::BorrowType::Shared )
+ {
+ DEBUG(this_var << " - Multi-use non-shared borrow, too complex to do");
+ continue;
+ }
+ DEBUG(this_var << " - Borrow of " << src_lv << " at " << slot.set_loc << ", used " << slot.n_deref_read << " times (dropped " << slot.drop_locs << ")");
+
+ // Locate usage sites (by walking forwards) and check for invalidation
+ auto cur_loc = slot.set_loc;
+ cur_loc.stmt_idx ++;
+ unsigned num_replaced = 0;
+ auto replace_cb = [&](::MIR::LValue& lv, auto _vu) {
+ if( lv.m_root == this_var.m_root )
+ {
+ ASSERT_BUG(Span(), !lv.m_wrappers.empty(), cur_loc << " " << lv);
+ assert(lv.m_wrappers.front().is_Deref());
+ // Make a LValue reference, then overwrite it
+ {
+ auto lvr = ::MIR::LValue::MRef(lv);
+ while(lvr.wrapper_count() > 1)
+ lvr.try_unwrap();
+ DEBUG(this_var << " " << cur_loc << " - Replace " << lvr << " with " << src_lv << " in " << lv);
+ lvr.replace(src_lv.clone());
+ }
+ DEBUG("= " << lv);
+ assert(lv.m_root != this_var.m_root);
+ assert(num_replaced < slot.n_deref_read);
+ num_replaced += 1;
+ }
+ return false;
+ };
+ for(bool stop = false; !stop; )
+ {
+ auto& cur_bb = fcn.blocks[cur_loc.bb_idx];
+ for(; cur_loc.stmt_idx < cur_bb.statements.size(); cur_loc.stmt_idx ++)
+ {
+ auto& stmt = cur_bb.statements[cur_loc.stmt_idx];
+ DEBUG(cur_loc << " " << stmt);
+ // Replace usage
+ bool invalidates = check_invalidates_lvalue(stmt, src_lv);
+ visit_mir_lvalues_mut(stmt, replace_cb);
+ if( num_replaced == slot.n_deref_read )
+ {
+ stop = true;
+ break;
+ }
+ // Check for invalidation (actual check done before replacement)
+ if( invalidates )
+ {
+ // Invalidated, stop here.
+ DEBUG(this_var << " - Source invalidated @ " << cur_loc << " in " << stmt);
+ stop = true;
+ break;
+ }
+ }
+ if( stop ) {
+ break;
+ }
+ // Replace usage
+ visit_mir_lvalues_mut(cur_bb.terminator, replace_cb);
+ if( num_replaced == slot.n_deref_read )
+ {
+ stop = true;
+ break;
+ }
+ // Check for invalidation
+ if( check_invalidates_lvalue(cur_bb.terminator, src_lv) )
+ {
+ DEBUG(this_var << " - Source invalidated @ " << cur_loc << " in " << cur_bb.terminator);
+ stop = true;
+ break;
+ }
+
+ TU_MATCH_HDRA( (cur_bb.terminator), { )
+ default:
+ stop = true;
+ break;
+ // TODO: History is needed to avoid infinite loops from triggering infinite looping here.
+ //TU_ARMA(Goto, e) {
+ // cur_pos.bb_idx = e;
+ // cur_pos.stmt_idx = 0;
+ // }
+ // NOTE: `Call` can't work in the presense of unwinding, would need to traverse both paths
+ //TU_ARMA(Call, e) {
+ // }
+ }
+ }
+
+ // If the source was an inner deref, update its counts
+ if( src_lv.m_root.is_Local() && !src_lv.m_wrappers.empty() && src_lv.m_wrappers.front().is_Deref() )
+ {
+ usage_info[src_lv.m_root.as_Local()].n_deref_read += num_replaced;
+ if(num_replaced == slot.n_deref_read)
+ {
+ usage_info[src_lv.m_root.as_Local()].n_deref_read -= 1;
+ }
+ }
+
+ // If all usage sites were updated, then remove the original assignment
+ if(num_replaced == slot.n_deref_read)
+ {
+ DEBUG(this_var << " - Erase " << slot.set_loc << " as it is no longer used (" << src_bb.statements[slot.set_loc.stmt_idx] << ")");
+ src_bb.statements[slot.set_loc.stmt_idx] = ::MIR::Statement();
+ for(const auto& drop_loc : slot.drop_locs)
+ {
+ DEBUG(this_var << " - Drop at " << drop_loc);
+ fcn.blocks[drop_loc.bb_idx].statements[drop_loc.stmt_idx] = ::MIR::Statement();
+ }
+ }
+#if 0
+ else if( num_replaced > 0 )
+ {
+ auto src_rval = ::std::move(src_bb.statements[slot.set_loc.stmt_idx].as_Assign().src);
+ src_bb.statements[slot.set_loc.stmt_idx] = ::MIR::Statement();
+ DEBUG(this_var << " - Move " << slot.set_loc << " to after " << cur_loc);
+ // TODO: Move the source borrow up to this point.
+ auto& cur_bb = fcn.blocks[cur_loc.bb_idx];
+ if( cur_loc.stmt_idx >= cur_bb.statements.size() )
+ {
+ auto push_bb_front = [&fcn,&this_var](unsigned b, ::MIR::RValue s){
+ fcn.blocks[b].statements.insert(fcn.blocks[b].statements.begin(), ::MIR::Statement::make_Assign({ this_var.clone(), ::std::move(s) }));
+ // TODO: Update all references to this block?
+ };
+ // Move the borrow to the next block?
+ // - Terminators shouldn't be able to invalidate...
+ TU_MATCH_HDRA( (cur_bb.terminator), { )
+ default:
+ TODO(Span(), "Move borrow to after terminator " << cur_bb.terminator);
+ TU_ARMA(Goto, e) {
+ push_bb_front(e, ::std::move(src_rval));
+ }
+ TU_ARMA(Call, e) {
+ push_bb_front(e.ret_block, src_rval.clone());
+ push_bb_front(e.panic_block, ::std::move(src_rval));
+ }
+ }
+ }
+ else
+ {
+ // If invalidated, then there _shouldn't_ be more to come (borrow rules)
+ TODO(Span(), "Move borrow to after " << cur_loc);
+ }
+ }
+#endif
+ else
+ {
+ // No replacement, keep the source where it is
+ DEBUG(this_var << " - Keep " << slot.set_loc);
+ }
+
+ // Any replacements? Then there was an actionable change
+ if( num_replaced > 0 )
+ {
+ changed = true;
+ }
+ }
+#endif
+
+ return changed;
+}
+
// --------------------------------------------------------------------
// Replaces uses of stack slots with what they were assigned with (when
// possible)
@@ -1373,10 +2072,16 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
bool changed = false;
TRACE_FUNCTION_FR("", changed);
+ changed |= MIR_Optimise_DeTemporary_SingleSetAndUse(state, fcn);
+ changed |= MIR_Optimise_DeTemporary_Borrows(state, fcn);
+
+
+ // OLD ALGORITHM.
for(unsigned int bb_idx = 0; bb_idx < fcn.blocks.size(); bb_idx ++)
{
auto& bb = fcn.blocks[bb_idx];
::std::map<unsigned,unsigned> local_assignments; // Local number -> statement index
+ // TODO: Keep track of what variables would invalidate a local (and compound on assignment)
::std::vector<unsigned> statements_to_remove; // List of statements that have to be removed
// ----- Helper closures -----
@@ -1388,7 +2093,7 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
const auto& src_rvalue = bb.statements[it->second].as_Assign().src;
// Destination invalidated?
- if( lv.is_Local() && it->first == lv.as_Local() )
+ if( lv.m_root.is_Local() && it->first == lv.m_root.as_Local() )
{
switch(vu)
{
@@ -1409,8 +2114,9 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
case ValUsage::Borrow: // Borrows are annoying, assume they invalidate anything used
case ValUsage::Write: // Mutated? It's invalidated
case ValUsage::Move: // Moved? Now invalid
- visit_mir_lvalues(src_rvalue, [&](const auto& s_lv, auto /*s_vu*/) {
- if( s_lv == lv )
+ visit_mir_lvalues(src_rvalue, [&](const ::MIR::LValue& s_lv, auto s_vu) {
+ //DEBUG(" " << s_lv << " ?= " << lv);
+ if( s_lv.m_root == lv.m_root )
{
DEBUG(state << "> Invalidates source of Local(" << it->first << ") - " << src_rvalue);
invalidated = true;
@@ -1444,39 +2150,37 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
// > For now, don't do the replacement if it would delete the assignment UNLESS it's directly being used)
// 2. Search for replacements
- bool top_level = true;
- visit_mir_lvalue_mut(top_lv, top_usage, [&](auto& ilv, auto /*i_usage*/) {
- if( ilv.is_Local() )
+ if( top_lv.m_root.is_Local() )
+ {
+ bool top_level = top_lv.m_wrappers.empty();
+ auto ilv = ::MIR::LValue::new_Local(top_lv.m_root.as_Local());
+ auto it = local_assignments.find(top_lv.m_root.as_Local());
+ if( it != local_assignments.end() )
{
- auto it = local_assignments.find(ilv.as_Local());
- if( it != local_assignments.end() )
+ const auto& new_val = bb.statements[it->second].as_Assign().src.as_Use();
+ // - Copy? All is good.
+ if( state.lvalue_is_copy(ilv) )
{
- // - Copy? All is good.
- if( state.lvalue_is_copy(ilv) )
- {
- ilv = bb.statements[it->second].as_Assign().src.as_Use().clone();
- DEBUG(state << "> Replace (and keep) Local(" << it->first << ") with " << ilv);
- }
- // - Top-level (directly used) also good.
- else if( top_level && top_usage == ValUsage::Move )
- {
- // TODO: DstMeta/DstPtr _doesn't_ move, so shouldn't trigger this.
- ilv = bb.statements[it->second].as_Assign().src.as_Use().clone();
- DEBUG(state << "> Replace (and remove) Local(" << it->first << ") with " << ilv);
- statements_to_remove.push_back( it->second );
- local_assignments.erase(it);
- }
- // - Otherwise, remove the record.
- else
- {
- DEBUG(state << "> Non-copy value used within a LValue, remove record of Local(" << it->first << ")");
- local_assignments.erase(it);
- }
+ top_lv = new_val.clone_wrapped(top_lv.m_wrappers.begin(), top_lv.m_wrappers.end());
+ DEBUG(state << "> Replace (and keep) Local(" << it->first << ") with " << new_val);
+ }
+ // - Top-level (directly used) also good.
+ else if( top_level && top_usage == ValUsage::Move )
+ {
+ // TODO: DstMeta/DstPtr _doesn't_ move, so shouldn't trigger this.
+ top_lv = new_val.clone();
+ DEBUG(state << "> Replace (and remove) Local(" << it->first << ") with " << new_val);
+ statements_to_remove.push_back( it->second );
+ local_assignments.erase(it);
+ }
+ // - Otherwise, remove the record.
+ else
+ {
+ DEBUG(state << "> Non-copy value used within a LValue, remove record of Local(" << it->first << ")");
+ local_assignments.erase(it);
}
}
- top_level = false;
- return false;
- });
+ }
// Return true to prevent recursion
return true;
};
@@ -1503,12 +2207,16 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
// - Check if this is a new assignment
if( stmt.is_Assign() && stmt.as_Assign().dst.is_Local() && stmt.as_Assign().src.is_Use() )
{
- if( visit_mir_lvalue(stmt.as_Assign().src.as_Use(), ValUsage::Read, [&](const auto& lv, auto /*vu*/) {
- return lv == stmt.as_Assign().dst;
- }) )
+ const auto& dst_lv = stmt.as_Assign().dst;
+ const auto& src_lv = stmt.as_Assign().src.as_Use();
+ if( visit_mir_lvalues_inner(src_lv, ValUsage::Read, [&](const auto& lv, auto) { return lv.m_root == dst_lv.m_root; }) )
{
DEBUG(state << "> Don't record, self-referrential");
}
+ else if( ::std::any_of(src_lv.m_wrappers.begin(), src_lv.m_wrappers.end(), [](const auto& w){ return w.is_Deref(); }) )
+ {
+ DEBUG(state << "> Don't record, dereference");
+ }
else
{
local_assignments.insert(::std::make_pair( stmt.as_Assign().dst.as_Local(), stmt_idx ));
@@ -1680,12 +2388,13 @@ bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& f
{
DEBUG("Replacing temporaries using {" << replacements << "}");
visit_mir_lvalues_mut(state, fcn, [&](auto& lv, auto ) {
- if( auto* ve = lv.opt_Local() ) {
- auto it = replacements.find(*ve);
+ if( lv.m_root.is_Local() )
+ {
+ auto it = replacements.find(lv.m_root.as_Local());
if( it != replacements.end() )
{
MIR_DEBUG(state, lv << " => Local(" << it->second << ")");
- *ve = it->second;
+ lv.m_root = ::MIR::LValue::Storage::new_Local(it->second);
return true;
}
}
@@ -1948,7 +2657,7 @@ bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Functio
if( stmt_idx == bb.statements.size() )
{
DEBUG("BB" << bb_idx << "/TERM - " << bb.terminator);
- if( terminator_invalidates_lvalue(bb.terminator, slot_lvalue) ) {
+ if( check_invalidates_lvalue(bb.terminator, slot_lvalue) ) {
return nullptr;
}
continue ;
@@ -1982,13 +2691,13 @@ bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Functio
if(stmt_idx == bb.statements.size())
{
DEBUG("BB" << bb_idx << "/TERM - " << bb.terminator);
- if( terminator_invalidates_lvalue(bb.terminator, src_lval) ) {
+ if( check_invalidates_lvalue(bb.terminator, src_lval) ) {
// Invalidated: Return.
return nullptr;
}
continue ;
}
- if( statement_invalidates_lvalue(bb.statements[stmt_idx], src_lval) ) {
+ if( check_invalidates_lvalue(bb.statements[stmt_idx], src_lval) ) {
// Invalidated: Return.
return nullptr;
}
@@ -2002,7 +2711,7 @@ bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Functio
}
// Check if the slot is invalidated (mutated)
- if( statement_invalidates_lvalue(stmt, slot_lvalue) ) {
+ if( check_invalidates_lvalue(stmt, slot_lvalue) ) {
return nullptr;
}
}
@@ -2021,33 +2730,34 @@ bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Functio
state.set_cur_stmt(bb_idx, i);
DEBUG(state << block.statements[i]);
visit_mir_lvalues_mut(block.statements[i], [&](::MIR::LValue& lv, auto vu) {
- if(const auto* e = lv.opt_Field())
+ if(vu == ValUsage::Read && lv.m_wrappers.size() > 1 && lv.m_wrappers.front().is_Field() && lv.m_root.is_Local())
{
- if(vu == ValUsage::Read && e->val->is_Local() ) {
- // TODO: This value _must_ be Copy for this optimisation to work.
- // - OR, it has to somehow invalidate the original tuple
- DEBUG(state << "Locating origin of " << lv);
- ::HIR::TypeRef tmp;
- if( !state.m_resolve.type_is_copy(state.sp, state.get_lvalue_type(tmp, *e->val)) )
+ auto field_index = lv.m_wrappers.front().as_Field();
+ auto inner_lv = ::MIR::LValue::new_Local(lv.m_root.as_Local());
+ auto outer_lv = ::MIR::LValue::new_Field(inner_lv.clone(), field_index);
+ // TODO: This value _must_ be Copy for this optimisation to work.
+ // - OR, it has to somehow invalidate the original tuple
+ DEBUG(state << "Locating origin of " << lv);
+ ::HIR::TypeRef tmp;
+ if( !state.m_resolve.type_is_copy(state.sp, state.get_lvalue_type(tmp, inner_lv)) )
+ {
+ DEBUG(state << "- not Copy, can't optimise");
+ return false;
+ }
+ const auto* source_lvalue = get_field(inner_lv, field_index, bb_idx, i);
+ if( source_lvalue )
+ {
+ if( outer_lv != *source_lvalue )
{
- DEBUG(state << "- not Copy, can't optimise");
- return false;
+ DEBUG(state << "Source is " << *source_lvalue);
+ lv = source_lvalue->clone_wrapped( lv.m_wrappers.begin() + 1, lv.m_wrappers.end() );
+ change_happend = true;
}
- const auto* source_lvalue = get_field(*e->val, e->field_index, bb_idx, i);
- if( source_lvalue )
+ else
{
- if( lv != *source_lvalue )
- {
- DEBUG(state << "Source is " << *source_lvalue);
- lv = source_lvalue->clone();
- change_happend = true;
- }
- else
- {
- DEBUG(state << "No change");
- }
- return false;
+ DEBUG(state << "No change");
}
+ return false;
}
}
return false;
@@ -2148,6 +2858,23 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
bb.terminator = ::MIR::Terminator::make_Goto(te.ret_block);
changed = true;
}
+ else if( tef.name == "needs_drop" )
+ {
+ // Returns `true` if the actual type given as `T` requires drop glue;
+ // returns `false` if the actual type provided for `T` implements `Copy`. (Either otherwise)
+ // NOTE: libarena assumes that this returns `true` iff T doesn't require drop glue.
+ const auto& ty = tef.params.m_types.at(0);
+ // - Only expand at this stage if there's no generics, and no unbound paths
+ if( !visit_ty_with(ty, [](const ::HIR::TypeRef& ty)->bool{
+ return ty.m_data.is_Generic() || TU_TEST1(ty.m_data, Path, .binding.is_Unbound());
+ }) )
+ {
+ bool needs_drop = state.m_resolve.type_needs_drop_glue(state.sp, ty);
+ bb.statements.push_back(::MIR::Statement::make_Assign({ mv$(te.ret_val), ::MIR::RValue::make_Constant(::MIR::Constant::make_Bool({needs_drop})) }));
+ bb.terminator = ::MIR::Terminator::make_Goto(te.ret_block);
+ changed = true;
+ }
+ }
else
{
// Ignore any other intrinsics
@@ -2170,13 +2897,42 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
::std::map< ::MIR::LValue, unsigned > known_values_var;
::std::map< unsigned, bool > known_drop_flags;
+ auto check_lv = [&](const ::MIR::LValue& lv)->::MIR::Constant {
+ auto it = known_values.find(lv);
+ if( it != known_values.end() )
+ {
+ DEBUG(state << "Value " << lv << " known to be" << it->second);
+ return it->second.clone();
+ }
+
+ // TODO: If the inner of the value is known,
+ // AND all indexes are known - expand
+ //if( !lv.m_wrappers.empty() )
+ //{
+ // it = known_values.find(lv.m_root);
+ // if( it != known_values.end() )
+ // {
+ // // TODO: Use HIR::Literal instead so composites can be handled.
+ // for(const auto& w : lv.m_wrappers)
+ // {
+ // }
+ // }
+ //}
+
+ // Not a known value, and not a known composite
+ // - Use a nullptr ItemAddr to indicate this
+ return ::MIR::Constant::make_ItemAddr({});
+ };
auto check_param = [&](::MIR::Param& p) {
if(const auto* pe = p.opt_LValue()) {
- auto it = known_values.find(*pe);
- if( it != known_values.end() )
+ auto nv = check_lv(*pe);
+ if( nv.is_ItemAddr() && !nv.as_ItemAddr() )
+ {
+ // ItemAddr with a nullptr inner means "no expansion"
+ }
+ else
{
- DEBUG(state << "Value " << *pe << " known to be " << it->second);
- p = it->second.clone();
+ p = mv$(nv);
}
}
};
@@ -2193,11 +2949,14 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
TU_MATCHA( (e->src), (se),
(Use,
- auto it = known_values.find(se);
- if( it != known_values.end() )
+ auto nv = check_lv(se);
+ if( nv.is_ItemAddr() && !nv.as_ItemAddr() )
{
- DEBUG(state << "Value " << se << " known to be" << it->second);
- e->src = it->second.clone();
+ // ItemAddr with a nullptr inner means "no expansion"
+ }
+ else
+ {
+ e->src = ::MIR::RValue::make_Constant(mv$(nv));
}
),
(Constant,
@@ -2219,75 +2978,157 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
const auto& val_l = se.val_l.as_Constant();
const auto& val_r = se.val_r.as_Constant();
- ::MIR::Constant new_value;
- bool replace = false;
- switch(se.op)
+ if( val_l.is_Const() || val_r.is_Const() )
{
- case ::MIR::eBinOp::EQ:
- if( val_l.is_Const() || val_r.is_Const() )
- ;
- else
+ }
+ else
+ {
+ struct H {
+ static int64_t truncate_s(::HIR::CoreType ct, int64_t v) {
+ return v;
+ }
+ static uint64_t truncate_u(::HIR::CoreType ct, uint64_t v) {
+ switch(ct)
+ {
+ case ::HIR::CoreType::U8: return v & 0xFF;
+ case ::HIR::CoreType::U16: return v & 0xFFFF;
+ case ::HIR::CoreType::U32: return v & 0xFFFFFFFF;
+ case ::HIR::CoreType::U64: return v;
+ case ::HIR::CoreType::U128: return v;
+ case ::HIR::CoreType::Usize: return v;
+ case ::HIR::CoreType::Char:
+ //MIR_BUG(state, "Invalid use of operator on char");
+ break;
+ default:
+ // Invalid type for Uint literal
+ break;
+ }
+ return v;
+ }
+ };
+ ::MIR::Constant new_value;
+ switch(se.op)
{
- replace = true;
+ case ::MIR::eBinOp::EQ:
new_value = ::MIR::Constant::make_Bool({val_l == val_r});
- }
- break;
- case ::MIR::eBinOp::NE:
- if( val_l.is_Const() || val_r.is_Const() )
- ;
- else
- {
- replace = true;
+ break;
+ case ::MIR::eBinOp::NE:
new_value = ::MIR::Constant::make_Bool({val_l != val_r});
- }
- break;
- case ::MIR::eBinOp::LT:
- if( val_l.is_Const() || val_r.is_Const() )
- ;
- else
- {
- replace = true;
+ break;
+ case ::MIR::eBinOp::LT:
new_value = ::MIR::Constant::make_Bool({val_l < val_r});
- }
- break;
- case ::MIR::eBinOp::LE:
- if( val_l.is_Const() || val_r.is_Const() )
- ;
- else
- {
- replace = true;
+ break;
+ case ::MIR::eBinOp::LE:
new_value = ::MIR::Constant::make_Bool({val_l <= val_r});
- }
- break;
- case ::MIR::eBinOp::GT:
- if( val_l.is_Const() || val_r.is_Const() )
- ;
- else
- {
- replace = true;
+ break;
+ case ::MIR::eBinOp::GT:
new_value = ::MIR::Constant::make_Bool({val_l > val_r});
- }
- break;
- case ::MIR::eBinOp::GE:
- if( val_l.is_Const() || val_r.is_Const() )
- ;
- else
- {
- replace = true;
+ break;
+ case ::MIR::eBinOp::GE:
new_value = ::MIR::Constant::make_Bool({val_l >= val_r});
+ break;
+
+ case ::MIR::eBinOp::ADD:
+ MIR_ASSERT(state, val_l.tag() == val_r.tag(), "Mismatched types for eBinOp::ADD - " << val_l << " + " << val_r);
+ //{TU_MATCH_HDRA( (val_l, val_r), {)
+ {TU_MATCH_HDRA( (val_l), {)
+ default:
+ break;
+ // TU_ARMav(Int, (le, re)) {
+ TU_ARMA(Int, le) { const auto& re = val_r.as_Int();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::ADD - " << val_l << " + " << val_r);
+ new_value = ::MIR::Constant::make_Int({ H::truncate_s(le.t, le.v + re.v), le.t });
+ }
+ TU_ARMA(Uint, le) { const auto& re = val_r.as_Uint();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::ADD - " << val_l << " + " << val_r);
+ new_value = ::MIR::Constant::make_Uint({ H::truncate_u(le.t, le.v + re.v), le.t });
+ }
+ }}
+ break;
+ case ::MIR::eBinOp::SUB:
+ MIR_ASSERT(state, val_l.tag() == val_r.tag(), "Mismatched types for eBinOp::SUB - " << val_l << " + " << val_r);
+ //{TU_MATCH_HDRA( (val_l, val_r), {)
+ {TU_MATCH_HDRA( (val_l), {)
+ default:
+ break;
+ // TU_ARMav(Int, (le, re)) {
+ TU_ARMA(Int, le) { const auto& re = val_r.as_Int();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::SUB - " << val_l << " - " << val_r);
+ new_value = ::MIR::Constant::make_Int({ H::truncate_s(le.t, le.v - re.v), le.t });
+ }
+ TU_ARMA(Uint, le) { const auto& re = val_r.as_Uint();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::SUB - " << val_l << " - " << val_r);
+ new_value = ::MIR::Constant::make_Uint({ H::truncate_u(le.t, le.v - re.v), le.t });
+ }
+ }}
+ break;
+ case ::MIR::eBinOp::MUL:
+ MIR_ASSERT(state, val_l.tag() == val_r.tag(), "Mismatched types for eBinOp::MUL - " << val_l << " * " << val_r);
+ //{TU_MATCH_HDRA( (val_l, val_r), {)
+ {TU_MATCH_HDRA( (val_l), {)
+ default:
+ break;
+ // TU_ARMav(Int, (le, re)) {
+ TU_ARMA(Int, le) { const auto& re = val_r.as_Int();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::MUL - " << val_l << " * " << val_r);
+ new_value = ::MIR::Constant::make_Int({ H::truncate_s(le.t, le.v * re.v), le.t });
+ }
+ TU_ARMA(Uint, le) { const auto& re = val_r.as_Uint();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::MUL - " << val_l << " * " << val_r);
+ new_value = ::MIR::Constant::make_Uint({ H::truncate_u(le.t, le.v * re.v), le.t });
+ }
+ }}
+ break;
+ case ::MIR::eBinOp::DIV:
+ MIR_ASSERT(state, val_l.tag() == val_r.tag(), "Mismatched types for eBinOp::DIV - " << val_l << " / " << val_r);
+ //{TU_MATCH_HDRA( (val_l, val_r), {)
+ {TU_MATCH_HDRA( (val_l), {)
+ default:
+ break;
+ // TU_ARMav(Int, (le, re)) {
+ TU_ARMA(Int, le) { const auto& re = val_r.as_Int();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::DIV - " << val_l << " / " << val_r);
+ MIR_ASSERT(state, re.v != 0, "Const eval error: Constant division by zero");
+ new_value = ::MIR::Constant::make_Int({ H::truncate_s(le.t, le.v / re.v), le.t });
+ }
+ TU_ARMA(Uint, le) { const auto& re = val_r.as_Uint();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::DIV - " << val_l << " / " << val_r);
+ MIR_ASSERT(state, re.v != 0, "Const eval error: Constant division by zero");
+ new_value = ::MIR::Constant::make_Uint({ H::truncate_u(le.t, le.v / re.v), le.t });
+ }
+ }}
+ break;
+ case ::MIR::eBinOp::MOD:
+ MIR_ASSERT(state, val_l.tag() == val_r.tag(), "Mismatched types for eBinOp::MOD - " << val_l << " % " << val_r);
+ //{TU_MATCH_HDRA( (val_l, val_r), {)
+ {TU_MATCH_HDRA( (val_l), {)
+ default:
+ break;
+ // TU_ARMav(Int, (le, re)) {
+ TU_ARMA(Int, le) { const auto& re = val_r.as_Int();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::MOD - " << val_l << " % " << val_r);
+ MIR_ASSERT(state, re.v != 0, "Const eval error: Constant division by zero");
+ new_value = ::MIR::Constant::make_Int({ H::truncate_s(le.t, le.v % re.v), le.t });
+ }
+ TU_ARMA(Uint, le) { const auto& re = val_r.as_Uint();
+ MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::MOD - " << val_l << " % " << val_r);
+ MIR_ASSERT(state, re.v != 0, "Const eval error: Constant division by zero");
+ new_value = ::MIR::Constant::make_Uint({ H::truncate_u(le.t, le.v % re.v), le.t });
+ }
+ }}
+ break;
+ // TODO: Other binary operations
+ // Could emit a TODO?
+ default:
+ break;
}
- break;
- // TODO: Other binary operations
- // Could emit a TODO?
- default:
- break;
- }
- if( replace )
- {
- DEBUG(state << " " << e->src << " = " << new_value);
- e->src = mv$(new_value);
- changed = true;
+ if( new_value != ::MIR::Constant() )
+ {
+ DEBUG(state << " " << e->src << " = " << new_value);
+ e->src = mv$(new_value);
+ changed = true;
+ }
}
}
),
@@ -2305,6 +3146,7 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
TU_MATCHA( (val), (ve),
(Uint,
auto val = ve.v;
+ replace = true;
switch(ve.t)
{
case ::HIR::CoreType::U8: val = (~val) & 0xFF; break;
@@ -2315,17 +3157,17 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
val = ~val;
break;
case ::HIR::CoreType::U128:
- val = ~val;
+ replace = false;
break;
case ::HIR::CoreType::Char:
MIR_BUG(state, "Invalid use of ! on char");
break;
default:
// Invalid type for Uint literal
+ replace = false;
break;
}
new_value = ::MIR::Constant::make_Uint({ val, ve.t });
- replace = true;
),
(Int,
// Is ! valid on Int?
@@ -2588,7 +3430,10 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
// --------------------------------------------------------------------
// Split `var = Tuple(...,)` into `varN = ...` if the tuple isn't used by
-// value.
+// value (nor borrowed).
+//
+// NOTE: The "nor borrowed" rule is needed to avoid issues when the first element of a tuple
+// is used as a proxy for the entire tuple.
// --------------------------------------------------------------------
bool MIR_Optimise_SplitAggregates(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
@@ -2642,6 +3487,18 @@ bool MIR_Optimise_SplitAggregates(::MIR::TypeResolve& state, ::MIR::Function& fc
auto it = potentials.find(lv.as_Local());
if( it != potentials.end() )
{
+ DEBUG(lv << " invalidated due to root usage");
+ potentials.erase(it);
+ }
+ }
+ // If the variable is borrowed (even via wrappers)
+ // TODO: Restrict this to when the borrow is just via field accesses
+ if( lv.m_root.is_Local() && vu == ValUsage::Borrow )
+ {
+ auto it = potentials.find(lv.m_root.as_Local());
+ if( it != potentials.end() )
+ {
+ DEBUG(lv << " invalidate due to any borrow");
potentials.erase(it);
}
}
@@ -2689,15 +3546,17 @@ bool MIR_Optimise_SplitAggregates(::MIR::TypeResolve& state, ::MIR::Function& fc
for(auto& blk : fcn.blocks)
{
auto cb = [&](auto& lv, auto _vu) {
- if(lv.is_Field() && lv.as_Field().val->is_Local())
+ if( !lv.m_wrappers.empty() && lv.m_wrappers.front().is_Field() && lv.m_root.is_Local() )
{
- auto fld_idx = lv.as_Field().field_index;
- auto it = replacements.find( lv.as_Field().val->as_Local() );
+ auto fld_idx = lv.m_wrappers.front().as_Field();
+ auto it = replacements.find( lv.m_root.as_Local() );
if( it != replacements.end() )
{
MIR_ASSERT(state, fld_idx < it->second.size(), "Tuple field index out of range");
DEBUG(state << "Replace " << lv << " with Local(" << it->second.at(fld_idx) << ")");
- lv = ::MIR::LValue::make_Local(it->second.at(fld_idx));
+
+ lv.m_wrappers.erase( lv.m_wrappers.begin() );
+ lv.m_root = ::MIR::LValue::Storage::new_Local(it->second.at(fld_idx));
}
}
return false;
@@ -2719,7 +3578,7 @@ bool MIR_Optimise_SplitAggregates(::MIR::TypeResolve& state, ::MIR::Function& fc
for(size_t i = 0; i < vals.size(); i ++)
{
- auto lv = ::MIR::LValue::make_Local(rit->second[i]);
+ auto lv = ::MIR::LValue::new_Local(rit->second[i]);
auto rv = vals[i].is_LValue()
? ::MIR::RValue(::std::move( vals[i].as_LValue() ))
: ::MIR::RValue(::std::move( vals[i].as_Constant() ))
@@ -2764,13 +3623,16 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
::std::vector<ValUse> local_uses;
void use_lvalue(const ::MIR::LValue& lv, ValUsage ut) {
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Argument,
- ),
- (Local,
- auto& vu = local_uses[e];
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( w.is_Index() ){
+ //local_uses[w.as_Index()].read += 1;
+ local_uses[w.as_Index()].borrow += 1;
+ }
+ }
+ if( lv.m_root.is_Local() )
+ {
+ auto& vu = local_uses[lv.m_root.as_Local()];
switch(ut)
{
case ValUsage::Move:
@@ -2778,23 +3640,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
case ValUsage::Write: vu.write += 1; break;
case ValUsage::Borrow: vu.borrow += 1; break;
}
- ),
- (Static,
- ),
- (Field,
- use_lvalue(*e.val, ut);
- ),
- (Deref,
- use_lvalue(*e.val, ut);
- ),
- (Index,
- use_lvalue(*e.val, ut);
- use_lvalue(*e.idx, ValUsage::Read);
- ),
- (Downcast,
- use_lvalue(*e.val, ut);
- )
- )
+ }
}
} val_uses = {
::std::vector<ValUse>(fcn.locals.size())
@@ -2810,7 +3656,11 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
// > Replace usage with the inner of the original `Use`
{
// 1. Assignments (forward propagate)
- ::std::map< ::MIR::LValue, ::MIR::RValue> replacements;
+ //::std::map< ::MIR::LValue::CRef, ::MIR::RValue> replacements;
+ ::std::vector< ::std::pair<::MIR::LValue, ::MIR::RValue> > replacements;
+ auto replacements_find = [&replacements](const ::MIR::LValue::CRef& lv) {
+ return ::std::find_if(replacements.begin(), replacements.end(), [&](const auto& e) { return lv == e.first; });
+ };
for(const auto& block : fcn.blocks)
{
if( block.terminator.tag() == ::MIR::Terminator::TAGDEAD )
@@ -2818,16 +3668,18 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
for(unsigned int stmt_idx = 0; stmt_idx < block.statements.size(); stmt_idx ++)
{
+ state.set_cur_stmt(&block - &fcn.blocks.front(), stmt_idx);
const auto& stmt = block.statements[stmt_idx];
+ DEBUG(state << stmt);
// > Assignment
if( ! stmt.is_Assign() )
continue ;
const auto& e = stmt.as_Assign();
// > Of a temporary from with a RValue::Use
- if( const auto* de = e.dst.opt_Local() )
+ if( e.dst.is_Local() )
{
- const auto& vu = val_uses.local_uses[*de];
- DEBUG(e.dst << " - VU " << e.dst << " R:" << vu.read << " W:" << vu.write << " B:" << vu.borrow);
+ const auto& vu = val_uses.local_uses[e.dst.as_Local()];
+ DEBUG(" - VU " << e.dst << " R:" << vu.read << " W:" << vu.write << " B:" << vu.borrow);
// TODO: Allow write many?
// > Where the variable is written once and read once
if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
@@ -2837,38 +3689,33 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
{
continue ;
}
- DEBUG(e.dst << " = " << e.src);
if( e.src.is_Use() )
{
// Keep the complexity down
const auto* srcp = &e.src.as_Use();
- while( srcp->is_Field() )
- srcp = &*srcp->as_Field().val;
- if( !srcp->is_Local() )
+ if( ::std::any_of(srcp->m_wrappers.begin(), srcp->m_wrappers.end(), [](auto& w) { return !w.is_Field(); }) )
+ continue ;
+ if( !srcp->m_root.is_Local() )
continue ;
- if( replacements.find(*srcp) != replacements.end() )
+ if( replacements_find(*srcp) != replacements.end() )
{
DEBUG("> Can't replace, source has pending replacement");
continue;
}
}
- // TODO: Allow any rvalue, but that currently breaks due to chaining
- //else if( e.src.is_Borrow() )
- //{
- //}
else
{
continue ;
}
bool src_is_lvalue = e.src.is_Use();
+ DEBUG("- Locate usage");
- auto is_lvalue_usage = [&](const auto& lv, auto ){ return lv == e.dst; };
-
- // Returns `true` if the passed lvalue is used as a part of the source
- auto is_lvalue_in_val = [&](const auto& lv) {
- return visit_mir_lvalues(e.src, [&](const auto& slv, auto ) { return lv == slv; });
+ auto is_lvalue_usage = [&](const auto& lv, auto ){
+ return lv.m_root == e.dst.m_root;
+ //return lv == e.dst;
};
+
// Eligable for replacement
// Find where this value is used
// - Stop on a conditional block terminator
@@ -2877,8 +3724,15 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
bool found = false;
for(unsigned int si2 = stmt_idx+1; si2 < block.statements.size(); si2 ++)
{
+ state.set_cur_stmt(&block - &fcn.blocks.front(), si2);
const auto& stmt2 = block.statements[si2];
- DEBUG("[find usage] " << stmt2);
+ DEBUG(state << "[find usage] " << stmt2);
+
+ // Check for invalidation (done first, to avoid cases where the source is moved into a struct)
+ if( check_invalidates_lvalue(stmt2, e.src.as_Use()) ) {
+ stop = true;
+ break;
+ }
// Usage found.
if( visit_mir_lvalues(stmt2, is_lvalue_usage) )
@@ -2899,18 +3753,18 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
stop = true;
break;
}
-
- // Determine if source is mutated.
- // > Assume that any mutating access of the root value counts (over-cautious)
- if( visit_mir_lvalues(stmt2, [&](const auto& lv, auto vu){ return /*vu == ValUsage::Write &&*/ is_lvalue_in_val(lv); }) )
- {
- stop = true;
- break;
- }
}
if( !stop )
{
- DEBUG("[find usage] " << block.terminator);
+ state.set_cur_stmt_term(&block - &fcn.blocks.front());
+ DEBUG(state << "[find usage] " << block.terminator);
+ if( src_is_lvalue )
+ {
+ visit_mir_lvalues(block.terminator, [&](const auto& lv, auto vu) {
+ found |= is_lvalue_usage(lv, vu);
+ return found;
+ });
+ }
TU_MATCHA( (block.terminator), (e),
(Incomplete,
),
@@ -2924,29 +3778,15 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
(Panic,
),
(If,
- if( src_is_lvalue && visit_mir_lvalue(e.cond, ValUsage::Read, is_lvalue_usage) )
- found = true;
stop = true;
),
(Switch,
- if( src_is_lvalue && visit_mir_lvalue(e.val, ValUsage::Read, is_lvalue_usage) )
- found = true;
stop = true;
),
(SwitchValue,
- if( src_is_lvalue && visit_mir_lvalue(e.val, ValUsage::Read, is_lvalue_usage) )
- found = true;
stop = true;
),
(Call,
- if( e.fcn.is_Value() )
- if( src_is_lvalue && visit_mir_lvalue(e.fcn.as_Value(), ValUsage::Read, is_lvalue_usage) )
- found = true;
- for(const auto& v : e.args)
- {
- if( src_is_lvalue && visit_mir_lvalue(v, ValUsage::Read, is_lvalue_usage) )
- found = true;
- }
stop = true;
)
)
@@ -2954,8 +3794,8 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
// Schedule a replacement in a future pass
if( found )
{
- DEBUG("> Replace " << e.dst << " with " << e.src.as_Use());
- replacements.insert( ::std::make_pair(e.dst.clone(), e.src.clone()) );
+ DEBUG("> Schedule replace " << e.dst << " with " << e.src.as_Use());
+ replacements.push_back( ::std::make_pair(e.dst.clone(), e.src.clone()) );
}
else
{
@@ -2964,21 +3804,26 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
} // for(stmt : block.statements)
}
+ DEBUG("replacements = " << replacements);
+
// Apply replacements within replacements
for(;;)
{
unsigned int inner_replaced_count = 0;
for(auto& r : replacements)
{
- visit_mir_lvalues_mut(r.second, [&](auto& lv, auto vu) {
+ visit_mir_lvalues_mut(r.second, [&](::MIR::LValue& lv, auto vu) {
if( vu == ValUsage::Read || vu == ValUsage::Move )
{
- auto it = replacements.find(lv);
- if( it != replacements.end() && it->second.is_Use() )
- {
- lv = it->second.as_Use().clone();
- inner_replaced_count ++;
- }
+ visit_mir_lvalue_mut(lv, vu, [&](::MIR::LValue::MRef& lvr, auto vu) {
+ auto it = replacements_find(lvr);
+ if( it != replacements.end() && it->second.is_Use() )
+ {
+ lvr.replace( it->second.as_Use().clone() );
+ inner_replaced_count ++;
+ }
+ return false;
+ });
}
return false;
});
@@ -2986,26 +3831,30 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
if( inner_replaced_count == 0 )
break;
}
+ DEBUG("replacements = " << replacements);
// Apply replacements
unsigned int replaced = 0;
while( replaced < replacements.size() )
{
auto old_replaced = replaced;
- auto cb = [&](auto& lv, auto vu){
- if( vu == ValUsage::Read || vu == ValUsage::Move )
- {
- auto it = replacements.find(lv);
- if( it != replacements.end() )
+ auto cb = [&](::MIR::LValue& lv, auto vu){
+ return visit_mir_lvalue_mut(lv, vu, [&](::MIR::LValue::MRef& lv, auto vu) {
+ if( vu == ValUsage::Read || vu == ValUsage::Move )
{
- MIR_ASSERT(state, it->second.tag() != ::MIR::RValue::TAGDEAD, "Replacement of " << lv << " fired twice");
- MIR_ASSERT(state, it->second.is_Use(), "Replacing a lvalue with a rvalue - " << lv << " with " << it->second);
- auto rval = ::std::move(it->second);
- lv = ::std::move(rval.as_Use());
- replaced += 1;
+ auto it = replacements_find(lv);
+ if( it != replacements.end() )
+ {
+ MIR_ASSERT(state, it->second.tag() != ::MIR::RValue::TAGDEAD, "Replacement of " << lv << " fired twice");
+ MIR_ASSERT(state, it->second.is_Use(), "Replacing a lvalue with a rvalue - " << lv << " with " << it->second);
+ auto rval = ::std::move(it->second);
+ DEBUG("> Do replace " << lv << " => " << rval);
+ lv.replace( ::std::move(rval.as_Use()) );
+ replaced += 1;
+ }
}
- }
- return false;
+ return false;
+ });
};
for(unsigned int block_idx = 0; block_idx < fcn.blocks.size(); block_idx ++)
{
@@ -3015,10 +3864,12 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
for(auto& stmt : block.statements)
{
state.set_cur_stmt(block_idx, (&stmt - &block.statements.front()));
+ DEBUG(state << stmt);
+#if 0
if( stmt.is_Assign() && stmt.as_Assign().src.is_Use() )
{
auto& e = stmt.as_Assign();
- auto it = replacements.find(e.src.as_Use());
+ auto it = replacements_find(e.src.as_Use());
if( it != replacements.end() )
{
MIR_ASSERT(state, it->second.tag() != ::MIR::RValue::TAGDEAD, "Replacement of " << it->first << " fired twice");
@@ -3027,6 +3878,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
}
}
else
+#endif
{
visit_mir_lvalues_mut(stmt, cb);
}
@@ -3043,8 +3895,11 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
{
state.set_cur_stmt(&block - &fcn.blocks.front(), (it - block.statements.begin()));
// If the statement was an assign of a replaced temporary, remove it.
- if( it->is_Assign() && replacements.count( it->as_Assign().dst ) > 0 )
+ auto it2 = replacements.end();
+ if( it->is_Assign() && (it2 = replacements_find(it->as_Assign().dst)) != replacements.end() ) {
+ DEBUG(state << "Delete " << *it);
it = block.statements.erase(it);
+ }
else {
MIR_ASSERT(state, !( it->is_Assign() && it->as_Assign().src.tag() == ::MIR::RValue::TAGDEAD ), "");
++it;
@@ -3066,8 +3921,8 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
if( it->as_Assign().src.tag() == ::MIR::RValue::TAGDEAD )
continue ;
auto& to_replace_lval = it->as_Assign().dst;
- if( const auto* e = to_replace_lval.opt_Local() ) {
- const auto& vu = val_uses.local_uses[*e];
+ if( to_replace_lval.is_Local() ){
+ const auto& vu = val_uses.local_uses[to_replace_lval.as_Local()];
if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
continue ;
}
@@ -3091,8 +3946,8 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
// `... = Use(to_replace_lval)`
// TODO: Ensure that the target isn't borrowed.
- if( const auto* e = new_dst_lval.opt_Local() ) {
- const auto& vu = val_uses.local_uses[*e];
+ if( new_dst_lval.is_Local() ) {
+ const auto& vu = val_uses.local_uses[new_dst_lval.as_Local()];
if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
break ;
}
@@ -3109,7 +3964,8 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
{
// Closure returns `true` if the passed lvalue is a component of `new_dst_lval`
auto is_lvalue_in_val = [&](const auto& lv) {
- return visit_mir_lvalue(new_dst_lval, ValUsage::Write, [&](const auto& slv, auto ) { return lv == slv; });
+ // Don't care about indexing?
+ return lv.m_root == new_dst_lval.m_root;
};
if( visit_mir_lvalues(*it3, [&](const auto& lv, auto ){ return is_lvalue_in_val(lv); }) )
{
@@ -3159,7 +4015,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
const ::MIR::LValue* new_dst = nullptr;
auto& blk2 = fcn.blocks.at(e.ret_block);
for(const auto& stmt : blk2.statements)
- {
+ {
// Find `RValue::Use( this_lvalue )`
if( stmt.is_Assign() && stmt.as_Assign().src.is_Use() && stmt.as_Assign().src.as_Use() == e.ret_val ) {
new_dst = &stmt.as_Assign().dst;
@@ -3170,21 +4026,36 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
// Ensure that the new destination value isn't used before assignment
if( new_dst )
{
- auto lvalue_impacts_dst = [&](const ::MIR::LValue& lv) {
- return visit_mir_lvalue(*new_dst, ValUsage::Write, [&](const auto& slv, auto ) { return lv == slv; });
+ auto lvalue_impacts_dst = [&](const ::MIR::LValue& lv)->bool {
+ // Returns true if the two lvalues share a common root
+ // TODO: Could restrict based on the presence of deref/field accesses?
+ // If `lv` is a local AND matches the index in `new_dst`, check for indexing
+ if( lv.is_Local() )
+ {
+ for(const auto& w : new_dst->m_wrappers)
+ {
+ if( w.is_Index() && w.as_Index() == lv.as_Local() )
+ {
+ return true;
+ }
+ }
+ }
+ return lv.m_root == new_dst->m_root;
};
for(auto it = blk2.statements.begin(); it != blk2.statements.end(); ++ it)
{
+ state.set_cur_stmt(&blk2 - &fcn.blocks.front(), it - blk2.statements.begin());
const auto& stmt = *it;
if( stmt.is_Assign() && stmt.as_Assign().src.is_Use() && stmt.as_Assign().src.as_Use() == e.ret_val )
{
- DEBUG("- Replace function return " << e.ret_val << " with " << *new_dst);
+ DEBUG(state << "- Replace function return " << e.ret_val << " with " << *new_dst);
e.ret_val = new_dst->clone();
+ // TODO: Invalidate the entry, instead of deleting?
it = blk2.statements.erase(it);
replacement_happend = true;
break;
}
- if( visit_mir_lvalues(stmt, [&](const auto& lv, ValUsage vu){ return lv == *new_dst || (vu == ValUsage::Write && lvalue_impacts_dst(lv)); }) )
+ if( visit_mir_lvalues(stmt, [&](const MIR::LValue& lv, ValUsage vu){ return lv == *new_dst || (vu == ValUsage::Write && lvalue_impacts_dst(lv)); }) )
{
break;
}
@@ -3218,17 +4089,14 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
}
// Remove assignments of locals that are never read
- TU_MATCH_DEF( ::MIR::LValue, (se->dst), (de),
- (
- ),
- (Local,
- const auto& vu = val_uses.local_uses[de];
+ if( se->dst.is_Local() )
+ {
+ const auto& vu = val_uses.local_uses[se->dst.as_Local()];
if( vu.write == 1 && vu.read == 0 && vu.borrow == 0 ) {
DEBUG(state << se->dst << " only written, removing write");
it = block.statements.erase(it)-1;
}
- )
- )
+ }
}
}
// NOTE: Calls can write values, but they also have side-effects
@@ -3356,9 +4224,12 @@ bool MIR_Optimise_DeadAssignments(::MIR::TypeResolve& state, ::MIR::Function& fc
for(const auto& bb : fcn.blocks)
{
auto cb = [&](const ::MIR::LValue& lv, ValUsage vu) {
- if( lv.is_Local() ) {
- read_locals[lv.as_Local()] = true;
+ if( lv.m_root.is_Local() ) {
+ read_locals[lv.m_root.as_Local()] = true;
}
+ for(const auto& w : lv.m_wrappers)
+ if(w.is_Index())
+ read_locals[w.as_Index()] = true;
return false;
};
for(const auto& stmt : bb.statements)
@@ -3425,7 +4296,7 @@ bool MIR_Optimise_NoopRemoval(::MIR::TypeResolve& state, ::MIR::Function& fcn)
if( it->is_Assign()
&& it->as_Assign().src.is_Borrow()
&& it->as_Assign().src.as_Borrow().val.is_Deref()
- && *it->as_Assign().src.as_Borrow().val.as_Deref().val == it->as_Assign().dst
+ && it->as_Assign().src.as_Borrow().val.clone_unwrapped() == it->as_Assign().dst
)
{
DEBUG(state << "Useless assignment (v = &*v), remove - " << *it);
@@ -3449,7 +4320,7 @@ bool MIR_Optimise_NoopRemoval(::MIR::TypeResolve& state, ::MIR::Function& fcn)
bool MIR_Optimise_GarbageCollect_Partial(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
::std::vector<bool> visited( fcn.blocks.size() );
- visit_blocks(state, fcn, [&visited](auto bb, const auto& _blokc) {
+ visit_blocks(state, fcn, [&visited](auto bb, const auto& /*block*/) {
assert( !visited[bb] );
visited[bb] = true;
});
@@ -3479,12 +4350,19 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
visited[bb] = true;
auto assigned_lval = [&](const ::MIR::LValue& lv) {
- const auto* lvp = &lv;
// TODO: Consume through indexing/field accesses
- while(lvp->is_Field())
- lvp = &*lvp->as_Field().val;
- if(const auto* le = lvp->opt_Local() )
- used_locals[*le] = true;
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( w.is_Field() ) {
+ }
+ else {
+ return ;
+ }
+ }
+ if( lv.m_root.is_Local() )
+ {
+ used_locals[lv.m_root.as_Local()] = true;
+ }
};
for(const auto& stmt : block.statements)
@@ -3558,20 +4436,23 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
auto it = fcn.blocks.begin();
for(unsigned int i = 0; i < visited.size(); i ++)
{
- if( !visited[i] )
- {
- // Delete
- DEBUG("GC bb" << i);
- it = fcn.blocks.erase(it);
- }
- else
+ if( visited[i] )
{
- auto lvalue_cb = [&](auto& lv, auto ) {
- if(auto* e = lv.opt_Local() ) {
- MIR_ASSERT(state, *e < local_rewrite_table.size(), "Variable out of range - " << lv);
+ auto lvalue_cb = [&](::MIR::LValue& lv, auto ) {
+ if( lv.m_root.is_Local() )
+ {
+ auto e = lv.m_root.as_Local();
+ MIR_ASSERT(state, e < local_rewrite_table.size(), "Variable out of range - " << lv);
// If the table entry for this variable is !0, it wasn't marked as used
- MIR_ASSERT(state, local_rewrite_table.at(*e) != ~0u, "LValue " << lv << " incorrectly marked as unused");
- *e = local_rewrite_table.at(*e);
+ MIR_ASSERT(state, local_rewrite_table.at(e) != ~0u, "LValue " << lv << " incorrectly marked as unused");
+ lv.m_root = ::MIR::LValue::Storage::new_Local(local_rewrite_table.at(e) );
+ }
+ for(auto& w : lv.m_wrappers)
+ {
+ if( w.is_Index())
+ {
+ w = ::MIR::LValue::Wrapper::new_Index(local_rewrite_table.at( w.as_Index() ));
+ }
}
return false;
};
@@ -3580,6 +4461,14 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
{
auto stmt_idx = &stmt - &it->statements.front();
state.set_cur_stmt(i, stmt_idx);
+
+ if( stmt == ::MIR::Statement() )
+ {
+ DEBUG(state << "Remove " << stmt << " - Pure default");
+ to_remove_statements[stmt_idx] = true;
+ continue ;
+ }
+
if( auto* se = stmt.opt_Drop() )
{
// If the drop flag was unset, either remove the drop or remove the drop flag reference
@@ -3595,6 +4484,14 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
continue ;
}
}
+
+ // HACK: Remove drop if it's of an unused value (TODO: only if it's conditional?)
+ if( se->slot.is_Local() && local_rewrite_table[se->slot.as_Local()] == ~0u )
+ {
+ DEBUG(state << "Remove " << stmt << " - Dropping non-set value");
+ to_remove_statements[stmt_idx] = true;
+ continue ;
+ }
}
visit_mir_lvalues_mut(stmt, lvalue_cb);
@@ -3637,6 +4534,7 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
}
state.set_cur_stmt_term(i);
// Rewrite and advance
+ visit_mir_lvalues_mut(it->terminator, lvalue_cb);
TU_MATCHA( (it->terminator), (e),
(Incomplete,
),
@@ -3650,49 +4548,45 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
(Panic,
),
(If,
- visit_mir_lvalue_mut(e.cond, ValUsage::Read, lvalue_cb);
e.bb0 = block_rewrite_table[e.bb0];
e.bb1 = block_rewrite_table[e.bb1];
),
(Switch,
- visit_mir_lvalue_mut(e.val, ValUsage::Read, lvalue_cb);
for(auto& target : e.targets)
target = block_rewrite_table[target];
),
(SwitchValue,
- visit_mir_lvalue_mut(e.val, ValUsage::Read, lvalue_cb);
for(auto& target : e.targets)
target = block_rewrite_table[target];
e.def_target = block_rewrite_table[e.def_target];
),
(Call,
- if( e.fcn.is_Value() ) {
- visit_mir_lvalue_mut(e.fcn.as_Value(), ValUsage::Read, lvalue_cb);
- }
- for(auto& v : e.args)
- visit_mir_lvalue_mut(v, ValUsage::Read, lvalue_cb);
- visit_mir_lvalue_mut(e.ret_val, ValUsage::Write, lvalue_cb);
e.ret_block = block_rewrite_table[e.ret_block];
e.panic_block = block_rewrite_table[e.panic_block];
)
)
// Delete all statements flagged in a bitmap for deletion
- auto stmt_it = it->statements.begin();
- for(auto flag : to_remove_statements)
- {
- if(flag) {
- stmt_it = it->statements.erase(stmt_it);
- }
- else {
- ++ stmt_it;
- }
- }
-
- ++it;
+ assert(it->statements.size() == to_remove_statements.size());
+ auto new_end = ::std::remove_if(it->statements.begin(), it->statements.end(), [&](const auto& s){
+ size_t stmt_idx = (&s - &it->statements.front());
+ return to_remove_statements[stmt_idx];
+ });
+ it->statements.erase(new_end, it->statements.end());
}
+ ++it;
}
+ auto new_blocks_end = ::std::remove_if(fcn.blocks.begin(), fcn.blocks.end(), [&](const auto& bb) {
+ size_t i = &bb - &fcn.blocks.front();
+ if( !visited[i] ) {
+ DEBUG("GC bb" << i);
+ }
+ return !visited[i];
+ });
+ fcn.blocks.erase(new_blocks_end, fcn.blocks.end());
+
+ // NOTE: Drop flags are bool, so can't use the above hack
for(unsigned int i = 0, j = 0; i < n_df; i ++)
{
if( !used_dfs[i] )
@@ -3842,7 +4736,9 @@ void MIR_OptimiseCrate_Inlining(const ::HIR::Crate& crate, TransList& list)
else if( hir_fcn.m_code )
{
auto& mir = hir_fcn.m_code.get_mir_or_error_mut(Span());
- did_inline_on_pass |= MIR_OptimiseInline(resolve, ip, mir, hir_fcn.m_args, hir_fcn.m_return, list);
+ bool did_opt = MIR_OptimiseInline(resolve, ip, mir, hir_fcn.m_args, hir_fcn.m_return, list);
+ mir.trans_enum_state = ::MIR::EnumCachePtr(); // Clear MIR enum cache
+ did_inline_on_pass |= did_opt;
}
else
{
diff --git a/src/parse/common.hpp b/src/parse/common.hpp
index 49499c86..d4a1d59a 100644
--- a/src/parse/common.hpp
+++ b/src/parse/common.hpp
@@ -40,15 +40,18 @@ extern ::std::vector<AST::PathNode> Parse_PathNodes(TokenStream& lex, eParsePath
extern AST::PathParams Parse_Path_GenericList(TokenStream& lex);
+extern AST::Visibility Parse_Publicity(TokenStream& lex, bool allow_restricted=true);
extern AST::HigherRankedBounds Parse_HRB(TokenStream& lex);
+extern ::AST::HigherRankedBounds Parse_HRB_Opt(TokenStream& lex);
extern AST::AttributeList Parse_ItemAttrs(TokenStream& lex);
extern void Parse_ParentAttrs(TokenStream& lex, AST::AttributeList& out);
extern AST::Attribute Parse_MetaItem(TokenStream& lex);
-extern ::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan ps, ::std::string name, TokenStream& lex);
+extern ::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan ps, RcString name, TokenStream& lex);
extern TypeRef Parse_Type(TokenStream& lex, bool allow_trait_list = true);
extern AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable);
extern void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl);
+extern AST::Named<AST::Item> Parse_Trait_Item(TokenStream& lex);
extern void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_items);
extern ::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::AttributeList meta_items);
extern void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod);
diff --git a/src/parse/eTokenType.enum.h b/src/parse/eTokenType.enum.h
index 5104142b..d5a0eb86 100644
--- a/src/parse/eTokenType.enum.h
+++ b/src/parse/eTokenType.enum.h
@@ -21,6 +21,7 @@ _(TOK_INTERPOLATED_STMT)
_(TOK_INTERPOLATED_BLOCK)
_(TOK_INTERPOLATED_META)
_(TOK_INTERPOLATED_ITEM)
+_(TOK_INTERPOLATED_VIS)
// Value tokens
_(TOK_IDENT)
@@ -58,6 +59,7 @@ _(TOK_SLASH)
_(TOK_DOT)
_(TOK_DOUBLE_DOT)
+_(TOK_DOUBLE_DOT_EQUAL)
_(TOK_TRIPLE_DOT)
_(TOK_EQUAL)
@@ -138,6 +140,7 @@ _(TOK_RWORD_SUPER)
_(TOK_RWORD_PROC)
_(TOK_RWORD_MOVE)
+_(TOK_RWORD_MACRO)
_(TOK_RWORD_ABSTRACT)
_(TOK_RWORD_FINAL)
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp
index 5194e1d8..2735c39e 100644
--- a/src/parse/expr.cpp
+++ b/src/parse/expr.cpp
@@ -32,8 +32,8 @@ ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon);
ExprNodeP Parse_Stmt_Let(TokenStream& lex);
ExprNodeP Parse_Expr0(TokenStream& lex);
ExprNodeP Parse_IfStmt(TokenStream& lex);
-ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime);
-ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime);
+ExprNodeP Parse_WhileStmt(TokenStream& lex, RcString lifetime);
+ExprNodeP Parse_ForStmt(TokenStream& lex, RcString lifetime);
ExprNodeP Parse_Expr_Match(TokenStream& lex);
ExprNodeP Parse_Expr1(TokenStream& lex);
ExprNodeP Parse_ExprMacro(TokenStream& lex, AST::Path tok);
@@ -57,13 +57,18 @@ ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe/*=false*/)
::std::shared_ptr<AST::Module> local_mod;
+ if( LOOK_AHEAD(lex) == TOK_INTERPOLATED_BLOCK )
+ {
+ GET_TOK(tok, lex);
+ return tok.take_frag_node();
+ }
+
GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
bool last_value_yielded = false;
while( LOOK_AHEAD(lex) != TOK_BRACE_CLOSE )
{
last_value_yielded = false;
- DEBUG("tok = " << tok);
// NOTE: Doc comments can appear within a function and apply to the function
if( lex.parse_state().parent_attrs )
@@ -103,7 +108,7 @@ ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST:
GET_TOK(tok, lex);
// `union Ident` - contextual keyword
- if( tok.type() == TOK_IDENT && tok.str() == "union" && lex.lookahead(0) == TOK_IDENT ) {
+ if( tok.type() == TOK_IDENT && tok.istr() == "union" && lex.lookahead(0) == TOK_IDENT ) {
PUTBACK(tok, lex);
if( !local_mod ) {
local_mod = lex.parse_state().get_current_mod().add_anon();
@@ -112,7 +117,7 @@ ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST:
return ExprNodeP();
}
- if( tok.type() == TOK_IDENT && tok.str() == "macro_rules" && lex.lookahead(0) == TOK_EXCLAM )
+ if( tok.type() == TOK_IDENT && tok.istr() == "macro_rules" && lex.lookahead(0) == TOK_EXCLAM )
{
// Special case - create a local module if macro_rules! is seen
// - Allows correct scoping of defined macros
@@ -124,6 +129,7 @@ ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST:
switch(tok.type())
{
// Items:
+ case TOK_INTERPOLATED_VIS:
case TOK_RWORD_PUB:
// NOTE: Allowed, but doesn't do much
case TOK_RWORD_TYPE:
@@ -185,7 +191,7 @@ ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence)
if( GET_TOK(tok, lex) == TOK_LIFETIME )
{
// Lifetimes can only precede loops... and blocks?
- ::std::string lifetime = tok.str();
+ auto lifetime = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
switch( GET_TOK(tok, lex) )
@@ -248,6 +254,7 @@ ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence)
case TOK_BRACE_OPEN:
{ PUTBACK(tok, lex); ret = Parse_ExprBlockNode(lex); }
+ // If the block is followed by `.` or `?`, it's actually an expression!
if( lex.lookahead(0) == TOK_DOT || lex.lookahead(0) == TOK_QMARK ) {
lex.putback( Token(Token::TagTakeIP(), InterpolatedFragment(InterpolatedFragment::EXPR, ret.release())) );
return Parse_ExprBlockLine_Stmt(lex, *add_silence);
@@ -284,7 +291,7 @@ ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence)
// If a braced macro invocation is the first part of a statement, don't expect a semicolon
if( lex.lookahead(1) == TOK_BRACE_OPEN || (lex.lookahead(1) == TOK_IDENT && lex.lookahead(2) == TOK_BRACE_OPEN) ) {
lex.getToken();
- return Parse_ExprMacro(lex, tok.str());
+ return Parse_ExprMacro(lex, tok.istr());
}
}
// Fall through to the statement code
@@ -316,7 +323,7 @@ ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon)
}
/// While loop (either as a statement, or as part of an expression)
-ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime)
+ExprNodeP Parse_WhileStmt(TokenStream& lex, RcString lifetime)
{
Token tok;
@@ -342,12 +349,12 @@ ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime)
}
}
/// For loop (either as a statement, or as part of an expression)
-ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime)
+ExprNodeP Parse_ForStmt(TokenStream& lex, RcString lifetime)
{
Token tok;
// Irrefutable pattern
- AST::Pattern pat = Parse_Pattern(lex, false);
+ auto pat = Parse_Pattern(lex, false);
GET_CHECK_TOK(tok, lex, TOK_RWORD_IN);
ExprNodeP val;
{
@@ -435,6 +442,9 @@ ExprNodeP Parse_Expr_Match(TokenStream& lex)
arm.m_attrs = Parse_ItemAttrs(lex);
+ // HACK: Questionably valid, but 1.29 librustc/hir/lowering.rs needs this
+ if( LOOK_AHEAD(lex) == TOK_PIPE )
+ GET_TOK(tok, lex);
do {
// Refutable pattern
arm.m_patterns.push_back( Parse_Pattern(lex, true) );
@@ -461,6 +471,17 @@ ExprNodeP Parse_Expr_Match(TokenStream& lex)
return NEWNODE( AST::ExprNode_Match, ::std::move(switch_val), ::std::move(arms) );
}
+/// "do catch" block
+ExprNodeP Parse_Expr_Try(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+ //Token tok;
+
+ auto inner = Parse_ExprBlockNode(lex);
+ //TODO(lex.point_span(), "do catch");
+ return NEWNODE(AST::ExprNode_Try, ::std::move(inner));
+}
+
/// Parses the 'stmt' fragment specifier
/// - Flow control
/// - Expressions
@@ -503,10 +524,10 @@ ExprNodeP Parse_Stmt(TokenStream& lex)
case TOK_RWORD_BREAK: type = AST::ExprNode_Flow::BREAK; break;
default: throw ParseError::BugCheck(/*lex,*/ "continue/break");
}
- ::std::string lifetime;
+ RcString lifetime;
if( GET_TOK(tok, lex) == TOK_LIFETIME )
{
- lifetime = tok.str();
+ lifetime = tok.istr(); // TODO: Hygine?
GET_TOK(tok, lex);
}
ExprNodeP val;
@@ -706,7 +727,7 @@ ExprNodeP Parse_Expr1_1(TokenStream& lex)
ExprNodeP left, right;
// Inclusive range to a value
- if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT ) {
+ if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT || (TARGETVER_1_29 && tok.type() == TOK_DOUBLE_DOT_EQUAL) ) {
right = next(lex);
return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, nullptr, mv$(right) );
}
@@ -746,6 +767,13 @@ LEFTASSOC(Parse_Expr1_2, Parse_Expr1_5,
case TOK_TRIPLE_DOT:
rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, mv$(rv), next(lex) );
break;
+ case TOK_DOUBLE_DOT_EQUAL:
+ if( TARGETVER_1_29 )
+ {
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, mv$(rv), next(lex) );
+ break;
+ }
+ // Fall through
)
// 1: Bool OR
LEFTASSOC(Parse_Expr1_5, Parse_Expr2,
@@ -920,26 +948,26 @@ ExprNodeP Parse_ExprFC(TokenStream& lex)
switch(GET_TOK(tok, lex))
{
case TOK_IDENT: {
- AST::PathNode path( mv$(tok.str()) , {});
+ AST::PathNode pn( tok.istr() , {});
switch( GET_TOK(tok, lex) )
{
case TOK_PAREN_OPEN:
PUTBACK(tok, lex);
- val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(path), Parse_ParenList(lex) );
+ val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(pn), Parse_ParenList(lex) );
break;
case TOK_DOUBLE_COLON:
GET_CHECK_TOK(tok, lex, TOK_LT);
- path.args() = Parse_Path_GenericList(lex);
- val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(path), Parse_ParenList(lex) );
+ pn.args() = Parse_Path_GenericList(lex);
+ val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(pn), Parse_ParenList(lex) );
break;
default:
- val = NEWNODE( AST::ExprNode_Field, ::std::move(val), ::std::string(path.name()) );
+ val = NEWNODE( AST::ExprNode_Field, ::std::move(val), pn.name() );
PUTBACK(tok, lex);
break;
}
break; }
case TOK_INTEGER:
- val = NEWNODE( AST::ExprNode_Field, ::std::move(val), FMT(tok.intval()) );
+ val = NEWNODE( AST::ExprNode_Field, ::std::move(val), RcString::new_interned(FMT(tok.intval())) );
break;
default:
throw ParseError::Unexpected(lex, mv$(tok));
@@ -1005,7 +1033,7 @@ ExprNodeP Parse_ExprVal_StructLiteral(TokenStream& lex, AST::Path path)
}
CHECK_TOK(tok, TOK_IDENT);
auto h = lex.getHygiene();
- auto name = mv$(tok.str());
+ auto name = tok.istr();
ExprNodeP val;
if( lex.lookahead(0) != TOK_COLON )
@@ -1110,6 +1138,23 @@ ExprNodeP Parse_ExprVal(TokenStream& lex)
return Parse_WhileStmt(lex, "");
case TOK_RWORD_FOR:
return Parse_ForStmt(lex, "");
+ case TOK_RWORD_DO:
+ if( TARGETVER_1_29 )
+ {
+ // `do catch` - stabilised later as `try`
+ if( GET_TOK(tok, lex) == TOK_IDENT && tok.istr() == "catch" )
+ {
+ return Parse_Expr_Try(lex);
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok);
+ }
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok);
+ }
case TOK_RWORD_MATCH:
return Parse_Expr_Match(lex);
case TOK_RWORD_IF:
@@ -1275,10 +1320,10 @@ ExprNodeP Parse_ExprMacro(TokenStream& lex, AST::Path path)
}
Token tok;
- ::std::string name = path.m_class.is_Local() ? path.m_class.as_Local().name : path.nodes()[0].name();
- ::std::string ident;
+ auto name = path.m_class.is_Local() ? path.m_class.as_Local().name : path.nodes()[0].name();
+ RcString ident;
if( GET_TOK(tok, lex) == TOK_IDENT ) {
- ident = mv$(tok.str());
+ ident = tok.istr();
}
else {
PUTBACK(tok, lex);
diff --git a/src/parse/interpolated_fragment.cpp b/src/parse/interpolated_fragment.cpp
index d8a8bc43..634309a5 100644
--- a/src/parse/interpolated_fragment.cpp
+++ b/src/parse/interpolated_fragment.cpp
@@ -31,6 +31,9 @@ InterpolatedFragment::~InterpolatedFragment()
case InterpolatedFragment::ITEM:
delete reinterpret_cast<AST::Named<AST::Item>*>(m_ptr);
break;
+ case InterpolatedFragment::VIS:
+ delete reinterpret_cast<AST::Visibility*>(m_ptr);
+ break;
}
}
}
@@ -82,6 +85,11 @@ InterpolatedFragment::InterpolatedFragment(TypeRef v):
m_ptr( new TypeRef(mv$(v)) )
{
}
+InterpolatedFragment::InterpolatedFragment(AST::Visibility v):
+ m_type( InterpolatedFragment::VIS ),
+ m_ptr( new AST::Visibility(mv$(v)) )
+{
+}
::std::ostream& operator<<(::std::ostream& os, InterpolatedFragment const& x)
{
@@ -117,6 +125,9 @@ InterpolatedFragment::InterpolatedFragment(TypeRef v):
const auto& named_item = *reinterpret_cast<const AST::Named<AST::Item>*>(x.m_ptr);
os << "item[" << named_item.data.tag_str() << "(" << named_item.name << ")]";
} break;
+ case InterpolatedFragment::VIS:
+ os << "vis[" << *reinterpret_cast<const AST::Visibility*>(x.m_ptr) << "]";
+ break;
}
return os;
}
diff --git a/src/parse/interpolated_fragment.hpp b/src/parse/interpolated_fragment.hpp
index 36539fb0..1e69fe26 100644
--- a/src/parse/interpolated_fragment.hpp
+++ b/src/parse/interpolated_fragment.hpp
@@ -12,6 +12,7 @@
class TypeRef;
class TokenTree;
namespace AST {
+ typedef bool Visibility;
class Pattern;
class Path;
class ExprNode;
@@ -37,6 +38,7 @@ public:
META,
ITEM,
+ VIS,
} m_type;
// Owned type-pruned pointer
@@ -53,6 +55,7 @@ public:
InterpolatedFragment(::AST::Named<AST::Item> );
~InterpolatedFragment();
InterpolatedFragment(Type , ::AST::ExprNode*);
+ InterpolatedFragment(AST::Visibility); // :vis
TokenTree& as_tt() { assert(m_type == TT); return *reinterpret_cast<TokenTree*>(m_ptr); }
const TokenTree& as_tt() const { assert(m_type == TT); return *reinterpret_cast<TokenTree*>(m_ptr); }
diff --git a/src/parse/lex.cpp b/src/parse/lex.cpp
index 8376eeee..90c8ccbe 100644
--- a/src/parse/lex.cpp
+++ b/src/parse/lex.cpp
@@ -83,8 +83,10 @@ static const struct {
TOKENT("-=", TOK_DASH_EQUAL),
TOKENT("->", TOK_THINARROW),
TOKENT(".", TOK_DOT),
+ // NOTE: These have special handling when following numbers
TOKENT("..", TOK_DOUBLE_DOT),
TOKENT("...",TOK_TRIPLE_DOT),
+ TOKENT("..=",TOK_DOUBLE_DOT_EQUAL),
TOKENT("/" , TOK_SLASH),
TOKENT("/*", BLOCKCOMMENT),
TOKENT("//", LINECOMMENT),
@@ -153,6 +155,7 @@ static const struct {
TOKENT("in", TOK_RWORD_IN),
TOKENT("let", TOK_RWORD_LET),
TOKENT("loop", TOK_RWORD_LOOP),
+ TOKENT("macro", TOK_RWORD_MACRO),
TOKENT("match", TOK_RWORD_MATCH),
TOKENT("mod", TOK_RWORD_MOD),
TOKENT("move", TOK_RWORD_MOVE),
@@ -402,9 +405,13 @@ Token Lexer::getTokenInt()
// Double/Triple Dot
if( ch == '.' )
{
- if( this->getc() == '.') {
+ ch = this->getc();
+ if( ch == '.') {
this->m_next_tokens.push_back(TOK_TRIPLE_DOT);
}
+ else if( ch == '=') {
+ this->m_next_tokens.push_back(TOK_DOUBLE_DOT_EQUAL);
+ }
else {
this->ungetc();
this->m_next_tokens.push_back(TOK_DOUBLE_DOT);
@@ -529,7 +536,7 @@ Token Lexer::getTokenInt()
str += ch;
}
}
- return Token(TOK_BYTESTRING, str);
+ return Token(TOK_BYTESTRING, mv$(str));
}
// Byte constant
else if( ch == '\'' ) {
@@ -601,7 +608,7 @@ Token Lexer::getTokenInt()
m_next_tokens.push_back(TOK_SQUARE_CLOSE);
m_next_tokens.push_back(Token(TOK_STRING, mv$(str)));
m_next_tokens.push_back(TOK_EQUAL);
- m_next_tokens.push_back(Token(TOK_IDENT, "doc"));
+ m_next_tokens.push_back(Token(TOK_IDENT, RcString::new_interned("doc")));
m_next_tokens.push_back(TOK_SQUARE_OPEN);
if(is_pdoc)
m_next_tokens.push_back(TOK_EXCLAM);
@@ -664,7 +671,7 @@ Token Lexer::getTokenInt()
m_next_tokens.push_back(TOK_SQUARE_CLOSE);
m_next_tokens.push_back(Token(TOK_STRING, mv$(str)));
m_next_tokens.push_back(TOK_EQUAL);
- m_next_tokens.push_back(Token(TOK_IDENT, "doc"));
+ m_next_tokens.push_back(Token(TOK_IDENT, RcString::new_interned("doc")));
m_next_tokens.push_back(TOK_SQUARE_OPEN);
if(is_pdoc)
m_next_tokens.push_back(TOK_EXCLAM);
@@ -697,7 +704,7 @@ Token Lexer::getTokenInt()
ch = this->getc();
}
this->ungetc();
- return Token(TOK_LIFETIME, str);
+ return Token(TOK_LIFETIME, RcString::new_interned(str));
}
else {
throw ParseError::Todo("Lex Fail - Expected ' after character constant");
@@ -721,7 +728,7 @@ Token Lexer::getTokenInt()
str += ch;
}
}
- return Token(TOK_STRING, str);
+ return Token(TOK_STRING, mv$(str));
}
default:
assert(!"bugcheck");
@@ -799,7 +806,7 @@ Token Lexer::getTokenInt_RawString(bool is_byte)
}
}
}
- return Token(is_byte ? TOK_BYTESTRING : TOK_STRING, val);
+ return Token(is_byte ? TOK_BYTESTRING : TOK_STRING, mv$(val));
}
Token Lexer::getTokenInt_Identifier(Codepoint leader, Codepoint leader2)
{
@@ -819,7 +826,7 @@ Token Lexer::getTokenInt_Identifier(Codepoint leader, Codepoint leader2)
if( str < RWORDS[i].chars ) break;
if( str == RWORDS[i].chars ) return Token((enum eTokenType)RWORDS[i].type);
}
- return Token(TOK_IDENT, mv$(str));
+ return Token(TOK_IDENT, RcString::new_interned(str));
}
// Takes the VERY lazy way of reading the float into a string then passing to strtod
diff --git a/src/parse/parseerror.cpp b/src/parse/parseerror.cpp
index 1bb30985..f2a5343b 100644
--- a/src/parse/parseerror.cpp
+++ b/src/parse/parseerror.cpp
@@ -61,7 +61,7 @@ ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok)//:
Span pos = tok.get_pos();
if(pos.filename == "")
pos = lex.point_span();
- ::std::cout << pos << ": Unexpected(" << tok << ")" << ::std::endl;
+ ERROR(pos, E0000, "Unexpected token " << tok);
}
ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, Token exp)//:
// m_tok( mv$(tok) )
@@ -69,22 +69,22 @@ ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, Tok
Span pos = tok.get_pos();
if(pos.filename == "")
pos = lex.point_span();
- ::std::cout << pos << ": Unexpected(" << tok << ", " << exp << ")" << ::std::endl;
+ ERROR(pos, E0000, "Unexpected token " << tok << ", expected " << exp);
}
ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, ::std::vector<eTokenType> exp)
{
Span pos = tok.get_pos();
if(pos.filename == "")
pos = lex.point_span();
- ::std::cout << pos << ": Unexpected " << tok << ", expected ";
- bool f = true;
- for(auto v: exp) {
- if(!f)
- ::std::cout << " or ";
- f = false;
- ::std::cout << Token::typestr(v);
- }
- ::std::cout << ::std::endl;
+ ERROR(pos, E0000, "Unexpected token " << tok << ", expected one of " << FMT_CB(os, {
+ bool f = true;
+ for(auto v: exp) {
+ if(!f)
+ os << " or ";
+ f = false;
+ os << Token::typestr(v);
+ }
+ }));
}
ParseError::Unexpected::~Unexpected() throw()
{
diff --git a/src/parse/paths.cpp b/src/parse/paths.cpp
index d103840e..8bfd20de 100644
--- a/src/parse/paths.cpp
+++ b/src/parse/paths.cpp
@@ -39,6 +39,9 @@ AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode)
return AST::Path(AST::Path::TagSuper(), count, Parse_PathNodes(lex, generic_mode));
}
+ case TOK_RWORD_CRATE:
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
+ return Parse_Path(lex, true, generic_mode);
case TOK_DOUBLE_COLON:
return Parse_Path(lex, true, generic_mode);
@@ -80,8 +83,14 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
Token tok;
if( is_abs )
{
- if( GET_TOK(tok, lex) == TOK_STRING ) {
- ::std::string cratename = tok.str();
+ // QUIRK: `::crate::foo` is valid (semi-surprisingly)
+ if( LOOK_AHEAD(lex) == TOK_RWORD_CRATE ) {
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_CRATE);
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
+ return AST::Path("", Parse_PathNodes(lex, generic_mode));
+ }
+ else if( GET_TOK(tok, lex) == TOK_STRING ) {
+ auto cratename = RcString::new_interned(tok.str());
GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
return AST::Path(cratename, Parse_PathNodes(lex, generic_mode));
}
@@ -94,6 +103,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
// TODO: TOK_INTERPOLATED_IDENT?
GET_CHECK_TOK(tok, lex, TOK_IDENT);
auto hygine = lex.getHygiene();
+ DEBUG("hygine = " << hygine);
PUTBACK(tok, lex);
return AST::Path(AST::Path::TagRelative(), mv$(hygine), Parse_PathNodes(lex, generic_mode));
}
@@ -112,7 +122,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
::AST::PathParams params;
CHECK_TOK(tok, TOK_IDENT);
- auto component = mv$( tok.str() );
+ auto component = mv$( tok.istr() );
GET_TOK(tok, lex);
if( generic_mode == PATH_GENERIC_TYPE )
@@ -133,18 +143,14 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
auto ps = lex.start_span();
DEBUG("Fn() hack");
::std::vector<TypeRef> args;
- if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE )
- {
- // Empty list
- }
- else
- {
- PUTBACK(tok, lex);
- do {
- // TODO: Trailing commas
- args.push_back( Parse_Type(lex) );
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- }
+ do {
+ // Trailing comma or empty list support
+ if( lex.lookahead(0) == TOK_PAREN_CLOSE ) {
+ GET_TOK(tok, lex);
+ break;
+ }
+ args.push_back( Parse_Type(lex) );
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
CHECK_TOK(tok, TOK_PAREN_CLOSE);
TypeRef ret_type = TypeRef( TypeRef::TagUnit(), Span(tok.get_pos()) );
@@ -160,7 +166,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
params = ::AST::PathParams {
{},
::make_vec1( TypeRef(TypeRef::TagTuple(), lex.end_span(ps), mv$(args)) ),
- ::make_vec1( ::std::make_pair( ::std::string("Output"), mv$(ret_type) ) )
+ ::make_vec1( ::std::make_pair( RcString::new_interned("Output"), mv$(ret_type) ) )
};
GET_TOK(tok, lex);
@@ -204,7 +210,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
::std::vector<TypeRef> types;
::std::vector<AST::LifetimeRef> lifetimes;
- ::std::vector< ::std::pair< ::std::string, TypeRef > > assoc_bounds;
+ ::std::vector< ::std::pair< RcString, TypeRef > > assoc_bounds;
do {
if( LOOK_AHEAD(lex) == TOK_GT || LOOK_AHEAD(lex) == TOK_DOUBLE_GT || LOOK_AHEAD(lex) == TOK_GTE || LOOK_AHEAD(lex) == TOK_DOUBLE_GT_EQUAL ) {
@@ -219,7 +225,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
case TOK_IDENT:
if( LOOK_AHEAD(lex) == TOK_EQUAL )
{
- ::std::string name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_EQUAL);
assoc_bounds.push_back( ::std::make_pair( mv$(name), Parse_Type(lex,false) ) );
break;
diff --git a/src/parse/pattern.cpp b/src/parse/pattern.cpp
index e2949a63..cd73c378 100644
--- a/src/parse/pattern.cpp
+++ b/src/parse/pattern.cpp
@@ -46,7 +46,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable)
if( tok.type() == TOK_IDENT && lex.lookahead(0) == TOK_EXCLAM )
{
lex.getToken();
- return AST::Pattern( AST::Pattern::TagMacro(), lex.end_span(ps), box$(Parse_MacroInvocation(ps, tok.str(), lex)));
+ return AST::Pattern( AST::Pattern::TagMacro(), lex.end_span(ps), box$(Parse_MacroInvocation(ps, tok.istr(), lex)));
}
if( tok.type() == TOK_INTERPOLATED_PATTERN )
{
@@ -87,12 +87,12 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable)
if( expect_bind )
{
CHECK_TOK(tok, TOK_IDENT);
- auto bind_name = Ident(lex.getHygiene(), mv$(tok.str()));
+ auto bind_name = lex.get_ident(mv$(tok));
// If there's no '@' after it, it's a name binding only (_ pattern)
if( GET_TOK(tok, lex) != TOK_AT )
{
PUTBACK(tok, lex);
- return AST::Pattern(AST::Pattern::TagBind(), lex.end_span(mv$(ps)), mv$(bind_name), bind_type, is_mut);
+ return AST::Pattern(AST::Pattern::TagBind(), lex.end_span(ps), mv$(bind_name), bind_type, is_mut);
}
binding = AST::PatternBinding( mv$(bind_name), bind_type, is_mut );
@@ -113,24 +113,25 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable)
break;
// Known value `IDENT ...`
case TOK_TRIPLE_DOT:
+ case TOK_DOUBLE_DOT_EQUAL:
break;
// Known binding `ident @`
case TOK_AT:
- binding = AST::PatternBinding( Ident(lex.getHygiene(), mv$(tok.str())), bind_type/*MOVE*/, is_mut/*false*/ );
+ binding = AST::PatternBinding( lex.get_ident(mv$(tok)), bind_type/*MOVE*/, is_mut/*false*/ );
GET_TOK(tok, lex); // '@'
GET_TOK(tok, lex); // Match lex.putback() below
break;
default: { // Maybe bind
- Ident name = Ident(lex.getHygiene(), mv$(tok.str()));
+ auto name = lex.get_ident(mv$(tok));
// if the pattern can be refuted (i.e this could be an enum variant), return MaybeBind
if( is_refutable ) {
assert(bind_type == ::AST::PatternBinding::Type::MOVE);
assert(is_mut == false);
- return AST::Pattern(AST::Pattern::TagMaybeBind(), lex.end_span(mv$(ps)), mv$(name));
+ return AST::Pattern(AST::Pattern::TagMaybeBind(), lex.end_span(ps), mv$(name));
}
// Otherwise, it IS a binding
else {
- return AST::Pattern(AST::Pattern::TagBind(), lex.end_span(mv$(ps)), mv$(name), bind_type, is_mut);
+ return AST::Pattern(AST::Pattern::TagBind(), lex.end_span(ps), mv$(name), bind_type, is_mut);
}
break;}
}
@@ -156,7 +157,9 @@ AST::Pattern Parse_PatternReal(TokenStream& lex, bool is_refutable)
}
auto ps = lex.start_span();
AST::Pattern ret = Parse_PatternReal1(lex, is_refutable);
- if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT )
+ if( (GET_TOK(tok, lex) == TOK_TRIPLE_DOT)
+ || (TARGETVER_1_29 && tok.type() == TOK_DOUBLE_DOT_EQUAL)
+ )
{
if( !ret.data().is_Value() )
throw ParseError::Generic(lex, "Using '...' with a non-value on left");
@@ -188,11 +191,11 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
switch( GET_TOK(tok, lex) )
{
case TOK_UNDERSCORE:
- return AST::Pattern( lex.end_span(mv$(ps)), AST::Pattern::Data() );
+ return AST::Pattern( lex.end_span(ps), AST::Pattern::Data() );
//case TOK_DOUBLE_DOT:
// return AST::Pattern( AST::Pattern::TagWildcard() );
case TOK_RWORD_BOX:
- return AST::Pattern( AST::Pattern::TagBox(), lex.end_span(mv$(ps)), Parse_Pattern(lex, is_refutable) );
+ return AST::Pattern( AST::Pattern::TagBox(), lex.end_span(ps), Parse_Pattern(lex, is_refutable) );
case TOK_DOUBLE_AMP:
lex.putback(TOK_AMP);
case TOK_AMP: {
@@ -203,7 +206,7 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
is_mut = true;
else
PUTBACK(tok, lex);
- return AST::Pattern( AST::Pattern::TagReference(), lex.end_span(mv$(ps)), is_mut, Parse_Pattern(lex, is_refutable) );
+ return AST::Pattern( AST::Pattern::TagReference(), lex.end_span(ps), is_mut, Parse_Pattern(lex, is_refutable) );
}
case TOK_RWORD_SELF:
case TOK_RWORD_SUPER:
@@ -221,44 +224,44 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
{
auto dt = tok.datatype();
// TODO: Ensure that the type is ANY or a signed integer
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Integer({dt, -tok.intval()}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({dt, -tok.intval()}) );
}
else if( tok.type() == TOK_FLOAT )
{
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Float({tok.datatype(), -tok.floatval()}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Float({tok.datatype(), -tok.floatval()}) );
}
else
{
throw ParseError::Unexpected(lex, tok, {TOK_INTEGER, TOK_FLOAT});
}
case TOK_FLOAT:
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Float({tok.datatype(), tok.floatval()}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Float({tok.datatype(), tok.floatval()}) );
case TOK_INTEGER:
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Integer({tok.datatype(), tok.intval()}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({tok.datatype(), tok.intval()}) );
case TOK_RWORD_TRUE:
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, 1}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, 1}) );
case TOK_RWORD_FALSE:
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, 0}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, 0}) );
case TOK_STRING:
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_String( mv$(tok.str()) ) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_String( mv$(tok.str()) ) );
case TOK_BYTESTRING:
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_ByteString({ mv$(tok.str()) }) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_ByteString({ mv$(tok.str()) }) );
case TOK_INTERPOLATED_EXPR: {
auto e = tok.take_frag_node();
if( auto* n = dynamic_cast<AST::ExprNode_String*>(e.get()) ) {
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_String( mv$(n->m_value) ) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_String( mv$(n->m_value) ) );
+ }
+ else if( auto* n = dynamic_cast<AST::ExprNode_ByteString*>(e.get()) ) {
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_ByteString({ mv$(n->m_value) }) );
}
- //else if( auto* n = dynamic_cast<AST::ExprNode_ByteString*>(e.get()) ) {
- // return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_ByteString( mv$(n->m_value) ) );
- //}
else if( auto* n = dynamic_cast<AST::ExprNode_Bool*>(e.get()) ) {
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, n->m_value}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({CORETYPE_BOOL, n->m_value}) );
}
else if( auto* n = dynamic_cast<AST::ExprNode_Integer*>(e.get()) ) {
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Integer({n->m_datatype, n->m_value}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Integer({n->m_datatype, n->m_value}) );
}
else if( auto* n = dynamic_cast<AST::ExprNode_Float*>(e.get()) ) {
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Float({n->m_datatype, n->m_value}) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Float({n->m_datatype, n->m_value}) );
}
else {
TODO(lex.point_span(), "Convert :expr into a pattern value - " << *e);
@@ -266,7 +269,7 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
} break;
case TOK_PAREN_OPEN:
- return AST::Pattern( AST::Pattern::TagTuple(), lex.end_span(mv$(ps)), Parse_PatternTuple(lex, is_refutable) );
+ return AST::Pattern( AST::Pattern::TagTuple(), lex.end_span(ps), Parse_PatternTuple(lex, is_refutable) );
case TOK_SQUARE_OPEN:
return Parse_PatternReal_Slice(lex, is_refutable);
default:
@@ -280,12 +283,12 @@ AST::Pattern Parse_PatternReal_Path(TokenStream& lex, ProtoSpan ps, AST::Path pa
switch( GET_TOK(tok, lex) )
{
case TOK_PAREN_OPEN:
- return AST::Pattern( AST::Pattern::TagNamedTuple(), lex.end_span(mv$(ps)), mv$(path), Parse_PatternTuple(lex, is_refutable) );
+ return AST::Pattern( AST::Pattern::TagNamedTuple(), lex.end_span(ps), mv$(path), Parse_PatternTuple(lex, is_refutable) );
case TOK_BRACE_OPEN:
return Parse_PatternStruct(lex, ps, mv$(path), is_refutable);
default:
PUTBACK(tok, lex);
- return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(mv$(ps)), AST::Pattern::Value::make_Named(mv$(path)) );
+ return AST::Pattern( AST::Pattern::TagValue(), lex.end_span(ps), AST::Pattern::Value::make_Named(mv$(path)) );
}
}
@@ -323,7 +326,7 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable)
if( has_binding ) {
if(is_split)
- ERROR(lex.end_span(mv$(ps)), E0000, "Multiple instances of .. in a slice pattern");
+ ERROR(lex.end_span(ps), E0000, "Multiple instances of .. in a slice pattern");
inner_binding = mv$(binding);
is_split = true;
@@ -346,13 +349,13 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable)
if( is_split )
{
- return ::AST::Pattern( lex.end_span(mv$(ps)), ::AST::Pattern::Data::make_SplitSlice({ mv$(leading), mv$(inner_binding), mv$(trailing) }) );
+ return ::AST::Pattern( lex.end_span(ps), ::AST::Pattern::Data::make_SplitSlice({ mv$(leading), mv$(inner_binding), mv$(trailing) }) );
}
else
{
assert( !inner_binding.is_valid() );
assert( trailing.empty() );
- return ::AST::Pattern( lex.end_span(mv$(ps)), ::AST::Pattern::Data::make_Slice({ mv$(leading) }) );
+ return ::AST::Pattern( lex.end_span(ps), ::AST::Pattern::Data::make_Slice({ mv$(leading) }) );
}
}
@@ -452,11 +455,11 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, ProtoSpan ps, AST::Path path,
i ++;
}
- return AST::Pattern(AST::Pattern::TagNamedTuple(), lex.end_span(mv$(ps)), mv$(path), AST::Pattern::TuplePat { mv$(leading), has_split, mv$(trailing) });
+ return AST::Pattern(AST::Pattern::TagNamedTuple(), lex.end_span(ps), mv$(path), AST::Pattern::TuplePat { mv$(leading), has_split, mv$(trailing) });
}
bool is_exhaustive = true;
- ::std::vector< ::std::pair< ::std::string, AST::Pattern> > subpats;
+ ::std::vector< ::std::pair< RcString, AST::Pattern> > subpats;
do {
GET_TOK(tok, lex);
DEBUG("tok = " << tok);
@@ -497,7 +500,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, ProtoSpan ps, AST::Path path,
CHECK_TOK(tok, TOK_IDENT);
auto field_ident = lex.get_ident(mv$(tok));
- ::std::string field_name;
+ RcString field_name;
GET_TOK(tok, lex);
AST::Pattern pat;
@@ -521,6 +524,6 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, ProtoSpan ps, AST::Path path,
} while( GET_TOK(tok, lex) == TOK_COMMA );
CHECK_TOK(tok, TOK_BRACE_CLOSE);
- return AST::Pattern(AST::Pattern::TagStruct(), lex.end_span(mv$(ps)), ::std::move(path), ::std::move(subpats), is_exhaustive);
+ return AST::Pattern(AST::Pattern::TagStruct(), lex.end_span(ps), ::std::move(path), ::std::move(subpats), is_exhaustive);
}
diff --git a/src/parse/root.cpp b/src/parse/root.cpp
index bc001c99..e81055ec 100644
--- a/src/parse/root.cpp
+++ b/src/parse/root.cpp
@@ -18,14 +18,17 @@
#include <expand/cfg.hpp> // check_cfg - for `mod nonexistant;`
#include <fstream> // Used by directory path
#include "lex.hpp" // New file lexer
+#include <parse/interpolated_fragment.hpp>
#include <ast/expr.hpp>
+#include <macro_rules/macro_rules.hpp>
+#include <path.h>
template<typename T>
Spanned<T> get_spanned(TokenStream& lex, ::std::function<T()> f) {
auto ps = lex.start_span();
auto v = f();
return Spanned<T> {
- lex.end_span( mv$(ps) ),
+ lex.end_span(ps),
mv$(v)
};
}
@@ -34,7 +37,7 @@ Spanned<T> get_spanned(TokenStream& lex, ::std::function<T()> f) {
// Check the next two tokens
#define LOOKAHEAD2(lex, tok1, tok2) ((lex).lookahead(0) == (tok1) && (lex).lookahead(1) == (tok2))
-::std::string dirname(::std::string input) {
+::helpers::path dirname(::std::string input) {
while( input.size() > 0 && input.back() != '/' && input.back() != '\\' ) {
input.pop_back();
}
@@ -47,10 +50,20 @@ AST::Attribute Parse_MetaItem(TokenStream& lex);
void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::AttributeList& mod_attrs);
bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv);
-//::AST::Path Parse_Publicity(TokenStream& lex)
-bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true)
+::AST::Visibility Parse_Publicity(TokenStream& lex, bool allow_restricted/*=true*/)
{
Token tok;
+ if( LOOK_AHEAD(lex) == TOK_INTERPOLATED_VIS )
+ {
+ GET_TOK(tok, lex);
+ return tok.take_frag_vis();
+ }
+ if( LOOK_AHEAD(lex) == TOK_RWORD_CRATE )
+ {
+ // TODO: Return a path that indicates the entire current crate
+ GET_TOK(tok, lex);
+ return true;
+ }
if( LOOK_AHEAD(lex) == TOK_RWORD_PUB )
{
GET_TOK(tok, lex);
@@ -98,12 +111,12 @@ bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true)
GET_CHECK_TOK(tok, lex, TOK_IDENT);
case TOK_RWORD_IN:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- path.nodes().push_back( AST::PathNode(tok.str()) );
+ path.nodes().push_back( AST::PathNode(tok.istr()) );
while( LOOK_AHEAD(lex) == TOK_DOUBLE_COLON )
{
GET_TOK(tok, lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- path.nodes().push_back( AST::PathNode(tok.str()) );
+ path.nodes().push_back( AST::PathNode(tok.istr()) );
}
break;
default:
@@ -137,7 +150,7 @@ bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true)
switch(GET_TOK(tok, lex))
{
case TOK_LIFETIME:
- rv.m_lifetimes.push_back(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), Ident(lex.getHygiene(), tok.str())));
+ rv.m_lifetimes.push_back(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), lex.get_ident(mv$(tok))));
break;
default:
throw ParseError::Unexpected(lex, tok, Token(TOK_LIFETIME));
@@ -163,7 +176,7 @@ namespace {
AST::LifetimeRef get_LifetimeRef(TokenStream& lex, Token tok)
{
CHECK_TOK(tok, TOK_LIFETIME);
- return AST::LifetimeRef(/*lex.point_span(), */Ident(lex.getHygiene(), mv$(tok.str())));
+ return AST::LifetimeRef(/*lex.point_span(), */lex.get_ident(mv$(tok)));
}
}
/// Parse type parameters in a definition
@@ -230,7 +243,7 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex)
GET_TOK(tok, lex);
if( tok.type() == TOK_IDENT )
{
- ::std::string param_name = mv$(tok.str());
+ auto param_name = tok.istr();
ret.add_ty_param( AST::TypeParam( lex.point_span(), ::std::move(attrs), param_name ) );
auto param_ty = TypeRef(lex.point_span(), param_name);
@@ -248,7 +261,7 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex)
}
else if( tok.type() == TOK_LIFETIME )
{
- auto param_name = tok.str();
+ auto param_name = tok.istr();
auto ref = get_LifetimeRef(lex, mv$(tok));
ret.add_lft_param(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), Ident(lex.getHygiene(), param_name) ));
if( GET_TOK(tok, lex) == TOK_COLON )
@@ -499,7 +512,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_
PUTBACK(tok, lex);
}
- return AST::Function(lex.end_span( mv$(ps) ), mv$(params), mv$(abi), is_unsafe, is_const, is_variadic, mv$(ret_type), mv$(args));
+ return AST::Function(lex.end_span(ps), mv$(params), mv$(abi), is_unsafe, is_const, is_variadic, mv$(ret_type), mv$(args));
}
AST::Function Parse_FunctionDefWithCode(TokenStream& lex, ::std::string abi, bool allow_self, bool is_unsafe, bool is_const)
@@ -609,7 +622,7 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::AttributeList& meta_items)
bool is_pub = Parse_Publicity(lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
TypeRef type = Parse_Type(lex);
@@ -628,6 +641,140 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::AttributeList& meta_items)
}
}
+AST::Named<AST::Item> Parse_Trait_Item(TokenStream& lex)
+{
+ Token tok;
+
+ auto item_attrs = Parse_ItemAttrs(lex);
+ SET_ATTRS(lex, item_attrs);
+
+ auto ps = lex.start_span();
+ {
+ ::AST::MacroInvocation inv;
+ if( Parse_MacroInvocation_Opt(lex, inv) )
+ {
+ return AST::Named<AST::Item>( lex.end_span(ps), mv$(item_attrs), false, "", AST::Item(mv$(inv)) );
+ }
+ }
+
+ GET_TOK(tok, lex);
+ bool is_specialisable = false;
+ if( tok.type() == TOK_IDENT && tok.istr() == "default" ) {
+ is_specialisable = true;
+ GET_TOK(tok, lex);
+ }
+ // TODO: Mark specialisation
+ (void)is_specialisable;
+
+ bool fn_is_const = false;
+ bool fn_is_unsafe = false;
+ ::std::string abi = ABI_RUST;
+
+ RcString name;
+ ::AST::Item rv;
+ switch(tok.type())
+ {
+ case TOK_RWORD_STATIC: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ auto ty = Parse_Type(lex);
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+
+ ::AST::Expr val;
+ if(GET_TOK(tok, lex) == TOK_EQUAL) {
+ val = Parse_Expr(lex);
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_SEMICOLON);
+
+ rv = ::AST::Static(::AST::Static::STATIC, mv$(ty), val);
+ break; }
+ case TOK_RWORD_CONST: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ auto ty = Parse_Type(lex);
+
+ ::AST::Expr val;
+ if(GET_TOK(tok, lex) == TOK_EQUAL) {
+ val = Parse_Expr(lex);
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_SEMICOLON);
+
+ rv = ::AST::Static(AST::Static::CONST, mv$(ty), val);
+ break; }
+ // Associated type
+ case TOK_RWORD_TYPE: {
+ auto atype_params = ::AST::GenericParams { };
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ if( GET_TOK(tok, lex) == TOK_COLON )
+ {
+ // Bounded associated type
+ Parse_TypeBound(lex, atype_params, TypeRef(lex.point_span(), "Self", 0xFFFF));
+ GET_TOK(tok, lex);
+ }
+ if( tok.type() == TOK_RWORD_WHERE ) {
+ throw ParseError::Todo(lex, "Where clause on associated type");
+ }
+
+ TypeRef default_type = TypeRef( lex.point_span() );
+ if( tok.type() == TOK_EQUAL ) {
+ default_type = Parse_Type(lex);
+ GET_TOK(tok, lex);
+ }
+
+ CHECK_TOK(tok, TOK_SEMICOLON);
+ rv = ::AST::TypeAlias( mv$(atype_params), mv$(default_type) );
+ break; }
+
+ // Functions (possibly unsafe)
+ case TOK_RWORD_UNSAFE:
+ fn_is_unsafe = true;
+ if( GET_TOK(tok, lex) == TOK_RWORD_EXTERN )
+ case TOK_RWORD_EXTERN:
+ {
+ abi = "C";
+ if( GET_TOK(tok, lex) == TOK_STRING )
+ abi = tok.str();
+ else
+ PUTBACK(tok, lex);
+
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_RWORD_FN);
+ case TOK_RWORD_FN: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ // Self allowed, prototype-form allowed (optional names and no code)
+ auto fcn = Parse_FunctionDef(lex, abi, true, true, fn_is_unsafe, fn_is_const);
+ if( GET_TOK(tok, lex) == TOK_BRACE_OPEN )
+ {
+ PUTBACK(tok, lex);
+ // Enter a new hygine scope for the function body. (TODO: Should this be in Parse_ExprBlock?)
+ lex.push_hygine();
+ fcn.set_code( Parse_ExprBlock(lex) );
+ lex.pop_hygine();
+ }
+ else if( tok.type() == TOK_SEMICOLON )
+ {
+ // Accept it
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok);
+ }
+ rv = ::std::move(fcn);
+ break; }
+ default:
+ throw ParseError::Unexpected(lex, tok);
+ }
+
+ return ::AST::Named<::AST::Item>( lex.end_span(ps), mv$(item_attrs), true, mv$(name), mv$(rv) );
+}
+
AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items)
{
TRACE_FUNCTION;
@@ -649,9 +796,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items
// TODO: Just add these as `where Self: <foo>` (would that break typecheck?)
do {
if( GET_TOK(tok, lex) == TOK_LIFETIME ) {
- // TODO: Need a better way of indiciating 'static than just an invalid path
- ASSERT_BUG(lex.point_span(), tok.str() == "static", "TODO: Support lifetimes other than 'static in trait bounds");
- supertraits.push_back( make_spanned( Span(tok.get_pos()), Type_TraitPath{ {}, AST::Path() } ) );
+ params.add_bound(::AST::GenericBound::make_TypeLifetime({ TypeRef(lex.point_span(), "Self"), ::AST::LifetimeRef(lex.get_ident(tok)) }));
}
else if( tok.type() == TOK_BRACE_OPEN ) {
break;
@@ -680,131 +825,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items
{
PUTBACK(tok, lex);
- auto item_attrs = Parse_ItemAttrs(lex);
- SET_ATTRS(lex, item_attrs);
-
- auto ps = lex.start_span();
- {
- ::AST::MacroInvocation inv;
- if( Parse_MacroInvocation_Opt(lex, inv) )
- {
- trait.items().push_back( AST::Named<AST::Item>("", AST::Item(mv$(inv)), false) );
- continue ;
- }
- GET_TOK(tok, lex);
- }
-
- bool is_specialisable = false;
- if( tok.type() == TOK_IDENT && tok.str() == "default" ) {
- is_specialisable = true;
- GET_TOK(tok, lex);
- }
- // TODO: Mark specialisation
- (void)is_specialisable;
-
- bool fn_is_const = false;
- bool fn_is_unsafe = false;
- ::std::string abi = ABI_RUST;
- switch(tok.type())
- {
- case TOK_RWORD_STATIC: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- auto ty = Parse_Type(lex);
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
-
- ::AST::Expr val;
- if(GET_TOK(tok, lex) == TOK_EQUAL) {
- val = Parse_Expr(lex);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_SEMICOLON);
-
- trait.add_static( mv$(name), mv$(item_attrs), ::AST::Static(AST::Static::STATIC, mv$(ty), val) );
- break; }
- case TOK_RWORD_CONST: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- auto ty = Parse_Type(lex);
-
- ::AST::Expr val;
- if(GET_TOK(tok, lex) == TOK_EQUAL) {
- val = Parse_Expr(lex);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_SEMICOLON);
-
- trait.add_static( mv$(name), mv$(item_attrs), ::AST::Static(AST::Static::CONST, mv$(ty), val) );
- break; }
- // Associated type
- case TOK_RWORD_TYPE: {
- auto atype_params = ::AST::GenericParams { };
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- if( GET_TOK(tok, lex) == TOK_COLON )
- {
- // Bounded associated type
- Parse_TypeBound(lex, atype_params, TypeRef(lex.point_span(), "Self", 0xFFFF));
- GET_TOK(tok, lex);
- }
- if( tok.type() == TOK_RWORD_WHERE ) {
- throw ParseError::Todo(lex, "Where clause on associated type");
- }
-
- TypeRef default_type = TypeRef( lex.point_span() );
- if( tok.type() == TOK_EQUAL ) {
- default_type = Parse_Type(lex);
- GET_TOK(tok, lex);
- }
-
- CHECK_TOK(tok, TOK_SEMICOLON);
- trait.add_type( ::std::move(name), mv$(item_attrs), ::std::move(default_type) );
- trait.items().back().data.as_Type().params() = mv$(atype_params);
- break; }
-
- // Functions (possibly unsafe)
- case TOK_RWORD_UNSAFE:
- fn_is_unsafe = true;
- if( GET_TOK(tok, lex) == TOK_RWORD_EXTERN )
- case TOK_RWORD_EXTERN:
- {
- abi = "C";
- if( GET_TOK(tok, lex) == TOK_STRING )
- abi = tok.str();
- else
- PUTBACK(tok, lex);
-
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_RWORD_FN);
- case TOK_RWORD_FN: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- ::std::string name = mv$(tok.str());
- // Self allowed, prototype-form allowed (optional names and no code)
- auto fcn = Parse_FunctionDef(lex, abi, true, true, fn_is_unsafe, fn_is_const);
- if( GET_TOK(tok, lex) == TOK_BRACE_OPEN )
- {
- PUTBACK(tok, lex);
- // Enter a new hygine scope for the function body. (TODO: Should this be in Parse_ExprBlock?)
- lex.push_hygine();
- fcn.set_code( Parse_ExprBlock(lex) );
- lex.pop_hygine();
- }
- else if( tok.type() == TOK_SEMICOLON )
- {
- // Accept it
- }
- else
- {
- throw ParseError::Unexpected(lex, tok);
- }
- trait.add_function( ::std::move(name), mv$(item_attrs), ::std::move(fcn) );
- break; }
- default:
- throw ParseError::Unexpected(lex, tok);
- }
+ trait.items().push_back( Parse_Trait_Item(lex) );
}
return trait;
@@ -842,7 +863,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items)
SET_ATTRS(lex, item_attrs);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- ::std::string name = mv$(tok.str());
+ auto name = tok.istr();
// Tuple-like variants
if( GET_TOK(tok, lex) == TOK_PAREN_OPEN )
{
@@ -880,7 +901,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items)
auto field_attrs = Parse_ItemAttrs(lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
auto ty = Parse_Type(lex);
fields.push_back( ::AST::StructItem(mv$(field_attrs), true, mv$(name), mv$(ty)) );
@@ -945,7 +966,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items)
bool is_pub = Parse_Publicity(lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
auto ty = Parse_Type(lex);
@@ -988,34 +1009,56 @@ AST::Attribute Parse_MetaItem(TokenStream& lex)
{
TRACE_FUNCTION;
Token tok;
- GET_TOK(tok, lex);
- if( tok.type() == TOK_INTERPOLATED_META ) {
+ if( lex.lookahead(0) == TOK_INTERPOLATED_META ) {
+ GET_TOK(tok, lex);
return mv$(tok.frag_meta());
}
auto ps = lex.start_span();
- CHECK_TOK(tok, TOK_IDENT);
- ::std::string name = mv$(tok.str());
+ GET_TOK(tok, lex);
+
+ switch(tok.type())
+ {
+ case TOK_IDENT:
+ break;
+ case TOK_INTEGER:
+ if( TARGETVER_1_29 )
+ return AST::Attribute(lex.end_span(ps), "", tok.to_str());
+ default:
+ throw ParseError::Unexpected(lex, tok, {TOK_IDENT, TOK_INTEGER});
+ }
+
+ auto name = tok.istr();
switch(GET_TOK(tok, lex))
{
case TOK_EQUAL:
switch(GET_TOK(tok, lex))
{
case TOK_STRING:
- return AST::Attribute(lex.end_span(mv$(ps)), name, tok.str());
+ return AST::Attribute(lex.end_span(ps), name, tok.str());
case TOK_INTERPOLATED_EXPR: {
auto n = tok.take_frag_node();
+ void Expand_BareExpr(const AST::Crate& , const AST::Module&, ::std::unique_ptr<AST::ExprNode>& n);
+ assert( lex.parse_state().crate );
+ assert( lex.parse_state().module );
+ Expand_BareExpr(*lex.parse_state().crate, *lex.parse_state().module, n);
if( auto* v = dynamic_cast<::AST::ExprNode_String*>(&*n) )
{
- return AST::Attribute(lex.end_span(mv$(ps)), name, mv$(v->m_value));
+ return AST::Attribute(lex.end_span(ps), name, mv$(v->m_value));
}
else
{
// - Force an error.
- CHECK_TOK(tok, TOK_STRING);
+ throw ParseError::Unexpected(lex, Token(InterpolatedFragment(InterpolatedFragment::EXPR, n.release())), TOK_STRING);
}
break; }
+ case TOK_INTEGER:
+ if( TARGETVER_1_29 )
+ return AST::Attribute(lex.end_span(ps), name, tok.to_str());
+ case TOK_IDENT:
+ if( TARGETVER_1_29 )
+ return AST::Attribute(lex.end_span(ps), name, tok.to_str());
default:
// - Force an error.
CHECK_TOK(tok, TOK_STRING);
@@ -1031,10 +1074,10 @@ AST::Attribute Parse_MetaItem(TokenStream& lex)
items.push_back(Parse_MetaItem(lex));
} while(GET_TOK(tok, lex) == TOK_COMMA);
CHECK_TOK(tok, TOK_PAREN_CLOSE);
- return AST::Attribute(lex.end_span(mv$(ps)), name, mv$(items)); }
+ return AST::Attribute(lex.end_span(ps), name, mv$(items)); }
default:
PUTBACK(tok, lex);
- return AST::Attribute(lex.end_span(mv$(ps)), name);
+ return AST::Attribute(lex.end_span(ps), name);
}
}
@@ -1145,7 +1188,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
if( Parse_MacroInvocation_Opt(lex, inv) )
{
impl.add_macro_invocation( mv$(inv) );
- impl.items().back().data->attrs = mv$(item_attrs);
+ impl.items().back().attrs = mv$(item_attrs);
return ;
}
}
@@ -1156,7 +1199,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
GET_TOK(tok, lex);
bool is_specialisable = false;
- if( tok.type() == TOK_IDENT && tok.str() == "default" ) {
+ if( tok.type() == TOK_IDENT && tok.istr() == "default" ) {
is_specialisable = true;
GET_TOK(tok, lex);
}
@@ -1168,10 +1211,11 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
{
case TOK_RWORD_TYPE: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_EQUAL);
- impl.add_type(is_public, is_specialisable, name, Parse_Type(lex));
+ auto ty = Parse_Type(lex);
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ impl.add_type(lex.end_span(ps), mv$(item_attrs), is_public, is_specialisable, name, mv$(ty));
break; }
case TOK_RWORD_UNSAFE:
fn_is_unsafe = true;
@@ -1183,7 +1227,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
if( tok.type() != TOK_RWORD_FN && tok.type() != TOK_RWORD_UNSAFE && !fn_is_unsafe )
{
CHECK_TOK(tok, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
auto ty = Parse_Type(lex);
GET_CHECK_TOK(tok, lex, TOK_EQUAL);
@@ -1191,7 +1235,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
auto i = ::AST::Static(AST::Static::CONST, mv$(ty), mv$(val));
- impl.add_static( is_public, is_specialisable, mv$(name), mv$(i) );
+ impl.add_static( lex.end_span(ps), mv$(item_attrs), is_public, is_specialisable, mv$(name), mv$(i) );
break ;
}
else if( tok.type() == TOK_RWORD_UNSAFE )
@@ -1218,19 +1262,16 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
case TOK_RWORD_FN: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
// TODO: Hygine on function names? - Not in impl blocks?
- ::std::string name = mv$(tok.str());
+ auto name = tok.istr();
DEBUG("Function " << name);
// - Self allowed, can't be prototype-form
auto fcn = Parse_FunctionDefWithCode(lex, abi, true, fn_is_unsafe, fn_is_const);
- impl.add_function(is_public, is_specialisable, mv$(name), mv$(fcn));
+ impl.add_function(lex.end_span(ps), mv$(item_attrs), is_public, is_specialisable, mv$(name), mv$(fcn));
break; }
default:
throw ParseError::Unexpected(lex, tok);
}
-
- impl.items().back().data->span = lex.end_span(mv$(ps));
- impl.items().back().data->attrs = mv$(item_attrs); // Empty for functions
}
AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::AttributeList& block_attrs)
@@ -1255,16 +1296,13 @@ AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::A
{
case TOK_RWORD_FN: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
// parse function as prototype
// - no self, is prototype, is unsafe and not const
auto i = ::AST::Item( Parse_FunctionDef(lex, abi, false, true, true,false) );
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- i.attrs = mv$(meta_items);
- i.span = lex.end_span(mv$(ps));
-
- rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } );
+ rv.add_item( AST::Named<AST::Item> { lex.end_span(ps), mv$(meta_items), is_public, mv$(name), mv$(i) } );
break; }
case TOK_RWORD_STATIC: {
bool is_mut = false;
@@ -1273,62 +1311,104 @@ AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::A
else
PUTBACK(tok, lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
auto type = Parse_Type(lex);
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
auto i = ::AST::Item(::AST::Static( (is_mut ? ::AST::Static::MUT : ::AST::Static::STATIC), mv$(type), ::AST::Expr() ));
- i.attrs = mv$(meta_items);
- i.span = lex.end_span(mv$(ps));
- rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } );
+ rv.add_item( AST::Named<AST::Item> { lex.end_span(ps), mv$(meta_items), is_public, mv$(name), mv$(i) } );
+ break; }
+ case TOK_RWORD_TYPE: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ auto name = tok.istr();
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ auto sp = lex.end_span(ps);
+ //TODO(sp, "Extern type");
+ auto i = ::AST::Item(::AST::TypeAlias( ::AST::GenericParams(), ::TypeRef(sp) ));
+ rv.add_item( AST::Named<AST::Item> { mv$(sp), mv$(meta_items), is_public, mv$(name), mv$(i) } );
break; }
default:
- throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_STATIC});
+ throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_STATIC, TOK_RWORD_TYPE});
}
}
return rv;
}
-void Parse_Use_Wildcard(Span sp, AST::Path base_path, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
+/// Parse multiple items from a use "statement"
+void Parse_Use_Inner(TokenStream& lex, ::std::vector<AST::UseItem::Ent>& entries, AST::Path& path)
{
- fcn( AST::UseStmt(mv$(sp), mv$(base_path)), "" ); // HACK! Empty path indicates wilcard import
-}
-void Parse_Use_Set(TokenStream& lex, const ProtoSpan& ps, const AST::Path& base_path, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
-{
- TRACE_FUNCTION;
-
Token tok;
- do {
- AST::Path path;
- ::std::string name;
- if( GET_TOK(tok, lex) == TOK_RWORD_SELF ) {
- path = ::AST::Path(base_path);
- name = base_path[base_path.size()-1].name();
- }
- else if( tok.type() == TOK_BRACE_CLOSE ) {
- break ;
- }
- else {
- CHECK_TOK(tok, TOK_IDENT);
- path = base_path + AST::PathNode(tok.str(), {});
- name = mv$(tok.str());
- }
- if( GET_TOK(tok, lex) == TOK_RWORD_AS ) {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- name = mv$(tok.str());
- }
- else {
- PUTBACK(tok, lex);
+ do
+ {
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_IDENT:
+ path.append( AST::PathNode( tok.istr(), {}) );
+ break;
+ case TOK_BRACE_OPEN:
+ // Can't be an empty list
+ if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) {
+ throw ParseError::Unexpected(lex, tok);
+ }
+ // Keep looping until a comma
+ do {
+ if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) {
+ // Trailing comma
+ GET_TOK(tok, lex);
+ break;
+ }
+ // - Handle `self` in braces differently
+ else if( LOOK_AHEAD(lex) == TOK_RWORD_SELF ) {
+ GET_TOK(tok, lex);
+ auto name = path.nodes().back().name();
+ if( LOOK_AHEAD(lex) == TOK_RWORD_AS ) {
+ GET_TOK(tok, lex);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ }
+ entries.push_back({ lex.point_span(), AST::Path(path), ::std::move(name) });
+ }
+ else {
+ size_t l = path.nodes().size();
+
+ Parse_Use_Inner(lex, entries, path);
+
+ assert(l <= path.nodes().size());
+ path.nodes().resize( l );
+ }
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ CHECK_TOK(tok, TOK_BRACE_CLOSE);
+ return;
+ case TOK_STAR:
+ entries.push_back({ lex.point_span(), AST::Path(path), "" });
+ return ;
+ default:
+ throw ParseError::Unexpected(lex, tok);
}
- fcn(AST::UseStmt(lex.end_span(ps), mv$(path)), mv$(name));
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- PUTBACK(tok, lex);
-}
+ } while( GET_TOK(tok, lex) == TOK_DOUBLE_COLON );
+
+ RcString name;
-void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
+ // NOTE: The above loop has to run once, so the last token HAS to have been an ident
+ if( tok.type() == TOK_RWORD_AS )
+ {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ }
+ else
+ {
+ PUTBACK(tok, lex);
+ ASSERT_BUG(lex.point_span(), path.nodes().size() > 0, "`use` with no path");
+ name = path.nodes().back().name();
+ }
+
+ // TODO: Get a span covering the final node.
+ entries.push_back({ lex.point_span(), AST::Path(path), ::std::move(name) });
+}
+::AST::UseItem Parse_Use(TokenStream& lex)
{
TRACE_FUNCTION;
@@ -1337,10 +1417,13 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::strin
::std::vector<AST::PathNode> nodes;
ProtoSpan span_start = lex.start_span();
+ ::std::vector<AST::UseItem::Ent> entries;
+
switch( GET_TOK(tok, lex) )
{
case TOK_RWORD_SELF:
path = AST::Path( AST::Path::TagSelf(), {} ); // relative path
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break;
case TOK_RWORD_SUPER: {
unsigned int count = 1;
@@ -1350,9 +1433,11 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::strin
count += 1;
}
path = AST::Path( AST::Path::TagSuper(), count, {} );
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break; }
- case TOK_IDENT:
- path.append( AST::PathNode(mv$(tok.str()), {}) );
+ case TOK_RWORD_CRATE:
+ // 1.29 absolute path
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break;
// Leading :: is allowed and ignored for the $crate feature
case TOK_DOUBLE_COLON:
@@ -1361,77 +1446,35 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::strin
if( LOOK_AHEAD(lex) == TOK_STRING )
{
GET_CHECK_TOK(tok, lex, TOK_STRING);
- path = ::AST::Path(tok.str(), {});
+ path = ::AST::Path(RcString::new_interned(tok.str()), {});
}
- else {
+ else
+ {
PUTBACK(tok, lex);
}
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break;
- case TOK_BRACE_OPEN:
- Parse_Use_Set(lex, span_start, path, fcn);
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
- return;
- case TOK_STAR:
- Parse_Use_Wildcard( lex.end_span(span_start), mv$(path), fcn );
- return;
case TOK_INTERPOLATED_PATH:
path = mv$(tok.frag_path());
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break;
default:
- throw ParseError::Unexpected(lex, tok);
- }
- while( GET_TOK(tok, lex) == TOK_DOUBLE_COLON )
- {
- if( GET_TOK(tok, lex) == TOK_IDENT )
- {
- path.append( AST::PathNode( mv$(tok.str()), {}) );
- }
- else
- {
- //path.set_span( lex.end_span(span_start) );
- switch( tok.type() )
- {
- case TOK_BRACE_OPEN:
- Parse_Use_Set(lex, span_start, mv$(path), fcn);
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
- break ;
- case TOK_STAR:
- Parse_Use_Wildcard( lex.end_span(span_start), mv$(path), fcn );
- break ;
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- // early return - This branch is either the end of the use statement, or a syntax error
- return ;
- }
- }
- //path.set_span( lex.end_span(span_start) );
-
- ::std::string name;
- // This should only be allowed if the last token was an ident
- // - Above checks ensure this
- if( tok.type() == TOK_RWORD_AS )
- {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- name = mv$(tok.str());
- }
- else
- {
PUTBACK(tok, lex);
- ASSERT_BUG(lex.point_span(), path.nodes().size() > 0, "`use` with no path");
- name = path.nodes().back().name();
+ break;
}
- fcn( AST::UseStmt(lex.end_span(span_start), mv$(path)), name);
+ Parse_Use_Inner(lex, entries, path);
+
+ return AST::UseItem { lex.end_span(span_start), mv$(entries) };
}
-::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan span_start, ::std::string name, TokenStream& lex)
+::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan span_start, RcString name, TokenStream& lex)
{
Token tok;
- ::std::string ident;
+ RcString ident;
if( GET_TOK(tok, lex) == TOK_IDENT ) {
- ident = mv$(tok.str());
+ ident = tok.istr();
}
else {
PUTBACK(tok, lex);
@@ -1448,14 +1491,19 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
{
// Good
}
+ else if( lex.lookahead(0) == TOK_INTERPOLATED_PATH && lex.lookahead(1) == TOK_EXCLAM )
+ {
+ // Also good.
+ }
else
{
return false;
}
auto ps = lex.start_span();
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = tok.str();
+ auto name_path = Parse_Path(lex, PATH_GENERIC_NONE);
+ ASSERT_BUG(lex.point_span(), name_path.nodes().size() == 1, "TODO: Support multi-component paths in macro invocations");
+ auto name = name_path.nodes()[0].name();
GET_CHECK_TOK(tok, lex, TOK_EXCLAM);
bool is_braced = (lex.lookahead(0) == TOK_BRACE_OPEN || (lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_BRACE_OPEN));
@@ -1469,6 +1517,102 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
return true;
}
+#if 0
+namespace {
+ ::AST::Module::FileInfo get_submod_file(
+ Span sp, const ::AST::Module::FileInfo& parent_fileinfo, const ::std::string& new_mod_name, const ::std::string& path_attr,
+ bool is_extern_file, bool is_cfg_disabled
+ )
+ {
+ ::AST::Module::FileInfo rv;
+ TRACE_FUNCTION_F(new_mod_name << ", " << path_attr << ", " << is_extern_file);
+ ::std::string sub_path;
+ bool sub_file_controls_dir = true;
+
+ // 1. Determine the base path for the module
+ if( parent_fileinfo.path == "-" ) {
+ if( path_attr.size() ) {
+ ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin");
+ }
+ sub_path = "-";
+ }
+ else if( path_attr.size() > 0 )
+ {
+ // #[path] present, add to the parent path
+ sub_path = dirname(parent_fileinfo.path) + path_attr;
+ }
+ else if( mod_fileinfo.controls_dir )
+ {
+ // The parent module is either the crate root, or a `mod.rs` (or otherwise a controller)
+ sub_path = parent_fileinfo.dir + name;
+ }
+ else
+ {
+ sub_path = parent_fileinfo.path;
+ sub_file_controls_dir = false;
+ }
+ DEBUG("Mod '" << name << "', sub_path = " << sub_path);
+
+ rv.path = sub_path;
+ rv.controls_dir = sub_file_controls_dir;
+
+ if( is_cfg_disabled || parent_fileinfo.force_no_load )
+ {
+ rv.force_no_load = true;
+ }
+ if( ! is_extern_file )
+ {
+ // If this is an inline module, set the path to just a directory
+ if( sub_path != "-" ) {
+ rv.path = sub_path + "/";
+ rv.dir = sub_path + "/";
+ }
+ else {
+ rv.path = "-";
+ }
+ }
+ else
+ {
+ if( sub_path == "-" )
+ {
+ ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin");
+ }
+ else
+ {
+ ::std::string newpath_dir = sub_path + "/";
+ ::std::string newpath_file = path_attr.size() > 0 ? sub_path : sub_path + ".rs";
+ DEBUG("newpath_dir = '" << newpath_dir << "', newpath_file = '" << newpath_file << "'");
+ ::std::ifstream ifs_dir (newpath_dir + "mod.rs");
+ ::std::ifstream ifs_file(newpath_file);
+ if( ifs_dir.is_open() && ifs_file.is_open() )
+ {
+ // Collision
+ ERROR(lex.point_span(), E0000, "Both modname.rs and modname/mod.rs exist");
+ }
+ else if( ifs_dir.is_open() )
+ {
+ // Load from dir
+ rv.path = newpath_dir + "mod.rs";
+ rv.dir = newpath_dir;
+ }
+ else if( ifs_file.is_open() )
+ {
+ rv.path = newpath_file;
+ rv.dir = newpath_dir;
+ rv.controls_dir = false;
+ }
+ else
+ {
+ // Can't find file
+ ERROR(sp, E0000, "Can't find file for '" << name << "' in '" << parent_fileinfo.dir << "'");
+ }
+ }
+ }
+ return rv;
+ }
+}
+#endif
+
::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::AttributeList meta_items)
{
TRACE_FUNCTION_F("mod_path="<<mod_path<<", meta_items="<<meta_items);
@@ -1489,24 +1633,20 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
auto rv = tok.take_frag_item();
// Transfer new attributes onto the item
for(auto& mi : meta_items.m_items)
- rv.data.attrs.m_items.push_back( mv$(mi) );
+ rv.attrs.m_items.push_back( mv$(mi) );
return rv;
}
auto ps = lex.start_span();
- ::std::string item_name;
+ RcString item_name;
::AST::Item item_data;
{
::AST::MacroInvocation inv;
if( Parse_MacroInvocation_Opt(lex, inv) )
{
- item_data = ::AST::Item( mv$(inv) );
- item_data.attrs = mv$(meta_items);
- item_data.span = lex.end_span(mv$(ps));
-
- return ::AST::Named< ::AST::Item> { "", mv$(item_data), false };
+ return ::AST::Named< ::AST::Item> { lex.end_span(ps), mv$(meta_items), false, "", ::AST::Item( mv$(inv) ) };
}
}
@@ -1515,16 +1655,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
switch( GET_TOK(tok, lex) )
{
case TOK_RWORD_USE:
- // NOTE: The only problem here is with things like `use foo::{a, b, c}` - all others are a single statement.
- // - These are caught by the condition in the closure
- Parse_Use(lex, [&](AST::UseStmt p, std::string s) {
- DEBUG(mod_path << " - use " << p << " as '" << s << "'");
- if( !item_data.is_None() )
- TODO(lex.point_span(), "Encode multi-item use statements as a single Item");
- item_data = ::AST::Item(mv$(p));
- item_name = mv$(s);
- });
- assert( !item_data.is_None() );
+ item_data = Parse_Use(lex);
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
break;
@@ -1540,7 +1671,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// `extern "<ABI>" fn ...`
case TOK_RWORD_FN: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, abi, false, false,false) );
break; }
// `extern "ABI" {`
@@ -1555,7 +1686,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// `extern fn ...`
case TOK_RWORD_FN:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, "C", false, false,false) );
break;
@@ -1574,20 +1705,20 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// `extern crate "crate-name" as crate_name;`
// NOTE: rustc doesn't allow this, keep in mrustc for for reparse support
case TOK_STRING:
- item_data = ::AST::Item::make_Crate({ tok.str() });
+ item_data = ::AST::Item::make_Crate({ RcString::new_interned(tok.str()) });
GET_CHECK_TOK(tok, lex, TOK_RWORD_AS);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
break;
// `extern crate crate_name;`
// `extern crate crate_name as other_name;`
case TOK_IDENT:
- item_name = mv$(tok.str());
+ item_name = tok.istr();
if(GET_TOK(tok, lex) == TOK_RWORD_AS) {
item_data = ::AST::Item::make_Crate({ mv$(item_name) });
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
}
else {
PUTBACK(tok, lex);
@@ -1610,7 +1741,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
switch( GET_TOK(tok, lex) )
{
case TOK_IDENT: {
- item_name = mv$(tok.str());
+ item_name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
TypeRef type = Parse_Type(lex);
@@ -1622,12 +1753,12 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
case TOK_RWORD_UNSAFE:
GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, true,true/*unsafe,const*/) );
break;
case TOK_RWORD_FN:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
// - self not allowed, not prototype
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, false,true/*unsafe,const*/) );
break;
@@ -1644,7 +1775,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
GET_TOK(tok, lex);
}
CHECK_TOK(tok, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
TypeRef type = Parse_Type(lex);
@@ -1674,20 +1805,20 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
}
GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, abi, false, true,false/*unsafe,const*/) );
break; }
// `unsafe fn`
case TOK_RWORD_FN:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
// - self not allowed, not prototype
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, true,false/*unsafe,const*/) );
break;
// `unsafe trait`
case TOK_RWORD_TRAIT: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
auto tr = Parse_TraitDef(lex, meta_items);
tr.set_is_unsafe();
item_data = ::AST::Item( ::std::move(tr) );
@@ -1704,8 +1835,21 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
else {
BUG(lex.point_span(), "Parse_Impl returned a variant other than Impl or NegImpl");
}
- return ::AST::Named< ::AST::Item> { "", mv$(impl), false };
+ return ::AST::Named< ::AST::Item> { Span(), {}, false, "", mv$(impl) };
}
+ // `unsafe auto trait`
+ case TOK_IDENT:
+ if( TARGETVER_1_29 && tok.istr() == "auto" ) {
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_TRAIT);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = tok.istr();
+ auto tr = Parse_TraitDef(lex, meta_items);
+ tr.set_is_unsafe();
+ tr.set_is_marker();
+ item_data = ::AST::Item( ::std::move(tr) );
+ break;
+ }
+ //goto default;
default:
throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_TRAIT, TOK_RWORD_IMPL});
}
@@ -1713,65 +1857,142 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// `fn`
case TOK_RWORD_FN:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
// - self not allowed, not prototype
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, false,false/*unsafe,const*/) );
break;
// `type`
case TOK_RWORD_TYPE:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_TypeAlias(lex) );
break;
// `struct`
case TOK_RWORD_STRUCT:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_Struct(lex, meta_items) );
break;
// `enum`
case TOK_RWORD_ENUM:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_EnumDef(lex, meta_items) );
break;
// Contextual keywords
case TOK_IDENT:
- if( tok.str() == "union" ) {
+ if( tok.istr() == "union" ) {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_Union(lex, meta_items) );
}
+ // `auto trait`
+ else if( TARGETVER_1_29 && tok.istr() == "auto" ) {
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_TRAIT);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = tok.istr();
+ auto tr = Parse_TraitDef(lex, meta_items);
+ tr.set_is_marker();
+ item_data = ::AST::Item( ::std::move(tr) );
+ }
else {
throw ParseError::Unexpected(lex, tok);
}
break;
// `impl`
case TOK_RWORD_IMPL:
- return ::AST::Named< ::AST::Item> { "", Parse_Impl(lex, mv$(meta_items)), false };
+ return ::AST::Named< ::AST::Item> { Span(), {}, false, "", Parse_Impl(lex, mv$(meta_items)) };
// `trait`
case TOK_RWORD_TRAIT:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) );
break;
+ case TOK_RWORD_MACRO:
+ if( TARGETVER_1_29 )
+ {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ auto name = tok.istr();
+ if( lex.lookahead(0) != TOK_PAREN_OPEN )
+ {
+ GET_TOK(tok, lex);
+ throw ParseError::Unexpected(lex, tok);
+ }
+ DEBUG("name = " << name);
+
+ ::std::vector<RcString> names;
+ auto ps = lex.start_span();
+ GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
+ auto arm_pat = Parse_MacroRules_Pat(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, names);
+ auto pat_span = lex.end_span(ps);
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
+ // TODO: Pass a flag that annotates all idents with the current module?
+ auto body = Parse_MacroRules_Cont(lex, TOK_BRACE_OPEN, TOK_BRACE_CLOSE, names);
+
+ auto mr = new MacroRules( );
+ mr->m_hygiene = lex.getHygiene();
+ {
+ Ident::ModPath mp;
+ for(const auto& node : mod_path.nodes())
+ {
+ mp.ents.push_back(node.name());
+ }
+ mr->m_hygiene.set_mod_path(::std::move(mp));
+ }
+ mr->m_rules.push_back(Parse_MacroRules_MakeArm(pat_span, ::std::move(arm_pat), ::std::move(body)));
+
+ item_name = name;
+ item_data = ::AST::Item( MacroRulesPtr(mr) );
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok);
+ }
+ break;
+
case TOK_RWORD_MOD: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
DEBUG("Sub module '" << name << "'");
AST::Module submod( mod_path + name );
+ // Check #[cfg] and don't load if it fails
+ struct H {
+ static bool check_item_cfg(const ::AST::AttributeList& attrs)
+ {
+ for(const auto& at : attrs.m_items) {
+ if( at.name() == "cfg" && !check_cfg(at.span(), at) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
// Rules for external files (/ path handling):
// - IF using stdin (path='-') - Disallow and propagate '-' as path
// - IF a #[path] attribute was passed, allow
// - IF in crate root or mod.rs, allow (input flag)
// - else, disallow and set flag
- ::std::string path_attr = (meta_items.has("path") ? meta_items.get("path")->string() : "");
+ ::std::string path_attr;
+ for(const auto& a : meta_items.m_items)
+ {
+ if( a.name() == "path" ) {
+ path_attr = a.string();
+ }
+ else if( a.name() == "cfg_attr" && a.items().at(1).name() == "path" ) {
+ if( check_cfg(a.span(), a.items().at(0)) ) {
+ path_attr = a.items().at(1).string();
+ }
+ }
+ else {
+ }
+ }
- //submod.m_file_info = get_submod_file(lex.end_span(ps), mod_fileinfo, name, path_attr, LOOK_AHEAD(lex) == TOK_SEMICOLON);
+ //submod.m_file_info = get_submod_file(lex.end_span(ps), mod_fileinfo, name, path_attr, LOOK_AHEAD(lex) == TOK_SEMICOLON, H::check_item_cfg(meta_items));
- ::std::string sub_path;
+ ::helpers::path sub_path;
bool sub_file_controls_dir = true;
if( mod_fileinfo.path == "-" ) {
if( path_attr.size() ) {
@@ -1781,15 +2002,16 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
}
else if( path_attr.size() > 0 )
{
- sub_path = dirname(mod_fileinfo.path) + path_attr;
+ sub_path = dirname(mod_fileinfo.path) / path_attr.c_str();
}
else if( mod_fileinfo.controls_dir )
{
- sub_path = dirname(mod_fileinfo.path) + name;
+ sub_path = dirname(mod_fileinfo.path) / name.c_str();
}
else
{
- sub_path = mod_fileinfo.path;
+ sub_path = dirname(mod_fileinfo.path) / mod_path.nodes().back().name().c_str() / name.c_str();
+ //sub_path = mod_fileinfo.path;
sub_file_controls_dir = false;
}
DEBUG("Mod '" << name << "', sub_path = " << sub_path);
@@ -1797,43 +2019,49 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
submod.m_file_info.path = sub_path;
submod.m_file_info.controls_dir = sub_file_controls_dir;
- // Check #[cfg] and don't load if it fails
- struct H {
- static bool check_item_cfg(const ::AST::AttributeList& attrs)
- {
- for(const auto& at : attrs.m_items) {
- if( at.name() == "cfg" && !check_cfg(at.span(), at) ) {
- return false;
- }
- }
- return true;
- }
- };
-
switch( GET_TOK(tok, lex) )
{
case TOK_BRACE_OPEN:
- submod.m_file_info.path = sub_path + "/";
+ submod.m_file_info.path = sub_path.str() + "/";
+ // TODO: If cfg fails, just eat the TT until a matching #[cfg]?
+ // - Or, mark the file infor as not being valid (so child modules don't try to load)
Parse_ModRoot(lex, submod, meta_items);
GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
break;
case TOK_SEMICOLON:
- if( sub_path == "-" ) {
+ if( sub_path.str() == "-" ) {
ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin");
}
- else if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir )
- {
- ERROR(lex.point_span(), E0000, "Can't load from files outside of mod.rs or crate root");
- }
else if( !H::check_item_cfg(meta_items) ) {
// Ignore - emit Item::None
item_name = mv$(name);
item_data = ::AST::Item( );
break ;
}
+ else if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir )
+ {
+ // TODO: Also search for curmod/submod.rs
+ //::std::string newpath_file = (mod_path.nodes().size() > 1 ? dirname(mod_fileinfo.path) + mod_path.nodes()[mod_path.nodes().size()-2].name() + "/" + name + ".rs" : "");
+ ::std::string newpath_file = (mod_path.nodes().size() >= 1 ? dirname(mod_fileinfo.path) / mod_path.nodes()[mod_path.nodes().size()-1].name().c_str() / name.c_str() + ".rs" : "");
+ DEBUG("newpath_file = '" << newpath_file << "' " << mod_fileinfo.path << " " << mod_path);
+ ::std::ifstream ifs_file(newpath_file);
+ if( ifs_file.is_open() )
+ {
+ submod.m_file_info.path = newpath_file;
+ submod.m_file_info.controls_dir = false;
+ DEBUG("- path = " << submod.m_file_info.path);
+ Lexer sub_lex(submod.m_file_info.path);
+ Parse_ModRoot(sub_lex, submod, meta_items);
+ GET_CHECK_TOK(tok, sub_lex, TOK_EOF);
+ }
+ else
+ {
+ ERROR(lex.point_span(), E0000, "Can't load from files outside of mod.rs or crate root");
+ }
+ }
else
{
- ::std::string newpath_dir = sub_path + "/";
+ ::std::string newpath_dir = sub_path.str() + "/";
::std::string newpath_file = path_attr.size() > 0 ? sub_path : sub_path + ".rs";
DEBUG("newpath_dir = '" << newpath_dir << "', newpath_file = '" << newpath_file << "'");
::std::ifstream ifs_dir (newpath_dir + "mod.rs");
@@ -1851,7 +2079,12 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
else if( ifs_file.is_open() )
{
submod.m_file_info.path = newpath_file;
+ if( path_attr == "" )
+ {
+ submod.m_file_info.controls_dir = false;
+ }
}
+ // TODO: If this is not a controlling file, look in `modname/` for the new module
else
{
// Can't find file
@@ -1874,10 +2107,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
throw ParseError::Unexpected(lex, tok);
}
- item_data.attrs = mv$(meta_items);
- item_data.span = lex.end_span(mv$(ps));
-
- return ::AST::Named< ::AST::Item> { mv$(item_name), mv$(item_data), is_public };
+ return ::AST::Named< ::AST::Item> { lex.end_span(ps), mv$(meta_items), is_public, mv$(item_name), mv$(item_data) };
}
void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_items)
@@ -1885,26 +2115,7 @@ void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_
SET_MODULE(lex, mod);
lex.parse_state().parent_attrs = &meta_items;
- //TRACE_FUNCTION;
- Token tok;
-
- // `use ...`
- // TODO: This doesn't spot `pub(path) use`.
- if( LOOK_AHEAD(lex) == TOK_RWORD_USE || (lex.lookahead(0) == TOK_RWORD_PUB && lex.lookahead(1) == TOK_RWORD_USE) )
- {
- bool is_public = Parse_Publicity(lex);
- GET_CHECK_TOK(tok, lex, TOK_RWORD_USE);
-
- Parse_Use(lex, [&mod,is_public,&meta_items](AST::UseStmt p, std::string s) {
- DEBUG(mod.path() << " - use " << p << " as '" << s << "'");
- mod.add_alias(is_public, mv$(p), s, meta_items.clone());
- });
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- }
- else
- {
- mod.add_item( Parse_Mod_Item_S(lex, mod.m_file_info, mod.path(), mv$(meta_items)) );
- }
+ mod.add_item( Parse_Mod_Item_S(lex, mod.m_file_info, mod.path(), mv$(meta_items)) );
}
void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod)
@@ -1959,6 +2170,7 @@ AST::Crate Parse_Crate(::std::string mainfile)
crate.root_module().m_file_info.path = mainpath;
crate.root_module().m_file_info.controls_dir = true;
+ lex.parse_state().crate = &crate;
Parse_ModRoot(lex, crate.root_module(), crate.m_attrs);
return crate;
diff --git a/src/parse/token.cpp b/src/parse/token.cpp
index 2e5a61d4..f9ecd028 100644
--- a/src/parse/token.cpp
+++ b/src/parse/token.cpp
@@ -35,6 +35,9 @@ Token::~Token()
case TOK_INTERPOLATED_META:
delete reinterpret_cast<AST::Attribute*>(m_data.as_Fragment());
break;
+ case TOK_INTERPOLATED_VIS:
+ delete reinterpret_cast<AST::Visibility*>(m_data.as_Fragment());
+ break;
default:
break;
}
@@ -49,6 +52,11 @@ Token::Token(enum eTokenType type):
m_type(type)
{
}
+Token::Token(enum eTokenType type, RcString str):
+ m_type(type),
+ m_data(Data::make_IString(mv$(str)))
+{
+}
Token::Token(enum eTokenType type, ::std::string str):
m_type(type),
m_data(Data::make_String(mv$(str)))
@@ -68,7 +76,12 @@ Token::Token(const InterpolatedFragment& frag)
{
switch(frag.m_type)
{
- case InterpolatedFragment::TT: throw "";
+ case InterpolatedFragment::TT:
+ throw "";
+ case InterpolatedFragment::VIS:
+ m_type = TOK_INTERPOLATED_VIS;
+ m_data = new AST::Visibility( *reinterpret_cast<const AST::Visibility*>(frag.m_ptr) );
+ break;
case InterpolatedFragment::TYPE:
m_type = TOK_INTERPOLATED_TYPE;
m_data = new TypeRef( reinterpret_cast<const TypeRef*>(frag.m_ptr)->clone() );
@@ -97,8 +110,8 @@ Token::Token(const InterpolatedFragment& frag)
case InterpolatedFragment::ITEM: {
m_type = TOK_INTERPOLATED_ITEM;
const auto& named = *reinterpret_cast<const AST::Named<AST::Item>*>(frag.m_ptr);
- ::AST::Item item = named.data.clone();
- m_data = new AST::Named<AST::Item>( named.name, mv$(item), named.is_pub );
+ auto item = named.data.clone();
+ m_data = new AST::Named<AST::Item>( named.span, named.attrs.clone(), named.is_pub, named.name, mv$(item) );
break; }
}
}
@@ -106,7 +119,12 @@ Token::Token(TagTakeIP, InterpolatedFragment frag)
{
switch(frag.m_type)
{
- case InterpolatedFragment::TT: throw "";
+ case InterpolatedFragment::TT:
+ throw "";
+ case InterpolatedFragment::VIS:
+ m_type = TOK_INTERPOLATED_VIS;
+ m_data = new AST::Visibility( mv$(*reinterpret_cast<AST::Visibility*>(frag.m_ptr)) );
+ break;
case InterpolatedFragment::TYPE:
m_type = TOK_INTERPOLATED_TYPE;
m_data = new TypeRef( mv$(*reinterpret_cast<TypeRef*>(frag.m_ptr)) );
@@ -150,6 +168,7 @@ Token::Token(const Token& t):
assert( t.m_data.tag() != Data::TAGDEAD );
TU_MATCH(Data, (t.m_data), (e),
(None, ),
+ (IString, m_data = Data::make_IString(e); ),
(String, m_data = Data::make_String(e); ),
(Integer, m_data = Data::make_Integer(e);),
(Float, m_data = Data::make_Float(e);),
@@ -165,6 +184,9 @@ Token Token::clone() const
TU_MATCH(Data, (m_data), (e),
(None,
),
+ (IString,
+ rv.m_data = Data::make_IString(e);
+ ),
(String,
rv.m_data = Data::make_String(e);
),
@@ -229,6 +251,15 @@ Token Token::clone() const
delete ptr;
return mv$(rv);
}
+::AST::Visibility Token::take_frag_vis()
+{
+ assert( m_type == TOK_INTERPOLATED_VIS );
+ auto ptr = reinterpret_cast<AST::Visibility*>(m_data.as_Fragment());
+ m_data.as_Fragment() = nullptr;
+ auto rv = mv$( *ptr );
+ delete ptr;
+ return mv$(rv);
+}
const char* Token::typestr(enum eTokenType type)
{
@@ -310,9 +341,10 @@ struct EscapedString {
case TOK_INTERPOLATED_META: return "/*:meta*/";
case TOK_INTERPOLATED_ITEM: return "/*:item*/";
case TOK_INTERPOLATED_IDENT: return "/*:ident*/";
+ case TOK_INTERPOLATED_VIS: return "/*:vis*/";
// Value tokens
- case TOK_IDENT: return m_data.as_String();
- case TOK_LIFETIME: return "'" + m_data.as_String();
+ case TOK_IDENT: return m_data.as_IString().c_str();
+ case TOK_LIFETIME: return FMT("'" << m_data.as_IString().c_str());
case TOK_INTEGER:
if( m_data.as_Integer().m_datatype == CORETYPE_ANY ) {
return FMT(m_data.as_Integer().m_intval);
@@ -360,8 +392,9 @@ struct EscapedString {
case TOK_SLASH: return "/";
case TOK_DOT: return ".";
- case TOK_DOUBLE_DOT: return "...";
- case TOK_TRIPLE_DOT: return "..";
+ case TOK_DOUBLE_DOT: return "..";
+ case TOK_DOUBLE_DOT_EQUAL: return "..=";
+ case TOK_TRIPLE_DOT: return "...";
case TOK_EQUAL: return "=";
case TOK_PLUS_EQUAL: return "+=";
@@ -454,6 +487,7 @@ struct EscapedString {
case TOK_RWORD_BE: return "be";
case TOK_RWORD_UNSIZED: return "unsized";
+ case TOK_RWORD_MACRO: return "macro";
}
throw ParseError::BugCheck("Reached end of Token::to_str");
}
@@ -485,13 +519,13 @@ struct EscapedString {
os << ":" << *reinterpret_cast<AST::Path*>(tok.m_data.as_Fragment());
break;
case TOK_INTERPOLATED_EXPR:
- os << ":" << *reinterpret_cast<AST::ExprNode*>(tok.m_data.as_Fragment());
+ os << ":" << *reinterpret_cast<const AST::ExprNode*>(tok.m_data.as_Fragment());
break;
case TOK_INTERPOLATED_STMT:
- os << ":" << *reinterpret_cast<AST::ExprNode*>(tok.m_data.as_Fragment());
+ os << ":" << *reinterpret_cast<const AST::ExprNode*>(tok.m_data.as_Fragment());
break;
case TOK_INTERPOLATED_BLOCK:
- os << ":" << *reinterpret_cast<AST::ExprNode*>(tok.m_data.as_Fragment());
+ os << ":" << *reinterpret_cast<const AST::ExprNode*>(tok.m_data.as_Fragment());
break;
case TOK_INTERPOLATED_META:
os << ":" << *reinterpret_cast<AST::Attribute*>(tok.m_data.as_Fragment());
diff --git a/src/parse/token.hpp b/src/parse/token.hpp
index 3605679b..0d9a8015 100644
--- a/src/parse/token.hpp
+++ b/src/parse/token.hpp
@@ -44,6 +44,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const Position& p);
class TypeRef;
class TokenTree;
namespace AST {
+ typedef bool Visibility;
class Pattern;
class Path;
class ExprNode;
@@ -63,6 +64,7 @@ class Token
TAGGED_UNION(Data, None,
(None, struct {}),
+ (IString, RcString),
(String, ::std::string),
(Integer, struct {
enum eCoreType m_datatype;
@@ -107,6 +109,7 @@ public:
Token(enum eTokenType type);
Token(enum eTokenType type, ::std::string str);
+ Token(enum eTokenType type, RcString str);
Token(uint64_t val, enum eCoreType datatype);
Token(double val, enum eCoreType datatype);
Token(const InterpolatedFragment& );
@@ -114,24 +117,28 @@ public:
Token(TagTakeIP, InterpolatedFragment );
enum eTokenType type() const { return m_type; }
+ const RcString& istr() const { return m_data.as_IString(); }
::std::string& str() { return m_data.as_String(); }
const ::std::string& str() const { return m_data.as_String(); }
enum eCoreType datatype() const { TU_MATCH_DEF(Data, (m_data), (e), (assert(!"Getting datatype of invalid token type");), (Integer, return e.m_datatype;), (Float, return e.m_datatype;)) throw ""; }
uint64_t intval() const { return m_data.as_Integer().m_intval; }
double floatval() const { return m_data.as_Float().m_floatval; }
+ // TODO: Replace these with a way of getting a InterpolatedFragment&
TypeRef& frag_type() { assert(m_type == TOK_INTERPOLATED_TYPE); return *reinterpret_cast<TypeRef*>( m_data.as_Fragment() ); }
AST::Path& frag_path() { assert(m_type == TOK_INTERPOLATED_PATH); return *reinterpret_cast<AST::Path*>( m_data.as_Fragment() ); }
AST::Pattern& frag_pattern() { assert(m_type == TOK_INTERPOLATED_PATTERN); return *reinterpret_cast<AST::Pattern*>( m_data.as_Fragment() ); }
AST::Attribute& frag_meta() { assert(m_type == TOK_INTERPOLATED_META); return *reinterpret_cast<AST::Attribute*>( m_data.as_Fragment() ); }
::std::unique_ptr<AST::ExprNode> take_frag_node();
::AST::Named<AST::Item> take_frag_item();
+ ::AST::Visibility take_frag_vis();
bool operator==(const Token& r) const {
if(type() != r.type())
return false;
TU_MATCH(Data, (m_data, r.m_data), (e, re),
(None, return true;),
+ (IString, return e == re; ),
(String, return e == re; ),
(Integer, return e.m_datatype == re.m_datatype && e.m_intval == re.m_intval;),
(Float, return e.m_datatype == re.m_datatype && e.m_floatval == re.m_floatval;),
diff --git a/src/parse/tokenstream.cpp b/src/parse/tokenstream.cpp
index 889c626c..6f0c57a1 100644
--- a/src/parse/tokenstream.cpp
+++ b/src/parse/tokenstream.cpp
@@ -138,11 +138,11 @@ Span TokenStream::point_span() const
Ident TokenStream::get_ident(Token tok) const
{
if(tok.type() == TOK_IDENT) {
- return Ident(getHygiene(), tok.str());
+ return Ident(getHygiene(), tok.istr());
}
else if(tok.type() == TOK_LIFETIME) {
// TODO: Maybe only when it's explicitly asked for?
- return Ident(getHygiene(), tok.str());
+ return Ident(getHygiene(), tok.istr());
}
else if( tok.type() == TOK_INTERPOLATED_IDENT ) {
TODO(getPosition(), "get_ident from TOK_INTERPOLATED_IDENT");
diff --git a/src/parse/tokenstream.hpp b/src/parse/tokenstream.hpp
index a9d325c2..25b6a3c1 100644
--- a/src/parse/tokenstream.hpp
+++ b/src/parse/tokenstream.hpp
@@ -16,6 +16,7 @@
namespace AST {
class Module;
+ class Crate;
class AttributeList;
}
@@ -27,6 +28,7 @@ struct ParseState
// A debugging hook that disables expansion of macros
bool no_expand_macros = false;
+ const ::AST::Crate* crate = nullptr;
::AST::Module* module = nullptr;
::AST::AttributeList* parent_attrs = nullptr;
diff --git a/src/parse/types.cpp b/src/parse/types.cpp
index ca5b7892..979a8045 100644
--- a/src/parse/types.cpp
+++ b/src/parse/types.cpp
@@ -15,6 +15,7 @@
TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list);
TypeRef Parse_Type_Fn(TokenStream& lex, AST::HigherRankedBounds hrbs = {});
TypeRef Parse_Type_Path(TokenStream& lex, AST::HigherRankedBounds hrbs, bool allow_trait_list);
+TypeRef Parse_Type_TraitObject(TokenStream& lex, ::AST::HigherRankedBounds hrbs = {});
TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list);
// === CODE ===
@@ -61,7 +62,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
case TOK_DOUBLE_LT: {
PUTBACK(tok, lex);
auto path = Parse_Path(lex, PATH_GENERIC_TYPE);
- return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), mv$(path));
+ return TypeRef(TypeRef::TagPath(), lex.end_span(ps), mv$(path));
}
//
case TOK_RWORD_FOR: {
@@ -82,7 +83,20 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
{
lex.getToken();
// TODO: path macros
- return TypeRef(TypeRef::TagMacro(), Parse_MacroInvocation(ps, mv$(tok.str()), lex));
+ return TypeRef(TypeRef::TagMacro(), Parse_MacroInvocation(ps, tok.istr(), lex));
+ }
+ if( TARGETVER_1_29 && tok.istr() == "dyn" )
+ {
+ if( lex.lookahead(0) == TOK_PAREN_OPEN ) {
+ GET_TOK(tok, lex);
+ auto rv = Parse_Type_TraitObject(lex, {});
+ GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE);
+ return rv;
+ }
+ else {
+ ::AST::HigherRankedBounds hrbs = Parse_HRB_Opt(lex);
+ return Parse_Type_TraitObject(lex, mv$(hrbs));
+ }
}
// or a primitive
//if( auto ct = coretype_fromstring(tok.str()) )
@@ -122,7 +136,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
else {
PUTBACK(tok, lex);
}
- return TypeRef(TypeRef::TagReference(), lex.end_span(mv$(ps)), ::std::move(lifetime), is_mut, Parse_Type(lex, false));
+ return TypeRef(TypeRef::TagReference(), lex.end_span(ps), ::std::move(lifetime), is_mut, Parse_Type(lex, false));
}
// '*' - Raw pointer
case TOK_STAR:
@@ -131,10 +145,10 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
{
case TOK_RWORD_MUT:
// Mutable pointer
- return TypeRef(TypeRef::TagPointer(), lex.end_span(mv$(ps)), true, Parse_Type(lex, false));
+ return TypeRef(TypeRef::TagPointer(), lex.end_span(ps), true, Parse_Type(lex, false));
case TOK_RWORD_CONST:
// Immutable pointer
- return TypeRef(TypeRef::TagPointer(), lex.end_span(mv$(ps)), false, Parse_Type(lex, false));
+ return TypeRef(TypeRef::TagPointer(), lex.end_span(ps), false, Parse_Type(lex, false));
default:
throw ParseError::Unexpected(lex, tok, {TOK_RWORD_CONST, TOK_RWORD_MUT});
}
@@ -147,11 +161,11 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
// Sized array
AST::Expr array_size = Parse_Expr(lex);
GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- return TypeRef(TypeRef::TagSizedArray(), lex.end_span(mv$(ps)), mv$(inner), array_size.take_node());
+ return TypeRef(TypeRef::TagSizedArray(), lex.end_span(ps), mv$(inner), array_size.take_node());
}
else if( tok.type() == TOK_SQUARE_CLOSE )
{
- return TypeRef(TypeRef::TagUnsizedArray(), lex.end_span(mv$(ps)), mv$(inner));
+ return TypeRef(TypeRef::TagUnsizedArray(), lex.end_span(ps), mv$(inner));
}
else {
throw ParseError::Unexpected(lex, tok/*, "; or ]"*/);
@@ -162,7 +176,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
case TOK_PAREN_OPEN: {
DEBUG("Tuple");
if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE )
- return TypeRef(TypeRef::TagTuple(), lex.end_span(mv$(ps)), {});
+ return TypeRef(TypeRef::TagTuple(), lex.end_span(ps), {});
PUTBACK(tok, lex);
TypeRef inner = Parse_Type(lex, true);
@@ -185,7 +199,8 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
types.push_back( Parse_Type(lex) );
}
CHECK_TOK(tok, TOK_PAREN_CLOSE);
- return TypeRef(TypeRef::TagTuple(), lex.end_span(mv$(ps)), mv$(types)); }
+ return TypeRef(TypeRef::TagTuple(), lex.end_span(ps), mv$(types));
+ }
}
default:
throw ParseError::Unexpected(lex, tok);
@@ -259,7 +274,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::AST::HigherRankedBounds hrbs)
PUTBACK(tok, lex);
}
- return TypeRef(TypeRef::TagFunction(), lex.end_span(mv$(ps)), mv$(hrbs), is_unsafe, mv$(abi), mv$(args), is_variadic, mv$(ret_type));
+ return TypeRef(TypeRef::TagFunction(), lex.end_span(ps), mv$(hrbs), is_unsafe, mv$(abi), mv$(args), is_variadic, mv$(ret_type));
}
TypeRef Parse_Type_Path(TokenStream& lex, ::AST::HigherRankedBounds hrbs, bool allow_trait_list)
@@ -268,16 +283,17 @@ TypeRef Parse_Type_Path(TokenStream& lex, ::AST::HigherRankedBounds hrbs, bool a
auto ps = lex.start_span();
+ auto path = Parse_Path(lex, PATH_GENERIC_TYPE);
if( hrbs.empty() && !allow_trait_list )
{
- return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), Parse_Path(lex, PATH_GENERIC_TYPE));
+ return TypeRef(TypeRef::TagPath(), lex.end_span(ps), mv$(path));
}
else
{
::std::vector<Type_TraitPath> traits;
::std::vector<AST::LifetimeRef> lifetimes;
- traits.push_back(Type_TraitPath { mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) });
+ traits.push_back(Type_TraitPath { mv$(hrbs), mv$(path) });
if( allow_trait_list )
{
@@ -303,38 +319,65 @@ TypeRef Parse_Type_Path(TokenStream& lex, ::AST::HigherRankedBounds hrbs, bool a
{
if( lifetimes.empty())
lifetimes.push_back(AST::LifetimeRef());
- return TypeRef(lex.end_span(mv$(ps)), mv$(traits), mv$(lifetimes));
+ return TypeRef(lex.end_span(ps), mv$(traits), mv$(lifetimes));
}
else
{
- return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), mv$(traits.at(0).path));
+ return TypeRef(TypeRef::TagPath(), lex.end_span(ps), mv$(traits.at(0).path));
}
}
}
-TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list)
+TypeRef Parse_Type_TraitObject(TokenStream& lex, ::AST::HigherRankedBounds hrbs)
{
Token tok;
-
auto ps = lex.start_span();
+
::std::vector<Type_TraitPath> traits;
- ::std::vector<AST::LifetimeRef> lifetimes;
- do {
+ ::std::vector<AST::LifetimeRef> lifetimes;
+
+ traits.push_back(Type_TraitPath { mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) });
+
+ while( lex.lookahead(0) == TOK_PLUS )
+ {
+ GET_CHECK_TOK(tok, lex, TOK_PLUS);
if( LOOK_AHEAD(lex) == TOK_LIFETIME ) {
GET_TOK(tok, lex);
lifetimes.push_back(AST::LifetimeRef( /*lex.point_span(),*/ lex.get_ident(mv$(tok)) ));
}
else
{
- AST::HigherRankedBounds hrbs;
if( lex.lookahead(0) == TOK_RWORD_FOR )
{
hrbs = Parse_HRB(lex);
}
traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) });
}
+ }
+
+ if( lifetimes.empty())
+ lifetimes.push_back(AST::LifetimeRef());
+ return TypeRef(lex.end_span(ps), mv$(traits), mv$(lifetimes));
+}
+TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list)
+{
+ Token tok;
+
+ auto ps = lex.start_span();
+ ::std::vector<Type_TraitPath> traits;
+ ::std::vector<AST::LifetimeRef> lifetimes;
+ do {
+ if( LOOK_AHEAD(lex) == TOK_LIFETIME ) {
+ GET_TOK(tok, lex);
+ lifetimes.push_back(AST::LifetimeRef( /*lex.point_span(),*/ lex.get_ident(mv$(tok)) ));
+ }
+ else
+ {
+ AST::HigherRankedBounds hrbs = Parse_HRB_Opt(lex);
+ traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) });
+ }
} while( GET_TOK(tok, lex) == TOK_PLUS );
PUTBACK(tok, lex);
- return TypeRef(lex.end_span(mv$(ps)), TypeData::make_ErasedType({ mv$(traits), mv$(lifetimes) }));
+ return TypeRef(lex.end_span(ps), TypeData::make_ErasedType({ mv$(traits), mv$(lifetimes) }));
}
diff --git a/src/rc_string.cpp b/src/rc_string.cpp
index 4025d8c8..b56f2e62 100644
--- a/src/rc_string.cpp
+++ b/src/rc_string.cpp
@@ -7,17 +7,19 @@
*/
#include <rc_string.hpp>
#include <cstring>
+#include <string>
#include <iostream>
+#include <algorithm> // std::max
RcString::RcString(const char* s, unsigned int len):
- m_ptr(nullptr),
- m_len(len)
+ m_ptr(nullptr)
{
if( len > 0 )
{
- m_ptr = new unsigned int[1 + (len+1 + sizeof(unsigned int)-1) / sizeof(unsigned int)];
- *m_ptr = 1;
- char* data_mut = reinterpret_cast<char*>(m_ptr + 1);
+ m_ptr = new unsigned int[2 + (len+1 + sizeof(unsigned int)-1) / sizeof(unsigned int)];
+ m_ptr[0] = 1;
+ m_ptr[1] = len;
+ char* data_mut = reinterpret_cast<char*>(m_ptr + 2);
for(unsigned int j = 0; j < len; j ++ )
data_mut[j] = s[j];
data_mut[len] = '\0';
@@ -25,16 +27,6 @@ RcString::RcString(const char* s, unsigned int len):
//::std::cout << "RcString(" << m_ptr << " \"" << *this << "\") - " << *m_ptr << " (creation)" << ::std::endl;
}
}
-RcString::RcString(const RcString& x):
- m_ptr(x.m_ptr),
- m_len(x.m_len)
-{
- if( m_ptr )
- {
- *m_ptr += 1;
- //::std::cout << "RcString(" << m_ptr << " \"" << *this << "\") - " << *m_ptr << " refs present (copy)" << ::std::endl;
- }
-}
RcString::~RcString()
{
if(m_ptr)
@@ -48,14 +40,87 @@ RcString::~RcString()
}
}
}
-bool RcString::operator==(const char* s) const
+Ordering RcString::ord(const char* s, size_t len) const
+{
+ if( m_ptr == nullptr )
+ return (len == 0 ? OrdEqual : OrdLess);
+ if( len == 0 )
+ return OrdGreater;
+
+ assert(this->size() > 0);
+ assert(len > 0);
+
+ int cmp = memcmp(this->c_str(), s, ::std::min(len, this->size()));
+ if(cmp == 0)
+ return ::ord(this->size(), len);
+ return ::ord(cmp, 0);
+}
+Ordering RcString::ord(const char* s) const
+{
+ if( m_ptr == nullptr )
+ return (*s == '\0' ? OrdEqual : OrdLess);
+
+ int cmp = strncmp(this->c_str(), s, this->size());
+ if( cmp == 0 )
+ {
+ if( s[this->size()] == '\0' )
+ return OrdEqual;
+ else
+ return OrdLess;
+ }
+ return ::ord(cmp, 0);
+}
+
+::std::ostream& operator<<(::std::ostream& os, const RcString& x)
{
- if( m_len == 0 )
- return *s == '\0';
- auto m = this->c_str();
- do {
- if( *m != *s )
- return false;
- } while( *m++ != '\0' && *s++ != '\0' );
- return true;
+ for(size_t i = 0; i < x.size(); i ++)
+ {
+ os << x.c_str()[i];
+ }
+ return os;
+}
+
+
+::std::set<RcString> RcString_interned_strings;
+
+RcString RcString::new_interned(const ::std::string& s)
+{
+#if 0
+ auto it = RcString_interned_strings.find(s);
+ if( it == RcString_interned_strings.end() )
+ {
+ it = RcString_interned_strings.insert(RcString(s)).first;
+ }
+ return *it;
+#else
+ // TODO: interning flag, so comparisons can just be a pointer comparison
+ // - Only want to set this flag on the cached instance
+ return *RcString_interned_strings.insert(RcString(s)).first;
+#endif
+}
+RcString RcString::new_interned(const char* s)
+{
+#if 0
+ auto it = RcString_interned_strings.find(s);
+ if( it == RcString_interned_strings.end() )
+ {
+ it = RcString_interned_strings.insert(RcString(s)).first;
+ }
+ return *it;
+#else
+ // TODO: interning flag, so comparisons can just be a pointer comparison
+ // - Only want to set this flag on the cached instance
+ return *RcString_interned_strings.insert(RcString(s)).first;
+#endif
+}
+
+size_t std::hash<RcString>::operator()(const RcString& s) const noexcept
+{
+ // http://www.cse.yorku.ca/~oz/hash.html "djb2"
+ size_t h = 5381;
+ for(auto c : s) {
+ h = h * 33 + (unsigned)c;
+ }
+ return h;
+ //return hash<std::string_view>(s.c_str(), s.size());
}
diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp
index 19da5820..86bc47c7 100644
--- a/src/resolve/absolute.cpp
+++ b/src/resolve/absolute.cpp
@@ -41,7 +41,7 @@ namespace
template<typename Val>
struct Named
{
- ::std::string name;
+ RcString name;
Val value;
};
template<typename Val>
@@ -65,6 +65,9 @@ namespace
}),
(Generic, struct {
// Map of names to slots
+ GenericSlot::Level level;
+ ::AST::GenericParams* params_def; // TODO: What if it's HRBs?, they have a different type
+ //::AST::HigherRankedBounds* hrbs_def;
::std::vector< Named< GenericSlot > > types;
::std::vector< Named< GenericSlot > > constants;
::std::vector< NamedI< GenericSlot > > lifetimes;
@@ -78,16 +81,20 @@ namespace
unsigned int m_block_level;
bool m_frozen_bind_set;
+ // Destination `GenericParams` for in_band_lifetimes
+ ::AST::GenericParams* m_ibl_target_generics;
+
Context(const ::AST::Crate& crate, const ::AST::Module& mod):
m_crate(crate),
m_mod(mod),
m_var_count(~0u),
m_block_level(0),
- m_frozen_bind_set( false )
+ m_frozen_bind_set( false ),
+ m_ibl_target_generics(nullptr)
{}
void push(const ::AST::HigherRankedBounds& params) {
- auto e = Ent::make_Generic({});
+ auto e = Ent::make_Generic({ GenericSlot::Level::Hrb, nullptr /*, &params*/ });
auto& data = e.as_Generic();
for(size_t i = 0; i < params.m_lifetimes.size(); i ++)
@@ -97,8 +104,8 @@ namespace
m_name_context.push_back(mv$(e));
}
- void push(const ::AST::GenericParams& params, GenericSlot::Level level, bool has_self=false) {
- auto e = Ent::make_Generic({});
+ void push(/*const */::AST::GenericParams& params, GenericSlot::Level level, bool has_self=false) {
+ auto e = Ent::make_Generic({ level, &params });
auto& data = e.as_Generic();
if( has_self ) {
@@ -279,6 +286,7 @@ namespace
Type,
Constant,
PatternValue,
+ //PatternAny,
Variable,
};
static const char* lookup_mode_msg(LookupMode mode) {
@@ -292,7 +300,7 @@ namespace
}
return "";
}
- AST::Path lookup(const Span& sp, const ::std::string& name, const Ident::Hygiene& src_context, LookupMode mode) const {
+ AST::Path lookup(const Span& sp, const RcString& name, const Ident::Hygiene& src_context, LookupMode mode) const {
auto rv = this->lookup_opt(name, src_context, mode);
if( !rv.is_valid() ) {
switch(mode)
@@ -306,13 +314,14 @@ namespace
}
return rv;
}
- static bool lookup_in_mod(const ::AST::Module& mod, const ::std::string& name, LookupMode mode, ::AST::Path& path) {
+ static bool lookup_in_mod(const ::AST::Module& mod, const RcString& name, LookupMode mode, ::AST::Path& path) {
switch(mode)
{
case LookupMode::Namespace:
{
auto v = mod.m_namespace_items.find(name);
if( v != mod.m_namespace_items.end() ) {
+ DEBUG("- NS: Namespace " << v->second.path);
path = ::AST::Path( v->second.path );
return true;
}
@@ -320,6 +329,7 @@ namespace
{
auto v = mod.m_type_items.find(name);
if( v != mod.m_type_items.end() ) {
+ DEBUG("- NS: Type " << v->second.path);
path = ::AST::Path( v->second.path );
return true;
}
@@ -327,32 +337,59 @@ namespace
break;
case LookupMode::Type:
- //if( name == "IntoIterator" ) {
- // DEBUG("lookup_in_mod(mod="<<mod.path()<<")");
- // for(const auto& v : mod.m_type_items) {
- // DEBUG("- " << v.first << " = " << (v.second.is_pub ? "pub " : "") << v.second.path);
- // }
- //}
{
auto v = mod.m_type_items.find(name);
if( v != mod.m_type_items.end() ) {
+ DEBUG("- TY: Type " << v->second.path);
path = ::AST::Path( v->second.path );
return true;
}
}
+ // HACK: For `Enum::Var { .. }` patterns matching value variants
+ {
+ auto v = mod.m_value_items.find(name);
+ if( v != mod.m_value_items.end() ) {
+ const auto& b = v->second.path.m_bindings.value;
+ if( /*const auto* be =*/ b.opt_EnumVar() ) {
+ DEBUG("- TY: Enum variant " << v->second.path);
+ path = ::AST::Path( v->second.path );
+ return true;
+ }
+ }
+ }
break;
+ //case LookupMode::PatternAny:
+ // {
+ // auto v = mod.m_type_items.find(name);
+ // if( v != mod.m_type_items.end() ) {
+ // DEBUG("- TY: Type " << v->second.path);
+ // path = ::AST::Path( v->second.path );
+ // return true;
+ // }
+ // auto v2 = mod.m_value_items.find(name);
+ // if( v2 != mod.m_value_items.end() ) {
+ // const auto& b = v2->second.path.m_bindings.value;
+ // if( b.is_EnumVar() ) {
+ // DEBUG("- TY: Enum variant " << v2->second.path);
+ // path = ::AST::Path( v2->second.path );
+ // return true;
+ // }
+ // }
+ // }
+ // break;
case LookupMode::PatternValue:
{
auto v = mod.m_value_items.find(name);
if( v != mod.m_value_items.end() ) {
- const auto& b = v->second.path.binding();
+ const auto& b = v->second.path.m_bindings.value;
switch( b.tag() )
{
- case ::AST::PathBinding::TAG_EnumVar:
- case ::AST::PathBinding::TAG_Static:
+ case ::AST::PathBinding_Value::TAG_EnumVar:
+ case ::AST::PathBinding_Value::TAG_Static:
+ DEBUG("- PV: Value " << v->second.path);
path = ::AST::Path( v->second.path );
return true;
- case ::AST::PathBinding::TAG_Struct:
+ case ::AST::PathBinding_Value::TAG_Struct:
// TODO: Restrict this to unit-like structs
if( b.as_Struct().struct_ && !b.as_Struct().struct_->m_data.is_Unit() )
;
@@ -360,6 +397,7 @@ namespace
;
else
{
+ DEBUG("- PV: Value " << v->second.path);
path = ::AST::Path( v->second.path );
return true;
}
@@ -375,6 +413,7 @@ namespace
{
auto v = mod.m_value_items.find(name);
if( v != mod.m_value_items.end() ) {
+ DEBUG("- C/V: Value " << v->second.path);
path = ::AST::Path( v->second.path );
return true;
}
@@ -383,8 +422,31 @@ namespace
}
return false;
}
- AST::Path lookup_opt(const ::std::string& name, const Ident::Hygiene& src_context, LookupMode mode) const {
+ AST::Path lookup_opt(const RcString& name, const Ident::Hygiene& src_context, LookupMode mode) const {
DEBUG("name=" << name <<", src_context=" << src_context);
+ // NOTE: src_context may provide a module to search
+ if( src_context.has_mod_path() )
+ {
+ DEBUG(src_context.mod_path().ents);
+ const AST::Module* mod = &m_crate.root_module();
+ for(const auto& node : src_context.mod_path().ents)
+ {
+ const AST::Module* next = nullptr;
+ for(const auto& i : mod->items())
+ {
+ if( i.name == node ) {
+ next = &i.data.as_Module();
+ break;
+ }
+ }
+ assert(next);
+ mod = next;
+ }
+ ::AST::Path rv;
+ if( this->lookup_in_mod(*mod, name, mode, rv) ) {
+ return rv;
+ }
+ }
for(auto it = m_name_context.rbegin(); it != m_name_context.rend(); ++ it)
{
TU_MATCH(Ent, (*it), (e),
@@ -451,7 +513,7 @@ namespace
case LookupMode::Namespace:
case LookupMode::Type: {
// Look up primitive types
- auto ct = coretype_fromstring(name);
+ auto ct = coretype_fromstring(name.c_str());
if( ct != CORETYPE_INVAL )
{
return ::AST::Path( ::AST::Path::TagUfcs(), TypeRef(Span("-",0,0,0,0), ct), ::AST::Path(), ::std::vector< ::AST::PathNode>() );
@@ -461,10 +523,22 @@ namespace
break;
}
+ // #![feature(extern_prelude)] - 2018-style extern paths
+ if( mode == LookupMode::Namespace && TARGETVER_1_29 && true /*m_crate.has_feature("extern_prelude")*/ )
+ {
+ DEBUG("Extern crates - " << FMT_CB(os, for(const auto& v: m_crate.m_extern_crates) os << v.first << ":" << v.second.m_short_name <<",";));
+ auto it = ::std::find_if(m_crate.m_extern_crates.begin(), m_crate.m_extern_crates.end(), [&](const auto& x){ return x.second.m_short_name == name; });
+ if( it != m_crate.m_extern_crates.end() )
+ {
+ DEBUG("- Found '" << name << "'");
+ return AST::Path(it->first, {});
+ }
+ }
+
return AST::Path();
}
- unsigned int lookup_local(const Span& sp, const ::std::string name, LookupMode mode) {
+ unsigned int lookup_local(const Span& sp, const RcString name, LookupMode mode) {
for(auto it = m_name_context.rbegin(); it != m_name_context.rend(); ++ it)
{
TU_MATCH(Ent, (*it), (e),
@@ -544,6 +618,10 @@ void Resolve_Absolute_Function(Context& item_context, ::AST::Function& fcn);
void Resolve_Absolute_PathParams(/*const*/ Context& context, const Span& sp, ::AST::PathParams& args)
{
+ for(auto& arg : args.m_lifetimes)
+ {
+ Resolve_Absolute_Lifetime(context, sp, arg);
+ }
for(auto& arg : args.m_types)
{
Resolve_Absolute_Type(context, arg);
@@ -592,7 +670,7 @@ void Resolve_Absolute_Path_BindUFCS(Context& context, const Span& sp, Context::L
{
// Trait is specified, definitely a trait item
// - Must resolve here
- const auto& pb = ufcs.trait->binding();
+ const auto& pb = ufcs.trait->m_bindings.type;
if( ! pb.is_Trait() ) {
ERROR(sp, E0000, "UFCS trait was not a trait - " << *ufcs.trait);
}
@@ -654,7 +732,7 @@ void Resolve_Absolute_Path_BindUFCS(Context& context, const Span& sp, Context::L
}
namespace {
- AST::Path split_into_crate(const Span& sp, AST::Path path, unsigned int start, const ::std::string& crate_name)
+ AST::Path split_into_crate(const Span& sp, AST::Path path, unsigned int start, const RcString& crate_name)
{
auto& nodes = path.nodes();
AST::Path np = AST::Path(crate_name, {});
@@ -662,10 +740,10 @@ namespace {
{
np.nodes().push_back( mv$(nodes[i]) );
}
- np.bind( path.binding().clone() );
+ np.m_bindings = path.m_bindings.clone();
return np;
}
- AST::Path split_into_ufcs_ty(const Span& sp, AST::Path path, unsigned int i /*item_name_idx*/)
+ AST::Path split_into_ufcs_ty(const Span& sp, const AST::Path& path, unsigned int i /*item_name_idx*/)
{
const auto& path_abs = path.m_class.as_Absolute();
auto type_path = ::AST::Path( path );
@@ -675,6 +753,8 @@ namespace {
for( unsigned int j = i+1; j < path_abs.nodes.size(); j ++ )
new_path.nodes().push_back( mv$(path_abs.nodes[j]) );
+ DEBUG(path << " -> " << new_path);
+
return new_path;
}
AST::Path split_replace_into_ufcs_path(const Span& sp, AST::Path path, unsigned int i, const AST::Path& ty_path_tpl)
@@ -716,7 +796,6 @@ namespace {
const auto& varname = p.m_components.back();
auto var_idx = e.find_variant(varname);
ASSERT_BUG(sp, var_idx != SIZE_MAX, "Extern crate import path points to non-present variant - " << p);
- auto pb = ::AST::PathBinding::make_EnumVar({nullptr, static_cast<unsigned>(var_idx), &e});
// Construct output path (with same set of parameters)
AST::Path rv( p.m_crate_name, {} );
@@ -724,7 +803,12 @@ namespace {
for(const auto& c : p.m_components)
rv.nodes().push_back( AST::PathNode(c) );
rv.nodes().back().args() = mv$( path.nodes().back().args() );
- rv.bind( mv$(pb) );
+ if( e.m_data.is_Data() && e.m_data.as_Data()[var_idx].is_struct ) {
+ rv.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({nullptr, static_cast<unsigned>(var_idx), &e});
+ }
+ else {
+ rv.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, static_cast<unsigned>(var_idx), &e});
+ }
path = mv$(rv);
return ;
@@ -735,7 +819,7 @@ namespace {
)
}
- ::AST::PathBinding pb;
+ ::AST::Path::Bindings pb;
const auto& name = p.m_components.back();
if( is_value )
@@ -749,19 +833,19 @@ namespace {
BUG(sp, "HIR Import item pointed to an import");
),
(Constant,
- pb = ::AST::PathBinding::make_Static({nullptr, nullptr});
+ pb.value = ::AST::PathBinding_Value::make_Static({nullptr, nullptr});
),
(Static,
- pb = ::AST::PathBinding::make_Static({nullptr, &e});
+ pb.value = ::AST::PathBinding_Value::make_Static({nullptr, &e});
),
(StructConstant,
- pb = ::AST::PathBinding::make_Struct({nullptr, &ext_crate.m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct()});
+ pb.value = ::AST::PathBinding_Value::make_Struct({nullptr, &ext_crate.m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct()});
),
(Function,
- pb = ::AST::PathBinding::make_Function({nullptr/*, &e*/});
+ pb.value = ::AST::PathBinding_Value::make_Function({nullptr/*, &e*/});
),
(StructConstructor,
- pb = ::AST::PathBinding::make_Struct({nullptr, &ext_crate.m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct()});
+ pb.value = ::AST::PathBinding_Value::make_Struct({nullptr, &ext_crate.m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct()});
)
)
}
@@ -776,22 +860,25 @@ namespace {
BUG(sp, "HIR Import item pointed to an import");
),
(Module,
- pb = ::AST::PathBinding::make_Module({nullptr, &e});
+ pb.type = ::AST::PathBinding_Type::make_Module({nullptr, &e});
),
(Trait,
- pb = ::AST::PathBinding::make_Trait({nullptr, &e});
+ pb.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e});
),
(TypeAlias,
- pb = ::AST::PathBinding::make_TypeAlias({nullptr/*, &e*/});
+ pb.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/});
+ ),
+ (ExternType,
+ pb.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/});
),
(Struct,
- pb = ::AST::PathBinding::make_Struct({nullptr, &e});
+ pb.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e});
),
(Union,
- pb = ::AST::PathBinding::make_Union({nullptr, &e});
+ pb.type = ::AST::PathBinding_Type::make_Union({nullptr, &e});
),
(Enum,
- pb = ::AST::PathBinding::make_Enum({nullptr, &e});
+ pb.type = ::AST::PathBinding_Type::make_Enum({nullptr, &e});
)
)
}
@@ -802,7 +889,7 @@ namespace {
for(const auto& c : p.m_components)
rv.nodes().push_back( AST::PathNode(c) );
rv.nodes().back().args() = mv$( path.nodes().back().args() );
- rv.bind( mv$(pb) );
+ rv.m_bindings = mv$(pb);
path = mv$(rv);
}
@@ -816,7 +903,7 @@ namespace {
switch(mode)
{
case Context::LookupMode::Namespace:
- path.bind( ::AST::PathBinding::make_Module({nullptr, &crate.m_hir->m_root_module}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_Module({nullptr, &crate.m_hir->m_root_module});
return ;
default:
TODO(sp, "Looking up a non-namespace, but pointed to crate root");
@@ -832,23 +919,30 @@ namespace {
if( it == hmod->m_mod_items.end() )
ERROR(sp, E0000, "Couldn't find path component '" << n.name() << "' of " << path);
- TU_MATCH(::HIR::TypeItem, (it->second->ent), (e),
- (Import,
+ TU_MATCH_HDRA( (it->second->ent), {)
+ TU_ARMA(Import, e) {
// - Update path then restart
auto newpath = AST::Path(e.path.m_crate_name, {});
for(const auto& n : e.path.m_components)
newpath.nodes().push_back( AST::PathNode(n) );
+ if( newpath.nodes().empty() ) {
+ ASSERT_BUG(sp, n.args().is_empty(), "Params present, but name resolves to a crate root - " << path << " #" << i << " -> " << newpath);
+ }
+ else {
+ newpath.nodes().back().args() = mv$(path.nodes()[i].args());
+ }
for(unsigned int j = i + 1; j < path.nodes().size(); j ++)
newpath.nodes().push_back( mv$(path.nodes()[j]) );
+ DEBUG("> Recurse with " << newpath);
path = mv$(newpath);
// TODO: Recursion limit
Resolve_Absolute_Path_BindAbsolute(context, sp, mode, path);
return ;
- ),
- (Module,
+ }
+ TU_ARMA(Module, e) {
hmod = &e;
- ),
- (Trait,
+ }
+ TU_ARMA(Trait, e) {
auto trait_path = ::AST::Path( crate.m_name, {} );
for(unsigned int j = start; j <= i; j ++)
trait_path.nodes().push_back( path_abs.nodes[j].name() );
@@ -862,7 +956,7 @@ namespace {
trait_path.nodes().back().args().m_types.push_back( ::TypeRef(sp) );
}
}
- trait_path.bind( ::AST::PathBinding::make_Trait({nullptr, &e}) );
+ trait_path.m_bindings.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e});
::AST::Path new_path;
const auto& next_node = path_abs.nodes[i+1];
@@ -892,23 +986,15 @@ namespace {
path = mv$(new_path);
return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path);
- ),
- (TypeAlias,
- path = split_into_crate(sp, mv$(path), start, crate.m_name);
- path = split_into_ufcs_ty(sp, mv$(path), i-start);
- return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path);
- ),
- (Struct,
- path = split_into_crate(sp, mv$(path), start, crate.m_name);
- path = split_into_ufcs_ty(sp, mv$(path), i-start);
- return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path);
- ),
- (Union,
+ }
+ case ::HIR::TypeItem::TAG_ExternType:
+ case ::HIR::TypeItem::TAG_TypeAlias:
+ case ::HIR::TypeItem::TAG_Struct:
+ case ::HIR::TypeItem::TAG_Union:
path = split_into_crate(sp, mv$(path), start, crate.m_name);
path = split_into_ufcs_ty(sp, mv$(path), i-start);
return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path);
- ),
- (Enum,
+ TU_ARMA(Enum, e) {
const auto& last_node = path_abs.nodes.back();
// If this refers to an enum variant, return the full path
auto idx = e.find_variant(last_node.name());
@@ -922,15 +1008,20 @@ namespace {
ERROR(sp, E0000, "Type parameters were not expected here (enum params go on the variant)");
}
- path.bind( ::AST::PathBinding::make_EnumVar({nullptr, static_cast<unsigned int>(idx), &e}) );
+ if( e.m_data.is_Data() && e.m_data.as_Data()[idx].is_struct ) {
+ path.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({nullptr, static_cast<unsigned int>(idx), &e});
+ }
+ else {
+ path.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, static_cast<unsigned int>(idx), &e});
+ }
path = split_into_crate(sp, mv$(path), start, crate.m_name);
return;
}
path = split_into_crate(sp, mv$(path), start, crate.m_name);
path = split_into_ufcs_ty(sp, mv$(path), i-start);
return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path);
- )
- )
+ }
+ }
}
const auto& name = path_abs.nodes.back().name();
@@ -949,22 +1040,25 @@ namespace {
return ;
),
(Trait,
- path.bind( ::AST::PathBinding::make_Trait({nullptr, &e}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e});
),
(Module,
- path.bind( ::AST::PathBinding::make_Module({nullptr, &e}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_Module({nullptr, &e});
+ ),
+ (ExternType,
+ path.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/});
),
(TypeAlias,
- path.bind( ::AST::PathBinding::make_TypeAlias({nullptr/*, &e*/}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/});
),
(Enum,
- path.bind( ::AST::PathBinding::make_Enum({nullptr, &e}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_Enum({nullptr, &e});
),
(Struct,
- path.bind( ::AST::PathBinding::make_Struct({nullptr, &e}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e});
),
(Union,
- path.bind( ::AST::PathBinding::make_Union({nullptr, &e}) );
+ path.m_bindings.type = ::AST::PathBinding_Type::make_Union({nullptr, &e});
)
)
// Update path (trim down to `start` and set crate name)
@@ -984,7 +1078,7 @@ namespace {
),
(StructConstant,
auto ty_path = e.ty;
- path.bind( ::AST::PathBinding::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)});
path = split_into_crate(sp, mv$(path), start, crate.m_name);
return ;
),
@@ -994,7 +1088,7 @@ namespace {
),
(Constant,
// Bind and update path
- path.bind( ::AST::PathBinding::make_Static({nullptr, nullptr}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr, nullptr});
path = split_into_crate(sp, mv$(path), start, crate.m_name);
return ;
)
@@ -1016,22 +1110,22 @@ namespace {
return ;
),
(Function,
- path.bind( ::AST::PathBinding::make_Function({nullptr/*, &e*/}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Function({nullptr/*, &e*/});
),
(StructConstructor,
auto ty_path = e.ty;
- path.bind( ::AST::PathBinding::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)});
),
(StructConstant,
auto ty_path = e.ty;
- path.bind( ::AST::PathBinding::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)});
),
(Static,
- path.bind( ::AST::PathBinding::make_Static({nullptr, &e}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr, &e});
),
(Constant,
// Bind
- path.bind( ::AST::PathBinding::make_Static({nullptr, nullptr}) );
+ path.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr, nullptr});
)
)
path = split_into_crate(sp, mv$(path), start, crate.m_name);
@@ -1061,7 +1155,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex
{
auto& n = path_abs.nodes[i];
- if( n.name()[0] == '#' ) {
+ if( n.name().c_str()[0] == '#' ) {
if( ! n.args().is_empty() ) {
ERROR(sp, E0000, "Type parameters were not expected here");
}
@@ -1072,7 +1166,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex
char c;
unsigned int idx;
- ::std::stringstream ss( n.name() );
+ ::std::stringstream ss( n.name().c_str() );
ss >> c;
ss >> idx;
assert( idx < mod->anon_mods().size() );
@@ -1088,7 +1182,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex
const auto& name_ref = it->second;
DEBUG("#" << i << " \"" << n.name() << "\" = " << name_ref.path << (name_ref.is_import ? " (import)" : "") );
- TU_MATCH_DEF(::AST::PathBinding, (name_ref.path.binding()), (e),
+ TU_MATCH_DEF(::AST::PathBinding_Type, (name_ref.path.m_bindings.type), (e),
(
ERROR(sp, E0000, "Encountered non-namespace item '" << n.name() << "' ("<<name_ref.path<<") in path " << path);
),
@@ -1235,7 +1329,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex
if( ! Context::lookup_in_mod(*mod, path_abs.nodes.back().name(), mode, tmp) ) {
ERROR(sp, E0000, "Couldn't find " << Context::lookup_mode_msg(mode) << " '" << path_abs.nodes.back().name() << "' of " << path);
}
- assert( ! tmp.binding().is_Unbound() );
+ ASSERT_BUG(sp, tmp.m_bindings.has_binding(), "Lookup for " << path << " succeeded, but had no binding");
// Replaces the path with the one returned by `lookup_in_mod`, ensuring that `use` aliases are eliminated
DEBUG("Replace " << path << " with " << tmp);
@@ -1282,8 +1376,9 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::
// HACK: If this is a primitive name, and resolved to a module.
// - If the next component isn't found in the located module
// > Instead use the type name.
- if( ! p.m_class.is_Local() && coretype_fromstring(e.nodes[0].name()) != CORETYPE_INVAL ) {
- TU_IFLET( ::AST::PathBinding, p.binding(), Module, pe,
+ if( ! p.m_class.is_Local() && coretype_fromstring(e.nodes[0].name().c_str()) != CORETYPE_INVAL ) {
+ if( const auto* pep = p.m_bindings.type.opt_Module() ) {
+ const auto& pe = *pep;
bool found = false;
const auto& name = e.nodes[1].name();
if( !pe.module_ ) {
@@ -1335,12 +1430,12 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::
}
if( !found )
{
- auto ct = coretype_fromstring(e.nodes[0].name());
+ auto ct = coretype_fromstring(e.nodes[0].name().c_str());
p = ::AST::Path( ::AST::Path::TagUfcs(), TypeRef(Span("-",0,0,0,0), ct), ::AST::Path(), ::std::vector< ::AST::PathNode>() );
}
DEBUG("Primitive module hack yeilded " << p);
- )
+ }
}
if( e.nodes.size() > 1 )
@@ -1381,7 +1476,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::
const auto& mp_nodes = context.m_mod.path().nodes();
// Ignore any leading anon modules
unsigned int start_len = mp_nodes.size();
- while( start_len > 0 && mp_nodes[start_len-1].name()[0] == '#' )
+ while( start_len > 0 && mp_nodes[start_len-1].name().c_str()[0] == '#' )
start_len --;
// - Create a new path
@@ -1405,7 +1500,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::
assert( e.count >= 1 );
// TODO: The first super should ignore any anon modules.
unsigned int start_len = e.count > mp_nodes.size() ? 0 : mp_nodes.size() - e.count;
- while( start_len > 0 && mp_nodes[start_len-1].name()[0] == '#' )
+ while( start_len > 0 && mp_nodes[start_len-1].name().c_str()[0] == '#' )
start_len --;
// - Create a new path
@@ -1447,7 +1542,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::
BUG(sp, "Path wasn't absolutised correctly");
),
(Local,
- if( path.binding().is_Unbound() )
+ if( !path.m_bindings.has_binding() )
{
TODO(sp, "Bind unbound local path - " << path);
}
@@ -1475,6 +1570,17 @@ void Resolve_Absolute_Lifetime(Context& context, const Span& sp, AST::LifetimeRe
return ;
}
+ if( lft.name() == "_" )
+ {
+ if( TARGETVER_1_19 )
+ {
+ ERROR(sp, E0000, "'_ is not a valid lifetime name in 1.19 mode");
+ }
+ // Note: '_ is just an explicit elided lifetime
+ lft.set_binding(AST::LifetimeRef::BINDING_INFER);
+ return ;
+ }
+
for(auto it = context.m_name_context.rbegin(); it != context.m_name_context.rend(); ++ it)
{
if( const auto* e = it->opt_Generic() )
@@ -1491,6 +1597,39 @@ void Resolve_Absolute_Lifetime(Context& context, const Span& sp, AST::LifetimeRe
}
}
+ if( TARGETVER_1_29 )
+ {
+ // If parsing a function header, add a new lifetime param to the function
+ // - Does the same apply to impl headers? Yes it does.
+ if( context.m_ibl_target_generics )
+ {
+ DEBUG("Considering in-band-lifetimes");
+ ASSERT_BUG(sp, !context.m_name_context.empty(), "Name context stack is empty");
+ auto it = context.m_name_context.rbegin();
+ ASSERT_BUG(sp, it->is_Generic(), "Name context stack end not Generic, instead " << it->tag_str());
+ while( it->as_Generic().level == GenericSlot::Level::Hrb ) {
+ it ++;
+ ASSERT_BUG(sp, it != context.m_name_context.rend(), "");
+ ASSERT_BUG(sp, it->is_Generic(), "Name context stack end not Generic, instead " << it->tag_str());
+ }
+ if( it->as_Generic().level != GenericSlot::Level::Hrb )
+ {
+ auto& context_gen = it->as_Generic();
+ auto& def_gen = *context.m_ibl_target_generics;
+ auto level = context_gen.level;
+ // 1. Assert that the last item of `context.m_name_context` is Generic, and matches `m_ibl_target_generics`
+ ASSERT_BUG(sp, context_gen.lifetimes.size() == def_gen.lft_params().size(), "");
+ ASSERT_BUG(sp, context_gen.types.size() == def_gen.ty_params().size(), "");
+ //ASSERT_BUG(sp, context_gen.constants.size() == def_gen.val_params().size(), "");
+ // 2. Add the new lifetime to both `m_ibl_target_generics` and the last entry in m_name_context
+ size_t idx = def_gen.lft_params().size();
+ def_gen.add_lft_param(AST::LifetimeParam(sp, {}, lft.name()));
+ context_gen.lifetimes.push_back( NamedI<GenericSlot> { lft.name(), GenericSlot { level, static_cast<unsigned short>(idx) } } );
+ lft.set_binding( idx | (static_cast<int>(level) << 8) );
+ return ;
+ }
+ }
+ }
ERROR(sp, E0000, "Couldn't find lifetime " << lft);
}
}
@@ -1565,7 +1704,7 @@ void Resolve_Absolute_Type(Context& context, TypeRef& type)
assert( ufcs.nodes.size() == 1);
)
- TU_IFLET(::AST::PathBinding, e.path.binding(), Trait, be,
+ TU_IFLET(::AST::PathBinding_Type, e.path.m_bindings.type, Trait, be,
auto ty = ::TypeRef( type.span(), ::make_vec1(Type_TraitPath { {}, mv$(e.path)}), {} );
type = mv$(ty);
return ;
@@ -1865,6 +2004,10 @@ void Resolve_Absolute_Pattern(Context& context, bool allow_refutable, ::AST::Pa
Resolve_Absolute_Pattern(context, allow_refutable, sp);
),
(Struct,
+ // TODO: `Struct { .. }` patterns can match anything
+ //if( e.sub_patterns.empty() && !e.is_exhaustive ) {
+ // auto rv = this->lookup_opt(name, src_context, mode);
+ //}
Resolve_Absolute_Path(context, pat.span(), Context::LookupMode::Type, e.path);
for(auto& sp : e.sub_patterns)
Resolve_Absolute_Pattern(context, allow_refutable, sp.second);
@@ -1895,17 +2038,20 @@ void Resolve_Absolute_ImplItems(Context& item_context, ::AST::NamedList< ::AST:
{
TU_MATCH(AST::Item, (i.data), (e),
(None, ),
- (MacroInv, BUG(i.data.span, "Resolve_Absolute_ImplItems - MacroInv");),
- (ExternBlock, BUG(i.data.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
- (Impl, BUG(i.data.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
- (NegImpl, BUG(i.data.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
- (Use, BUG(i.data.span, "Resolve_Absolute_ImplItems - Use");),
- (Module, BUG(i.data.span, "Resolve_Absolute_ImplItems - Module");),
- (Crate , BUG(i.data.span, "Resolve_Absolute_ImplItems - Crate");),
- (Enum , BUG(i.data.span, "Resolve_Absolute_ImplItems - Enum");),
- (Trait , BUG(i.data.span, "Resolve_Absolute_ImplItems - Trait");),
- (Struct, BUG(i.data.span, "Resolve_Absolute_ImplItems - Struct");),
- (Union , BUG(i.data.span, "Resolve_Absolute_ImplItems - Union");),
+ (MacroInv,
+ //BUG(i.span, "Resolve_Absolute_ImplItems - MacroInv");
+ ),
+ (ExternBlock, BUG(i.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
+ (Impl, BUG(i.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
+ (NegImpl, BUG(i.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
+ (Macro, BUG(i.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());),
+ (Use, BUG(i.span, "Resolve_Absolute_ImplItems - Use");),
+ (Module, BUG(i.span, "Resolve_Absolute_ImplItems - Module");),
+ (Crate , BUG(i.span, "Resolve_Absolute_ImplItems - Crate");),
+ (Enum , BUG(i.span, "Resolve_Absolute_ImplItems - Enum");),
+ (Trait , BUG(i.span, "Resolve_Absolute_ImplItems - Trait");),
+ (Struct, BUG(i.span, "Resolve_Absolute_ImplItems - Struct");),
+ (Union , BUG(i.span, "Resolve_Absolute_ImplItems - Union");),
(Type,
DEBUG("Type - " << i.name);
assert( e.params().ty_params().size() == 0 );
@@ -1919,26 +2065,7 @@ void Resolve_Absolute_ImplItems(Context& item_context, ::AST::NamedList< ::AST:
),
(Function,
DEBUG("Function - " << i.name);
- item_context.push( e.params(), GenericSlot::Level::Method );
- Resolve_Absolute_Generic(item_context, e.params());
-
- Resolve_Absolute_Type( item_context, e.rettype() );
- for(auto& arg : e.args())
- Resolve_Absolute_Type( item_context, arg.second );
-
- {
- auto _h = item_context.enter_rootblock();
- item_context.push_block();
- for(auto& arg : e.args()) {
- Resolve_Absolute_Pattern( item_context, false, arg.first );
- }
-
- Resolve_Absolute_Expr( item_context, e.code() );
-
- item_context.pop_block();
- }
-
- item_context.pop( e.params() );
+ Resolve_Absolute_Function(item_context, e);
),
(Static,
DEBUG("Static - " << i.name);
@@ -1959,16 +2086,17 @@ void Resolve_Absolute_ImplItems(Context& item_context, ::std::vector< ::AST::Im
(None, ),
(MacroInv, ),
- (Impl , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (NegImpl, BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (ExternBlock, BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Use , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Module, BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Crate , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Enum , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Trait , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Struct, BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
- (Union , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Impl , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (NegImpl, BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (ExternBlock, BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Macro , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Use , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Module, BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Crate , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Enum , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Trait , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Struct, BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
+ (Union , BUG(i.sp, "Resolve_Absolute_ImplItems - " << i.data->tag_str());),
(Type,
DEBUG("Type - " << i.name);
assert( e.params().ty_params().size() == 0 );
@@ -1997,12 +2125,17 @@ void Resolve_Absolute_Function(Context& item_context, ::AST::Function& fcn)
{
TRACE_FUNCTION_F("");
item_context.push( fcn.params(), GenericSlot::Level::Method );
+ item_context.m_ibl_target_generics = &fcn.params();
+ DEBUG("- Generics");
Resolve_Absolute_Generic(item_context, fcn.params());
+ DEBUG("- Prototype types");
Resolve_Absolute_Type( item_context, fcn.rettype() );
for(auto& arg : fcn.args())
Resolve_Absolute_Type( item_context, arg.second );
+ item_context.m_ibl_target_generics = nullptr;
+ DEBUG("- Body");
{
auto _h = item_context.enter_rootblock();
item_context.push_block();
@@ -2122,12 +2255,14 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod )
),
(Use,
),
+ (Macro,
+ ),
(ExternBlock,
for(auto& i2 : e.items())
{
TU_MATCH_DEF(AST::Item, (i2.data), (e2),
(
- BUG(i2.data.span, "Unexpected item in ExternBlock - " << i2.data.tag_str());
+ BUG(i.span, "Unexpected item in ExternBlock - " << i2.data.tag_str());
),
(None,
),
@@ -2142,33 +2277,40 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod )
),
(Impl,
auto& def = e.def();
- DEBUG("impl " << def.trait().ent << " for " << def.type());
if( !def.type().is_valid() )
{
- DEBUG("---- MARKER IMPL for " << def.trait().ent);
+ TRACE_FUNCTION_F("impl " << def.trait().ent << " for ..");
item_context.push(def.params(), GenericSlot::Level::Top);
- Resolve_Absolute_Generic(item_context, def.params());
+
+ item_context.m_ibl_target_generics = &def.params();
assert( def.trait().ent.is_valid() );
Resolve_Absolute_Path(item_context, def.trait().sp, Context::LookupMode::Type, def.trait().ent);
+ item_context.m_ibl_target_generics = nullptr;
+
+ Resolve_Absolute_Generic(item_context, def.params());
if( e.items().size() != 0 ) {
- ERROR(i.data.span, E0000, "impl Trait for .. with methods");
+ ERROR(i.span, E0000, "impl Trait for .. with methods");
}
item_context.pop(def.params());
- const_cast< ::AST::Trait*>(def.trait().ent.binding().as_Trait().trait_)->set_is_marker();
+ const_cast< ::AST::Trait*>(def.trait().ent.m_bindings.type.as_Trait().trait_)->set_is_marker();
}
else
{
+ TRACE_FUNCTION_F("impl " << def.trait().ent << " for " << def.type());
item_context.push_self( def.type() );
item_context.push(def.params(), GenericSlot::Level::Top);
- Resolve_Absolute_Generic(item_context, def.params());
+ item_context.m_ibl_target_generics = &def.params();
Resolve_Absolute_Type(item_context, def.type());
if( def.trait().ent.is_valid() ) {
Resolve_Absolute_Path(item_context, def.trait().sp, Context::LookupMode::Type, def.trait().ent);
}
+ item_context.m_ibl_target_generics = nullptr;
+
+ Resolve_Absolute_Generic(item_context, def.params());
Resolve_Absolute_ImplItems(item_context, e.items());
@@ -2178,15 +2320,18 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod )
),
(NegImpl,
auto& impl_def = e;
- DEBUG("impl ! " << impl_def.trait().ent << " for " << impl_def.type());
+ TRACE_FUNCTION_F("impl ! " << impl_def.trait().ent << " for " << impl_def.type());
item_context.push_self( impl_def.type() );
item_context.push(impl_def.params(), GenericSlot::Level::Top);
- Resolve_Absolute_Generic(item_context, impl_def.params());
+ item_context.m_ibl_target_generics = &impl_def.params();
Resolve_Absolute_Type(item_context, impl_def.type());
if( !impl_def.trait().ent.is_valid() )
- BUG(i.data.span, "Encountered negative impl with no trait");
+ BUG(i.span, "Encountered negative impl with no trait");
Resolve_Absolute_Path(item_context, impl_def.trait().sp, Context::LookupMode::Type, impl_def.trait().ent);
+ item_context.m_ibl_target_generics = nullptr;
+
+ Resolve_Absolute_Generic(item_context, impl_def.params());
// No items
diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp
index 659bded4..1511583e 100644
--- a/src/resolve/index.cpp
+++ b/src/resolve/index.cpp
@@ -17,7 +17,7 @@ enum class IndexName
Value,
};
-void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst_mod, const AST::UseStmt& i_data, bool is_pub);
+void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst_mod, const AST::UseItem::Ent& i_data, bool is_pub);
::std::ostream& operator<<(::std::ostream& os, const IndexName& loc)
{
@@ -32,7 +32,7 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst
}
throw "";
}
-::std::unordered_map< ::std::string, ::AST::Module::IndexEnt >& get_mod_index(::AST::Module& mod, IndexName location) {
+::std::unordered_map< RcString, ::AST::Module::IndexEnt >& get_mod_index(::AST::Module& mod, IndexName location) {
switch(location)
{
case IndexName::Namespace:
@@ -57,8 +57,9 @@ namespace {
}
} // namespace
-void _add_item(const Span& sp, AST::Module& mod, IndexName location, const ::std::string& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true)
+void _add_item(const Span& sp, AST::Module& mod, IndexName location, const RcString& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true)
{
+ ASSERT_BUG(sp, ir.m_bindings.has_binding(), "");
auto& list = get_mod_index(mod, location);
bool was_import = (ir != mod.path() + name);
@@ -66,7 +67,7 @@ void _add_item(const Span& sp, AST::Module& mod, IndexName location, const ::std
{
if( error_on_collision )
{
- ERROR(sp, E0000, "Duplicate definition of name '" << name << "' in " << location << " scope (" << mod.path() << ")");
+ ERROR(sp, E0000, "Duplicate definition of name '" << name << "' in " << location << " scope (" << mod.path() << ") " << ir << ", and " << list[name].path);
}
else if( list.at(name).path == ir )
{
@@ -89,12 +90,12 @@ void _add_item(const Span& sp, AST::Module& mod, IndexName location, const ::std
assert(rec.second);
}
}
-void _add_item_type(const Span& sp, AST::Module& mod, const ::std::string& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true)
+void _add_item_type(const Span& sp, AST::Module& mod, const RcString& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true)
{
_add_item(sp, mod, IndexName::Namespace, name, is_pub, ::AST::Path(ir), error_on_collision);
_add_item(sp, mod, IndexName::Type, name, is_pub, mv$(ir), error_on_collision);
}
-void _add_item_value(const Span& sp, AST::Module& mod, const ::std::string& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true)
+void _add_item_value(const Span& sp, AST::Module& mod, const RcString& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true)
{
_add_item(sp, mod, IndexName::Value, name, is_pub, mv$(ir), error_on_collision);
}
@@ -120,52 +121,57 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod)
(NegImpl,
),
+ (Macro,
+ // TODO: Add to a macro list
+ ),
+
(Use,
// Skip for now
),
// - Types/modules only
(Module,
- p.bind( ::AST::PathBinding::make_Module({&e}) );
- _add_item(i.data.span, mod, IndexName::Namespace, i.name, i.is_pub, mv$(p));
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Module({&e});
+ _add_item(i.span, mod, IndexName::Namespace, i.name, i.is_pub, mv$(p));
),
(Crate,
- ASSERT_BUG(i.data.span, crate.m_extern_crates.count(e.name) > 0, "Referenced crate '" << e.name << "' isn't loaded for `extern crate`");
- p.bind( ::AST::PathBinding::make_Crate({ &crate.m_extern_crates.at(e.name) }) );
- _add_item(i.data.span, mod, IndexName::Namespace, i.name, i.is_pub, mv$(p));
+ ASSERT_BUG(i.span, crate.m_extern_crates.count(e.name) > 0, "Referenced crate '" << e.name << "' isn't loaded for `extern crate`");
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Crate({ &crate.m_extern_crates.at(e.name) });
+ _add_item(i.span, mod, IndexName::Namespace, i.name, i.is_pub, mv$(p));
),
(Enum,
- p.bind( ::AST::PathBinding::make_Enum({&e}) );
- _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Enum({&e});
+ _add_item_type(i.span, mod, i.name, i.is_pub, mv$(p));
),
(Union,
- p.bind( ::AST::PathBinding::make_Union({&e}) );
- _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Union({&e});
+ _add_item_type(i.span, mod, i.name, i.is_pub, mv$(p));
),
(Trait,
- p.bind( ::AST::PathBinding::make_Trait({&e}) );
- _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Trait({&e});
+ _add_item_type(i.span, mod, i.name, i.is_pub, mv$(p));
),
(Type,
- p.bind( ::AST::PathBinding::make_TypeAlias({&e}) );
- _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ p.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({&e});
+ _add_item_type(i.span, mod, i.name, i.is_pub, mv$(p));
),
// - Mixed
(Struct,
- p.bind( ::AST::PathBinding::make_Struct({&e}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Struct({&e});
// - If the struct is a tuple-like struct (or unit-like), it presents in the value namespace
if( ! e.m_data.is_Struct() ) {
- _add_item_value(i.data.span, mod, i.name, i.is_pub, p);
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Struct({&e});
+ _add_item_value(i.span, mod, i.name, i.is_pub, p);
}
- _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ _add_item_type(i.span, mod, i.name, i.is_pub, mv$(p));
),
// - Values only
(Function,
- p.bind( ::AST::PathBinding::make_Function({&e}) );
- _add_item_value(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Function({&e});
+ _add_item_value(i.span, mod, i.name, i.is_pub, mv$(p));
),
(Static,
- p.bind( ::AST::PathBinding::make_Static({&e}) );
- _add_item_value(i.data.span, mod, i.name, i.is_pub, mv$(p));
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Static({&e});
+ _add_item_value(i.span, mod, i.name, i.is_pub, mv$(p));
)
)
}
@@ -176,80 +182,79 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod)
{
if( ! i.data.is_Use() )
continue ;
- const auto& i_data = i.data.as_Use();
- if( i.name != "" )
+ for(const auto& i_data : i.data.as_Use().entries)
+ if( i_data.name != "" )
{
// TODO: Ensure that the path is canonical?
const auto& sp = i_data.sp;
- struct H {
- static void handle_pb(const Span& sp, AST::Module& mod, const AST::Named<AST::Item>& i, const AST::PathBinding& pb, bool allow_collide)
- {
- const auto& i_data = i.data.as_Use();
- TU_MATCH(::AST::PathBinding, (pb), (e),
- (Unbound,
- ),
- (Variable,
- BUG(sp, "Import was bound to variable");
- ),
- (TypeParameter,
- BUG(sp, "Import was bound to type parameter");
- ),
- (TraitMethod,
- BUG(sp, "Import was bound to trait method");
- ),
- (StructMethod,
- BUG(sp, "Import was bound to struct method");
- ),
-
- (Crate , _add_item(sp, mod, IndexName::Namespace, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (Module, _add_item(sp, mod, IndexName::Namespace, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (Enum, _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (Union, _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (Trait, _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (TypeAlias,_add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ),
-
- (Struct,
- _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide);
- // - If the struct is a tuple-like struct, it presents in the value namespace
- assert(e.struct_ || e.hir);
- if( !(e.struct_ ? e.struct_->m_data.is_Struct() : e.hir->m_data.is_Named()) )
- {
- _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide);
- }
- ),
- (Static , _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (Function, _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ),
- (EnumVar ,
- bool is_struct = false;
- if( e.enum_ ) {
- ASSERT_BUG(sp, e.idx < e.enum_->variants().size(), "Variant out of range for " << i_data.path);
- is_struct = e.enum_->variants().at(e.idx).m_data.is_Struct();
- }
- else {
- //ASSERT_BUG(sp, e.idx < e.hir->m_variants.size(), "Variant out of range for " << i_data.path);
- is_struct = TU_TEST1(e.hir->m_data, Data, .at(e.idx).is_struct);
- }
- if( is_struct )
- _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide);
- else
- _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide);
- )
- )
+ ASSERT_BUG(sp, i_data.path.m_bindings.has_binding(), "`use " << i_data.path << "` left unbound in module " << mod.path());
+
+ bool allow_collide = false;
+ // - Types
+ {TU_MATCH_HDRA( (i_data.path.m_bindings.type), {)
+ TU_ARMA(Unbound, _e) {
+ DEBUG(i_data.name << " - Not a type/module");
}
- };
- if( i_data.path.binding().is_Unbound() ) {
- BUG(sp, "`use " << i_data.path << "` left unbound in module " << mod.path());
- }
- else {
- H::handle_pb(sp, mod, i, i_data.path.binding(), false);
- }
- if( i_data.alt_binding.is_Unbound() ) {
- // Doesn't matter
- }
- else {
- H::handle_pb(sp, mod, i, i_data.alt_binding, true);
- }
+ TU_ARMA(TypeParameter, e)
+ BUG(sp, "Import was bound to type parameter");
+ TU_ARMA(Crate , e)
+ _add_item(sp, mod, IndexName::Namespace, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Module, e)
+ _add_item(sp, mod, IndexName::Namespace, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Enum, e)
+ _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Union, e)
+ _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Trait, e)
+ _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(TypeAlias, e)
+ _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Struct, e)
+ _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(EnumVar, e)
+ _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ }}
+ // - Values
+ {TU_MATCH_HDRA( (i_data.path.m_bindings.value), {)
+ TU_ARMA(Unbound, _e) {
+ DEBUG(i_data.name << " - Not a value");
+ }
+ TU_ARMA(Variable, e)
+ BUG(sp, "Import was bound to a variable");
+ TU_ARMA(Struct, e)
+ _add_item_value(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(EnumVar, e)
+ _add_item_value(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Static , e)
+ _add_item_value(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ TU_ARMA(Function, e)
+ _add_item_value(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide);
+ }}
+ // - Macros
+ {TU_MATCH_HDRA( (i_data.path.m_bindings.macro), {)
+ TU_ARMA(Unbound, _e) {
+ DEBUG(i_data.name << " - Not a macro");
+ }
+ TU_ARMA(MacroRules, e) {
+ ::std::vector<RcString> path;
+ path.push_back( i_data.path.m_class.as_Absolute().crate );
+ for(const auto& node : i_data.path.m_class.as_Absolute().nodes )
+ path.push_back( node.name() );
+ mod.m_macro_imports.push_back({
+ i.is_pub, i_data.name, mv$(path), e.mac
+ });
+ }
+ TU_ARMA(ProcMacro, e) {
+ TODO(sp, "ProcMacro import");
+ }
+ TU_ARMA(ProcMacroAttribute, e) {
+ TODO(sp, "ProcMacroAttribute import");
+ }
+ TU_ARMA(ProcMacroDerive, e) {
+ TODO(sp, "ProcMacroDerive import");
+ }
+ }}
}
else
{
@@ -285,35 +290,59 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C
{
for(const auto& it : hmod.m_mod_items) {
const auto& ve = *it.second;
- if( ve.is_public ) {
+ if( ve.publicity.is_global() ) {
+ const auto* vep = &ve.ent;
AST::Path p;
- if( ve.ent.is_Import() ) {
- p = hir_to_ast( ve.ent.as_Import().path );
+ if( vep->is_Import() ) {
+ const auto& spath = vep->as_Import().path;
+ p = hir_to_ast( spath );
+
+ ASSERT_BUG(sp, crate.m_extern_crates.count(spath.m_crate_name) == 1, "Crate " << spath.m_crate_name << " is not loaded");
+ const auto* hmod = &crate.m_extern_crates.at(spath.m_crate_name).m_hir->m_root_module;
+ for(unsigned int i = 0; i < spath.m_components.size()-1; i ++) {
+ const auto& hit = hmod->m_mod_items.at( spath.m_components[i] );
+ // Only support enums on the penultimate component
+ if( i == spath.m_components.size()-2 && hit->ent.is_Enum() ) {
+ p.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({nullptr, 0});
+ _add_item_type( sp, dst_mod, it.first, is_pub, mv$(p), false );
+ hmod = nullptr;
+ break ;
+ }
+ ASSERT_BUG(sp, hit->ent.is_Module(), "Path component " << spath.m_components[i] << " of " << spath << " is not a module, instead " << hit->ent.tag_str());
+ hmod = &hit->ent.as_Module();
+ }
+ if( !hmod )
+ continue ;
+ vep = &hmod->m_mod_items.at( spath.m_components.back() )->ent;
}
else {
p = path + it.first;
}
- TU_MATCHA( (ve.ent), (e),
+ TU_MATCHA( (*vep), (e),
(Import,
//throw "";
+ TODO(sp, "Get binding for HIR import? " << e.path);
),
(Module,
- p.bind( ::AST::PathBinding::make_Module({nullptr, &e}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Module({nullptr, &e});
),
(Trait,
- p.bind( ::AST::PathBinding::make_Trait({nullptr, &e}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e});
),
(Struct,
- p.bind( ::AST::PathBinding::make_Struct({nullptr, &e}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e});
),
(Union,
- p.bind( ::AST::PathBinding::make_Union({nullptr, &e}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Union({nullptr, &e});
),
(Enum,
- p.bind( ::AST::PathBinding::make_Enum({nullptr}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_Enum({nullptr});
),
(TypeAlias,
- p.bind( ::AST::PathBinding::make_TypeAlias({nullptr}) );
+ p.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr});
+ ),
+ (ExternType,
+ p.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr});
)
)
_add_item_type( sp, dst_mod, it.first, is_pub, mv$(p), false );
@@ -321,7 +350,7 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C
}
for(const auto& it : hmod.m_value_items) {
const auto& ve = *it.second;
- if( ve.is_public ) {
+ if( ve.publicity.is_global() ) {
AST::Path p;
const auto* vep = &ve.ent;
if( ve.ent.is_Import() ) {
@@ -333,8 +362,8 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C
for(unsigned int i = 0; i < spath.m_components.size()-1; i ++) {
const auto& it = hmod->m_mod_items.at( spath.m_components[i] );
if(it->ent.is_Enum()) {
- ASSERT_BUG(sp, i + 1 == spath.m_components.size() - 1, "");
- p.bind( ::AST::PathBinding::make_EnumVar({nullptr, 0}) );
+ ASSERT_BUG(sp, i + 1 == spath.m_components.size() - 1, "Found enum not at penultimate component of HIR import path");
+ p.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, 0}); // TODO: What's the index?
vep = nullptr;
hmod = nullptr;
break ;
@@ -355,20 +384,20 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C
throw "";
),
(Constant,
- p.bind( ::AST::PathBinding::make_Static({nullptr}) );
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr});
),
(Static,
- p.bind( ::AST::PathBinding::make_Static({nullptr}) );
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr});
),
// TODO: What if these refer to an enum variant?
(StructConstant,
- p.bind( ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct() }) );
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct() });
),
(StructConstructor,
- p.bind( ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct() }) );
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct() });
),
(Function,
- p.bind( ::AST::PathBinding::make_Function({nullptr}) );
+ p.m_bindings.value = ::AST::PathBinding_Value::make_Function({nullptr});
)
)
}
@@ -406,26 +435,36 @@ void Resolve_Index_Module_Wildcard__submod(AST::Crate& crate, AST::Module& dst_m
{
if( ! i.data.is_Use() )
continue ;
- if( i.name != "" )
- continue ;
- Resolve_Index_Module_Wildcard__use_stmt(crate, dst_mod, i.data.as_Use(), import_as_pub);
+ for(const auto& e : i.data.as_Use().entries)
+ {
+ if( e.name != "" )
+ continue ;
+ Resolve_Index_Module_Wildcard__use_stmt(crate, dst_mod, e, import_as_pub);
+ }
}
}
stack.erase(&src_mod);
}
-void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst_mod, const AST::UseStmt& i_data, bool is_pub)
+void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst_mod, const AST::UseItem::Ent& i_data, bool is_pub)
{
const auto& sp = i_data.sp;
- const auto& b = i_data.path.binding();
+ const auto& b = i_data.path.m_bindings.type;
- TU_IFLET(::AST::PathBinding, b, Crate, e,
+ TU_IFLET(::AST::PathBinding_Type, b, Crate, e,
DEBUG("Glob crate " << i_data.path);
const auto& hmod = e.crate_->m_hir->m_root_module;
Resolve_Index_Module_Wildcard__glob_in_hir_mod(sp, crate, dst_mod, hmod, i_data.path, is_pub);
+ // TODO: Macros too
+ for(const auto& pm : e.crate_->m_hir->m_proc_macros)
+ {
+ dst_mod.m_macro_imports.push_back({
+ is_pub, pm.name, make_vec2(e.crate_->m_hir->m_crate_name, pm.name), nullptr
+ });
+ }
)
- else TU_IFLET(::AST::PathBinding, b, Module, e,
+ else TU_IFLET(::AST::PathBinding_Type, b, Module, e,
DEBUG("Glob mod " << i_data.path);
if( !e.module_ )
{
@@ -438,7 +477,9 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst
Resolve_Index_Module_Wildcard__submod(crate, dst_mod, *e.module_, is_pub);
}
)
- else TU_IFLET(::AST::PathBinding, b, Enum, e,
+ else if( const auto* ep = b.opt_Enum() )
+ {
+ const auto& e = *ep;
ASSERT_BUG(sp, e.enum_ || e.hir, "Glob import but enum pointer not set - " << i_data.path);
if( e.enum_ )
{
@@ -446,11 +487,12 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst
unsigned int idx = 0;
for( const auto& ev : e.enum_->variants() ) {
::AST::Path p = i_data.path + ev.m_name;
- p.bind( ::AST::PathBinding::make_EnumVar({e.enum_, idx}) );
if( ev.m_data.is_Struct() ) {
+ p.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({e.enum_, idx});
_add_item_type ( sp, dst_mod, ev.m_name, is_pub, mv$(p), false );
}
else {
+ p.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({e.enum_, idx});
_add_item_value( sp, dst_mod, ev.m_name, is_pub, mv$(p), false );
}
@@ -467,7 +509,7 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst
for(const auto& ev : de->variants)
{
::AST::Path p = i_data.path + ev.name;
- p.bind( ::AST::PathBinding::make_EnumVar({nullptr, idx, e.hir}) );
+ p.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, idx, e.hir});
_add_item_value( sp, dst_mod, ev.name, is_pub, mv$(p), false );
@@ -480,12 +522,13 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst
for(const auto& ev : *de)
{
::AST::Path p = i_data.path + ev.name;
- p.bind( ::AST::PathBinding::make_EnumVar({nullptr, idx, e.hir}) );
if( ev.is_struct ) {
+ p.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({nullptr, idx, e.hir});
_add_item_type ( sp, dst_mod, ev.name, is_pub, mv$(p), false );
}
else {
+ p.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, idx, e.hir});
_add_item_value( sp, dst_mod, ev.name, is_pub, mv$(p), false );
}
@@ -493,7 +536,7 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst
}
}
}
- )
+ }
else
{
BUG(sp, "Invalid path binding for glob import: " << b.tag_str() << " - "<<i_data.path);
@@ -515,9 +558,12 @@ void Resolve_Index_Module_Wildcard(AST::Crate& crate, AST::Module& mod)
{
if( ! i.data.is_Use() )
continue ;
- if( i.name != "" )
- continue ;
- Resolve_Index_Module_Wildcard__use_stmt(crate, mod, i.data.as_Use(), i.is_pub);
+ for(const auto& e : i.data.as_Use().entries )
+ {
+ if( e.name != "" )
+ continue ;
+ Resolve_Index_Module_Wildcard__use_stmt(crate, mod, e, i.is_pub);
+ }
}
// Mark this as having all the items it ever will.
@@ -598,9 +644,9 @@ void Resolve_Index_Module_Normalise_Path_ext(const ::AST::Crate& crate, const Sp
{
TU_IFLET( ::HIR::TypeItem, it_m->second->ent, Import, e,
// Replace the path with this path (maintaining binding)
- auto binding = path.binding().clone();
+ auto bindings = path.m_bindings.clone();
path = hir_to_ast(e.path);
- path.bind( mv$(binding) );
+ path.m_bindings = mv$(bindings);
)
return ;
}
@@ -611,9 +657,9 @@ void Resolve_Index_Module_Normalise_Path_ext(const ::AST::Crate& crate, const Sp
{
TU_IFLET( ::HIR::ValueItem, it_v->second->ent, Import, e,
// Replace the path with this path (maintaining binding)
- auto binding = path.binding().clone();
+ auto bindings = path.m_bindings.clone();
path = hir_to_ast(e.path);
- path.bind( mv$(binding) );
+ path.m_bindings = mv$(bindings);
)
return ;
}
@@ -648,27 +694,26 @@ bool Resolve_Index_Module_Normalise_Path(const ::AST::Crate& crate, const Span&
auto new_path = ie.path;
for(unsigned int j = i+1; j < info.nodes.size(); j ++)
new_path.nodes().push_back( mv$(info.nodes[j]) );
- new_path.bind( path.binding().clone() );
+ new_path.m_bindings = path.m_bindings.clone();
path = mv$(new_path);
return Resolve_Index_Module_Normalise_Path(crate, sp, path, loc);
}
else {
- TU_MATCH_DEF(::AST::PathBinding, (ie.path.binding()), (e),
- (
+ TU_MATCH_HDR( (ie.path.m_bindings.type), {)
+ default:
BUG(sp, "Path " << path << " pointed to non-module " << ie.path);
- ),
- (Module,
+ TU_ARM( ie.path.m_bindings.type, Module, e) {
mod = e.module_;
- ),
- (Crate,
+ }
+ TU_ARM( ie.path.m_bindings.type, Crate, e) {
Resolve_Index_Module_Normalise_Path_ext(crate, sp, path, loc, *e.crate_, i+1);
return false;
- ),
- (Enum,
+ }
+ TU_ARM( ie.path.m_bindings.type, Enum, e) {
// NOTE: Just assuming that if an Enum is hit, it's sane
return false;
- )
- )
+ }
+ }
}
}
@@ -716,7 +761,7 @@ void Resolve_Index_Module_Normalise(const ::AST::Crate& crate, const Span& mod_s
for( auto& item : mod.items() )
{
TU_IFLET(AST::Item, item.data, Module, e,
- Resolve_Index_Module_Normalise(crate, item.data.span, e);
+ Resolve_Index_Module_Normalise(crate, item.span, e);
)
}
diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp
index 23f7e70c..8a9a3167 100644
--- a/src/resolve/use.cpp
+++ b/src/resolve/use.cpp
@@ -22,8 +22,8 @@ enum class Lookup
::AST::Path Resolve_Use_AbsolutisePath(const ::AST::Path& base_path, ::AST::Path path);
void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path path, ::std::span< const ::AST::Module* > parent_modules={});
-::AST::PathBinding Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules, Lookup allow=Lookup::Any);
-::AST::PathBinding Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start, Lookup allow);
+::AST::Path::Bindings Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& source_mod_path, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules);
+::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start);
void Resolve_Use(::AST::Crate& crate)
@@ -51,7 +51,7 @@ void Resolve_Use(::AST::Crate& crate)
// How can this happen?
DEBUG("Relative " << path);
// EVIL HACK: If the current module is an anon module, refer to the parent
- if( base_path.nodes().size() > 0 && base_path.nodes().back().name()[0] == '#' ) {
+ if( base_path.nodes().size() > 0 && base_path.nodes().back().name().c_str()[0] == '#' ) {
AST::Path np("", {});
for( unsigned int i = 0; i < base_path.nodes().size() - 1; i ++ )
np.nodes().push_back( base_path.nodes()[i] );
@@ -65,7 +65,7 @@ void Resolve_Use(::AST::Crate& crate)
(Self,
DEBUG("Self " << path);
// EVIL HACK: If the current module is an anon module, refer to the parent
- if( base_path.nodes().size() > 0 && base_path.nodes().back().name()[0] == '#' ) {
+ if( base_path.nodes().size() > 0 && base_path.nodes().back().name().c_str()[0] == '#' ) {
AST::Path np("", {});
for( unsigned int i = 0; i < base_path.nodes().size() - 1; i ++ )
np.nodes().push_back( base_path.nodes()[i] );
@@ -86,7 +86,7 @@ void Resolve_Use(::AST::Crate& crate)
// TODO: Do this in a cleaner manner.
unsigned int n_anon = 0;
// Skip any anon modules in the way (i.e. if the current module is an anon, go to the parent)
- while( base_path.nodes().size() > n_anon && base_path.nodes()[ base_path.nodes().size()-1-n_anon ].name()[0] == '#' )
+ while( base_path.nodes().size() > n_anon && base_path.nodes()[ base_path.nodes().size()-1-n_anon ].name().c_str()[0] == '#' )
n_anon ++;
for( unsigned int i = 0; i < base_path.nodes().size() - e.count - n_anon; i ++ )
np.nodes().push_back( base_path.nodes()[i] );
@@ -113,60 +113,42 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
auto& use_stmt_data = use_stmt.data.as_Use();
const Span& span = use_stmt_data.sp;
- use_stmt_data.path = Resolve_Use_AbsolutisePath(span, path, mv$(use_stmt_data.path));
- if( !use_stmt_data.path.m_class.is_Absolute() )
- BUG(span, "Use path is not absolute after absolutisation");
-
- // TODO: Have Resolve_Use_GetBinding return the actual path
- use_stmt_data.path.bind( Resolve_Use_GetBinding(span, crate, use_stmt_data.path, parent_modules) );
- DEBUG("'" << use_stmt.name << "' = " << use_stmt_data.path);
-
- // - If doing a glob, ensure the item type is valid
- if( use_stmt.name == "" )
+ for(auto& use_ent : use_stmt_data.entries)
{
- TU_MATCH_DEF(::AST::PathBinding, (use_stmt_data.path.binding()), (e),
- (
- ERROR(span, E0000, "Wildcard import of invalid item type - " << use_stmt_data.path);
- ),
- (Enum,
- ),
- (Crate,
- ),
- (Module,
+ use_ent.path = Resolve_Use_AbsolutisePath(span, path, mv$(use_ent.path));
+ if( !use_ent.path.m_class.is_Absolute() )
+ BUG(span, "Use path is not absolute after absolutisation");
+
+ // NOTE: Use statements can refer to _three_ different items
+ // - types/modules ("type namespace")
+ // - values ("value namespace")
+ // - macros ("macro namespace")
+ // TODO: Have Resolve_Use_GetBinding return the actual path
+ use_ent.path.m_bindings = Resolve_Use_GetBinding(span, crate, path, use_ent.path, parent_modules);
+ if( !use_ent.path.m_bindings.has_binding() )
+ {
+ ERROR(span, E0000, "Unable to resolve `use` target " << use_ent.path);
+ }
+ DEBUG("'" << use_ent.name << "' = " << use_ent.path);
+
+ // - If doing a glob, ensure the item type is valid
+ if( use_ent.name == "" )
+ {
+ TU_MATCH_DEF(::AST::PathBinding_Type, (use_ent.path.m_bindings.type), (e),
+ (
+ ERROR(span, E0000, "Wildcard import of invalid item type - " << use_ent.path);
+ ),
+ (Enum,
+ ),
+ (Crate,
+ ),
+ (Module,
+ )
)
- )
- }
- else
- {
- // TODO: Handle case where a use can resolve to two different items (one value, one type/namespace)
- // - Easiest way is with an extra binding slot
- Lookup allow = Lookup::Any;
- switch( use_stmt_data.path.binding().tag() )
+ }
+ else
{
- case ::AST::PathBinding::TAG_Crate:
- case ::AST::PathBinding::TAG_Module:
- case ::AST::PathBinding::TAG_Trait:
- case ::AST::PathBinding::TAG_TypeAlias:
- case ::AST::PathBinding::TAG_Enum:
- allow = Lookup::Value;
- break;
- case ::AST::PathBinding::TAG_Struct:
- case ::AST::PathBinding::TAG_Union:
- allow = Lookup::Value;
- break;
- case ::AST::PathBinding::TAG_EnumVar:
- allow = Lookup::Value;
- break;
- case ::AST::PathBinding::TAG_Static:
- case ::AST::PathBinding::TAG_Function:
- allow = Lookup::Type;
- break;
- // DEAD, Unbound, ...
- default: break;
- }
- ASSERT_BUG(span, allow != Lookup::Any, "Invalid path binding type in use statement - " << use_stmt_data.path);
- use_stmt_data.alt_binding = Resolve_Use_GetBinding(span, crate, use_stmt_data.path, parent_modules, allow);
- DEBUG("- Alt Binding: " << use_stmt_data.alt_binding);
+ }
}
}
@@ -235,6 +217,9 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
(None,
// Deleted, ignore
),
+ (MacroInv,
+ // TODO: Should this already be deleted?
+ ),
(Type,
),
(Function,
@@ -264,25 +249,24 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
}
}
-::AST::PathBinding Resolve_Use_GetBinding_Mod(
+::AST::Path::Bindings Resolve_Use_GetBinding_Mod(
const Span& span,
- const ::AST::Crate& crate, const ::AST::Module& mod,
- const ::std::string& des_item_name,
- ::std::span< const ::AST::Module* > parent_modules,
- Lookup allow
+ const ::AST::Crate& crate, const ::AST::Path& source_mod_path, const ::AST::Module& mod,
+ const RcString& des_item_name,
+ ::std::span< const ::AST::Module* > parent_modules
)
{
+ ::AST::Path::Bindings rv;
// If the desired item is an anon module (starts with #) then parse and index
- if( des_item_name.size() > 0 && des_item_name[0] == '#' ) {
+ if( des_item_name.size() > 0 && des_item_name.c_str()[0] == '#' ) {
unsigned int idx = 0;
if( ::std::sscanf(des_item_name.c_str(), "#%u", &idx) != 1 ) {
BUG(span, "Invalid anon path segment '" << des_item_name << "'");
}
- if( idx >= mod.anon_mods().size() ) {
- BUG(span, "Invalid anon path segment '" << des_item_name << "'");
- }
+ ASSERT_BUG(span, idx < mod.anon_mods().size(), "Invalid anon path segment '" << des_item_name << "'");
assert( mod.anon_mods()[idx] );
- return ::AST::PathBinding::make_Module({&*mod.anon_mods()[idx], nullptr});
+ rv.type = ::AST::PathBinding_Type::make_Module({&*mod.anon_mods()[idx], nullptr});
+ return rv;
}
// Seach for the name defined in the module.
@@ -292,8 +276,6 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
continue ;
if( item.name == des_item_name ) {
- //if( allow != Lookup::Any )
- // DEBUG(mod.path() << " " << des_item_name << " " << item.data.tag_str());
TU_MATCH(::AST::Item, (item.data), (e),
(None,
// IMPOSSIBLE - Handled above
@@ -301,6 +283,9 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
(MacroInv,
BUG(span, "Hit MacroInv in use resolution");
),
+ (Macro,
+ //rv.macro = ::AST::PathBinding_Macro::make_MacroRules({nullptr, e.get()});
+ ),
(Use,
continue; // Skip for now
),
@@ -314,48 +299,48 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
BUG(span, "Hit Extern in use resolution");
),
(Crate,
- if( allow != Lookup::Value )
- ASSERT_BUG(span, crate.m_extern_crates.count(e.name), "Crate '" << e.name << "' not loaded");
- return ::AST::PathBinding::make_Crate({ &crate.m_extern_crates.at(e.name) });
+ ASSERT_BUG(span, crate.m_extern_crates.count(e.name), "Crate '" << e.name << "' not loaded");
+ rv.type = ::AST::PathBinding_Type::make_Crate({ &crate.m_extern_crates.at(e.name) });
),
(Type,
- if( allow != Lookup::Value )
- return ::AST::PathBinding::make_TypeAlias({&e});
+ rv.type = ::AST::PathBinding_Type::make_TypeAlias({&e});
),
(Trait,
- if( allow != Lookup::Value )
- return ::AST::PathBinding::make_Trait({&e});
+ rv.type = ::AST::PathBinding_Type::make_Trait({&e});
),
(Function,
- if( allow != Lookup::Type )
- return ::AST::PathBinding::make_Function({&e});
+ rv.value = ::AST::PathBinding_Value::make_Function({&e});
),
(Static,
- if( allow != Lookup::Type )
- return ::AST::PathBinding::make_Static({&e});
+ rv.value = ::AST::PathBinding_Value::make_Static({&e});
),
(Struct,
- if( allow != Lookup::Value )
- return ::AST::PathBinding::make_Struct({&e});
- if( e.m_data.is_Tuple() && allow != Lookup::Type )
- return ::AST::PathBinding::make_Struct({&e});
+ // TODO: What happens with name collisions?
+ if( !e.m_data.is_Struct() )
+ rv.value = ::AST::PathBinding_Value::make_Struct({&e});
+ rv.type = ::AST::PathBinding_Type::make_Struct({&e});
),
(Enum,
- if( allow != Lookup::Value )
- return ::AST::PathBinding::make_Enum({&e});
+ rv.type = ::AST::PathBinding_Type::make_Enum({&e});
),
(Union,
- if( allow != Lookup::Value )
- return ::AST::PathBinding::make_Union({&e});
+ rv.type = ::AST::PathBinding_Type::make_Union({&e});
),
(Module,
- if( allow != Lookup::Value )
- return ::AST::PathBinding::make_Module({&e});
+ rv.type = ::AST::PathBinding_Type::make_Module({&e});
)
)
}
}
+ // TODO: macros
+ for(const auto& mac : mod.macros())
+ {
+ if( mac.name == des_item_name ) {
+ rv.macro = ::AST::PathBinding_Macro::make_MacroRules({ nullptr, &*mac.data });
+ break;
+ }
+ }
// Imports
for( const auto& imp : mod.items() )
@@ -363,127 +348,153 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path
if( ! imp.data.is_Use() )
continue ;
const auto& imp_data = imp.data.as_Use();
- const Span& sp2 = imp_data.sp;
- if( imp.name == des_item_name ) {
- DEBUG("- Named import " << imp.name << " = " << imp_data);
- if( imp_data.path.binding().is_Unbound() ) {
- DEBUG(" > Needs resolve");
- // TODO: Handle possibility of recursion
- //out_path = imp_data.path;
- return Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_data.path), parent_modules, allow);
- }
- else {
- if( allow != Lookup::Any && allow != Lookup::AnyOpt )
+ for( const auto& imp_e : imp_data.entries )
+ {
+ const Span& sp2 = imp_e.sp;
+ if( imp_e.name == des_item_name ) {
+ DEBUG("- Named import " << imp_e.name << " = " << imp_e.path);
+ if( !imp_e.path.m_bindings.has_binding() )
{
- switch( imp_data.path.binding().tag() )
+ DEBUG(" > Needs resolve p=" << &imp_e.path);
+ static ::std::vector<const ::AST::Path*> s_mods;
+ if( ::std::find(s_mods.begin(), s_mods.end(), &imp_e.path) == s_mods.end() )
{
- case ::AST::PathBinding::TAG_Crate:
- case ::AST::PathBinding::TAG_Module:
- case ::AST::PathBinding::TAG_Trait:
- case ::AST::PathBinding::TAG_TypeAlias:
- case ::AST::PathBinding::TAG_Enum:
- if( allow != Lookup::Type )
- continue;
- break;
- case ::AST::PathBinding::TAG_Struct:
- break;
- case ::AST::PathBinding::TAG_EnumVar:
- break;
- case ::AST::PathBinding::TAG_Static:
- case ::AST::PathBinding::TAG_Function:
- if( allow != Lookup::Value )
- continue;
- break;
- default:
- break;
+ s_mods.push_back(&imp_e.path);
+ rv.merge_from( Resolve_Use_GetBinding(sp2, crate, mod.path(), Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules) );
+ s_mods.pop_back();
+ }
+ else
+ {
+ DEBUG("Recursion on path " << &imp_e.path << " " << imp_e.path);
}
- }
- //out_path = imp_data.path;
- return imp_data.path.binding().clone();
- }
- }
- if( imp.is_pub && imp.name == "" ) {
- DEBUG("- Search glob of " << imp_data.path);
- // INEFFICIENT! Resolves and throws away the result (because we can't/shouldn't mutate here)
- ::AST::PathBinding binding_;
- const auto* binding = &imp_data.path.binding();
- if( binding->is_Unbound() ) {
- DEBUG("Temp resolving wildcard " << imp_data);
- // Handle possibility of recursion
- static ::std::vector<const ::AST::UseStmt*> resolve_stack_ptrs;
- if( ::std::find(resolve_stack_ptrs.begin(), resolve_stack_ptrs.end(), &imp_data) == resolve_stack_ptrs.end() )
- {
- resolve_stack_ptrs.push_back( &imp_data );
- binding_ = Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_data.path), parent_modules);
- // *waves hand* I'm not evil.
- const_cast< ::AST::PathBinding&>( imp_data.path.binding() ) = binding_.clone();
- binding = &binding_;
- resolve_stack_ptrs.pop_back();
}
else {
- continue ;
+ //out_path = imp_e.path;
+ rv.merge_from( imp_e.path.m_bindings.clone() );
}
- }
- else {
- //out_path = imp_data.path;
+ continue ;
}
- TU_MATCH_DEF(::AST::PathBinding, (*binding), (e),
- (
- BUG(sp2, "Wildcard import expanded to an invalid item class - " << binding->tag_str());
- ),
- (Crate,
- assert(e.crate_);
- const ::HIR::Module& hmod = e.crate_->m_hir->m_root_module;
- auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0, allow);
- if( ! rv.is_Unbound() ) {
- return mv$(rv);
- }
- ),
- (Module,
- auto allow_inner = (allow == Lookup::Any ? Lookup::AnyOpt : allow);
- assert(e.module_);
- // TODO: Prevent infinite recursion?
- auto rv = Resolve_Use_GetBinding_Mod(span, crate, *e.module_, des_item_name, {}, allow_inner);
- if( ! rv.is_Unbound() ) {
- return mv$(rv);
- }
- ),
- (Enum,
- assert(e.enum_ || e.hir);
- if( e.enum_ ) {
- const auto& enm = *e.enum_;
- unsigned int i = 0;
- for(const auto& var : enm.variants())
+ // TODO: Correct privacy rules (if the origin of this lookup can see this item)
+ if( (imp.is_pub || mod.path().is_parent_of(source_mod_path)) && imp_e.name == "" )
+ {
+ DEBUG("- Search glob of " << imp_e.path << " in " << mod.path());
+ // INEFFICIENT! Resolves and throws away the result (because we can't/shouldn't mutate here)
+ ::AST::Path::Bindings bindings_;
+ const auto* bindings = &imp_e.path.m_bindings;
+ if( bindings->type.is_Unbound() ) {
+ DEBUG("Temp resolving wildcard " << imp_e.path);
+ // Handle possibility of recursion
+ static ::std::vector<const ::AST::UseItem*> resolve_stack_ptrs;
+ if( ::std::find(resolve_stack_ptrs.begin(), resolve_stack_ptrs.end(), &imp_data) == resolve_stack_ptrs.end() )
{
- if( var.m_name == des_item_name ) {
- return ::AST::PathBinding::make_EnumVar({ &enm, i });
+ resolve_stack_ptrs.push_back( &imp_data );
+ bindings_ = Resolve_Use_GetBinding(sp2, crate, mod.path(), Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules);
+ if( bindings_.type.is_Unbound() ) {
+ DEBUG("Recursion detected, skipping " << imp_e.path);
+ continue ;
}
- i ++;
+ // *waves hand* I'm not evil.
+ const_cast< ::AST::Path::Bindings&>( imp_e.path.m_bindings ) = bindings_.clone();
+ bindings = &bindings_;
+ resolve_stack_ptrs.pop_back();
+ }
+ else {
+ continue ;
}
}
else {
- const auto& enm = *e.hir;
- auto idx = enm.find_variant(des_item_name);
- if( idx != SIZE_MAX )
- {
- return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned>(idx), &enm });
+ //out_path = imp_e.path;
+ }
+
+ TU_MATCH_HDRA( (bindings->type), {)
+ TU_ARMA(Crate, e) {
+ assert(e.crate_);
+ const ::HIR::Module& hmod = e.crate_->m_hir->m_root_module;
+ auto imp_rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0);
+ if( imp_rv.has_binding() ) {
+ rv.merge_from( imp_rv );
+ }
}
+ TU_ARMA(Module, e) {
+ if( e.module_ ) {
+ // TODO: Prevent infinite recursion?
+ static ::std::vector<const AST::Module*> s_use_glob_mod_stack;
+ if( ::std::find(s_use_glob_mod_stack.begin(), s_use_glob_mod_stack.end(), &*e.module_) == s_use_glob_mod_stack.end() )
+ {
+ s_use_glob_mod_stack.push_back( &*e.module_ );
+ rv.merge_from( Resolve_Use_GetBinding_Mod(span, crate, mod.path(), *e.module_, des_item_name, {}) );
+ s_use_glob_mod_stack.pop_back();
+ }
+ else
+ {
+ DEBUG("Recursion prevented of " << e.module_->path());
+ }
+ }
+ else if( e.hir ) {
+ const ::HIR::Module& hmod = *e.hir;
+ rv.merge_from( Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0) );
+ }
+ else {
+ BUG(span, "NULL module for binding on glob of " << imp_e.path);
+ }
+ }
+ TU_ARMA(Enum, e) {
+ assert(e.enum_ || e.hir);
+ if( e.enum_ ) {
+ const auto& enm = *e.enum_;
+ unsigned int i = 0;
+ for(const auto& var : enm.variants())
+ {
+ if( var.m_name == des_item_name ) {
+ ::AST::Path::Bindings tmp_rv;
+ if( var.m_data.is_Struct() )
+ tmp_rv.type = ::AST::PathBinding_Type::make_EnumVar({ &enm, i });
+ else
+ tmp_rv.value = ::AST::PathBinding_Value::make_EnumVar({ &enm, i });
+ rv.merge_from(tmp_rv);
+ break;
+ }
+ i ++;
+ }
+ }
+ else {
+ const auto& enm = *e.hir;
+ auto idx = enm.find_variant(des_item_name);
+ if( idx != SIZE_MAX )
+ {
+ ::AST::Path::Bindings tmp_rv;
+ if( enm.m_data.is_Data() && enm.m_data.as_Data()[idx].is_struct ) {
+ tmp_rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast<unsigned>(idx), &enm });
+ }
+ else {
+ tmp_rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast<unsigned>(idx), &enm });
+ }
+ rv.merge_from(tmp_rv);
+ break;
+ }
+ }
+ } break;
+ default:
+ BUG(sp2, "Wildcard import expanded to an invalid item class - " << bindings->type.tag_str());
+ break;
}
- )
- )
+ }
}
}
+ if( rv.has_binding() )
+ {
+ return rv;
+ }
- if( mod.path().nodes().size() > 0 && mod.path().nodes().back().name()[0] == '#' ) {
+ if( mod.path().nodes().size() > 0 && mod.path().nodes().back().name().c_str()[0] == '#' ) {
assert( parent_modules.size() > 0 );
- return Resolve_Use_GetBinding_Mod(span, crate, *parent_modules.back(), des_item_name, parent_modules.subspan(0, parent_modules.size()-1), allow);
+ return Resolve_Use_GetBinding_Mod(span, crate, source_mod_path, *parent_modules.back(), des_item_name, parent_modules.subspan(0, parent_modules.size()-1));
}
else {
- if( allow == Lookup::Any )
- ERROR(span, E0000, "Could not find node '" << des_item_name << "' in module " << mod.path());
- else
- return ::AST::PathBinding::make_Unbound({});
+ //if( allow == Lookup::Any )
+ // ERROR(span, E0000, "Could not find node '" << des_item_name << "' in module " << mod.path());
+ return ::AST::Path::Bindings();
}
}
@@ -532,13 +543,15 @@ namespace {
}
}
-::AST::PathBinding Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start, Lookup allow)
+::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start)
{
- TRACE_FUNCTION_F(path);
+ ::AST::Path::Bindings rv;
+ TRACE_FUNCTION_F(path << " offset " << start);
const auto& nodes = path.nodes();
const ::HIR::Module* hmod = &hmodr;
for(unsigned int i = start; i < nodes.size() - 1; i ++)
{
+ DEBUG("m_mod_items = {" << FMT_CB(ss, for(const auto& e : hmod->m_mod_items) ss << e.first << ", ";) << "}");
auto it = hmod->m_mod_items.find(nodes[i].name());
if( it == hmod->m_mod_items.end() ) {
// BZZT!
@@ -566,7 +579,13 @@ namespace {
if( idx == SIZE_MAX ) {
ERROR(span, E0000, "Unable to find variant " << path);
}
- return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &enm });
+ if( enm.m_data.is_Data() && enm.m_data.as_Data()[idx].is_struct ) {
+ rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &enm });
+ }
+ else {
+ rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &enm });
+ }
+ return rv;
}
else {
hmod = reinterpret_cast<const ::HIR::Module*>(ptr);
@@ -586,16 +605,23 @@ namespace {
if(idx == SIZE_MAX) {
ERROR(span, E0000, "Unable to find variant " << path);
}
- return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &e });
+ if( e.m_data.is_Data() && e.m_data.as_Data()[idx].is_struct ) {
+ rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &e });
+ }
+ else {
+ rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &e });
+ }
+ return rv;
)
)
}
- if( allow != Lookup::Value )
+ // - namespace/type items
{
auto it = hmod->m_mod_items.find(nodes.back().name());
- if( it != hmod->m_mod_items.end() ) {
+ if( it != hmod->m_mod_items.end() )
+ {
const auto* item_ptr = &it->second->ent;
- DEBUG("E : " << nodes.back().name() << " = " << item_ptr->tag_str());
+ DEBUG("E : Mod " << nodes.back().name() << " = " << item_ptr->tag_str());
if( item_ptr->is_Import() ) {
const auto& e = item_ptr->as_Import();
const auto& ec = crate.m_extern_crates.at( e.path.m_crate_name );
@@ -605,94 +631,139 @@ namespace {
p.m_components.pop_back();
const auto& enm = ec.m_hir->get_typeitem_by_path(span, p, true).as_Enum();
assert(e.idx < enm.num_variants());
- return ::AST::PathBinding::make_EnumVar({ nullptr, e.idx, &enm });
+ rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, e.idx, &enm });
+ }
+ else if( e.path.m_components.empty() )
+ {
+ rv.type = ::AST::PathBinding_Type::make_Module({nullptr, &ec.m_hir->m_root_module});
+ }
+ else
+ {
+ item_ptr = &ec.m_hir->get_typeitem_by_path(span, e.path, true); // ignore_crate_name=true
}
- if( e.path.m_components.empty() )
- return ::AST::PathBinding::make_Module({nullptr, &ec.m_hir->m_root_module});
- item_ptr = &ec.m_hir->get_typeitem_by_path(span, e.path, true); // ignore_crate_name=true
}
- TU_MATCHA( (*item_ptr), (e),
- (Import,
- BUG(span, "Recursive import in " << path << " - " << it->second->ent.as_Import().path << " -> " << e.path);
- ),
- (Module,
- return ::AST::PathBinding::make_Module({nullptr, &e});
- ),
- (TypeAlias,
- return ::AST::PathBinding::make_TypeAlias({nullptr});
- ),
- (Enum,
- return ::AST::PathBinding::make_Enum({nullptr, &e});
- ),
- (Struct,
- return ::AST::PathBinding::make_Struct({nullptr, &e});
- ),
- (Union,
- return ::AST::PathBinding::make_Union({nullptr, &e});
- ),
- (Trait,
- return ::AST::PathBinding::make_Trait({nullptr, &e});
+ if( rv.type.is_Unbound() )
+ {
+ TU_MATCHA( (*item_ptr), (e),
+ (Import,
+ BUG(span, "Recursive import in " << path << " - " << it->second->ent.as_Import().path << " -> " << e.path);
+ ),
+ (Module,
+ rv.type = ::AST::PathBinding_Type::make_Module({nullptr, &e});
+ ),
+ (TypeAlias,
+ rv.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr});
+ ),
+ (ExternType,
+ rv.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); // Lazy.
+ ),
+ (Enum,
+ rv.type = ::AST::PathBinding_Type::make_Enum({nullptr, &e});
+ ),
+ (Struct,
+ rv.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e});
+ ),
+ (Union,
+ rv.type = ::AST::PathBinding_Type::make_Union({nullptr, &e});
+ ),
+ (Trait,
+ rv.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e});
+ )
)
- )
+ }
+ }
+ else
+ {
+ DEBUG("Types = " << FMT_CB(ss, for(const auto& e : hmod->m_mod_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; }));
}
- DEBUG("Types = " << FMT_CB(ss, for(const auto& e : hmod->m_mod_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; }));
}
- if( allow != Lookup::Type )
+ // - Values
{
auto it2 = hmod->m_value_items.find(nodes.back().name());
if( it2 != hmod->m_value_items.end() ) {
const auto* item_ptr = &it2->second->ent;
- DEBUG("E : " << nodes.back().name() << " = " << item_ptr->tag_str());
+ DEBUG("E : Value " << nodes.back().name() << " = " << item_ptr->tag_str());
if( item_ptr->is_Import() ) {
const auto& e = item_ptr->as_Import();
// This doesn't need to recurse - it can just do a single layer (as no Import should refer to another)
const auto& ec = crate.m_extern_crates.at( e.path.m_crate_name );
- if( e.is_variant ) {
+ if( e.is_variant )
+ {
auto p = e.path;
p.m_components.pop_back();
const auto& enm = ec.m_hir->get_typeitem_by_path(span, p, true).as_Enum();
assert(e.idx < enm.num_variants());
- return ::AST::PathBinding::make_EnumVar({ nullptr, e.idx, &enm });
+ rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, e.idx, &enm });
+ }
+ else
+ {
+ item_ptr = &ec.m_hir->get_valitem_by_path(span, e.path, true); // ignore_crate_name=true
}
- item_ptr = &ec.m_hir->get_valitem_by_path(span, e.path, true); // ignore_crate_name=true
}
- TU_MATCHA( (*item_ptr), (e),
- (Import,
- BUG(span, "Recursive import in " << path << " - " << it2->second->ent.as_Import().path << " -> " << e.path);
- ),
- (Constant,
- return ::AST::PathBinding::make_Static({ nullptr });
- ),
- (Static,
- return ::AST::PathBinding::make_Static({ nullptr });
- ),
- // TODO: What happens if these two refer to an enum constructor?
- (StructConstant,
- ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty);
- return ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() });
- ),
- (StructConstructor,
- ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty);
- return ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() });
- ),
- (Function,
- return ::AST::PathBinding::make_Function({ nullptr });
+ if( rv.value.is_Unbound() )
+ {
+ TU_MATCHA( (*item_ptr), (e),
+ (Import,
+ BUG(span, "Recursive import in " << path << " - " << it2->second->ent.as_Import().path << " -> " << e.path);
+ ),
+ (Constant,
+ rv.value = ::AST::PathBinding_Value::make_Static({ nullptr });
+ ),
+ (Static,
+ rv.value = ::AST::PathBinding_Value::make_Static({ nullptr });
+ ),
+ // TODO: What happens if these two refer to an enum constructor?
+ (StructConstant,
+ ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty);
+ rv.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() });
+ ),
+ (StructConstructor,
+ ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty);
+ rv.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() });
+ ),
+ (Function,
+ rv.value = ::AST::PathBinding_Value::make_Function({ nullptr });
+ )
)
- )
+ }
+ }
+ else
+ {
+ DEBUG("Values = " << FMT_CB(ss, for(const auto& e : hmod->m_value_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; }));
}
-
- DEBUG("Values = " << FMT_CB(ss, for(const auto& e : hmod->m_value_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; }));
}
- DEBUG("E : None");
- return ::AST::PathBinding::make_Unbound({});
+ if( rv.type.is_Unbound() && rv.value.is_Unbound() )
+ {
+ DEBUG("E : None");
+ }
+ return rv;
}
-::AST::PathBinding Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const AST::ExternCrate& ec, unsigned int start, Lookup allow)
+::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const AST::ExternCrate& ec, unsigned int start)
{
- return Resolve_Use_GetBinding__ext(span, crate, path, ec.m_hir->m_root_module, start, allow);
+ DEBUG("Crate " << ec.m_name);
+ auto rv = Resolve_Use_GetBinding__ext(span, crate, path, ec.m_hir->m_root_module, start);
+ if( start + 1 == path.nodes().size() )
+ {
+ const auto& name = path.nodes().back().name();
+ auto it = ec.m_hir->m_exported_macros.find( name );
+ if( it != ec.m_hir->m_exported_macros.end() )
+ {
+ rv.macro = ::AST::PathBinding_Macro::make_MacroRules({ &ec, &*it->second });
+ }
+
+ {
+ auto it = ::std::find_if( ec.m_hir->m_proc_macros.begin(), ec.m_hir->m_proc_macros.end(), [&](const auto& pm){ return pm.name == name;} );
+ if( it != ec.m_hir->m_proc_macros.end() )
+ {
+ rv.macro = ::AST::PathBinding_Macro::make_ProcMacro({ &ec, name });
+ }
+ }
+ }
+ return rv;
}
-::AST::PathBinding Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules, Lookup allow)
+::AST::Path::Bindings Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& source_mod_path, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules)
{
TRACE_FUNCTION_F(path);
//::AST::Path rv;
@@ -701,15 +772,18 @@ namespace {
if( path.m_class.is_Absolute() && path.m_class.as_Absolute().crate != "" ) {
const auto& path_abs = path.m_class.as_Absolute();
- ASSERT_BUG(span, crate.m_extern_crates.count(path_abs.crate), "Crate '" << path_abs.crate << "' not loaded");
- return Resolve_Use_GetBinding__ext(span, crate, path, crate.m_extern_crates.at( path_abs.crate ), 0, allow);
+ ASSERT_BUG(span, crate.m_extern_crates.count(path_abs.crate.c_str()), "Crate '" << path_abs.crate << "' not loaded");
+ return Resolve_Use_GetBinding__ext(span, crate, path, crate.m_extern_crates.at( path_abs.crate.c_str() ), 0);
}
+ ::AST::Path::Bindings rv;
+
const AST::Module* mod = &crate.m_root_module;
const auto& nodes = path.nodes();
if( nodes.size() == 0 ) {
// An import of the root.
- return ::AST::PathBinding::make_Module({ mod, nullptr });
+ rv.type = ::AST::PathBinding_Type::make_Module({ mod, nullptr });
+ return rv;
}
for( unsigned int i = 0; i < nodes.size()-1; i ++ )
{
@@ -718,54 +792,90 @@ namespace {
//rv = Resolve_Use_CanoniseAndBind_Mod(span, crate, *mod, mv$(rv), nodes[i].name(), parent_modules, Lookup::Type);
//const auto& b = rv.binding();
assert(mod);
- auto b = Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.at(i).name(), parent_modules, Lookup::Type);
- TU_MATCH_DEF(::AST::PathBinding, (b), (e),
- (
- ERROR(span, E0000, "Unexpected item type " << b.tag_str() << " in import of " << path);
- ),
- (Unbound,
- ERROR(span, E0000, "Cannot find component " << i << " of " << path);
- ),
- (Crate,
+ auto b = Resolve_Use_GetBinding_Mod(span, crate, source_mod_path, *mod, nodes.at(i).name(), parent_modules);
+ TU_MATCH_HDRA( (b.type), {)
+ default:
+ ERROR(span, E0000, "Unexpected item type " << b.type.tag_str() << " in import of " << path);
+ TU_ARMA(Unbound, e) {
+ ERROR(span, E0000, "Cannot find component " << i << " of " << path << " (" << b.type << ")");
+ }
+ TU_ARMA(Crate, e) {
// TODO: Mangle the original path (or return a new path somehow)
- return Resolve_Use_GetBinding__ext(span, crate, path, *e.crate_, i+1, allow);
- ),
- (Enum,
- const auto& enum_ = *e.enum_;
+ return Resolve_Use_GetBinding__ext(span, crate, path, *e.crate_, i+1);
+ }
+ TU_ARMA(Enum, e) {
+ ASSERT_BUG(span, e.enum_ || e.hir, "nullptr enum pointer in node " << i << " of " << path);
+ ASSERT_BUG(span, e.enum_ == nullptr || e.hir == nullptr, "both AST and HIR pointers set in node " << i << " of " << path);
i += 1;
if( i != nodes.size() - 1 ) {
ERROR(span, E0000, "Encountered enum at unexpected location in import");
}
+ ASSERT_BUG(span, i < nodes.size(), "Enum import position error, " << i << " >= " << nodes.size() << " - " << path);
const auto& node2 = nodes[i];
- int variant_index = -1;
- for( unsigned int j = 0; j < enum_.variants().size(); j ++ )
+
+ unsigned variant_index = 0;
+ bool is_value = false;
+ if(e.hir)
{
- if( enum_.variants()[j].m_name == node2.name() ) {
- variant_index = j;
- break ;
+ const auto& enum_ = *e.hir;
+ size_t idx = enum_.find_variant(node2.name());
+ if( idx == ~0u ) {
+ ERROR(span, E0000, "Unknown enum variant " << path);
}
+ TU_MATCH_HDRA( (enum_.m_data), {)
+ TU_ARMA(Value, ve) {
+ is_value = true;
+ }
+ TU_ARMA(Data, ve) {
+ is_value = !ve[idx].is_struct;
+ }
+ }
+ DEBUG("AST Enum variant - " << variant_index << ", is_value=" << is_value);
}
- if( variant_index < 0 ) {
- ERROR(span, E0000, "Unknown enum variant '" << node2.name() << "'");
- }
+ else
+ {
+ const auto& enum_ = *e.enum_;
+ for( const auto& var : enum_.variants() )
+ {
+ if( var.m_name == node2.name() ) {
+ is_value = !var.m_data.is_Struct();
+ break ;
+ }
+ variant_index ++;
+ }
+ if( variant_index == enum_.variants().size() ) {
+ ERROR(span, E0000, "Unknown enum variant '" << node2.name() << "'");
+ }
- return ::AST::PathBinding::make_EnumVar({&enum_, static_cast<unsigned int>(variant_index)});
- ),
- (Module,
+ DEBUG("AST Enum variant - " << variant_index << ", is_value=" << is_value << " " << enum_.variants()[variant_index].m_data.tag_str());
+ }
+ if( is_value ) {
+ rv.value = ::AST::PathBinding_Value::make_EnumVar({e.enum_, variant_index, e.hir});
+ }
+ else {
+ rv.type = ::AST::PathBinding_Type::make_EnumVar({e.enum_, variant_index, e.hir});
+ }
+ return rv;
+ }
+ TU_ARMA(Module, e) {
ASSERT_BUG(span, e.module_ || e.hir, "nullptr module pointer in node " << i << " of " << path);
if( !e.module_ )
{
assert(e.hir);
// TODO: Mangle the original path (or return a new path somehow)
- return Resolve_Use_GetBinding__ext(span, crate, path, *e.hir, i+1, allow);
+ return Resolve_Use_GetBinding__ext(span, crate, path, *e.hir, i+1);
}
mod = e.module_;
- )
- )
+ }
+ }
}
assert(mod);
- return Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.back().name(), parent_modules, allow);
+ return Resolve_Use_GetBinding_Mod(span, crate, source_mod_path, *mod, nodes.back().name(), parent_modules);
}
+//::AST::PathBinding_Macro Resolve_Use_GetBinding_Macro(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules)
+//{
+// throw "";
+//}
diff --git a/src/slice.hpp b/src/slice.hpp
new file mode 100644
index 00000000..2011e8c2
--- /dev/null
+++ b/src/slice.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <stddef.h>
+
+template<typename T>
+class slice
+{
+ T* ptr;
+ size_t len;
+public:
+ slice(T* ptr, size_t len): ptr(ptr), len(len) {}
+
+ T* begin() { return ptr; }
+ T* end() { return ptr + len; }
+ const T* begin() const { return ptr; }
+ const T* end() const { return ptr + len; }
+};
+
+namespace std {
+ template<typename T>
+ ostream& operator<<(ostream& os, const slice<T>& x) {
+ os << "[";
+ bool first = true;
+ for(const auto& e : x)
+ {
+ if(!first)
+ os << ",";
+ first = false;
+ os << e;
+ }
+ os << "]";
+ return os;
+ }
+}
+
diff --git a/src/span.cpp b/src/span.cpp
index 34f2637e..7e3968d1 100644
--- a/src/span.cpp
+++ b/src/span.cpp
@@ -22,7 +22,7 @@ Span::Span(const Position& pos):
}
Span::Span():
outer_span(),
- filename("")/*,
+ filename(""),
start_line(0), start_ofs(0),
end_line(0), end_ofs(0) // */
{
@@ -66,10 +66,10 @@ void Span::error(ErrorType tag, ::std::function<void(::std::ostream&)> msg) cons
#endif
}
void Span::warning(WarningType tag, ::std::function<void(::std::ostream&)> msg) const {
- print_span_message(*this, [&](auto& os){os << "warning" << tag;}, msg);
+ print_span_message(*this, [&](auto& os){os << "warn:" << tag;}, msg);
}
void Span::note(::std::function<void(::std::ostream&)> msg) const {
- print_span_message(*this, [](auto& os){os << "note";}, msg);
+ print_span_message(*this, [](auto& os){os << "note:";}, msg);
}
::std::ostream& operator<<(::std::ostream& os, const Span& sp)
diff --git a/src/trans/allocator.cpp b/src/trans/allocator.cpp
index 5f61093d..9f5559ae 100644
--- a/src/trans/allocator.cpp
+++ b/src/trans/allocator.cpp
@@ -12,25 +12,14 @@
#define DEF_METHOD(name, ret) { #name, AllocatorDataTy::ret, sizeof(ALLOCATOR_METHODS_ARGS_##name)/sizeof(AllocatorDataTy), ALLOCATOR_METHODS_ARGS_##name }
DEF_METHOD_ARGS(alloc, AllocatorDataTy::Layout)
-DEF_METHOD_ARGS(oom, AllocatorDataTy::AllocError)
DEF_METHOD_ARGS(dealloc, AllocatorDataTy::Ptr, AllocatorDataTy::Layout)
-DEF_METHOD_ARGS(usable_size, AllocatorDataTy::LayoutRef)
-DEF_METHOD_ARGS(realloc, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Layout)
+DEF_METHOD_ARGS(realloc, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Usize)
DEF_METHOD_ARGS(alloc_zeroed, AllocatorDataTy::Layout)
-DEF_METHOD_ARGS(alloc_excess, AllocatorDataTy::Layout)
-DEF_METHOD_ARGS(realloc_excess, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Layout)
-DEF_METHOD_ARGS(grow_in_place, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Layout)
-DEF_METHOD_ARGS(shrink_in_place, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Layout)
-const AllocatorMethod ALLOCATOR_METHODS[10] = {
+const AllocatorMethod ALLOCATOR_METHODS[4] = {
DEF_METHOD(alloc, ResultPtr),
- DEF_METHOD(oom, Never),
DEF_METHOD(dealloc, Unit),
- DEF_METHOD(usable_size, UsizePair),
DEF_METHOD(realloc, ResultPtr),
- DEF_METHOD(alloc_zeroed, ResultPtr),
- DEF_METHOD(alloc_excess, ResultExcess),
- DEF_METHOD(realloc_excess, ResultExcess),
- DEF_METHOD(grow_in_place, ResultUnit),
- DEF_METHOD(shrink_in_place, ResultUnit)
+ DEF_METHOD(alloc_zeroed, ResultPtr)
};
+const size_t NUM_ALLOCATOR_METHODS = sizeof(ALLOCATOR_METHODS)/sizeof(ALLOCATOR_METHODS[0]);
diff --git a/src/trans/allocator.hpp b/src/trans/allocator.hpp
index 8a4e5186..c124ef57 100644
--- a/src/trans/allocator.hpp
+++ b/src/trans/allocator.hpp
@@ -9,17 +9,12 @@
enum class AllocatorDataTy {
// - Return
- Never, // !
Unit, // ()
ResultPtr, // (..., *mut i8) + *mut u8
- ResultExcess, // (..., *mut i8, *mut i8) + *mut u8
- UsizePair, // (..., *mut usize, *mut usize) + ()
- ResultUnit, // i8
// - Args
Layout, // usize, usize
- LayoutRef, // *const Layout [actually *const i8]
- AllocError, // *const i8
Ptr, // *mut u8
+ Usize, // usize
};
struct AllocatorMethod {
const char* name;
@@ -33,5 +28,6 @@ enum class AllocatorKind {
DefaultExe,
};
-extern const AllocatorMethod ALLOCATOR_METHODS[10];
+extern const AllocatorMethod ALLOCATOR_METHODS[];
+extern const size_t NUM_ALLOCATOR_METHODS;
diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp
new file mode 100644
index 00000000..71f95a26
--- /dev/null
+++ b/src/trans/auto_impls.cpp
@@ -0,0 +1,248 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * trans/auto_impls.cpp
+ * - Automatic trait/method impls
+ *
+ * Handles implementing Clone (when in 1.29 mode)
+ */
+#include "main_bindings.hpp"
+#include "trans_list.hpp"
+#include <hir/hir.hpp>
+#include <mir/mir.hpp>
+#include <hir_typeck/common.hpp> // monomorph
+#include <hir_typeck/static.hpp> // StaticTraitResolve
+#include <deque>
+#include <algorithm> // find_if
+
+namespace {
+ struct State
+ {
+ ::HIR::Crate& crate;
+ StaticTraitResolve resolve;
+ const TransList& trans_list;
+ ::std::deque<::HIR::TypeRef> todo_list;
+ ::std::set<::HIR::TypeRef> done_list;
+
+ ::HIR::SimplePath lang_Clone;
+
+ State(::HIR::Crate& crate, const TransList& trans_list):
+ crate(crate),
+ resolve( crate ),
+ trans_list(trans_list)
+ {
+ lang_Clone = crate.get_lang_item_path(Span(), "clone");
+ }
+
+ void enqueue_type(const ::HIR::TypeRef& ty) {
+ if( this->trans_list.auto_clone_impls.count(ty) == 0 && this->done_list.count(ty) == 0 ) {
+ this->done_list.insert( ty.clone() );
+ this->todo_list.push_back( ty.clone() );
+ }
+ }
+ };
+}
+
+namespace {
+ ::MIR::Param clone_field(const State& state, const Span& sp, ::MIR::Function& mir_fcn, const ::HIR::TypeRef& subty, ::MIR::LValue fld_lvalue)
+ {
+ if( state.resolve.type_is_copy(sp, subty) )
+ {
+ return ::std::move(fld_lvalue);
+ }
+ else
+ {
+ const auto& lang_Clone = state.resolve.m_crate.get_lang_item_path(sp, "clone");
+ // Allocate to locals (one for the `&T`, the other for the cloned `T`)
+ auto borrow_lv = ::MIR::LValue::new_Local( mir_fcn.locals.size() );
+ mir_fcn.locals.push_back(::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, subty.clone()));
+ auto res_lv = ::MIR::LValue::new_Local( mir_fcn.locals.size() );
+ mir_fcn.locals.push_back(subty.clone());
+
+ // Call `<T as Clone>::clone`, passing a borrow of the field
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ borrow_lv.clone(),
+ ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(fld_lvalue) })
+ }));
+ bb.terminator = ::MIR::Terminator::make_Call({
+ static_cast<unsigned>(mir_fcn.blocks.size() + 2), // return block (after the panic block below)
+ static_cast<unsigned>(mir_fcn.blocks.size() + 1), // panic block (next block)
+ res_lv.clone(),
+ ::MIR::CallTarget( ::HIR::Path(subty.clone(), lang_Clone, "clone") ),
+ ::make_vec1<::MIR::Param>( ::std::move(borrow_lv) )
+ });
+ mir_fcn.blocks.push_back(::std::move( bb ));
+
+ // Stub panic handling (TODO: Make this iterate `values` and drop all of them)
+ ::MIR::BasicBlock panic_bb;
+ panic_bb.terminator = ::MIR::Terminator::make_Diverge({});
+ mir_fcn.blocks.push_back(::std::move( panic_bb ));
+
+ // Save the output of the `clone` call
+ return ::std::move(res_lv);
+ }
+ }
+}
+
+void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty)
+{
+ Span sp;
+ TRACE_FUNCTION_F(ty);
+
+ // Create MIR
+ ::MIR::Function mir_fcn;
+ if( state.resolve.type_is_copy(sp, ty) )
+ {
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ ::MIR::LValue::new_Return(),
+ ::MIR::RValue::make_Use( ::MIR::LValue::new_Deref( ::MIR::LValue::new_Argument(0) ) )
+ }));
+ bb.terminator = ::MIR::Terminator::make_Return({});
+ mir_fcn.blocks.push_back(::std::move( bb ));
+ }
+ else
+ {
+ TU_MATCH_HDRA( (ty.m_data), {)
+ default:
+ TODO(sp, "auto Clone for " << ty << " - Unknown and not Copy");
+ TU_ARMA(Path, te) {
+ // closures are identified by the name starting with 'closure#'
+ if( TU_TEST1(te.path.m_data, Generic, .m_path.m_components.back().compare(0, 8, "closure#") == 0) ) {
+ const auto& gp = te.path.m_data.as_Generic();
+ const auto& str = state.resolve.m_crate.get_struct_by_path(sp, gp.m_path);
+ Trans_Params p;
+ p.sp = sp;
+ p.pp_impl = gp.m_params.clone();
+ ::std::vector< ::MIR::Param> values; values.reserve( str.m_data.as_Tuple().size() );
+ for(const auto& fld : str.m_data.as_Tuple())
+ {
+ ::HIR::TypeRef tmp;
+ const auto& ty_m = monomorphise_type_needed(fld.ent) ? (tmp = p.monomorph(state.resolve, fld.ent)) : fld.ent;
+ auto fld_lvalue = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref(::MIR::LValue::new_Argument(0)), static_cast<unsigned>(values.size()) );
+ values.push_back( clone_field(state, sp, mir_fcn, ty_m, mv$(fld_lvalue)) );
+ }
+ // Construct the result value
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ ::MIR::LValue::new_Return(),
+ ::MIR::RValue::make_Struct({ gp.clone(), mv$(values) })
+ }));
+ bb.terminator = ::MIR::Terminator::make_Return({});
+ mir_fcn.blocks.push_back(::std::move( bb ));
+ }
+ else {
+ TODO(sp, "auto Clone for " << ty << " - Unknown and not Copy");
+ }
+ }
+ TU_ARMA(Array, te) {
+ ASSERT_BUG(sp, te.size_val < 256, "TODO: Is more than 256 elements sane for auto-generated non-Copy Clone impl? " << ty);
+ ::std::vector< ::MIR::Param> values; values.reserve(te.size_val);
+ for(size_t i = 0; i < te.size_val; i ++)
+ {
+ auto fld_lvalue = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref(::MIR::LValue::new_Argument(0)), static_cast<unsigned>(values.size()) );
+ values.push_back( clone_field(state, sp, mir_fcn, *te.inner, mv$(fld_lvalue)) );
+ }
+ // Construct the result
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ ::MIR::LValue::new_Return(),
+ ::MIR::RValue::make_Array({ mv$(values) })
+ }));
+ bb.terminator = ::MIR::Terminator::make_Return({});
+ mir_fcn.blocks.push_back(::std::move( bb ));
+ }
+ TU_ARMA(Tuple, te) {
+ assert(te.size() > 0);
+
+ ::std::vector< ::MIR::Param> values; values.reserve(te.size());
+ // For each field of the tuple, create a clone (either using Copy if posible, or calling Clone::clone)
+ for(const auto& subty : te)
+ {
+ auto fld_lvalue = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref(::MIR::LValue::new_Argument(0)), static_cast<unsigned>(values.size()) );
+ values.push_back( clone_field(state, sp, mir_fcn, subty, mv$(fld_lvalue)) );
+ }
+
+ // Construct the result tuple
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ ::MIR::LValue::new_Return(),
+ ::MIR::RValue::make_Tuple({ mv$(values) })
+ }));
+ bb.terminator = ::MIR::Terminator::make_Return({});
+ mir_fcn.blocks.push_back(::std::move( bb ));
+ }
+ }
+ }
+
+ // Function
+ ::HIR::Function fcn {
+ /*m_save_code=*/false,
+ ::HIR::Linkage {},
+ ::HIR::Function::Receiver::BorrowShared,
+ /*m_abi=*/ABI_RUST,
+ /*m_unsafe =*/false,
+ /*m_const=*/false,
+ ::HIR::GenericParams {},
+ /*m_args=*/::make_vec1(::std::make_pair(
+ ::HIR::Pattern( ::HIR::PatternBinding(false, ::HIR::PatternBinding::Type::Move, "self", 0), ::HIR::Pattern::Data::make_Any({}) ),
+ ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone())
+ )),
+ /*m_variadic=*/false,
+ /*m_return=*/ty.clone(),
+ ::HIR::ExprPtr {}
+ };
+ fcn.m_code.m_mir = ::MIR::FunctionPointer( new ::MIR::Function(mv$(mir_fcn)) );
+
+ // Impl
+ ::HIR::TraitImpl impl;
+ impl.m_type = mv$(ty);
+ impl.m_methods.insert(::std::make_pair( RcString::new_interned("clone"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::std::move(fcn) } ));
+
+ // Add impl to the crate
+ auto& list = state.crate.m_trait_impls[state.lang_Clone].get_list_for_type_mut(impl.m_type);
+ list.push_back( box$(impl) );
+}
+
+void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list)
+{
+ if( TARGETVER_1_19 )
+ return ;
+
+ State state { crate, trans_list };
+
+ // Generate for all
+ for(const auto& ty : trans_list.auto_clone_impls)
+ {
+ state.done_list.insert( ty.clone() );
+ Trans_AutoImpl_Clone(state, ty.clone());
+ }
+
+ while( !state.todo_list.empty() )
+ {
+ auto ty = ::std::move(state.todo_list.front());
+ state.todo_list.pop_back();
+
+ Trans_AutoImpl_Clone(state, mv$(ty));
+ }
+
+ auto impl_list_it = crate.m_trait_impls.find(state.lang_Clone);
+ for(const auto& ty : state.done_list)
+ {
+ assert(impl_list_it != crate.m_trait_impls.end());
+ // TODO: Find a way of turning a set into a vector so items can be erased.
+
+ auto p = ::HIR::Path(ty.clone(), ::HIR::GenericPath(state.lang_Clone), "clone");
+ //DEBUG("add_function(" << p << ")");
+ auto e = trans_list.add_function(::std::move(p));
+
+ const auto* impl_list = impl_list_it->second.get_list_for_type(ty);
+ ASSERT_BUG(Span(), impl_list, "No impl list of Clone for " << ty);
+ auto& impl = **::std::find_if( impl_list->begin(), impl_list->end(), [&](const auto& i){ return i->m_type == ty; });
+ assert( impl.m_methods.size() == 1 );
+ e->ptr = &impl.m_methods.begin()->second.data;
+ }
+}
+
diff --git a/src/trans/codegen.cpp b/src/trans/codegen.cpp
index 9e93caba..3a75e623 100644
--- a/src/trans/codegen.cpp
+++ b/src/trans/codegen.cpp
@@ -15,19 +15,23 @@
#include "codegen.hpp"
#include "monomorphise.hpp"
-void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const ::HIR::Crate& crate, const TransList& list, bool is_executable)
+void Trans_Codegen(const ::std::string& outfile, CodegenOutput out_ty, const TransOptions& opt, const ::HIR::Crate& crate, const TransList& list, const ::std::string& hir_file)
{
static Span sp;
- ::std::unique_ptr<CodeGenerator> codegen;
+ ::std::unique_ptr<CodeGenerator> codegen;
if( opt.mode == "monomir" )
{
codegen = Trans_Codegen_GetGenerator_MonoMir(crate, outfile);
}
- else
+ else if( opt.mode == "c" )
{
codegen = Trans_Codegen_GetGeneratorC(crate, outfile);
}
+ else
+ {
+ BUG(sp, "Unknown codegen mode '" << opt.mode << "'");
+ }
// 1. Emit structure/type definitions.
// - Emit in the order they're needed.
@@ -43,6 +47,9 @@ void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const
TU_MATCHA( (te.binding), (tpb),
(Unbound, throw ""; ),
(Opaque, throw ""; ),
+ (ExternType,
+ //codegen->emit_extern_type(sp, te.path.m_data.as_Generic(), *tpb);
+ ),
(Struct,
codegen->emit_struct(sp, te.path.m_data.as_Generic(), *tpb);
),
@@ -186,6 +193,6 @@ void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const
}
}
- codegen->finalise(is_executable, opt);
+ codegen->finalise(opt, out_ty, hir_file);
}
diff --git a/src/trans/codegen.hpp b/src/trans/codegen.hpp
index b769e350..070e0232 100644
--- a/src/trans/codegen.hpp
+++ b/src/trans/codegen.hpp
@@ -27,7 +27,7 @@ class CodeGenerator
{
public:
virtual ~CodeGenerator() {}
- virtual void finalise(bool is_executable, const TransOptions& opt) {}
+ virtual void finalise(const TransOptions& opt, CodegenOutput out_ty, const ::std::string& hir_file) {}
// Called on all types directly mentioned (e.g. variables, arguments, and fields)
// - Inner-most types are visited first.
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
index 538c3bb2..631db28b 100644
--- a/src/trans/codegen_c.cpp
+++ b/src/trans/codegen_c.cpp
@@ -162,11 +162,6 @@ namespace {
class CodeGenerator_C:
public CodeGenerator
{
- enum class MetadataType {
- None,
- Slice,
- TraitObject,
- };
enum class Mode {
//FullStd,
Gcc, // Use GCC/Clang extensions
@@ -311,6 +306,19 @@ namespace {
<< "\treturn ((v&0xFFFFFFFF) == 0 ? __builtin_ctz(v>>32) + 32 : __builtin_ctz(v));\n"
<< "}\n"
;
+ // Atomic hackery
+ for(int sz = 8; sz <= 64; sz *= 2)
+ {
+ m_of
+ << "static inline uint"<<sz<<"_t __mrustc_atomicloop"<<sz<<"(volatile uint"<<sz<<"_t* slot, uint"<<sz<<"_t param, int ordering, uint"<<sz<<"_t (*cb)(uint"<<sz<<"_t, uint"<<sz<<"_t)) {"
+ << " int ordering_load = (ordering == memory_order_release || ordering == memory_order_acq_rel ? memory_order_relaxed : ordering);" // If Release, Load with Relaxed
+ << " for(;;) {"
+ << " uint"<<sz<<"_t v = atomic_load_explicit((_Atomic uint"<<sz<<"_t*)slot, ordering_load);"
+ << " if( atomic_compare_exchange_strong_explicit((_Atomic uint"<<sz<<"_t*)slot, &v, cb(v, param), ordering, ordering_load) ) return v;"
+ << " }"
+ << "}\n"
+ ;
+ }
break;
case Compiler::Msvc:
m_of
@@ -408,7 +416,20 @@ namespace {
<< "static inline uint8_t InterlockedExchangeNoFence8(volatile uint8_t* v, uint8_t n){ return InterlockedExchange8(v, n); }\n"
<< "static inline uint8_t InterlockedExchangeAcquire8(volatile uint8_t* v, uint8_t n){ return InterlockedExchange8(v, n); }\n"
<< "static inline uint8_t InterlockedExchangeRelease8(volatile uint8_t* v, uint8_t n){ return InterlockedExchange8(v, n); }\n"
+ << "static inline uint8_t InterlockedCompareExchange32(volatile uint32_t* v, uint32_t n, uint32_t e){ return InterlockedCompareExchange(v, n, e); }\n"
;
+ // Atomic hackery
+ for(int sz = 8; sz <= 64; sz *= 2)
+ {
+ m_of
+ << "static inline uint"<<sz<<"_t __mrustc_atomicloop"<<sz<<"(volatile uint"<<sz<<"_t* slot, uint"<<sz<<"_t param, uint"<<sz<<"_t (*cb)(uint"<<sz<<"_t, uint"<<sz<<"_t)) {"
+ << " for(;;) {"
+ << " uint"<<sz<<"_t v = InterlockedCompareExchange" << sz << "(slot, 0,0);"
+ << " if( InterlockedCompareExchange" << sz << "(slot, v, cb(v, param)) == v ) return v;"
+ << " }"
+ << "}\n"
+ ;
+ }
break;
}
@@ -567,12 +588,37 @@ namespace {
<< "\t}\n"
<< "\treturn SIZE_MAX;\n"
<< "}\n"
+ // Map of reversed nibbles 0 1 2 3 4 5 6 7 8 9 10 11 12 14 15
+ << "static const uint8_t __mrustc_revmap[16] = { 0, 8, 4,12, 2,10, 6,14, 1, 9, 5,13, 3, 7,15};\n"
+ << "static inline uint8_t __mrustc_bitrev8(uint8_t v) { if(v==0||v==0xFF) return v; return __mrustc_revmap[v>>4]|(__mrustc_revmap[v&15]<<4); }\n"
+ << "static inline uint16_t __mrustc_bitrev16(uint16_t v) { if(v==0) return 0; return ((uint16_t)__mrustc_bitrev8(v>>8))|((uint16_t)__mrustc_bitrev8(v)<<8); }\n"
+ << "static inline uint32_t __mrustc_bitrev32(uint32_t v) { if(v==0) return 0; return ((uint32_t)__mrustc_bitrev16(v>>16))|((uint32_t)__mrustc_bitrev16(v)<<16); }\n"
+ << "static inline uint64_t __mrustc_bitrev64(uint64_t v) { if(v==0) return 0; return ((uint64_t)__mrustc_bitrev32(v>>32))|((uint64_t)__mrustc_bitrev32(v)<<32); }\n"
+ // TODO: 128
;
+ if( m_options.emulated_i128 )
+ {
+ m_of << "static inline uint128_t __mrustc_bitrev128(uint128_t v) { uint128_t rv = { __mrustc_bitrev64(v.hi), __mrustc_bitrev64(v.lo) }; return rv; }\n";
+ }
+ else
+ {
+ m_of << "static inline uint128_t __mrustc_bitrev128(uint128_t v) { if(v==0) return 0; uint128_t rv = ((uint128_t)__mrustc_bitrev64(v>>64))|((uint128_t)__mrustc_bitrev64(v)<<64); }\n";
+ }
+ for(int sz = 8; sz <= 64; sz *= 2)
+ {
+ m_of
+ << "static inline uint"<<sz<<"_t __mrustc_op_umax"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return (a > b ? a : b); }\n"
+ << "static inline uint"<<sz<<"_t __mrustc_op_umin"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return (a < b ? a : b); }\n"
+ << "static inline uint"<<sz<<"_t __mrustc_op_imax"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return ((int"<<sz<<"_t)a > (int"<<sz<<"_t)b ? a : b); }\n"
+ << "static inline uint"<<sz<<"_t __mrustc_op_imin"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return ((int"<<sz<<"_t)a < (int"<<sz<<"_t)b ? a : b); }\n"
+ << "static inline uint"<<sz<<"_t __mrustc_op_and_not"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return ~(a & b); }\n"
+ ;
+ }
}
~CodeGenerator_C() {}
- void finalise(bool is_executable, const TransOptions& opt) override
+ void finalise(const TransOptions& opt, CodegenOutput out_ty, const ::std::string& hir_file) override
{
// Emit box drop glue after everything else to avoid definition ordering issues
for(auto& e : m_box_glue_todo)
@@ -580,9 +626,14 @@ namespace {
emit_box_drop_glue( mv$(e.first), *e.second );
}
- // TODO: Define this function in MIR.
- if( is_executable )
+ const bool create_shims = (out_ty == CodegenOutput::Executable);
+
+ // TODO: Support dynamic libraries too
+ // - No main, but has the rest.
+ // - Well... for cdylibs that's the case, for rdylibs it's not
+ if( out_ty == CodegenOutput::Executable )
{
+ // TODO: Define this function in MIR?
m_of << "int main(int argc, const char* argv[]) {\n";
auto c_start_path = m_resolve.m_crate.get_lang_item_path_opt("mrustc-start");
if( c_start_path == ::HIR::SimplePath() )
@@ -596,7 +647,11 @@ namespace {
m_of << "\treturn " << Trans_Mangle(::HIR::GenericPath(c_start_path)) << "(argc, argv);\n";
}
m_of << "}\n";
+ }
+ // Auto-generated code/items for the "root" rust binary (cdylib or executable)
+ if( create_shims )
+ {
if( m_compiler == Compiler::Gcc )
{
m_of
@@ -604,6 +659,95 @@ namespace {
<< "__thread void* mrustc_panic_value;\n"
;
}
+
+ // Allocator/panic shims
+ if( TARGETVER_1_29 )
+ {
+ const char* alloc_prefix = "__rdl_";
+ for(size_t i = 0; i < NUM_ALLOCATOR_METHODS; i++)
+ {
+ struct H {
+ static void ty_args(::std::vector<const char*>& out, AllocatorDataTy t) {
+ switch(t)
+ {
+ case AllocatorDataTy::Unit:
+ case AllocatorDataTy::ResultPtr: // (..., *mut i8) + *mut u8
+ throw "";
+ // - Args
+ case AllocatorDataTy::Layout: // usize, usize
+ out.push_back("uintptr_t");
+ out.push_back("uintptr_t");
+ break;
+ case AllocatorDataTy::Ptr: // *mut u8
+ out.push_back("int8_t*");
+ break;
+ case AllocatorDataTy::Usize:
+ out.push_back("uintptr_t");
+ break;
+ }
+ }
+ static const char* ty_ret(AllocatorDataTy t) {
+ switch(t)
+ {
+ case AllocatorDataTy::Unit:
+ return "void";
+ case AllocatorDataTy::ResultPtr: // (..., *mut i8) + *mut u8
+ return "int8_t*";
+ // - Args
+ case AllocatorDataTy::Layout: // usize, usize
+ case AllocatorDataTy::Ptr: // *mut u8
+ case AllocatorDataTy::Usize:
+ throw "";
+ }
+ throw "";
+ }
+ static void emit_proto(::std::ostream& os, const AllocatorMethod& method, const char* name_prefix, const ::std::vector<const char*>& args) {
+ os << H::ty_ret(method.ret) << " " << name_prefix << method.name << "(";
+ for(size_t j = 0; j < args.size(); j ++)
+ {
+ if( j != 0 )
+ os << ", ";
+ os << args[j] << " a" << j;
+ }
+ os << ")";
+ }
+ };
+ const auto& method = ALLOCATOR_METHODS[i];
+ ::std::vector<const char*> args;
+ for(size_t j = 0; j < method.n_args; j ++)
+ H::ty_args(args, method.args[j]);
+ H::emit_proto(m_of, method, "__rust_", args); m_of << " {\n";
+ m_of << "\textern "; H::emit_proto(m_of, method, alloc_prefix, args); m_of << ";\n";
+ m_of << "\treturn " << alloc_prefix << method.name << "(";
+ for(size_t j = 0; j < args.size(); j ++)
+ {
+ if( j != 0 )
+ m_of << ", ";
+ m_of << "a" << j;
+ }
+ m_of << ");\n";
+ m_of << "}\n";
+ }
+
+ // Bind `panic_impl` lang item to the item tagged with `panic_implementation`
+ m_of << "uint32_t panic_impl(uintptr_t payload) {";
+ const auto& panic_impl_path = m_crate.get_lang_item_path(Span(), "mrustc-panic_implementation");
+ m_of << "extern uint32_t " << Trans_Mangle(panic_impl_path) << "(uintptr_t payload);";
+ m_of << "return " << Trans_Mangle(panic_impl_path) << "(payload);";
+ m_of << "}\n";
+
+ // TODO: Bind `oom` lang item to the item tagged with `alloc_error_handler`
+ // - Can do this in enumerate/auto_impls instead, for better iteraction with enum
+ // XXX: HACK HACK HACK - This only works with libcore/libstd's current layout
+ auto layout_path = ::HIR::SimplePath("core", {"alloc", "Layout"});
+ auto oom_method = ::HIR::SimplePath("std", {"alloc", "rust_oom"});
+ m_of << "struct s_" << Trans_Mangle(layout_path) << "_A { uintptr_t a, b; };\n";
+ m_of << "void oom_impl(struct s_" << Trans_Mangle(layout_path) << "_A l) {"
+ << " extern void " << Trans_Mangle(oom_method) << "(struct s_" << Trans_Mangle(layout_path) << "_A l);"
+ << " " << Trans_Mangle(oom_method) << "(l);"
+ << " }\n"
+ ;
+ }
}
m_of.flush();
@@ -676,14 +820,65 @@ namespace {
{
args.push_back("-g");
}
+ args.push_back("-fPIC");
args.push_back("-o");
- args.push_back(m_outfile_path.c_str());
+ switch(out_ty)
+ {
+ case CodegenOutput::DynamicLibrary:
+ case CodegenOutput::Executable:
+ case CodegenOutput::Object:
+ args.push_back(m_outfile_path .c_str());
+ break;
+ case CodegenOutput::StaticLibrary:
+ args.push_back(m_outfile_path+".o");
+ break;
+ }
args.push_back(m_outfile_path_c.c_str());
- if( is_executable )
+ switch(out_ty)
{
+ case CodegenOutput::DynamicLibrary:
+ args.push_back("-shared");
+ case CodegenOutput::Executable:
for( const auto& crate : m_crate.m_ext_crates )
{
- args.push_back(crate.second.m_path + ".o");
+ auto is_dylib = [](const ::HIR::ExternCrate& c) {
+ bool rv = false;
+ // TODO: Better rule than this
+ rv |= (c.m_path.compare(c.m_path.size() - 3, 3, ".so") == 0);
+ rv |= (c.m_path.compare(c.m_path.size() - 4, 4, ".dll") == 0);
+ return rv;
+ };
+ // If this crate is included in a dylib crate, ignore it
+ bool is_in_dylib = false;
+ for( const auto& crate2 : m_crate.m_ext_crates )
+ {
+ if( is_dylib(crate2.second) )
+ {
+ for(const auto& subcrate : crate2.second.m_data->m_ext_crates)
+ {
+ if( subcrate.second.m_path == crate.second.m_path ) {
+ DEBUG(crate.first << " referenced by dylib " << crate2.first);
+ is_in_dylib = true;
+ }
+ }
+ }
+ if( is_in_dylib )
+ break;
+ }
+ // NOTE: Only exclude non-dylibs referenced by other dylibs
+ if( is_in_dylib && !is_dylib(crate.second) ) {
+ }
+ else if( crate.second.m_path.compare(crate.second.m_path.size() - 5, 5, ".rlib") == 0 ) {
+ args.push_back(crate.second.m_path + ".o");
+ }
+ else if( is_dylib(crate.second) ) {
+ // TODO: Get the dir and base name (strip `lib` and `.so` off)
+ // and emit -L/-Wl,-rpath if that path isn't already emitted.
+ args.push_back(crate.second.m_path);
+ }
+ else {
+ // Proc macro.
+ }
}
for(const auto& path : link_dirs )
{
@@ -708,10 +903,12 @@ namespace {
{
args.push_back( a.c_str() );
}
- }
- else
- {
+ // TODO: Include the HIR file as a magic object?
+ break;
+ case CodegenOutput::StaticLibrary:
+ case CodegenOutput::Object:
args.push_back("-c");
+ break;
}
break;
case Compiler::Msvc:
@@ -738,13 +935,27 @@ namespace {
args.push_back("/DEBUG");
args.push_back("/Zi");
}
- if(is_executable)
+ switch(out_ty)
{
+ case CodegenOutput::Executable:
+ case CodegenOutput::DynamicLibrary:
args.push_back(FMT("/Fe" << m_outfile_path));
+ switch(out_ty)
+ {
+ case CodegenOutput::Executable:
+ args.push_back("/link");
+ break;
+ case CodegenOutput::DynamicLibrary:
+ args.push_back("/LD");
+ break;
+ default:
+ throw "bug";
+ }
+
for( const auto& crate : m_crate.m_ext_crates )
{
- args.push_back(crate.second.m_path + ".o");
+ args.push_back(crate.second.m_path + ".obj");
}
// Crate-specified libraries
for(const auto& lib : m_crate.m_ext_libs) {
@@ -764,18 +975,20 @@ namespace {
}
args.push_back("kernel32.lib"); // Needed for Interlocked*
- args.push_back("/link");
-
// Command-line specified linker search directories
for(const auto& path : link_dirs )
{
args.push_back(FMT("/LIBPATH:" << path));
}
- }
- else
- {
+ break;
+ case CodegenOutput::StaticLibrary:
+ args.push_back("/c");
+ args.push_back(FMT("/Fo" << m_outfile_path << ".obj"));
+ break;
+ case CodegenOutput::Object:
args.push_back("/c");
args.push_back(FMT("/Fo" << m_outfile_path));
+ break;
}
break;
}
@@ -820,8 +1033,45 @@ namespace {
exit(1);
}
}
+
+ // HACK! Static libraries aren't implemented properly yet, just touch the output file
+ if( out_ty == CodegenOutput::StaticLibrary )
+ {
+ ::std::ofstream of( m_outfile_path );
+ if( !of.good() )
+ {
+ // TODO: Error?
+ }
+ }
}
+ void emit_box_drop(unsigned indent_level, const ::HIR::TypeRef& inner_type, const ::MIR::LValue& slot, bool run_destructor)
+ {
+ auto indent = RepeatLitStr { "\t", static_cast<int>(indent_level) };
+ // Emit a call to box_free for the type
+ if( run_destructor )
+ {
+ auto inner_ptr =
+ ::MIR::LValue::new_Field(
+ ::MIR::LValue::new_Field(
+ ::MIR::LValue::new_Field(
+ slot.clone()
+ ,0)
+ ,0)
+ ,0)
+ ;
+ emit_destructor_call( ::MIR::LValue::new_Deref(mv$(inner_ptr)), inner_type, true, indent_level );
+ }
+ // TODO: This is specific to the official liballoc's owned_box
+ ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { inner_type.clone() } };
+ if( TARGETVER_1_29 ) {
+ // In 1.29, `box_free` takes Unique, so pass the Unique within the Box
+ m_of << indent << Trans_Mangle(box_free) << "("; emit_lvalue(slot); m_of << "._0);\n";
+ }
+ else {
+ m_of << indent << Trans_Mangle(box_free) << "("; emit_lvalue(slot); m_of << "._0._0._0);\n";
+ }
+ }
void emit_box_drop_glue(::HIR::GenericPath p, const ::HIR::Struct& item)
{
auto struct_ty = ::HIR::TypeRef( p.clone(), &item );
@@ -841,13 +1091,7 @@ namespace {
m_mir_res = &mir_res;
m_of << "static void " << Trans_Mangle(drop_glue_path) << "(struct s_" << Trans_Mangle(p) << "* rv) {\n";
- // Obtain inner pointer
- // TODO: This is very specific to the structure of the official liballoc's Box.
- m_of << "\t"; emit_ctype(args[0].second, FMT_CB(ss, ss << "arg0"; )); m_of << " = rv->_0._0._0;\n";
- // Call destructor of inner data
- emit_destructor_call( ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) }), *ity, true, 1);
- // Emit a call to box_free for the type
- m_of << "\t" << Trans_Mangle(box_free) << "(arg0);\n";
+ emit_box_drop(1, *ity, ::MIR::LValue::new_Deref(::MIR::LValue::new_Return()), /*run_destructor=*/true);
m_of << "}\n";
m_mir_res = nullptr;
@@ -887,6 +1131,9 @@ namespace {
(Struct,
m_of << "struct s_" << Trans_Mangle(te.path) << ";\n";
),
+ (ExternType,
+ m_of << "struct x_" << Trans_Mangle(te.path) << ";\n";
+ ),
(Union,
m_of << "union u_" << Trans_Mangle(te.path) << ";\n";
),
@@ -990,13 +1237,13 @@ namespace {
m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(ty); m_of << "* rv) {\n";
if( m_resolve.type_needs_drop_glue(sp, ty) )
{
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ auto self = ::MIR::LValue::new_Deref(::MIR::LValue::new_Return());
+ auto fld_lv = ::MIR::LValue::new_Field(mv$(self), 0);
for(const auto& ity : te)
{
// TODO: What if it's a ZST?
emit_destructor_call(fld_lv, ity, /*unsized_valid=*/false, 1);
- fld_lv.as_Field().field_index ++;
+ fld_lv.inc_Field();
}
}
m_of << "}\n";
@@ -1034,11 +1281,13 @@ namespace {
::MIR::Function empty_fcn;
::MIR::TypeResolve top_mir_res { sp, m_resolve, FMT_CB(ss, ss << "struct " << p;), ::HIR::TypeRef(), {}, empty_fcn };
m_mir_res = &top_mir_res;
+ // TODO: repr(transparent) and repr(align(foo))
bool is_packed = item.m_repr == ::HIR::Struct::Repr::Packed;
TRACE_FUNCTION_F(p);
auto item_ty = ::HIR::TypeRef::new_path(p.clone(), &item);
const auto* repr = Target_GetTypeRepr(sp, m_resolve, item_ty);
+ MIR_ASSERT(*m_mir_res, repr, "No repr for struct " << p);
::std::vector<unsigned> fields;
for(const auto& ent : repr->fields)
@@ -1165,7 +1414,15 @@ namespace {
// - Drop Glue
::std::vector< ::std::pair<::HIR::Pattern,::HIR::TypeRef> > args;
- if( item.m_markings.has_drop_impl ) {
+ // NOTE: 1.29 has Box impl Drop, but as a no-op - override that here.
+ // - TODO: This override/definition should be done by the caller
+ if( m_resolve.is_type_owned_box(struct_ty) )
+ {
+ m_box_glue_todo.push_back( ::std::make_pair( mv$(struct_ty.m_data.as_Path().path.m_data.as_Generic()), &item ) );
+ m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ");\n";
+ return ;
+ }
+ else if( item.m_markings.has_drop_impl ) {
// If the type is defined outside the current crate, define as static (to avoid conflicts when we define it)
if( p.m_path.m_crate_name != m_crate.m_crate_name )
{
@@ -1178,11 +1435,8 @@ namespace {
}
m_of << "void " << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ");\n";
}
- else if( m_resolve.is_type_owned_box(struct_ty) )
- {
- m_box_glue_todo.push_back( ::std::make_pair( mv$(struct_ty.m_data.as_Path().path.m_data.as_Generic()), &item ) );
- m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ");\n";
- return ;
+ else {
+ // No drop impl (magic or no)
}
::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, args, empty_fcn };
@@ -1195,13 +1449,12 @@ namespace {
m_of << "\t" << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "(rv);\n";
}
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ auto self = ::MIR::LValue::new_Deref(::MIR::LValue::new_Return());
+ auto fld_lv = ::MIR::LValue::new_Field(mv$(self), 0);
for(size_t i = 0; i < repr->fields.size(); i++)
{
- fld_lv.as_Field().field_index = i;
-
emit_destructor_call(fld_lv, repr->fields[i].ty, /*unsized_valid=*/true, /*indent=*/1);
+ fld_lv.inc_Field();
}
}
m_of << "}\n";
@@ -1439,14 +1692,14 @@ namespace {
{
m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n";
}
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
+ auto self = ::MIR::LValue::new_Deref(::MIR::LValue::new_Return());
if( const auto* e = repr->variants.opt_NonZero() )
{
unsigned idx = 1 - e->zero_variant;
// TODO: Fat pointers?
m_of << "\tif( (*rv)"; emit_enum_path(repr, e->field); m_of << " != 0 ) {\n";
- emit_destructor_call( ::MIR::LValue::make_Downcast({ box$(self), idx }), repr->fields[idx].ty, false, 2 );
+ emit_destructor_call( ::MIR::LValue::new_Downcast(mv$(self), idx), repr->fields[idx].ty, false, 2 );
m_of << "\t}\n";
}
else if( repr->fields.size() <= 1 )
@@ -1456,15 +1709,15 @@ namespace {
}
else if( const auto* e = repr->variants.opt_Values() )
{
- auto var_lv =::MIR::LValue::make_Downcast({ box$(self), 0 });
+ auto var_lv =::MIR::LValue::new_Downcast(mv$(self), 0);
m_of << "\tswitch(rv->TAG) {\n";
for(unsigned int var_idx = 0; var_idx < e->values.size(); var_idx ++)
{
- var_lv.as_Downcast().variant_index = var_idx;
m_of << "\tcase " << e->values[var_idx] << ":\n";
emit_destructor_call(var_lv, repr->fields[var_idx].ty, /*unsized_valid=*/false, /*indent=*/2);
m_of << "\t\tbreak;\n";
+ var_lv.inc_Downcast();
}
m_of << "\t}\n";
}
@@ -1621,7 +1874,7 @@ namespace {
// Handled with asm() later
break;
case Compiler::Msvc:
- //m_of << "#pragma comment(linker, \"/alternatename:_" << Trans_Mangle(p) << "=" << item.m_linkage.name << "\")\n";
+ //m_of << "#pragma comment(linker, \"/alternatename:" << Trans_Mangle(p) << "=" << item.m_linkage.name << "\")\n";
m_of << "#define " << Trans_Mangle(p) << " " << item.m_linkage.name << "\n";
break;
//case Compiler::Std11:
@@ -1710,6 +1963,7 @@ namespace {
TU_MATCHA((te.binding), (pbe),
(Unbound, MIR_BUG(*m_mir_res, "Unbound type path " << ty); ),
(Opaque, MIR_BUG(*m_mir_res, "Opaque type path " << ty); ),
+ (ExternType, MIR_BUG(*m_mir_res, "Extern type literal " << ty); ),
(Struct,
TU_MATCHA( (pbe->m_data), (se),
(Unit,
@@ -1743,6 +1997,9 @@ namespace {
};
TU_MATCHA( (lit), (e),
(Invalid, m_of << "/* INVALID */"; ),
+ (Defer,
+ MIR_BUG(*m_mir_res, "Defer literal encountered");
+ ),
(List,
m_of << "{";
if( ty.m_data.is_Array() )
@@ -1835,10 +2092,10 @@ namespace {
break;
case ::HIR::CoreType::U64:
case ::HIR::CoreType::Usize:
- m_of << ::std::hex << "0x" << e << ::std::dec;
+ m_of << ::std::hex << "0x" << e << "ull" << ::std::dec;
break;
case ::HIR::CoreType::U128:
- m_of << ::std::hex << "0x" << e << ::std::dec;
+ m_of << ::std::hex << "0x" << e << "ull" << ::std::dec;
break;
case ::HIR::CoreType::I8:
m_of << static_cast<uint16_t>( static_cast<int8_t>(e) );
@@ -1852,7 +2109,7 @@ namespace {
case ::HIR::CoreType::I64:
case ::HIR::CoreType::I128:
case ::HIR::CoreType::Isize:
- m_of << static_cast<int64_t>(e);
+ m_of << static_cast<int64_t>(e) << "ll";
break;
case ::HIR::CoreType::Char:
assert(0 <= e && e <= 0x10FFFF);
@@ -2052,8 +2309,7 @@ namespace {
}
{
- auto vtable_sp = trait_path.m_path;
- vtable_sp.m_components.back() += "#vtable";
+ const auto& vtable_sp = trait.m_vtable_path;
auto vtable_params = trait_path.m_params.clone();
for(const auto& ty : trait.m_type_indexes) {
auto aty = ::HIR::TypeRef( ::HIR::Path( type.clone(), trait_path.clone(), ty.first ) );
@@ -2089,8 +2345,13 @@ namespace {
{
m_of << "\t""(void*)" << Trans_Mangle(::HIR::Path(type.clone(), "#drop_glue")) << ",\n";
}
- m_of << "\t""sizeof("; emit_ctype(type); m_of << "),\n";
- m_of << "\t""ALIGNOF("; emit_ctype(type); m_of << "),\n";
+
+ {
+ size_t size, align;
+ // NOTE: Uses the Size+Align version because that doesn't panic on unsized
+ MIR_ASSERT(*m_mir_res, Target_GetSizeAndAlignOf(sp, m_resolve, type, size, align), "Unexpected generic? " << type);
+ m_of << "\t" << size << ", " << align << ",\n";
+ }
for(unsigned int i = 0; i < trait.m_value_indexes.size(); i ++ )
{
@@ -2123,9 +2384,19 @@ namespace {
m_of << "// EXTERN extern \"" << item.m_abi << "\" " << p << "\n";
// For MSVC, make a static wrapper that goes and calls the actual function
- if( item.m_linkage.name != "" && m_compiler == Compiler::Msvc )
+ if( item.m_linkage.name.rfind("llvm.", 0) == 0 )
{
m_of << "static ";
+ emit_function_header(p, item, params);
+ // TODO: Hand off to compiler-specific intrinsics
+ m_of << " { abort(); }\n";
+ m_mir_res = nullptr;
+ return ;
+ }
+ else if( item.m_linkage.name != "" && m_compiler == Compiler::Msvc )
+ {
+ m_of << "#pragma comment(linker, \"/alternatename:" << Trans_Mangle(p) << "=" << item.m_linkage.name << "\")\n";
+ m_of << "extern ";
}
else if( item.m_linkage.name == "_Unwind_RaiseException" )
{
@@ -2153,48 +2424,6 @@ namespace {
m_of << " asm(\"" << item.m_linkage.name << "\")";
break;
case Compiler::Msvc:
- m_of << " {\n";
- // A few hacky hard-coded signatures
- if( item.m_linkage.name == "SetFilePointerEx" )
- {
- // LARGE_INTEGER
- m_of << "\tLARGE_INTEGER arg1_v;\n";
- m_of << "\targ1_v.QuadPart = arg1;\n";
- m_of << "\treturn SetFilePointerEx(arg0, arg1_v, arg2, arg3);\n";
- }
- else if( item.m_linkage.name == "CopyFileExW" )
- {
- // Not field access to undo an Option<fn()>
- m_of << "\treturn CopyFileExW(arg0, arg1, arg2.DATA.var_1._0, arg3, arg4, arg5);\n";
- }
- // BUG: libtest defines this as returning an i32, but it's void
- else if( item.m_linkage.name == "GetSystemInfo" )
- {
- m_of << "\tGetSystemInfo(arg0);\n";
- m_of << "\treturn 0;\n";
- }
- else
- {
- m_of << "\t";
- if( TU_TEST1(item.m_return.m_data, Tuple, .size() == 0) )
- ;
- else if( item.m_return.m_data.is_Diverge() )
- ;
- else {
- m_of << "return ";
- if( item.m_return.m_data.is_Pointer() )
- m_of << "(void*)";
- }
- m_of << item.m_linkage.name << "(";
- for(size_t i = 0; i < item.m_args.size(); i ++ )
- {
- if( i > 0 )
- m_of << ", ";
- m_of << "arg" << i;
- }
- m_of << ");\n";
- }
- m_of << "}";
break;
}
}
@@ -2212,6 +2441,7 @@ namespace {
m_of << "// PROTO extern \"" << item.m_abi << "\" " << p << "\n";
if( item.m_linkage.name != "" )
{
+ // If this function is implementing an external ABI, just rename it (don't bother with per-compiler trickery).
m_of << "#define " << Trans_Mangle(p) << " " << item.m_linkage.name << "\n";
}
if( is_extern_def )
@@ -2693,10 +2923,7 @@ namespace {
// Shallow drops are only valid on owned_box
if( const auto* ity = m_resolve.is_type_owned_box(ty) )
{
- // Emit a call to box_free for the type
- ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { ity->clone() } };
- // TODO: This is specific to the official liballoc's owned_box
- m_of << indent << Trans_Mangle(box_free) << "("; emit_lvalue(e.slot); m_of << "._0._0._0);\n";
+ emit_box_drop(1, *ity, e.slot, /*run_destructor=*/false);
}
else
{
@@ -2709,6 +2936,7 @@ namespace {
}
if( e.flag_idx != ~0u )
m_of << indent << "}\n";
+ m_of << indent << "// ^ " << stmt << "\n";
break; }
case ::MIR::Statement::TAG_Asm:
switch(m_compiler)
@@ -2728,14 +2956,14 @@ namespace {
::HIR::TypeRef tmp;
const auto& ty = mir_res.get_lvalue_type(tmp, e.dst);
- if( e.dst.is_Deref() && this->type_is_bad_zst(ty) )
+ if( /*(e.dst.is_Deref() || e.dst.is_Field()) &&*/ this->type_is_bad_zst(ty) )
{
- m_of << "/* ZST deref */";
+ m_of << "/* ZST assign */\n";
break;
}
- TU_MATCHA( (e.src), (ve),
- (Use,
+ TU_MATCH_HDRA( (e.src), {)
+ TU_ARMA(Use, ve) {
::HIR::TypeRef tmp;
const auto& ty = mir_res.get_lvalue_type(tmp, ve);
if( ty == ::HIR::TypeRef::new_diverge() ) {
@@ -2752,13 +2980,13 @@ namespace {
emit_lvalue(e.dst);
m_of << " = ";
emit_lvalue(ve);
- ),
- (Constant,
+ }
+ TU_ARMA(Constant, ve) {
emit_lvalue(e.dst);
m_of << " = ";
emit_constant(ve, &e.dst);
- ),
- (SizedArray,
+ }
+ TU_ARMA(SizedArray, ve) {
if( ve.count == 0 ) {
}
else if( ve.count == 1 ) {
@@ -2777,34 +3005,35 @@ namespace {
m_of << "for(unsigned int i = 0; i < " << ve.count << "; i ++)\n";
m_of << indent << "\t"; emit_lvalue(e.dst); m_of << ".DATA[i] = "; emit_param(ve.val);
}
- ),
- (Borrow,
+ }
+ TU_ARMA(Borrow, ve) {
::HIR::TypeRef tmp;
const auto& ty = mir_res.get_lvalue_type(tmp, ve.val);
bool special = false;
// If the inner value was a deref, just copy the pointer verbatim
- TU_IFLET(::MIR::LValue, ve.val, Deref, le,
+ if( ve.val.is_Deref() )
+ {
emit_lvalue(e.dst);
m_of << " = ";
- emit_lvalue(*le.val);
+ emit_lvalue( ::MIR::LValue::CRef(ve.val).inner_ref() );
special = true;
- )
+ }
// Magic for taking a &-ptr to unsized field of a struct.
// - Needs to get metadata from bottom-level pointer.
- else TU_IFLET(::MIR::LValue, ve.val, Field, le,
+ else if( ve.val.is_Field() ) {
if( metadata_type(ty) != MetadataType::None ) {
- const ::MIR::LValue* base_val = &*le.val;
- while(base_val->is_Field())
- base_val = &*base_val->as_Field().val;
- MIR_ASSERT(mir_res, base_val->is_Deref(), "DST access must be via a deref");
- const ::MIR::LValue& base_ptr = *base_val->as_Deref().val;
+ auto base_val = ::MIR::LValue::CRef(ve.val).inner_ref();
+ while(base_val.is_Field())
+ base_val.try_unwrap();
+ MIR_ASSERT(mir_res, base_val.is_Deref(), "DST access must be via a deref");
+ const auto base_ptr = base_val.inner_ref();
// Construct the new DST
emit_lvalue(e.dst); m_of << ".META = "; emit_lvalue(base_ptr); m_of << ".META;\n" << indent;
emit_lvalue(e.dst); m_of << ".PTR = &"; emit_lvalue(ve.val);
special = true;
}
- )
+ }
else {
}
@@ -2813,50 +3042,55 @@ namespace {
if( !special && m_options.disallow_empty_structs && ve.val.is_Field() && this->type_is_bad_zst(ty) )
{
// Work backwards to the first non-ZST field
- const auto* val_fp = &ve.val.as_Field();
- while( val_fp->val->is_Field() )
+ auto val_fp = ::MIR::LValue::CRef(ve.val);
+ assert(val_fp.is_Field());
+ while( val_fp.inner_ref().is_Field() )
{
::HIR::TypeRef tmp;
- const auto& ty = mir_res.get_lvalue_type(tmp, *val_fp->val);
+ const auto& ty = mir_res.get_lvalue_type(tmp, val_fp.inner_ref());
if( !this->type_is_bad_zst(ty) )
break;
+ val_fp.try_unwrap();
}
+ assert(val_fp.is_Field());
// Here, we have `val_fp` be a LValue::Field that refers to a ZST, but the inner of the field points to a non-ZST or a local
emit_lvalue(e.dst);
m_of << " = ";
// If the index is zero, then the best option is to borrow the source
- if( val_fp->val->is_Downcast() )
+ auto field_inner = val_fp.inner_ref();
+ if( field_inner.is_Downcast() )
{
- m_of << "(void*)& "; emit_lvalue(*val_fp->val->as_Downcast().val);
+ m_of << "(void*)& "; emit_lvalue(field_inner.inner_ref());
}
- else if( val_fp->field_index == 0 )
+ else if( val_fp.as_Field() == 0 )
{
- m_of << "(void*)& "; emit_lvalue(*val_fp->val);
+ m_of << "(void*)& "; emit_lvalue(field_inner);
}
else
{
::HIR::TypeRef tmp;
- auto tmp_lv = ::MIR::LValue::make_Field({ box$(val_fp->val->clone()), val_fp->field_index - 1 });
+ auto tmp_lv = ::MIR::LValue::new_Field( field_inner.clone(), val_fp.as_Field() - 1 );
bool use_parent = false;
for(;;)
{
const auto& ty = mir_res.get_lvalue_type(tmp, tmp_lv);
if( !this->type_is_bad_zst(ty) )
break;
- if( tmp_lv.as_Field().field_index == 0 )
+ auto idx = tmp_lv.as_Field();
+ if( idx == 0 )
{
use_parent = true;
break;
}
- tmp_lv.as_Field().field_index -= 1;
+ tmp_lv.m_wrappers.back() = ::MIR::LValue::Wrapper::new_Field(idx - 1);
}
// Reached index zero, with still ZST
if( use_parent )
{
- m_of << "(void*)& "; emit_lvalue(*val_fp->val);
+ m_of << "(void*)& "; emit_lvalue(field_inner);
}
// Use the address after the previous item
else
@@ -2873,11 +3107,11 @@ namespace {
m_of << " = ";
m_of << "& "; emit_lvalue(ve.val);
}
- ),
- (Cast,
+ }
+ TU_ARMA(Cast, ve) {
emit_rvalue_cast(mir_res, e.dst, ve);
- ),
- (BinOp,
+ }
+ TU_ARMA(BinOp, ve) {
emit_lvalue(e.dst);
m_of << " = ";
::HIR::TypeRef tmp, tmp_r;
@@ -3028,8 +3262,8 @@ namespace {
{
m_of << ".lo";
}
- ),
- (UniOp,
+ }
+ TU_ARMA(UniOp, ve) {
::HIR::TypeRef tmp;
const auto& ty = mir_res.get_lvalue_type(tmp, e.dst);
@@ -3064,24 +3298,24 @@ namespace {
break;
}
emit_lvalue(ve.val);
- ),
- (DstMeta,
+ }
+ TU_ARMA(DstMeta, ve) {
emit_lvalue(e.dst);
m_of << " = ";
emit_lvalue(ve.val);
m_of << ".META";
- ),
- (DstPtr,
+ }
+ TU_ARMA(DstPtr, ve) {
emit_lvalue(e.dst);
m_of << " = ";
emit_lvalue(ve.val);
m_of << ".PTR";
- ),
- (MakeDst,
+ }
+ TU_ARMA(MakeDst, ve) {
emit_lvalue(e.dst); m_of << ".PTR = "; emit_param(ve.ptr_val); m_of << ";\n" << indent;
emit_lvalue(e.dst); m_of << ".META = "; emit_param(ve.meta_val);
- ),
- (Tuple,
+ }
+ TU_ARMA(Tuple, ve) {
bool has_emitted = false;
for(unsigned int j = 0; j < ve.vals.size(); j ++)
{
@@ -3105,15 +3339,15 @@ namespace {
m_of << "._" << j << " = ";
emit_param(ve.vals[j]);
}
- ),
- (Array,
+ }
+ TU_ARMA(Array, ve) {
for(unsigned int j = 0; j < ve.vals.size(); j ++) {
if( j != 0 ) m_of << ";\n" << indent;
emit_lvalue(e.dst); m_of << ".DATA[" << j << "] = ";
emit_param(ve.vals[j]);
}
- ),
- (Variant,
+ }
+ TU_ARMA(Variant, ve) {
const auto& tyi = m_crate.get_typeitem_by_path(sp, ve.path.m_path);
if( tyi.is_Union() )
{
@@ -3170,8 +3404,8 @@ namespace {
{
BUG(mir_res.sp, "Unexpected type in Variant");
}
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, ve) {
if( ve.vals.empty() )
{
if( m_options.disallow_empty_structs )
@@ -3209,8 +3443,8 @@ namespace {
emit_param(ve.vals[j]);
}
}
- )
- )
+ }
+ }
m_of << ";";
m_of << "\t// " << e.dst << " = " << e.src;
m_of << "\n";
@@ -3577,6 +3811,11 @@ namespace {
{
omit_assign = true;
}
+
+ if( this->type_is_bad_zst( m_mir_res->get_lvalue_type(tmp, e.ret_val) ) )
+ {
+ omit_assign = true;
+ }
}
TU_MATCHA( (e.fcn), (e2),
@@ -3775,41 +4014,133 @@ namespace {
{
auto indent = RepeatLitStr{ "\t", static_cast<int>(indent_level) };
- if( e.tpl == "fnstcw $0" )
+ struct H {
+ static bool check_list(const std::vector<std::pair<std::string, MIR::LValue>>& have, const ::std::initializer_list<const char*>& exp)
+ {
+ if( have.size() != exp.size() )
+ return false;
+ auto h_it = have.begin();
+ auto e_it = exp.begin();
+ for(; h_it != have.end(); ++ h_it, ++e_it)
+ {
+ if( h_it->first != *e_it )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+ auto matches_template = [&e,&mir_res](const char* tpl, ::std::initializer_list<const char*> inputs, ::std::initializer_list<const char*> outputs)->bool {
+ if( e.tpl == tpl )
+ {
+ if( !H::check_list(e.inputs, inputs) || !H::check_list(e.outputs, outputs) )
+ {
+ MIR_BUG(mir_res, "Hard-coded asm translation doesn't apply - `" << e.tpl << "` inputs=" << e.inputs << " outputs=" << e.outputs);
+ }
+ return true;
+ }
+ return false;
+ };
+
+ if( matches_template("fnstcw $0", /*input=*/{}, /*output=*/{"*m"}) )
{
// HARD CODE: `fnstcw` -> _control87
- if( !(e.inputs.size() == 0 && e.outputs.size() == 1 && e.outputs[0].first == "=*m") )
- MIR_BUG(mir_res, "Hard-coded asm translation doesn't apply - `" << e.tpl << "` inputs=" << e.inputs << " outputs=" << e.outputs);
m_of << indent << "*("; emit_lvalue(e.outputs[0].second); m_of << ") = _control87(0,0);\n";
return ;
}
- else if( e.tpl == "fldcw $0" )
+ else if( matches_template("fldcw $0", /*input=*/{"m"}, /*output=*/{}) )
{
// HARD CODE: `fldcw` -> _control87
- if( !(e.inputs.size() == 1 && e.inputs[0].first == "m" && e.outputs.size() == 0) )
- MIR_BUG(mir_res, "Hard-coded asm translation doesn't apply - `" << e.tpl << "` inputs=" << e.inputs << " outputs=" << e.outputs);
m_of << indent << "_control87("; emit_lvalue(e.inputs[0].second); m_of << ", 0xFFFF);\n";
return ;
}
- else if( e.tpl == "int $$0x29" )
+ else if( matches_template("int $$0x29", /*input=*/{"{ecx}"}, /*output=*/{}) )
{
- if( !(e.inputs.size() == 1 && e.inputs[0].first == "{ecx}" && e.outputs.size() == 0) )
- MIR_BUG(mir_res, "Hard-coded asm translation doesn't apply - `" << e.tpl << "` inputs=" << e.inputs << " outputs=" << e.outputs);
m_of << indent << "__fastfail("; emit_lvalue(e.inputs[0].second); m_of << ");\n";
return ;
}
- else if( e.tpl == "pause" )
+ else if( matches_template("pause", /*input=*/{}, /*output=*/{}) )
{
- if( !(e.inputs.size() == 0 && e.outputs.size() == 0) )
- MIR_BUG(mir_res, "Hard-coded asm translation doesn't apply - `" << e.tpl << "` inputs=" << e.inputs << " outputs=" << e.outputs);
m_of << indent << "_mm_pause();\n";
return ;
}
+ else if( matches_template("cpuid\n", /*input=*/{"{eax}", "{ecx}"}, /*output=*/{"={eax}", "={ebx}", "={ecx}", "={edx}"}) )
+ {
+ m_of << indent << "{";
+ m_of << " int cpuid_out[4];";
+ m_of << " __cpuidex(cpuid_out, "; emit_lvalue(e.inputs[0].second); m_of << ", "; emit_lvalue(e.inputs[1].second); m_of << ");";
+ m_of << " "; emit_lvalue(e.outputs[0].second); m_of << " = cpuid_out[0];";
+ m_of << " "; emit_lvalue(e.outputs[1].second); m_of << " = cpuid_out[1];";
+ m_of << " "; emit_lvalue(e.outputs[2].second); m_of << " = cpuid_out[2];";
+ m_of << " "; emit_lvalue(e.outputs[3].second); m_of << " = cpuid_out[3];";
+ m_of << " }\n";
+ return ;
+ }
+ else if( matches_template("pushfq; popq $0", /*input=*/{}, /*output=*/{"=r"}) )
+ {
+ m_of << indent; emit_lvalue(e.outputs[0].second); m_of << " = __readeflags();\n";
+ return ;
+ }
+ else if( matches_template("pushq $0; popfq", /*input=*/{"r"}, /*output=*/{}) )
+ {
+ m_of << indent << "__writeeflags("; emit_lvalue(e.inputs[0].second); m_of << ");\n";
+ return ;
+ }
+ else if( matches_template("xgetbv", /*input=*/{"{ecx}"}, /*output=*/{"={eax}", "={edx}"}) )
+ {
+ m_of << indent << "{";
+ m_of << " unsigned __int64 v = _xgetbv("; emit_lvalue(e.inputs[0].second); m_of << ");";
+ m_of << " "; emit_lvalue(e.outputs[0].second); m_of << " = (uint32_t)(v & 0xFFFFFFFF);";
+ m_of << " "; emit_lvalue(e.outputs[1].second); m_of << " = (uint32_t)(v >> 32);";
+ m_of << " }\n";
+ return ;
+ }
+ // parking_lot src/elision.rs
+ else if( matches_template("xacquire; lock; cmpxchgl $2, $1", /*input=*/{"r", "{rax}"}, /*output=*/{"={rax}", "+*m"}) )
+ {
+ m_of << indent << "InterlockedCompareExchangeAcquire(";
+ emit_lvalue(e.outputs[1].second); m_of << ",";
+ emit_lvalue(e.inputs[0].second); m_of << ",";
+ emit_lvalue(e.inputs[1].second);
+ m_of << ");\n";
+ return ;
+ }
+ else if( matches_template("xrelease; lock; cmpxchgl $2, $1", /*input=*/{"r", "{rax}"}, /*output=*/{"={rax}", "+*m"}) )
+ {
+ m_of << indent << "InterlockedCompareExchangeRelease(";
+ emit_lvalue(e.outputs[1].second); m_of << ",";
+ emit_lvalue(e.inputs[0].second); m_of << ",";
+ emit_lvalue(e.inputs[1].second);
+ m_of << ");\n";
+ return ;
+ }
+ else if( matches_template("xacquire; lock; cmpxchgq $2, $1", /*input=*/{"r", "{rax}"}, /*output=*/{"={rax}", "+*m"}) )
+ {
+ m_of << indent << "InterlockedCompareExchange64Acquire(";
+ emit_lvalue(e.outputs[1].second); m_of << ",";
+ emit_lvalue(e.inputs[0].second); m_of << ",";
+ emit_lvalue(e.inputs[1].second);
+ m_of << ");\n";
+ return ;
+ }
+ else if( matches_template("xrelease; lock; cmpxchgq $2, $1", /*input=*/{"r", "{rax}"}, /*output=*/{"={rax}", "+*m"}) )
+ {
+ m_of << indent << "InterlockedCompareExchange64Release(";
+ emit_lvalue(e.outputs[1].second); m_of << ",";
+ emit_lvalue(e.inputs[0].second); m_of << ",";
+ emit_lvalue(e.inputs[1].second);
+ m_of << ");\n";
+ return ;
+ }
else
{
// No hard-coded translations.
}
+ if( Target_GetCurSpec().m_backend_c.m_c_compiler == "amd64" ) {
+ MIR_TODO(mir_res, "MSVC amd64 doesn't support inline assembly, need to have a transform for '" << e.tpl << "'");
+ }
if( !e.inputs.empty() || !e.outputs.empty() )
{
MIR_TODO(mir_res, "Inputs/outputs in msvc inline assembly - `" << e.tpl << "` inputs=" << e.inputs << " outputs=" << e.outputs);
@@ -3823,9 +4154,6 @@ namespace {
#endif
}
- if( Target_GetCurSpec().m_backend_c.m_c_compiler == "amd64" ) {
- MIR_TODO(mir_res, "MSVC amd64 doesn't support inline assembly, need to have a transform for '" << e.tpl << "'");
- }
m_of << indent << "__asm {\n";
m_of << indent << "\t";
@@ -3914,7 +4242,7 @@ namespace {
}
}
- void emit_intrinsic_call(const ::std::string& name, const ::HIR::PathParams& params, const ::MIR::Terminator::Data_Call& e)
+ void emit_intrinsic_call(const RcString& name, const ::HIR::PathParams& params, const ::MIR::Terminator::Data_Call& e)
{
const auto& mir_res = *m_mir_res;
enum class Ordering
@@ -3947,7 +4275,7 @@ namespace {
}
throw "";
};
- auto get_atomic_ordering = [&](const ::std::string& name, size_t prefix_len)->Ordering {
+ auto get_atomic_ordering = [&](const RcString& name, size_t prefix_len)->Ordering {
if( name.size() < prefix_len )
{
return Ordering::SeqCst;
@@ -4112,11 +4440,14 @@ namespace {
}
};
if( name == "size_of" ) {
- emit_lvalue(e.ret_val); m_of << " = sizeof("; emit_ctype(params.m_types.at(0)); m_of << ")";
+ size_t size = 0;
+ MIR_ASSERT(mir_res, Target_GetSizeOf(sp, m_resolve, params.m_types.at(0), size), "Can't get size of " << params.m_types.at(0));
+ emit_lvalue(e.ret_val); m_of << " = " << size;
}
- else if( name == "min_align_of" ) {
- //emit_lvalue(e.ret_val); m_of << " = alignof("; emit_ctype(params.m_types.at(0)); m_of << ")";
- emit_lvalue(e.ret_val); m_of << " = ALIGNOF("; emit_ctype(params.m_types.at(0)); m_of << ")";
+ else if( name == "min_align_of" || name == "align_of" ) {
+ size_t align = 0;
+ MIR_ASSERT(mir_res, Target_GetAlignOf(sp, m_resolve, params.m_types.at(0), align), "Can't get alignment of " << params.m_types.at(0));
+ emit_lvalue(e.ret_val); m_of << " = " << align;
}
else if( name == "size_of_val" ) {
emit_lvalue(e.ret_val); m_of << " = ";
@@ -4124,6 +4455,7 @@ namespace {
//TODO: Get the unsized type and use that in place of MetadataType
auto inner_ty = get_inner_unsized_type(ty);
if( inner_ty == ::HIR::TypeRef() ) {
+ // TODO: Target_GetSizeOf
m_of << "sizeof("; emit_ctype(ty); m_of << ")";
}
else if( const auto* te = inner_ty.m_data.opt_Slice() ) {
@@ -4216,8 +4548,8 @@ namespace {
emit_lvalue(e.ret_val); m_of << ".META = " << s.size() << "";
}
else if( name == "transmute" ) {
- const auto& ty_dst = params.m_types.at(0);
- const auto& ty_src = params.m_types.at(1);
+ const auto& ty_src = params.m_types.at(0);
+ const auto& ty_dst = params.m_types.at(1);
auto is_ptr = [](const ::HIR::TypeRef& ty){ return ty.m_data.is_Borrow() || ty.m_data.is_Pointer(); };
if( this->type_is_bad_zst(ty_dst) )
{
@@ -4225,7 +4557,7 @@ namespace {
}
else if( e.args.at(0).is_Constant() )
{
- m_of << "{ "; emit_ctype(ty_src, FMT_CB(s, s << "v";)); m_of << " = "; emit_param(e.args.at(0)); m_of << ";";
+ m_of << "{ "; emit_ctype(ty_src, FMT_CB(s, s << "v";)); m_of << " = "; emit_param(e.args.at(0)); m_of << "; ";
m_of << "memcpy( &"; emit_lvalue(e.ret_val); m_of << ", &v, sizeof("; emit_ctype(ty_dst); m_of << ")); ";
m_of << "}";
}
@@ -4244,7 +4576,9 @@ namespace {
emit_lvalue(e.ret_val); m_of << ".META = ";
switch(dst_meta)
{
+ case MetadataType::Unknown: assert(!"Impossible");
case MetadataType::None: assert(!"Impossible");
+ case MetadataType::Zero: assert(!"Impossible");
case MetadataType::Slice: m_of << "(size_t)"; break;
case MetadataType::TraitObject: m_of << "(const void*)"; break;
}
@@ -4257,7 +4591,7 @@ namespace {
}
else
{
- m_of << "memcpy( &"; emit_lvalue(e.ret_val); m_of << ", &"; emit_param(e.args.at(0)); m_of << ", sizeof("; emit_ctype(params.m_types.at(0)); m_of << "))";
+ m_of << "memcpy( &"; emit_lvalue(e.ret_val); m_of << ", &"; emit_param(e.args.at(0)); m_of << ", sizeof("; emit_ctype(ty_src); m_of << "))";
}
}
else if( name == "copy_nonoverlapping" || name == "copy" ) {
@@ -4277,6 +4611,7 @@ namespace {
m_of << ", "; emit_param(e.args.at(2)); m_of << " * sizeof("; emit_ctype(params.m_types.at(0)); m_of << ")";
m_of << ")";
}
+ // NOTE: This is generic, and fills count*sizeof(T) (unlike memset)
else if( name == "write_bytes" ) {
if( this->type_is_bad_zst(params.m_types.at(0)) ) {
m_of << "/* zst */";
@@ -4292,7 +4627,7 @@ namespace {
// Nothing needs to be done, this just stops the destructor from running.
}
else if( name == "drop_in_place" ) {
- emit_destructor_call( ::MIR::LValue::make_Deref({ box$(e.args.at(0).as_LValue().clone()) }), params.m_types.at(0), true, 1 /* TODO: get from caller */ );
+ emit_destructor_call( ::MIR::LValue::new_Deref(e.args.at(0).as_LValue().clone()), params.m_types.at(0), true, /*indent_level=*/1 /* TODO: get from caller */ );
}
else if( name == "needs_drop" ) {
// Returns `true` if the actual type given as `T` requires drop glue;
@@ -4329,7 +4664,7 @@ namespace {
{
case Compiler::Gcc:
m_of << "{ ";
- m_of << " jmp_buf jmpbuf; mrustc_panic_target = &jmpbuf;";
+ m_of << " jmp_buf jmpbuf, *old = mrustc_panic_target; mrustc_panic_target = &jmpbuf;";
m_of << " if(setjmp(jmpbuf)) {";
// NOTE: gcc unwind has a pointer as its `local_ptr` parameter
m_of << " *(void**)("; emit_param(e.args.at(2)); m_of << ") = mrustc_panic_value;";
@@ -4347,7 +4682,8 @@ namespace {
case Compiler::Gcc:
m_of << ";";
m_of << " }";
- m_of << " mrustc_panic_target = NULL;";
+ m_of << " if(mrustc_panic_target != &jmpbuf) { abort(); }";
+ m_of << " mrustc_panic_target = old;";
m_of << " }";
break;
default:
@@ -4417,6 +4753,22 @@ namespace {
m_of << "("; emit_param(e.args.at(0)); m_of << ")";
}
}
+ else if( name == "bitreverse" ) {
+ const auto& ty = params.m_types.at(0);
+ MIR_ASSERT(mir_res, ty.m_data.is_Primitive(), "Invalid type passed to bitreverse. Must be a primitive, got " << ty);
+ emit_lvalue(e.ret_val); m_of << " = ";
+ switch(get_prim_size(ty))
+ {
+ case 8: m_of << "__mrustc_bitrev8"; break;
+ case 16: m_of << "__mrustc_bitrev16"; break;
+ case 32: m_of << "__mrustc_bitrev32"; break;
+ case 64: m_of << "__mrustc_bitrev64"; break;
+ case 128: m_of << "__mrustc_bitrev128"; break;
+ default:
+ MIR_TODO(mir_res, "bswap<" << ty << ">");
+ }
+ m_of << "("; emit_param(e.args.at(0)); m_of << ")";
+ }
// > Obtain the discriminane of a &T as u64
else if( name == "discriminant_value" ) {
const auto& ty = params.m_types.at(0);
@@ -4623,7 +4975,8 @@ namespace {
}
}
// Unchecked Arithmatic
- else if( name == "unchecked_div" ) {
+ // - exact_div is UB to call on a non-multiple
+ else if( name == "unchecked_div" || name == "exact_div") {
emit_lvalue(e.ret_val); m_of << " = ";
if( type_is_emulated_i128(params.m_types.at(0)) )
{
@@ -4696,7 +5049,7 @@ namespace {
// Bit Twiddling
// - CounT Leading Zeroes
// - CounT Trailing Zeroes
- else if( name == "ctlz" || name == "ctlz_nonzero" || name == "cttz" ) {
+ else if( name == "ctlz" || name == "ctlz_nonzero" || name == "cttz" || name == "cttz_nonzero" ) {
auto emit_arg0 = [&](){ emit_param(e.args.at(0)); };
const auto& ty = params.m_types.at(0);
emit_lvalue(e.ret_val); m_of << " = (";
@@ -4828,6 +5181,11 @@ namespace {
else if( name == "volatile_store" ) {
m_of << "*(volatile "; emit_ctype(params.m_types.at(0)); m_of << "*)"; emit_param(e.args.at(0)); m_of << " = "; emit_param(e.args.at(1));
}
+ else if( name == "nontemporal_store" ) {
+ // TODO: Actually do a non-temporal store
+ // GCC: _mm_stream_* (depending on input type, which must be `repr(simd)`)
+ m_of << "*(volatile "; emit_ctype(params.m_types.at(0)); m_of << "*)"; emit_param(e.args.at(0)); m_of << " = "; emit_param(e.args.at(1));
+ }
// --- Atomics!
// > Single-ordering atomics
else if( name == "atomic_xadd" || name.compare(0, 7+4+1, "atomic_xadd_") == 0 ) {
@@ -4842,6 +5200,18 @@ namespace {
auto ordering = get_atomic_ordering(name, 7+3+1);
emit_atomic_arith(AtomicOp::And, ordering);
}
+ else if( name == "atomic_nand" || name.compare(0, 7+4+1, "atomic_nand_") == 0 ) {
+ auto ordering = get_atomic_ordering(name, 7+4+1);
+ const auto& ty = params.m_types.at(0);
+ emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "(";
+ emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1));
+ if( m_compiler == Compiler::Gcc )
+ {
+ m_of << ", " << get_atomic_ty_gcc(ordering);
+ }
+ m_of << ", __mrustc_op_and_not" << get_prim_size(ty);
+ m_of << ")";
+ }
else if( name == "atomic_or" || name.compare(0, 7+2+1, "atomic_or_") == 0 ) {
auto ordering = get_atomic_ordering(name, 7+2+1);
emit_atomic_arith(AtomicOp::Or, ordering);
@@ -4850,6 +5220,34 @@ namespace {
auto ordering = get_atomic_ordering(name, 7+3+1);
emit_atomic_arith(AtomicOp::Xor, ordering);
}
+ else if( name == "atomic_max" || name.compare(0, 7+3+1, "atomic_max_") == 0
+ || name == "atomic_min" || name.compare(0, 7+3+1, "atomic_min_") == 0 ) {
+ auto ordering = get_atomic_ordering(name, 7+3+1);
+ const auto& ty = params.m_types.at(0);
+ const char* op = (name.c_str()[7+1] == 'a' ? "imax" : "imin"); // m'a'x vs m'i'n
+ emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "(";
+ emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1));
+ if( m_compiler == Compiler::Gcc )
+ {
+ m_of << ", " << get_atomic_ty_gcc(ordering);
+ }
+ m_of << ", __mrustc_op_" << op << get_prim_size(ty);
+ m_of << ")";
+ }
+ else if( name == "atomic_umax" || name.compare(0, 7+4+1, "atomic_umax_") == 0
+ || name == "atomic_umin" || name.compare(0, 7+4+1, "atomic_umin_") == 0 ) {
+ auto ordering = get_atomic_ordering(name, 7+4+1);
+ const auto& ty = params.m_types.at(0);
+ const char* op = (name.c_str()[7+2] == 'a' ? "umax" : "umin"); // m'a'x vs m'i'n
+ emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "(";
+ emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1));
+ if( m_compiler == Compiler::Gcc )
+ {
+ m_of << ", " << get_atomic_ty_gcc(ordering);
+ }
+ m_of << ", __mrustc_op_" << op << get_prim_size(ty);
+ m_of << ")";
+ }
else if( name == "atomic_load" || name.compare(0, 7+4+1, "atomic_load_") == 0 ) {
auto ordering = get_atomic_ordering(name, 7+4+1);
emit_lvalue(e.ret_val); m_of << " = ";
@@ -4872,11 +5270,7 @@ namespace {
m_of << "atomic_store_explicit("; emit_atomic_cast(); emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", " << get_atomic_ty_gcc(ordering) << ")";
break;
case Compiler::Msvc:
- emit_msvc_atomic_op("InterlockedCompareExchange", ordering, true); emit_param(e.args.at(0)); m_of << ", ";
- emit_param(e.args.at(1));
- m_of << ", ";
- emit_param(e.args.at(1));
- m_of << ")";
+ m_of << "*"; emit_param(e.args.at(0)); m_of << " = "; emit_param(e.args.at(1));
break;
}
}
@@ -4960,6 +5354,11 @@ namespace {
else if( name == "atomic_singlethreadfence" || name.compare(0, 7+18, "atomic_singlethreadfence_") == 0 ) {
// TODO: Does this matter?
}
+ // -- Platform Intrinsics --
+ else if( name.compare(0, 9, "platform:") == 0 ) {
+ // TODO: Platform intrinsics
+ m_of << "abort() /* TODO: Platform intrinsic \"" << name << "\" */";
+ }
else {
MIR_BUG(mir_res, "Unknown intrinsic '" << name << "'");
}
@@ -4994,7 +5393,7 @@ namespace {
if( te.type == ::HIR::BorrowType::Owned )
{
// Call drop glue on inner.
- emit_destructor_call( ::MIR::LValue::make_Deref({ box$(slot.clone()) }), *te.inner, true, indent_level );
+ emit_destructor_call( ::MIR::LValue::new_Deref(slot.clone()), *te.inner, true, indent_level );
}
),
(Path,
@@ -5004,15 +5403,14 @@ namespace {
const char* make_fcn = nullptr;
switch( metadata_type(ty) )
{
+ case MetadataType::Unknown:
+ MIR_BUG(*m_mir_res, ty << " unknown metadata");
case MetadataType::None:
-
+ case MetadataType::Zero:
if( this->type_is_bad_zst(ty) && (slot.is_Field() || slot.is_Downcast()) )
{
m_of << indent << Trans_Mangle(p) << "((void*)&";
- if( slot.is_Field() )
- emit_lvalue(*slot.as_Field().val);
- else
- emit_lvalue(*slot.as_Downcast().val);
+ emit_lvalue(::MIR::LValue::CRef(slot).inner_ref());
m_of << ");\n";
}
else
@@ -5027,7 +5425,7 @@ namespace {
m_of << indent << Trans_Mangle(p) << "( " << make_fcn << "(";
if( slot.is_Deref() )
{
- emit_lvalue(*slot.as_Deref().val);
+ emit_lvalue( ::MIR::LValue::CRef(slot).inner_ref() );
m_of << ".PTR";
}
else
@@ -5035,10 +5433,10 @@ namespace {
m_of << "&"; emit_lvalue(slot);
}
m_of << ", ";
- const auto* lvp = &slot;
- while(const auto* le = lvp->opt_Field()) lvp = &*le->val;
- MIR_ASSERT(*m_mir_res, lvp->is_Deref(), "Access to unized type without a deref - " << *lvp << " (part of " << slot << ")");
- emit_lvalue(*lvp->as_Deref().val); m_of << ".META";
+ auto lvr = ::MIR::LValue::CRef(slot);
+ while(lvr.is_Field()) lvr.try_unwrap();
+ MIR_ASSERT(*m_mir_res, lvr.is_Deref(), "Access to unized type without a deref - " << lvr << " (part of " << slot << ")");
+ emit_lvalue(lvr.inner_ref()); m_of << ".META";
m_of << ") );\n";
break;
}
@@ -5048,7 +5446,7 @@ namespace {
if( te.size_val > 0 )
{
m_of << indent << "for(unsigned i = 0; i < " << te.size_val << "; i++) {\n";
- emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Local(~0u)) }), *te.inner, false, indent_level+1);
+ emit_destructor_call(::MIR::LValue::new_Index(slot.clone(), ::MIR::LValue::Storage::MAX_ARG), *te.inner, false, indent_level+1);
m_of << "\n" << indent << "}";
}
),
@@ -5056,24 +5454,24 @@ namespace {
// Emit destructors for all entries
if( te.size() > 0 )
{
- ::MIR::LValue lv = ::MIR::LValue::make_Field({ box$(slot.clone()), 0 });
+ ::MIR::LValue lv = ::MIR::LValue::new_Field(slot.clone(), 0);
for(unsigned int i = 0; i < te.size(); i ++)
{
- lv.as_Field().field_index = i;
emit_destructor_call(lv, te[i], unsized_valid && (i == te.size()-1), indent_level);
+ lv.inc_Field();
}
}
),
(TraitObject,
MIR_ASSERT(*m_mir_res, unsized_valid, "Dropping TraitObject without a pointer");
// Call destructor in vtable
- const auto* lvp = &slot;
- while(const auto* le = lvp->opt_Field()) lvp = &*le->val;
- MIR_ASSERT(*m_mir_res, lvp->is_Deref(), "Access to unized type without a deref - " << *lvp << " (part of " << slot << ")");
- m_of << indent << "((VTABLE_HDR*)"; emit_lvalue(*lvp->as_Deref().val); m_of << ".META)->drop(";
- if( const auto* ve = slot.opt_Deref() )
+ auto lvr = ::MIR::LValue::CRef(slot);
+ while(lvr.is_Field()) lvr.try_unwrap();
+ MIR_ASSERT(*m_mir_res, lvr.is_Deref(), "Access to unized type without a deref - " << lvr << " (part of " << slot << ")");
+ m_of << indent << "((VTABLE_HDR*)"; emit_lvalue(lvr.inner_ref()); m_of << ".META)->drop(";
+ if( slot.is_Deref() )
{
- emit_lvalue(*ve->val); m_of << ".PTR";
+ emit_lvalue(::MIR::LValue::CRef(slot).inner_ref()); m_of << ".PTR";
}
else
{
@@ -5083,12 +5481,12 @@ namespace {
),
(Slice,
MIR_ASSERT(*m_mir_res, unsized_valid, "Dropping Slice without a pointer");
- const auto* lvp = &slot;
- while(const auto* le = lvp->opt_Field()) lvp = &*le->val;
- MIR_ASSERT(*m_mir_res, lvp->is_Deref(), "Access to unized type without a deref - " << *lvp << " (part of " << slot << ")");
+ auto lvr = ::MIR::LValue::CRef(slot);
+ while(lvr.is_Field()) lvr.try_unwrap();
+ MIR_ASSERT(*m_mir_res, lvr.is_Deref(), "Access to unized type without a deref - " << lvr << " (part of " << slot << ")");
// Call destructor on all entries
- m_of << indent << "for(unsigned i = 0; i < "; emit_lvalue(*lvp->as_Deref().val); m_of << ".META; i++) {\n";
- emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Local(~0u)) }), *te.inner, false, indent_level+1);
+ m_of << indent << "for(unsigned i = 0; i < "; emit_lvalue(lvr.inner_ref()); m_of << ".META; i++) {\n";
+ emit_destructor_call(::MIR::LValue::new_Index(slot.clone(), ::MIR::LValue::Storage::MAX_ARG), *te.inner, false, indent_level+1);
m_of << "\n" << indent << "}";
)
)
@@ -5100,8 +5498,22 @@ namespace {
auto v = m_resolve.get_value(m_mir_res->sp, path, params);
if( const auto* e = v.opt_Constant() )
{
- ty = params.monomorph(m_mir_res->sp, (*e)->m_type);
- return (*e)->m_value_res;
+ const auto& hir_const = **e;
+ ty = params.monomorph(m_mir_res->sp, hir_const.m_type);
+ if( hir_const.m_value_res.is_Defer() )
+ {
+ // Do some form of lookup of a pre-cached evaluated monomorphised constant
+ // - Maybe on the `Constant` entry there can be a list of pre-monomorphised values
+ auto it = hir_const.m_monomorph_cache.find(path);
+ if( it == hir_const.m_monomorph_cache.end() )
+ {
+ MIR_BUG(*m_mir_res, "Constant with Defer literal and no cached monomorphisation - " << path);
+ // TODO: Can do the consteval here?
+ }
+ MIR_ASSERT(*m_mir_res, !it->second.is_Defer(), "get_literal_for_const - Cached literal was Defer - " << path);
+ return it->second;
+ }
+ return hir_const.m_value_res;
}
else
{
@@ -5146,7 +5558,7 @@ namespace {
void assign_from_literal(::std::function<void()> emit_dst, const ::HIR::TypeRef& ty, const ::HIR::Literal& lit)
{
- //TRACE_FUNCTION_F("ty=" << ty << ", lit=" << lit);
+ TRACE_FUNCTION_F("ty=" << ty << ", lit=" << lit);
Span sp;
::HIR::TypeRef tmp;
auto monomorph_with = [&](const ::HIR::PathParams& pp, const ::HIR::TypeRef& ty)->const ::HIR::TypeRef& {
@@ -5168,6 +5580,9 @@ namespace {
TU_MATCHA((te.binding), (pbe),
(Unbound, MIR_BUG(*m_mir_res, "Unbound type path " << ty); ),
(Opaque, MIR_BUG(*m_mir_res, "Opaque type path " << ty); ),
+ (ExternType,
+ MIR_BUG(*m_mir_res, "Extern type literal");
+ ),
(Struct,
TU_MATCHA( (pbe->m_data), (se),
(Unit,
@@ -5203,6 +5618,9 @@ namespace {
(Invalid,
m_of << "/* INVALID */";
),
+ (Defer,
+ MIR_BUG(*m_mir_res, "Defer literal encountered");
+ ),
(List,
if( ty.m_data.is_Array() )
{
@@ -5276,7 +5694,10 @@ namespace {
const auto& ity = *ty.m_data.as_Borrow().inner;
switch( metadata_type(ity) )
{
+ case MetadataType::Unknown:
+ MIR_BUG(*m_mir_res, ity << " - Unknown meta");
case MetadataType::None:
+ case MetadataType::Zero:
emit_dst(); m_of << " = &" << Trans_Mangle(e);
break;
case MetadataType::Slice:
@@ -5313,116 +5734,125 @@ namespace {
)
}
- void emit_lvalue(const ::MIR::LValue& val) {
- TU_MATCHA( (val), (e),
- (Return,
+ void emit_lvalue(const ::MIR::LValue::CRef& val)
+ {
+ TU_MATCH_HDRA( (val), {)
+ TU_ARMA(Return, _e) {
m_of << "rv";
- ),
- (Argument,
- m_of << "arg" << e.idx;
- ),
- (Local,
- if( e == ~0u )
+ }
+ TU_ARMA(Argument, e) {
+ m_of << "arg" << e;
+ }
+ TU_ARMA(Local, e) {
+ if( e == ::MIR::LValue::Storage::MAX_ARG )
m_of << "i";
else
m_of << "var" << e;
- ),
- (Static,
+ }
+ TU_ARMA(Static, e) {
m_of << Trans_Mangle(e);
- ),
- (Field,
+ }
+ TU_ARMA(Field, field_index) {
::HIR::TypeRef tmp;
- const auto& ty = m_mir_res->get_lvalue_type(tmp, *e.val);
- if( ty.m_data.is_Slice() ) {
- if( e.val->is_Deref() )
+ auto inner = val.inner_ref();
+ const auto& ty = m_mir_res->get_lvalue_type(tmp, inner);
+ if( ty.m_data.is_Slice() )
+ {
+ if( inner.is_Deref() )
{
m_of << "(("; emit_ctype(*ty.m_data.as_Slice().inner); m_of << "*)";
- emit_lvalue(*e.val->as_Deref().val);
+ emit_lvalue(inner.inner_ref());
m_of << ".PTR)";
}
else
{
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
}
- m_of << "[" << e.field_index << "]";
+ m_of << "[" << field_index << "]";
}
else if( ty.m_data.is_Array() ) {
- emit_lvalue(*e.val);
- m_of << ".DATA[" << e.field_index << "]";
+ emit_lvalue(inner);
+ m_of << ".DATA[" << field_index << "]";
}
- else if( e.val->is_Deref() ) {
+ else if( inner.is_Deref() ) {
auto dst_type = metadata_type(ty);
if( dst_type != MetadataType::None )
{
- m_of << "(("; emit_ctype(ty); m_of << "*)"; emit_lvalue(*e.val->as_Deref().val); m_of << ".PTR)->_" << e.field_index;
+ m_of << "(("; emit_ctype(ty); m_of << "*)"; emit_lvalue(inner.inner_ref()); m_of << ".PTR)->_" << field_index;
}
else
{
- emit_lvalue(*e.val->as_Deref().val);
- m_of << "->_" << e.field_index;
+ emit_lvalue(inner.inner_ref());
+ m_of << "->_" << field_index;
}
}
else {
- emit_lvalue(*e.val);
- m_of << "._" << e.field_index;
+ emit_lvalue(inner);
+ m_of << "._" << field_index;
}
- ),
- (Deref,
- // TODO: If the type is unsized, then this pointer is a fat pointer, so we need to cast the data pointer.
+ }
+ TU_ARMA(Deref, _e) {
+ auto inner = val.inner_ref();
::HIR::TypeRef tmp;
const auto& ty = m_mir_res->get_lvalue_type(tmp, val);
auto dst_type = metadata_type(ty);
+ // If the type is unsized, then this pointer is a fat pointer, so we need to cast the data pointer.
if( dst_type != MetadataType::None )
{
m_of << "(*("; emit_ctype(ty); m_of << "*)";
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
m_of << ".PTR)";
}
else
{
m_of << "(*";
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
m_of << ")";
}
- ),
- (Index,
+ }
+ TU_ARMA(Index, index_local) {
+ auto inner = val.inner_ref();
::HIR::TypeRef tmp;
- const auto& ty = m_mir_res->get_lvalue_type(tmp, *e.val);
+ const auto& ty = m_mir_res->get_lvalue_type(tmp, inner);
m_of << "(";
if( ty.m_data.is_Slice() ) {
- if( e.val->is_Deref() )
+ if( inner.is_Deref() )
{
m_of << "("; emit_ctype(*ty.m_data.as_Slice().inner); m_of << "*)";
- emit_lvalue(*e.val->as_Deref().val);
+ emit_lvalue(inner.inner_ref());
m_of << ".PTR";
}
else {
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
}
}
else if( ty.m_data.is_Array() ) {
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
m_of << ".DATA";
}
else {
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
}
m_of << ")[";
- emit_lvalue(*e.idx);
+ emit_lvalue(::MIR::LValue::new_Local(index_local));
m_of << "]";
- ),
- (Downcast,
+ }
+ TU_ARMA(Downcast, variant_index) {
+ auto inner = val.inner_ref();
::HIR::TypeRef tmp;
- const auto& ty = m_mir_res->get_lvalue_type(tmp, *e.val);
- emit_lvalue(*e.val);
+ const auto& ty = m_mir_res->get_lvalue_type(tmp, inner);
+ emit_lvalue(inner);
MIR_ASSERT(*m_mir_res, ty.m_data.is_Path(), "Downcast on non-Path type - " << ty);
if( ty.m_data.as_Path().binding.is_Enum() )
{
m_of << ".DATA";
}
- m_of << ".var_" << e.variant_index;
- )
- )
+ m_of << ".var_" << variant_index;
+ }
+ }
+ }
+ void emit_lvalue(const ::MIR::LValue& val) {
+ emit_lvalue( ::MIR::LValue::CRef(val) );
}
void emit_constant(const ::MIR::Constant& ve, const ::MIR::LValue* dst_ptr=nullptr)
{
@@ -5443,6 +5873,16 @@ namespace {
{
switch(c.t)
{
+ // TODO: These should already have been truncated/reinterpreted, but just in case.
+ case ::HIR::CoreType::I8:
+ m_of << static_cast<int>( static_cast<int8_t>(c.v) ); // cast to int, because `int8_t` is printed as a `char`
+ break;
+ case ::HIR::CoreType::I16:
+ m_of << static_cast<int16_t>(c.v);
+ break;
+ case ::HIR::CoreType::I32:
+ m_of << static_cast<int32_t>(c.v);
+ break;
case ::HIR::CoreType::I64:
case ::HIR::CoreType::Isize:
m_of << c.v;
@@ -5455,6 +5895,7 @@ namespace {
}
else
{
+ m_of << "(int128_t)";
m_of << c.v;
m_of << "ll";
}
@@ -5488,6 +5929,7 @@ namespace {
}
else
{
+ m_of << "(uint128_t)";
m_of << ::std::hex << "0x" << c.v << "ull" << ::std::dec;
}
break;
@@ -5524,11 +5966,17 @@ namespace {
(Const,
// TODO: This should have been eliminated? ("MIR Cleanup" should have removed all inline Const references)
::HIR::TypeRef ty;
- const auto& lit = get_literal_for_const(c.p, ty);
- if(lit.is_Integer() || lit.is_Float() || lit.is_String())
+ const auto& lit = get_literal_for_const(*c.p, ty);
+ if(lit.is_Integer() || lit.is_Float())
{
emit_literal(ty, lit, {});
}
+ else if( lit.is_String())
+ {
+ m_of << "make_sliceptr(";
+ this->print_escaped_string( lit.as_String() );
+ m_of << ", " << ::std::dec << lit.as_String().size() << ")";
+ }
else
{
// NOTE: GCC hack - statement expressions
@@ -5539,7 +5987,7 @@ namespace {
}
),
(ItemAddr,
- TU_MATCHA( (c.m_data), (pe),
+ TU_MATCHA( (c->m_data), (pe),
(Generic,
if( pe.m_path.m_components.size() > 1 && m_crate.get_typeitem_by_path(sp, pe.m_path, false, true).is_Enum() )
;
@@ -5556,7 +6004,7 @@ namespace {
}
),
(UfcsUnknown,
- MIR_BUG(*m_mir_res, "UfcsUnknown in trans " << c);
+ MIR_BUG(*m_mir_res, "UfcsUnknown in trans " << *c);
),
(UfcsInherent,
// TODO: If the target is a function, don't emit the &
@@ -5567,7 +6015,7 @@ namespace {
m_of << "&";
)
)
- m_of << Trans_Mangle(c);
+ m_of << Trans_Mangle(*c);
)
)
}
@@ -5633,6 +6081,10 @@ namespace {
(Enum,
m_of << "struct e_" << Trans_Mangle(te.path);
),
+ (ExternType,
+ //m_of << "struct x_" << Trans_Mangle(te.path);
+ return ;
+ ),
(Unbound,
MIR_BUG(*m_mir_res, "Unbound type path in trans - " << ty);
),
@@ -5741,61 +6193,9 @@ namespace {
return ::HIR::TypeRef();
}
}
- // TODO: Move this to a more common location
- MetadataType metadata_type(const ::HIR::TypeRef& ty) const
- {
- if( ty == ::HIR::CoreType::Str || ty.m_data.is_Slice() ) {
- return MetadataType::Slice;
- }
- else if( ty.m_data.is_TraitObject() ) {
- return MetadataType::TraitObject;
- }
- else if( ty.m_data.is_Path() )
- {
- TU_MATCH_DEF( ::HIR::TypeRef::TypePathBinding, (ty.m_data.as_Path().binding), (tpb),
- (
- MIR_BUG(*m_mir_res, "Unbound/opaque path in trans - " << ty);
- ),
- (Struct,
- switch( tpb->m_struct_markings.dst_type )
- {
- case ::HIR::StructMarkings::DstType::None:
- return MetadataType::None;
- case ::HIR::StructMarkings::DstType::Possible: {
- // TODO: How to figure out? Lazy way is to check the monomorpised type of the last field (structs only)
- const auto& path = ty.m_data.as_Path().path.m_data.as_Generic();
- const auto& str = *ty.m_data.as_Path().binding.as_Struct();
- auto monomorph = [&](const auto& tpl) {
- auto rv = monomorphise_type(sp, str.m_params, path.m_params, tpl);
- m_resolve.expand_associated_types(sp, rv);
- return rv;
- };
- TU_MATCHA( (str.m_data), (se),
- (Unit, MIR_BUG(*m_mir_res, "Unit-like struct with DstType::Possible"); ),
- (Tuple, return metadata_type( monomorph(se.back().ent) ); ),
- (Named, return metadata_type( monomorph(se.back().second.ent) ); )
- )
- //MIR_TODO(*m_mir_res, "Determine DST type when ::Possible - " << ty);
- return MetadataType::None;
- }
- case ::HIR::StructMarkings::DstType::Slice:
- return MetadataType::Slice;
- case ::HIR::StructMarkings::DstType::TraitObject:
- return MetadataType::TraitObject;
- }
- ),
- (Union,
- return MetadataType::None;
- ),
- (Enum,
- return MetadataType::None;
- )
- )
- throw "";
- }
- else {
- return MetadataType::None;
- }
+
+ MetadataType metadata_type(const ::HIR::TypeRef& ty) const {
+ return m_resolve.metadata_type(m_mir_res ? m_mir_res->sp : sp, ty);
}
void emit_ctype_ptr(const ::HIR::TypeRef& inner_ty, ::FmtLambda inner) {
@@ -5804,9 +6204,12 @@ namespace {
//}
//else
{
- switch( metadata_type(inner_ty) )
+ switch( this->metadata_type(inner_ty) )
{
+ case MetadataType::Unknown:
+ BUG(sp, inner_ty << " unknown metadata type");
case MetadataType::None:
+ case MetadataType::Zero:
emit_ctype(inner_ty, FMT_CB(ss, ss << "*" << inner;));
break;
case MetadataType::Slice:
@@ -5821,7 +6224,7 @@ namespace {
bool is_dst(const ::HIR::TypeRef& ty) const
{
- return metadata_type(ty) != MetadataType::None;
+ return this->metadata_type(ty) != MetadataType::None;
}
};
Span CodeGenerator_C::sp;
diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp
index 73de19d3..58739805 100644
--- a/src/trans/codegen_mmir.cpp
+++ b/src/trans/codegen_mmir.cpp
@@ -18,6 +18,8 @@
namespace
{
+ size_t PTR_BASE = 0x1000; // See matching value in standalone_miri value.hpp
+
size_t Target_GetSizeOf_Required(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty)
{
size_t size;
@@ -39,47 +41,51 @@ namespace
::std::ostream& operator<<(::std::ostream& os, const Fmt<::MIR::LValue>& x)
{
- auto fmt_lhs = [](::std::ostream& os, const ::MIR::LValue& lv) {
- if( lv.is_Deref() ) {
- os << "(" << fmt(lv) << ")";
- }
- else {
- os << fmt(lv);
- }
- };
- switch(x.e.tag())
+ for(const auto& w : ::reverse(x.e.m_wrappers))
{
- case ::MIR::LValue::TAGDEAD: throw "";
- TU_ARM(x.e, Return, _e) (void)_e;
+ if( w.is_Deref() ) {
+ os << "(*";
+ }
+ }
+ TU_MATCHA( (x.e.m_root), (e),
+ (Return,
os << "RETURN";
- break;
- TU_ARM(x.e, Local, e)
+ ),
+ (Local,
os << "var" << e;
- break;
- TU_ARM(x.e, Argument, e)
- os << "arg" << e.idx;
- break;
- TU_ARM(x.e, Static, e)
+ ),
+ (Argument,
+ os << "arg" << e;
+ ),
+ (Static,
os << e;
- break;
- TU_ARM(x.e, Deref, e)
- os << "*" << fmt(*e.val);
- break;
- TU_ARM(x.e, Field, e) {
- fmt_lhs(os, *e.val);
- // Avoid `0.` existing in the output
- if( e.val->is_Field() || e.val->is_Downcast() )
- os << " ";
- os << "." << e.field_index;
- } break;
- TU_ARM(x.e, Index, e) {
- fmt_lhs(os, *e.val);
- os << "[" << fmt(*e.idx) << "]";
- } break;
- TU_ARM(x.e, Downcast, e) {
- fmt_lhs(os, *e.val);
- os << "@" << e.variant_index;
- } break;
+ )
+ )
+ bool was_num = false;
+ for(const auto& w : x.e.m_wrappers)
+ {
+ bool prev_was_num = was_num; was_num = false;
+ switch(w.tag())
+ {
+ case ::MIR::LValue::Wrapper::TAGDEAD: throw "";
+ TU_ARM(w, Deref, e)
+ os << ")";
+ break;
+ TU_ARM(w, Field, field_index) {
+ // Add a space to prevent accidental float literals
+ if( prev_was_num )
+ os << " ";
+ os << "." << field_index;
+ was_num = true;
+ } break;
+ TU_ARM(w, Index, e) {
+ os << "[" << fmt(::MIR::LValue::new_Local(e)) << "]";
+ } break;
+ TU_ARM(w, Downcast, variant_index) {
+ os << "@" << variant_index;
+ was_num = true;
+ } break;
+ }
}
return os;
}
@@ -112,7 +118,10 @@ namespace
os << " " << v.t;
} break;
TU_ARM(e, ItemAddr, v) {
- os << "ADDROF " << v;
+ os << "ADDROF " << *v;
+ } break;
+ TU_ARM(e, Const, v) {
+ BUG(Span(), "Stray named constant in MIR after cleanup - " << e);
} break;
default:
os << e;
@@ -158,18 +167,18 @@ namespace
CodeGenerator_MonoMir(const ::HIR::Crate& crate, const ::std::string& outfile):
m_crate(crate),
m_resolve(crate),
- m_outfile_path(outfile + ".mir"),
- m_of(m_outfile_path)
+ m_outfile_path(outfile),
+ m_of(m_outfile_path + ".mir")
{
for( const auto& crate : m_crate.m_ext_crates )
{
- m_of << "crate \"" << FmtEscaped(crate.second.m_path) << ".o.mir\";\n";
+ m_of << "crate \"" << FmtEscaped(crate.second.m_path) << ".mir\";\n";
}
}
- void finalise(bool is_executable, const TransOptions& opt) override
+ void finalise(const TransOptions& opt, CodegenOutput out_ty, const ::std::string& hir_file) override
{
- if( is_executable )
+ if( out_ty == CodegenOutput::Executable )
{
m_of << "fn ::main#(isize, *const *const i8): isize {\n";
auto c_start_path = m_resolve.m_crate.get_lang_item_path_opt("mrustc-start");
@@ -190,10 +199,33 @@ namespace
m_of << "\t\tRETURN\n";
m_of << "\t}\n";
m_of << "}\n";
+
+ {
+ // Bind `panic_impl` lang item to the item tagged with `panic_implementation`
+ const auto& panic_impl_path = m_crate.get_lang_item_path(Span(), "mrustc-panic_implementation");
+ m_of << "fn ::panic_impl#(usize): u32 = \"panic_impl\":\"Rust\" {\n";
+ m_of << "\t0: {\n";
+ m_of << "\t\tCALL RETURN = " << panic_impl_path << "(arg0) goto 1 else 2\n";
+ m_of << "\t}\n";
+ m_of << "\t1: { RETURN }\n";
+ m_of << "\t2: { DIVERGE }\n";
+ m_of << "}\n";
+
+ // TODO: OOM impl?
+ }
}
m_of.flush();
m_of.close();
+
+ // HACK! Create the output file, but keep it empty
+ {
+ ::std::ofstream of( m_outfile_path );
+ if( !of.good() )
+ {
+ // TODO: Error?
+ }
+ }
}
@@ -233,14 +265,14 @@ namespace
m_of << "\t0: {\n";
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ auto self = ::MIR::LValue::new_Deref( ::MIR::LValue::new_Argument(0) );
+ auto fld_lv = ::MIR::LValue::new_Field(mv$(self), 0);
for(const auto& e : repr->fields)
{
if( m_resolve.type_needs_drop_glue(sp, e.ty) ) {
m_of << "\t\t""DROP " << fmt(fld_lv) << ";\n";
}
- fld_lv.as_Field().field_index += 1;
+ fld_lv.inc_Field();
}
m_of << "\t\t""RETURN\n";
m_of << "\t}\n";
@@ -336,9 +368,9 @@ namespace
const auto& te = t.m_data.as_TraitObject();
//auto vtp = t.m_data.as_TraitObject().m_trait.m_path;
- auto vtable_gp = te.m_trait.m_path.clone();
- vtable_gp.m_path.m_components.back() += "#vtable";
const auto& trait = resolve.m_crate.get_trait_by_path(sp, te.m_trait.m_path.m_path);
+ auto vtable_gp = ::HIR::GenericPath(trait.m_vtable_path);
+ vtable_gp.m_params = te.m_trait.m_path.m_params.clone();
vtable_gp.m_params.m_types.resize( vtable_gp.m_params.m_types.size() + trait.m_type_indexes.size() );
for(const auto& ty : trait.m_type_indexes) {
auto aty = te.m_trait.m_type_bounds.at(ty.first).clone();
@@ -364,8 +396,8 @@ namespace
};
- // TODO: Generate the drop glue (and determine if there is any)
- bool has_drop_glue = m_resolve.type_needs_drop_glue(sp, ty);
+ // Generate the drop glue (and determine if there is any)
+ bool has_drop_glue = m_resolve.type_needs_drop_glue(sp, ty);
const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty);
MIR_ASSERT(*m_mir_res, repr, "No repr for struct " << ty);
@@ -396,13 +428,13 @@ namespace
//ASSERT_BUG(sp, !item.m_markings.has_drop_impl, "Box shouldn't have a Drop impl");
// TODO: This is very specific to the structure of the official liballoc's Box.
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) });
- auto fld_p_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
- fld_p_lv = ::MIR::LValue::make_Field({ box$(fld_p_lv), 0 });
- fld_p_lv = ::MIR::LValue::make_Field({ box$(fld_p_lv), 0 });
+ auto self = ::MIR::LValue::new_Deref( ::MIR::LValue::new_Argument(0) );
+ auto fld_p_lv = ::MIR::LValue::new_Field( mv$(self), 0 );
+ fld_p_lv = ::MIR::LValue::new_Field( mv$(fld_p_lv), 0 );
+ fld_p_lv = ::MIR::LValue::new_Field( mv$(fld_p_lv), 0 );
if( m_resolve.type_needs_drop_glue(sp, *ity) ) {
- auto fld_lv = ::MIR::LValue::make_Deref({ box$(fld_p_lv.clone()) });
+ auto fld_lv = ::MIR::LValue::new_Deref( fld_p_lv.clone() );
m_of << "\t\t""DROP " << fmt(fld_lv) << ";\n";
}
@@ -432,14 +464,14 @@ namespace
m_of << "\t2: {\n";
}
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ auto self = ::MIR::LValue::new_Deref( ::MIR::LValue::new_Argument(0) );
+ auto fld_lv = ::MIR::LValue::new_Field( mv$(self), 0 );
for(const auto& e : repr->fields)
{
if( m_resolve.type_needs_drop_glue(sp, e.ty) ) {
m_of << "\t\t""DROP " << fmt(fld_lv) << ";\n";
}
- fld_lv.as_Field().field_index += 1;
+ fld_lv.inc_Field();
}
}
m_of << "\t\t""RETURN\n";
@@ -448,6 +480,51 @@ namespace
}
m_mir_res = nullptr;
}
+ virtual void emit_constructor_enum(const Span& sp, const ::HIR::GenericPath& var_path, const ::HIR::Enum& item, size_t var_idx)
+ {
+ TRACE_FUNCTION_F(var_path);
+
+ ::HIR::TypeRef tmp;
+ auto monomorph = [&](const auto& x)->const auto& {
+ if( monomorphise_type_needed(x) ) {
+ tmp = monomorphise_type(sp, item.m_params, var_path.m_params, x);
+ m_resolve.expand_associated_types(sp, tmp);
+ return tmp;
+ }
+ else {
+ return x;
+ }
+ };
+
+ auto enum_path = var_path.clone();
+ enum_path.m_path.m_components.pop_back();
+
+ // Create constructor function
+ const auto& var_ty = item.m_data.as_Data().at(var_idx).type;
+ const auto& e = var_ty.m_data.as_Path().binding.as_Struct()->m_data.as_Tuple();
+ m_of << "fn " << var_path << "(";
+ for(unsigned int i = 0; i < e.size(); i ++)
+ {
+ if(i != 0)
+ m_of << ", ";
+ m_of << monomorph(e[i].ent);
+ }
+ m_of << "): " << enum_path << " {\n";
+ m_of << "\tlet var0: " << monomorph(var_ty) << ";\n";
+ m_of << "\t0: {\n";
+ m_of << "\t\tASSIGN var0 = { ";
+ for(unsigned int i = 0; i < e.size(); i ++)
+ {
+ if(i != 0)
+ m_of << ", ";
+ m_of << "arg" << i;
+ }
+ m_of << " }: " << monomorph(var_ty) << ";\n";
+ m_of << "\t\tASSIGN RETURN = VARIANT " << enum_path << " " << var_idx << " var0;\n";
+ m_of << "\t\tRETURN\n";
+ m_of << "\t}\n";
+ m_of << "}";
+ }
void emit_constructor_struct(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Struct& item) override
{
TRACE_FUNCTION_F(p);
@@ -462,7 +539,7 @@ namespace
return x;
}
};
- // Crate constructor function
+ // Create constructor function
const auto& e = item.m_data.as_Tuple();
m_of << "fn " << p << "(";
for(unsigned int i = 0; i < e.size(); i ++)
@@ -494,10 +571,17 @@ namespace
TRACE_FUNCTION_F(p);
::HIR::TypeRef ty = ::HIR::TypeRef::new_path(p.clone(), &item);
+ bool has_drop_glue = m_resolve.type_needs_drop_glue(sp, ty);
+ auto drop_glue_path = ::HIR::Path(ty.clone(), "drop_glue#");
+
const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty);
MIR_ASSERT(*m_mir_res, repr, "No repr for union " << ty);
m_of << "type " << p << " {\n";
m_of << "\tSIZE " << repr->size << ", ALIGN " << repr->align << ";\n";
+ if( has_drop_glue )
+ {
+ m_of << "\tDROP " << drop_glue_path << ";\n";
+ }
for(const auto& e : repr->fields)
{
m_of << "\t" << e.offset << " = " << e.ty << ";\n";
@@ -508,28 +592,28 @@ namespace
}
m_of << "}\n";
- // TODO: Drop glue!
-#if 0
- // Drop glue (calls destructor if there is one)
- auto item_ty = ::HIR::TypeRef(p.clone(), &item);
- auto drop_glue_path = ::HIR::Path(item_ty.clone(), "#drop_glue");
- auto item_ptr_ty = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Owned, item_ty.clone());
- auto drop_impl_path = (item.m_markings.has_drop_impl ? ::HIR::Path(item_ty.clone(), m_resolve.m_lang_Drop, "drop") : ::HIR::Path(::HIR::SimplePath()));
- ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), item_ptr_ty, {}, empty_fcn };
- m_mir_res = &mir_res;
-
- if( item.m_markings.has_drop_impl )
- {
- m_of << "tUNIT " << Trans_Mangle(drop_impl_path) << "(union u_" << Trans_Mangle(p) << "*rv);\n";
- }
-
- m_of << "static void " << Trans_Mangle(drop_glue_path) << "(union u_" << Trans_Mangle(p) << "* rv) {\n";
- if( item.m_markings.has_drop_impl )
+ if( has_drop_glue )
{
- m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n";
+ m_of << "fn " << drop_glue_path << "(&move " << ty << ") {\n";
+ if( item.m_markings.has_drop_impl ) {
+ m_of << "\tlet nms: &mut " << ty << ";\n";
+ }
+ m_of << "\t0: {\n";
+ if( item.m_markings.has_drop_impl )
+ {
+ m_of << "\t\t""ASSIGN nms = &mut *arg0;\n";
+ m_of << "\t\t""CALL unit = " << ::HIR::Path(ty.clone(), m_resolve.m_lang_Drop, "drop") << "(nms) goto 2 else 1\n";
+ m_of << "\t}\n";
+ m_of << "\t1: {\n";
+ m_of << "\t\tDIVERGE\n";
+ m_of << "\t}\n";
+ m_of << "\t2: {\n";
+ }
+ // NOTE: Unions don't drop inner values, but do call the destructor
+ m_of << "\t\tRETURN\n";
+ m_of << "\t}\n";
+ m_of << "}\n";
}
- m_of << "}\n";
-#endif
}
void emit_enum(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Enum& item) override
@@ -542,11 +626,18 @@ namespace
TRACE_FUNCTION_F(p);
::HIR::TypeRef ty = ::HIR::TypeRef::new_path(p.clone(), &item);
+ // Generate the drop glue (and determine if there is any)
+ bool has_drop_glue = m_resolve.type_needs_drop_glue(sp, ty);
+ auto drop_glue_path = ::HIR::Path(ty.clone(), "drop_glue#");
+
const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty);
MIR_ASSERT(*m_mir_res, repr, "No repr for enum " << ty);
m_of << "type " << p << " {\n";
m_of << "\tSIZE " << repr->size << ", ALIGN " << repr->align << ";\n";
- // TODO: Drop glue path
+ if( has_drop_glue )
+ {
+ m_of << "\tDROP " << drop_glue_path << ";\n";
+ }
for(const auto& e : repr->fields)
{
m_of << "\t" << e.offset << " = " << e.ty << ";\n";
@@ -591,64 +682,61 @@ namespace
}
m_of << "}\n";
-#if 0
// ---
// - Drop Glue
// ---
- auto struct_ty = ::HIR::TypeRef(p.clone(), &item);
- auto drop_glue_path = ::HIR::Path(struct_ty.clone(), "#drop_glue");
- auto struct_ty_ptr = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Owned, struct_ty.clone());
- auto drop_impl_path = (item.m_markings.has_drop_impl ? ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") : ::HIR::Path(::HIR::SimplePath()));
- ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, {}, empty_fcn };
- m_mir_res = &mir_res;
-
- if( item.m_markings.has_drop_impl )
- {
- m_of << "tUNIT " << Trans_Mangle(drop_impl_path) << "(struct e_" << Trans_Mangle(p) << "*rv);\n";
- }
-
- m_of << "static void " << Trans_Mangle(drop_glue_path) << "(struct e_" << Trans_Mangle(p) << "* rv) {\n";
-
- // If this type has an impl of Drop, call that impl
- if( item.m_markings.has_drop_impl )
- {
- m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n";
- }
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
-
- if( nonzero_path.size() > 0 )
- {
- // TODO: Fat pointers?
- m_of << "\tif( (*rv)._1"; emit_nonzero_path(nonzero_path); m_of << " ) {\n";
- emit_destructor_call( ::MIR::LValue::make_Field({ box$(self), 1 }), monomorph(item.m_data.as_Data()[1].type), false, 2 );
- m_of << "\t}\n";
- }
- else if( const auto* e = item.m_data.opt_Data() )
+ if( has_drop_glue )
{
- auto var_lv =::MIR::LValue::make_Downcast({ box$(self), 0 });
+ m_of << "fn " << drop_glue_path << "(&move " << ty << ") {\n";
+ if( item.m_markings.has_drop_impl ) {
+ m_of << "\tlet nms: &mut " << ty << ";\n";
+ }
+ m_of << "\t0: {\n";
- m_of << "\tswitch(rv->TAG) {\n";
- for(unsigned int var_idx = 0; var_idx < e->size(); var_idx ++)
+ size_t first_drop_bb;
+ if( item.m_markings.has_drop_impl )
{
- var_lv.as_Downcast().variant_index = var_idx;
- m_of << "\tcase " << var_idx << ":\n";
- emit_destructor_call(var_lv, monomorph( (*e)[var_idx].type ), false, 2);
- m_of << "\tbreak;\n";
+ m_of << "\t\t""ASSIGN nms = &mut *arg0;\n";
+ m_of << "\t\t""CALL unit = " << ::HIR::Path(ty.clone(), m_resolve.m_lang_Drop, "drop") << "(nms) goto 2 else 1\n";
+ m_of << "\t}\n";
+ m_of << "\t1: {\n";
+ m_of << "\t\tDIVERGE\n";
+ m_of << "\t}\n";
+ m_of << "\t2: {\n";
+ first_drop_bb = 3;
}
- m_of << "\t}\n";
- }
- else
- {
- // Value enum
- // Glue does nothing (except call the destructor, if there is one)
+ else
+ {
+ first_drop_bb = 1;
+ }
+ if( const auto* e = item.m_data.opt_Data() )
+ {
+ m_of << "\t\tSWITCH *arg0 { ";
+ for(unsigned int var_idx = 0; var_idx < e->size(); var_idx ++)
+ {
+ if( var_idx != 0 )
+ {
+ m_of << ", ";
+ }
+ m_of << (first_drop_bb + var_idx);
+ }
+ m_of << " }\n";
+ m_of << "\t}\n";
+ for(unsigned int var_idx = 0; var_idx < e->size(); var_idx ++)
+ {
+ m_of << "\t" << (first_drop_bb+var_idx) << ": {\n";
+ m_of << "\t\tDROP (*arg0)@" << var_idx << ";\n";
+ m_of << "\t\tRETURN\n";
+ m_of << "\t}\n";
+ }
+ }
+ else
+ {
+ m_of << "\t}\n";
+ }
+ m_of << "}\n";
}
- m_of << "}\n";
- if( nonzero_path.size() )
- {
- m_enum_repr_cache.insert( ::std::make_pair( p.clone(), mv$(nonzero_path) ) );
- }
-#endif
m_mir_res = nullptr;
}
struct Reloc {
@@ -656,6 +744,13 @@ namespace
size_t len;
const ::HIR::Path* p;
::std::string bytes;
+
+ static Reloc new_named(size_t ofs, size_t len, const ::HIR::Path* p) {
+ return Reloc { ofs, len, p, "" };
+ }
+ static Reloc new_bytes(size_t ofs, size_t len, ::std::string bytes) {
+ return Reloc { ofs, len, nullptr, ::std::move(bytes) };
+ }
};
void emit_str_byte(uint8_t b) {
if( b == 0 ) {
@@ -845,9 +940,9 @@ namespace
{
ASSERT_BUG(sp, lit.is_String(), ty << " not Literal::String - " << lit);
const auto& s = lit.as_String();
- putsize(0);
+ putsize(PTR_BASE + 0);
putsize(s.size());
- out_relocations.push_back(Reloc { base_ofs, 8, nullptr, s });
+ out_relocations.push_back(Reloc::new_bytes(base_ofs, 8, s));
break;
}
// fall
@@ -856,35 +951,41 @@ namespace
size_t ity_size, ity_align;
Target_GetSizeAndAlignOf(sp, m_resolve, ity, ity_size, ity_align);
bool is_unsized = (ity_size == SIZE_MAX);
- if( lit.is_BorrowPath() )
- {
- putsize(0);
- out_relocations.push_back(Reloc { base_ofs, 8, &lit.as_BorrowPath(), "" });
+
+ TU_MATCH_HDRA( (lit), { )
+ TU_ARMA(BorrowPath, le) {
+ putsize(PTR_BASE);
+ out_relocations.push_back(Reloc::new_named(base_ofs, 8, &le));
if( is_unsized )
{
// TODO: Get the size of the pointed-to array
// OR: Find out the source item type and the target trait.
putsize(0);
}
- break;
- }
- else if( lit.is_Integer() )
- {
- ASSERT_BUG(sp, lit.as_Integer() == 0, "Pointer from integer not 0");
+ }
+ TU_ARMA(Integer, le) {
+ ASSERT_BUG(sp, le == 0, "Pointer from integer not 0");
ASSERT_BUG(sp, ty.m_data.is_Pointer(), "Borrow from integer");
- putsize(0);
+ putsize(le);
if( is_unsized )
{
putsize(0);
}
- break;
+ }
+ TU_ARMA(String, le) {
+ const auto& s = lit.as_String();
+ putsize(PTR_BASE);
+ putsize(s.size());
+ out_relocations.push_back(Reloc::new_bytes(base_ofs, 8, s));
+ }
+ break; default:
+ TODO(sp, "Emit a pointer - " << ty << " from literal " << lit);
}
- TODO(sp, "Pointers - " << ty << " w/ " << lit);
} break;
case ::HIR::TypeRef::Data::TAG_Function:
ASSERT_BUG(sp, lit.is_BorrowPath(), ty << " not Literal::BorrowPath - " << lit);
- putsize(0);
- out_relocations.push_back(Reloc { base_ofs, 8, &lit.as_BorrowPath(), "" });
+ putsize(PTR_BASE);
+ out_relocations.push_back(Reloc::new_named(base_ofs, 8, &lit.as_BorrowPath()));
break;
TU_ARM(ty.m_data, Array, te) {
// What about byte strings?
@@ -936,16 +1037,17 @@ namespace
const size_t ptr_size = Target_GetCurSpec().m_arch.m_pointer_bits / 8;
const auto& trait_path = p.m_data.as_UfcsKnown().trait;
const auto& type = *p.m_data.as_UfcsKnown().type;
+ bool has_drop_glue = m_resolve.type_needs_drop_glue(sp, type);
::HIR::TypeRef vtable_ty;
{
- auto vtable_sp = trait_path.m_path;
- vtable_sp.m_components.back() += "#vtable";
+ const auto& vtable_sp = trait.m_vtable_path;
auto vtable_params = trait_path.m_params.clone();
for(const auto& ty : trait.m_type_indexes) {
auto aty = ::HIR::TypeRef( ::HIR::Path( type.clone(), trait_path.clone(), ty.first ) );
m_resolve.expand_associated_types(sp, aty);
vtable_params.m_types.push_back( mv$(aty) );
+ //vtable_params.m_types.at(ty.second) = ::std::move(aty);
}
const auto& vtable_ref = m_crate.get_struct_by_path(sp, vtable_sp);
vtable_ty = ::HIR::TypeRef( ::HIR::GenericPath(mv$(vtable_sp), mv$(vtable_params)), &vtable_ref );
@@ -956,7 +1058,7 @@ namespace
m_of << "static " << p << ": " << vtable_ty << " = \"";
// - Data
// Drop
- emit_str_usize(0);
+ emit_str_usize(has_drop_glue ? PTR_BASE : 0);
// Align
emit_str_usize(align);
// Size
@@ -964,15 +1066,17 @@ namespace
// Methods
for(unsigned int i = 0; i < trait.m_value_indexes.size(); i ++ )
{
- emit_str_usize(0);
+ emit_str_usize(PTR_BASE);
}
m_of << "\" {";
// - Relocations
auto monomorph_cb_trait = monomorphise_type_get_cb(sp, &type, &trait_path.m_params, nullptr);
// Drop
- // - TODO: Some types don't have drop glue
- m_of << "@0+" << ptr_size << " = " << ::HIR::Path(type.clone(), "drop_glue#") << ", ";
+ if( has_drop_glue )
+ {
+ m_of << "@0+" << ptr_size << " = " << ::HIR::Path(type.clone(), "drop_glue#") << ", ";
+ }
// Methods
for(unsigned int i = 0; i < trait.m_value_indexes.size(); i ++ )
{
@@ -1029,11 +1133,6 @@ namespace
::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << p;), ret_type, arg_types, *code };
m_mir_res = &mir_res;
- if( item.m_linkage.name != "" )
- {
- // TODO: Save the linkage name.
- }
-
// - Signature
m_of << "fn " << p << "(";
for(unsigned int i = 0; i < item.m_args.size(); i ++)
@@ -1041,7 +1140,12 @@ namespace
if( i != 0 ) m_of << ", ";
m_of << params.monomorph(m_resolve, item.m_args[i].second);
}
- m_of << "): " << ret_type << " {\n";
+ m_of << "): " << ret_type;
+ if( item.m_linkage.name != "" )
+ {
+ m_of << " = \"" << item.m_linkage.name << "\":\"" << item.m_abi << "\"";
+ }
+ m_of << " {\n";
// - Locals
for(unsigned int i = 0; i < code->locals.size(); i ++) {
DEBUG("var" << i << " : " << code->locals[i]);
@@ -1103,8 +1207,8 @@ namespace
case ::MIR::eBinOp::SUB_OV: m_of << "-^"; break;
case ::MIR::eBinOp::MUL: m_of << "*"; break;
case ::MIR::eBinOp::MUL_OV: m_of << "*^"; break;
- case ::MIR::eBinOp::DIV: m_of << "*"; break;
- case ::MIR::eBinOp::DIV_OV: m_of << "*^"; break;
+ case ::MIR::eBinOp::DIV: m_of << "/"; break;
+ case ::MIR::eBinOp::DIV_OV: m_of << "/^"; break;
case ::MIR::eBinOp::MOD: m_of << "%"; break;
case ::MIR::eBinOp::BIT_OR: m_of << "|"; break;
case ::MIR::eBinOp::BIT_AND:m_of << "&"; break;
diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp
index 4e04ddf9..d8426022 100644
--- a/src/trans/enumerate.cpp
+++ b/src/trans/enumerate.cpp
@@ -11,6 +11,7 @@
#include "trans_list.hpp"
#include <hir/hir.hpp>
#include <mir/mir.hpp>
+#include <mir/helpers.hpp>
#include <hir_typeck/common.hpp> // monomorph
#include <hir_typeck/static.hpp> // StaticTraitResolve
#include <hir/item_path.hpp>
@@ -47,11 +48,12 @@ namespace {
TransList Trans_Enumerate_CommonPost(EnumState& state);
void Trans_Enumerate_Types(EnumState& state);
void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, const Trans_Params& pp);
+void Trans_Enumerate_FillFrom_PathMono(EnumState& state, ::HIR::Path path);
void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Function& function, const Trans_Params& pp);
void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Static& stat, TransList_Static& stat_out, Trans_Params pp={});
void Trans_Enumerate_FillFrom_VTable (EnumState& state, ::HIR::Path vtable_path, const Trans_Params& pp);
void Trans_Enumerate_FillFrom_Literal(EnumState& state, const ::HIR::Literal& lit, const Trans_Params& pp);
-void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, const Trans_Params& pp);
+void Trans_Enumerate_FillFrom_MIR(MIR::EnumCache& state, const ::MIR::Function& code);
/// Enumerate trans items starting from `::main` (binary crate)
TransList Trans_Enumerate_Main(const ::HIR::Crate& crate)
@@ -63,21 +65,25 @@ TransList Trans_Enumerate_Main(const ::HIR::Crate& crate)
auto c_start_path = crate.get_lang_item_path_opt("mrustc-start");
if( c_start_path == ::HIR::SimplePath() )
{
+ // user entrypoint
+ auto main_path = crate.get_lang_item_path(Span(), "mrustc-main");
+ const auto& main_fcn = crate.get_function_by_path(sp, main_path);
+
+ state.enum_fcn( main_path, main_fcn, {} );
+
// "start" language item
// - Takes main, and argc/argv as arguments
{
auto start_path = crate.get_lang_item_path(sp, "start");
const auto& fcn = crate.get_function_by_path(sp, start_path);
- state.enum_fcn( start_path, fcn, {} );
- }
-
- // user entrypoint
- {
- auto main_path = crate.get_lang_item_path(Span(), "mrustc-main");
- const auto& fcn = crate.get_function_by_path(sp, main_path);
-
- state.enum_fcn( main_path, fcn, {} );
+ Trans_Params lang_start_pp;
+ if( TARGETVER_1_29 )
+ {
+ // With 1.29, this now takes main's return type as a type parameter
+ lang_start_pp.pp_method.m_types.push_back( main_fcn.m_return.clone() );
+ }
+ state.enum_fcn( start_path, fcn, mv$(lang_start_pp) );
}
}
else
@@ -148,39 +154,29 @@ namespace {
const bool EMIT_ALL = true;
for(auto& vi : mod.m_value_items)
{
- Trans_Enumerate_ValItem(state, vi.second->ent, EMIT_ALL || (is_visible && vi.second->is_public), [&](){ return mod_path + vi.first; });
+ Trans_Enumerate_ValItem(state, vi.second->ent, EMIT_ALL || (is_visible && vi.second->publicity.is_global()), [&](){ return mod_path + vi.first; });
}
for(auto& ti : mod.m_mod_items)
{
if(auto* e = ti.second->ent.opt_Module() )
{
- Trans_Enumerate_Public_Mod(state, *e, mod_path + ti.first, ti.second->is_public);
+ Trans_Enumerate_Public_Mod(state, *e, mod_path + ti.first, ti.second->publicity.is_global());
}
}
}
-}
-
-/// Enumerate trans items for all public non-generic items (library crate)
-TransList Trans_Enumerate_Public(::HIR::Crate& crate)
-{
- static Span sp;
- EnumState state { crate };
- Trans_Enumerate_Public_Mod(state, crate.m_root_module, ::HIR::SimplePath(crate.m_crate_name,{}), true);
-
- // Impl blocks
- StaticTraitResolve resolve { crate };
- for(auto& impl : crate.m_trait_impls)
+ void Trans_Enumerate_Public_TraitImpl(EnumState& state, StaticTraitResolve& resolve, const ::HIR::SimplePath& trait_path, /*const*/ ::HIR::TraitImpl& impl)
{
- const auto& impl_ty = impl.second.m_type;
- TRACE_FUNCTION_F("Impl " << impl.first << impl.second.m_trait_args << " for " << impl_ty);
- if( impl.second.m_params.m_types.size() == 0 )
+ static Span sp;
+ const auto& impl_ty = impl.m_type;
+ TRACE_FUNCTION_F("Impl " << trait_path << impl.m_trait_args << " for " << impl_ty);
+ if( impl.m_params.m_types.size() == 0 )
{
- auto cb_monomorph = monomorphise_type_get_cb(sp, &impl_ty, &impl.second.m_trait_args, nullptr);
+ auto cb_monomorph = monomorphise_type_get_cb(sp, &impl_ty, &impl.m_trait_args, nullptr);
// Emit each method/static (in the trait itself)
- const auto& trait = crate.get_trait_by_path(sp, impl.first);
+ const auto& trait = resolve.m_crate.get_trait_by_path(sp, trait_path);
for(const auto& vi : trait.m_values)
{
TRACE_FUNCTION_F("Item " << vi.first << " : " << vi.second.tag_str());
@@ -222,11 +218,12 @@ TransList Trans_Enumerate_Public(::HIR::Crate& crate)
if( !rv )
continue ;
}
- auto p = ::HIR::Path(impl_ty.clone(), ::HIR::GenericPath(impl.first, impl.second.m_trait_args.clone()), vi.first);
- Trans_Enumerate_FillFrom_Path(state, p, {});
+ auto path = ::HIR::Path(impl_ty.clone(), ::HIR::GenericPath(trait_path, impl.m_trait_args.clone()), vi.first);
+ Trans_Enumerate_FillFrom_PathMono(state, mv$(path));
+ //state.enum_fcn(mv$(path), fcn.second.data, {});
}
}
- for(auto& m : impl.second.m_methods)
+ for(auto& m : impl.m_methods)
{
if( m.second.data.m_params.m_types.size() > 0 )
m.second.data.m_save_code = true;
@@ -234,37 +231,88 @@ TransList Trans_Enumerate_Public(::HIR::Crate& crate)
}
else
{
- for(auto& m : impl.second.m_methods)
+ for(auto& m : impl.m_methods)
{
m.second.data.m_save_code = true;
}
}
}
- for(auto& impl : crate.m_type_impls)
+}
+
+/// Enumerate trans items for all public non-generic items (library crate)
+TransList Trans_Enumerate_Public(::HIR::Crate& crate)
+{
+ static Span sp;
+ EnumState state { crate };
+
+ Trans_Enumerate_Public_Mod(state, crate.m_root_module, ::HIR::SimplePath(crate.m_crate_name,{}), true);
+
+ // Impl blocks
+ StaticTraitResolve resolve { crate };
+ for(auto& impl_group : crate.m_trait_impls)
{
- if( impl.m_params.m_types.size() == 0 )
+ const auto& trait_path = impl_group.first;
+ for(auto& impl_list : impl_group.second.named)
{
- for(auto& fcn : impl.m_methods)
+ for(auto& impl : impl_list.second)
{
- if( fcn.second.data.m_params.m_types.size() == 0 )
+ Trans_Enumerate_Public_TraitImpl(state, resolve, trait_path, *impl);
+ }
+ }
+ for(auto& impl : impl_group.second.non_named)
+ {
+ Trans_Enumerate_Public_TraitImpl(state, resolve, trait_path, *impl);
+ }
+ for(auto& impl : impl_group.second.generic)
+ {
+ Trans_Enumerate_Public_TraitImpl(state, resolve, trait_path, *impl);
+ }
+ }
+ struct H1
+ {
+ static void enumerate_type_impl(EnumState& state, ::HIR::TypeImpl& impl)
+ {
+ TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << impl.m_type);
+ if( impl.m_params.m_types.size() == 0 )
+ {
+ for(auto& fcn : impl.m_methods)
{
- auto p = ::HIR::Path(impl.m_type.clone(), fcn.first);
- Trans_Enumerate_FillFrom_Path(state, p, {});
+ DEBUG("fn " << fcn.first << fcn.second.data.m_params.fmt_args());
+ if( fcn.second.data.m_params.m_types.size() == 0 )
+ {
+ auto path = ::HIR::Path(impl.m_type.clone(), fcn.first);
+ state.enum_fcn(mv$(path), fcn.second.data, {});
+ }
+ else
+ {
+ fcn.second.data.m_save_code = true;
+ }
}
- else
+ }
+ else
+ {
+ for(auto& m : impl.m_methods)
{
- fcn.second.data.m_save_code = true;
+ m.second.data.m_save_code = true;
}
}
}
- else
+ };
+ for(auto& impl_grp : crate.m_type_impls.named)
+ {
+ for(auto& impl : impl_grp.second)
{
- for(auto& m : impl.m_methods)
- {
- m.second.data.m_save_code = true;
- }
+ H1::enumerate_type_impl(state, *impl);
}
}
+ for(auto& impl : crate.m_type_impls.non_named)
+ {
+ H1::enumerate_type_impl(state, *impl);
+ }
+ for(auto& impl : crate.m_type_impls.generic)
+ {
+ H1::enumerate_type_impl(state, *impl);
+ }
auto rv = Trans_Enumerate_CommonPost(state);
@@ -332,6 +380,7 @@ TransList Trans_Enumerate_Public(::HIR::Crate& crate)
return rv;
}
+#if 0
void Trans_Enumerate_Cleanup(const ::HIR::Crate& crate, TransList& list)
{
EnumState state { crate };
@@ -377,6 +426,7 @@ void Trans_Enumerate_Cleanup(const ::HIR::Crate& crate, TransList& list)
ASSERT_BUG(Span(), it != list.m_functions.end(), "Enumerate Error - New function appeared after monomorphisation - " << e.first);
}
}
+#endif
/// Common post-processing
void Trans_Enumerate_CommonPost_Run(EnumState& state)
@@ -400,7 +450,8 @@ TransList Trans_Enumerate_CommonPost(EnumState& state)
return mv$(state.rv);
}
-namespace {
+namespace
+{
struct PtrComp
{
template<typename T>
@@ -413,7 +464,8 @@ namespace {
::StaticTraitResolve m_resolve;
::std::vector< ::std::pair< ::HIR::TypeRef, bool> >& out_list;
- ::std::map< ::HIR::TypeRef, bool > visited;
+ // TODO: Have a list of indexes into `out_list`, sorted by typeref ordering
+ ::std::vector<size_t> visited_map;
::std::set< const ::HIR::TypeRef*, PtrComp> active_set;
TypeVisitor(const ::HIR::Crate& crate, ::std::vector< ::std::pair< ::HIR::TypeRef, bool > >& out_list):
@@ -422,6 +474,11 @@ namespace {
out_list(out_list)
{}
+ ~TypeVisitor()
+ {
+ DEBUG("Visited a total of " << visited_map.size());
+ }
+
void visit_struct(const ::HIR::GenericPath& path, const ::HIR::Struct& item) {
static Span sp;
::HIR::TypeRef tmp;
@@ -499,16 +556,16 @@ namespace {
{
// If the type has already been visited, AND either this is a shallow visit, or the previous wasn't
{
- auto it = visited.find(ty);
- if( it != visited.end() )
+ auto idx_it = ::std::lower_bound(visited_map.begin(), visited_map.end(), ty, [&](size_t i, const ::HIR::TypeRef& t){ return out_list[i].first < t; });
+ if( idx_it != visited_map.end() && out_list[*idx_it].first == ty)
{
+ auto it = &out_list[*idx_it];
if( it->second == false || mode == Mode::Shallow )
{
// Return early
return ;
}
DEBUG("-- " << ty << " already visited as shallow");
- it->second = false;
}
}
TRACE_FUNCTION_F(ty << " - " << (mode == Mode::Shallow ? "Shallow" : (mode == Mode::Normal ? "Normal" : "Deep")));
@@ -566,6 +623,9 @@ namespace {
(Opaque,
BUG(Span(), "Opaque type hit in enumeration - " << ty);
),
+ (ExternType,
+ // No innards to visit
+ ),
(Struct,
visit_struct(te.path.m_data.as_Generic(), *tpb);
),
@@ -583,8 +643,7 @@ namespace {
const auto& trait = *te.m_trait.m_trait_ptr;
ASSERT_BUG(Span(), ! te.m_trait.m_path.m_path.m_components.empty(), "TODO: Data trait is empty, what can be done?");
- auto vtable_ty_spath = te.m_trait.m_path.m_path;
- vtable_ty_spath.m_components.back() += "#vtable";
+ const auto& vtable_ty_spath = trait.m_vtable_path;
const auto& vtable_ref = m_crate.get_struct_by_path(sp, vtable_ty_spath);
// Copy the param set from the trait in the trait object
::HIR::PathParams vtable_params = te.m_trait.m_path.m_params.clone();
@@ -626,36 +685,30 @@ namespace {
bool shallow = (mode == Mode::Shallow);
{
- auto rv = visited.insert( ::std::make_pair(ty.clone(), shallow) );
- if( !rv.second && ! shallow )
+ auto idx_it = ::std::lower_bound(visited_map.begin(), visited_map.end(), ty, [&](size_t i, const ::HIR::TypeRef& t){ return out_list[i].first < t; });
+ if( idx_it == visited_map.end() || out_list[*idx_it].first != ty )
{
- rv.first->second = false;
+ // Add a new entry
+ visited_map.insert(idx_it, out_list.size());
+ }
+ else
+ {
+ // Previous visit was shallow, but this one isn't
+ // - Update the entry to the to-be-pushed entry with shallow=false
+ if( !shallow && out_list[*idx_it].second )
+ {
+ *idx_it = out_list.size();
+ }
}
}
out_list.push_back( ::std::make_pair(ty.clone(), shallow) );
DEBUG("Add type " << ty << (shallow ? " (Shallow)": ""));
}
- };
-}
-
-// Enumerate types required for the enumerated items
-void Trans_Enumerate_Types(EnumState& state)
-{
- static Span sp;
- TypeVisitor tv { state.crate, state.rv.m_types };
- unsigned int types_count = 0;
- bool constructors_added;
- do
- {
- // Visit all functions that haven't been type-visited yet
- for(unsigned int i = 0; i < state.fcns_to_type_visit.size(); i++)
+ void __attribute__ ((noinline)) visit_function(const ::HIR::Path& path, const ::HIR::Function& fcn, const Trans_Params& pp)
{
- auto p = state.fcns_to_type_visit[i];
- TRACE_FUNCTION_F("Function " << ::std::find_if(state.rv.m_functions.begin(), state.rv.m_functions.end(), [&](const auto&x){ return x.second.get() == p; })->first);
- assert(p->ptr);
- const auto& fcn = *p->ptr;
- const auto& pp = p->pp;
+ Span sp;
+ auto& tv = *this;
::HIR::TypeRef tmp;
auto monomorph = [&](const auto& ty)->const auto& {
@@ -693,284 +746,170 @@ void Trans_Enumerate_Types(EnumState& state)
for(const auto& ty : mir.locals)
tv.visit_type(monomorph(ty));
- // TODO: Find all LValue::Deref instances and get the result type
+ // Find all LValue::Deref instances and get the result type
+ ::MIR::TypeResolve::args_t empty_args;
+ ::HIR::TypeRef empty_ty;
+ ::MIR::TypeResolve mir_res(sp, tv.m_resolve, FMT_CB(fcn_path), /*ret_ty=*/empty_ty, empty_args, mir);
for(const auto& block : mir.blocks)
{
- struct H {
- static const ::HIR::TypeRef& visit_lvalue(TypeVisitor& tv, const Trans_Params& pp, const ::HIR::Function& fcn, const ::MIR::LValue& lv, ::HIR::TypeRef* tmp_ty_ptr = nullptr) {
- static ::HIR::TypeRef blank;
- TRACE_FUNCTION_F(lv << (tmp_ty_ptr ? " [type]" : ""));
+ struct MirVisitor
+ //:public ::MIR::Visitor
+ {
+ TypeVisitor& tv;
+ const Trans_Params& pp;
+ const ::HIR::Function& fcn;
+ const ::MIR::TypeResolve& mir_res;
+
+ MirVisitor(TypeVisitor& tv, const Trans_Params& pp, const ::HIR::Function& fcn, const ::MIR::TypeResolve& mir_res)
+ :tv(tv)
+ ,pp(pp)
+ ,fcn(fcn)
+ ,mir_res(mir_res)
+ {
+ }
+
+ void visit_lvalue(const ::MIR::LValue& lv) //override
+ {
+ TRACE_FUNCTION_F(lv);
+ if( ::std::none_of(lv.m_wrappers.begin(), lv.m_wrappers.end(), [](const auto& w){ return w.is_Deref(); }) )
+ {
+ return ;
+ }
+ ::HIR::TypeRef tmp;
auto monomorph_outer = [&](const auto& tpl)->const auto& {
- assert(tmp_ty_ptr);
if( monomorphise_type_needed(tpl) ) {
- return *tmp_ty_ptr = pp.monomorph(tv.m_resolve, tpl);
+ return tmp = pp.monomorph(tv.m_resolve, tpl);
}
else {
return tpl;
}
};
+ const ::HIR::TypeRef* ty_p = nullptr;;
// Recurse, if Deref get the type and add it to the visitor
- TU_MATCHA( (lv), (e),
+ TU_MATCHA( (lv.m_root), (e),
(Return,
- if( tmp_ty_ptr ) {
- TODO(Span(), "Get return type for MIR type enumeration");
- }
+ MIR_TODO(mir_res, "Get return type for MIR type enumeration");
),
(Argument,
- if( tmp_ty_ptr ) {
- return monomorph_outer(fcn.m_args[e.idx].second);
- }
+ ty_p = &monomorph_outer(fcn.m_args[e].second);
),
(Local,
- if( tmp_ty_ptr ) {
- return monomorph_outer(fcn.m_code.m_mir->locals[e]);
- }
+ ty_p = &monomorph_outer(fcn.m_code.m_mir->locals[e]);
),
(Static,
- if( tmp_ty_ptr ) {
- const auto& path = e;
- TU_MATCHA( (path.m_data), (pe),
- (Generic,
- ASSERT_BUG(Span(), pe.m_params.m_types.empty(), "Path params on static - " << path);
- const auto& s = tv.m_resolve.m_crate.get_static_by_path(Span(), pe.m_path);
- return s.m_type;
- ),
- (UfcsKnown,
- TODO(Span(), "LValue::Static - UfcsKnown - " << path);
- ),
- (UfcsUnknown,
- BUG(Span(), "Encountered UfcsUnknown in LValue::Static - " << path);
- ),
- (UfcsInherent,
- TODO(Span(), "LValue::Static - UfcsInherent - " << path);
- )
- )
- }
- ),
- (Field,
- const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr);
- if( tmp_ty_ptr )
- {
- TU_MATCH_DEF(::HIR::TypeRef::Data, (ity.m_data), (te),
- (
- BUG(Span(), "Field access of unexpected type - " << ity);
- ),
- (Tuple,
- return te[e.field_index];
- ),
- (Array,
- return *te.inner;
- ),
- (Slice,
- return *te.inner;
- ),
- (Path,
- ASSERT_BUG(Span(), te.binding.is_Struct(), "Field on non-Struct - " << ity);
- const auto& str = *te.binding.as_Struct();
- auto monomorph = [&](const auto& ty)->const auto& {
- if( monomorphise_type_needed(ty) ) {
- *tmp_ty_ptr = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, ty);
- tv.m_resolve.expand_associated_types(sp, *tmp_ty_ptr);
- return *tmp_ty_ptr;
- }
- else {
- return ty;
- }
- };
- TU_MATCHA( (str.m_data), (se),
- (Unit,
- BUG(Span(), "Field on unit-like struct - " << ity);
- ),
- (Tuple,
- ASSERT_BUG(Span(), e.field_index < se.size(), "Field index out of range in struct " << te.path);
- return monomorph(se.at(e.field_index).ent);
- ),
- (Named,
- ASSERT_BUG(Span(), e.field_index < se.size(), "Field index out of range in struct " << te.path);
- return monomorph(se.at(e.field_index).second.ent);
- )
- )
- )
- )
- }
- ),
- (Deref,
- ::HIR::TypeRef tmp;
- if( !tmp_ty_ptr ) tmp_ty_ptr = &tmp;
-
- const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr);
- TU_MATCH_DEF(::HIR::TypeRef::Data, (ity.m_data), (te),
- (
- BUG(Span(), "Deref of unexpected type - " << ity);
+ // TODO: Monomorphise the path then hand to MIR::TypeResolve?
+ const auto& path = e;
+ TU_MATCHA( (path.m_data), (pe),
+ (Generic,
+ MIR_ASSERT(mir_res, pe.m_params.m_types.empty(), "Path params on static - " << path);
+ const auto& s = tv.m_resolve.m_crate.get_static_by_path(mir_res.sp, pe.m_path);
+ ty_p = &s.m_type;
),
- (Path,
- if( const auto* inner_ptr = tv.m_resolve.is_type_owned_box(ity) )
- {
- DEBUG("- Add type " << ity);
- tv.visit_type(*inner_ptr);
- return *inner_ptr;
- }
- else {
- BUG(Span(), "Deref on unexpected type - " << ity);
- }
+ (UfcsKnown,
+ MIR_TODO(mir_res, "LValue::Static - UfcsKnown - " << path);
),
- (Borrow,
- DEBUG("- Add type " << ity);
- tv.visit_type(*te.inner);
- return *te.inner;
+ (UfcsUnknown,
+ MIR_BUG(mir_res, "Encountered UfcsUnknown in LValue::Static - " << path);
),
- (Pointer,
- DEBUG("- Add type " << ity);
- tv.visit_type(*te.inner);
- return *te.inner;
+ (UfcsInherent,
+ MIR_TODO(mir_res, "LValue::Static - UfcsInherent - " << path);
)
)
- ),
- (Index,
- visit_lvalue(tv,pp,fcn, *e.idx, tmp_ty_ptr);
- const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr);
- if( tmp_ty_ptr )
- {
- TU_MATCH_DEF(::HIR::TypeRef::Data, (ity.m_data), (te),
- (
- BUG(Span(), "Index of unexpected type - " << ity);
- ),
- (Array,
- return *te.inner;
- ),
- (Slice,
- return *te.inner;
- )
- )
- }
- ),
- (Downcast,
- const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr);
- if( tmp_ty_ptr )
- {
- TU_MATCH_DEF( ::HIR::TypeRef::Data, (ity.m_data), (te),
- (
- BUG(Span(), "Downcast on unexpected type - " << ity);
- ),
- (Path,
- if( te.binding.is_Enum() )
- {
- const auto& enm = *te.binding.as_Enum();
- auto monomorph = [&](const auto& ty)->auto {
- ::HIR::TypeRef rv = monomorphise_type(pp.sp, enm.m_params, te.path.m_data.as_Generic().m_params, ty);
- tv.m_resolve.expand_associated_types(sp, rv);
- return rv;
- };
- ASSERT_BUG(Span(), enm.m_data.is_Data(), "");
- const auto& variants = enm.m_data.as_Data();
- ASSERT_BUG(Span(), e.variant_index < variants.size(), "Variant index out of range");
- const auto& raw_ty = variants[e.variant_index].type;
- if( monomorphise_type_needed(raw_ty) ) {
- return *tmp_ty_ptr = monomorph(raw_ty);
- }
- else {
- return raw_ty;
- }
- }
- else
- {
- const auto& unm = *te.binding.as_Union();
- ASSERT_BUG(Span(), e.variant_index < unm.m_variants.size(), "Variant index out of range");
- const auto& variant = unm.m_variants[e.variant_index];
- const auto& var_ty = variant.second.ent;
-
- if( monomorphise_type_needed(var_ty) ) {
- *tmp_ty_ptr = monomorphise_type(pp.sp, unm.m_params, te.path.m_data.as_Generic().m_params, variant.second.ent);
- tv.m_resolve.expand_associated_types(pp.sp, *tmp_ty_ptr);
- return *tmp_ty_ptr;
- }
- else {
- return var_ty;
- }
- }
- )
- )
- }
)
)
- return blank;
+ assert(ty_p);
+ for(const auto& w : lv.m_wrappers)
+ {
+ ty_p = &mir_res.get_unwrapped_type(tmp, w, *ty_p);
+ if( w.is_Deref() )
+ {
+ tv.visit_type(*ty_p);
+ }
+ }
}
- static void visit_param(TypeVisitor& tv, const Trans_Params& pp, const ::HIR::Function& fcn, const ::MIR::Param& p)
+ void visit_const(const ::MIR::Constant& p)
+ {
+ }
+
+ void visit_param(const ::MIR::Param& p)
{
TU_MATCHA( (p), (e),
(LValue,
- H::visit_lvalue(tv, pp, fcn, e);
+ this->visit_lvalue(e);
),
(Constant,
+ this->visit_const(e);
)
)
}
};
+ MirVisitor mir_visit(tv, pp, fcn, mir_res);
for(const auto& stmt : block.statements)
{
TU_MATCHA( (stmt), (se),
(Drop,
- H::visit_lvalue(tv,pp,fcn, se.slot);
+ mir_visit.visit_lvalue(se.slot);
),
(SetDropFlag,
),
(Asm,
for(const auto& v : se.outputs)
- H::visit_lvalue(tv,pp,fcn, v.second);
+ mir_visit.visit_lvalue(v.second);
for(const auto& v : se.inputs)
- H::visit_lvalue(tv,pp,fcn, v.second);
+ mir_visit.visit_lvalue(v.second);
),
(ScopeEnd,
),
(Assign,
- H::visit_lvalue(tv,pp,fcn, se.dst);
+ mir_visit.visit_lvalue(se.dst);
TU_MATCHA( (se.src), (re),
(Use,
- H::visit_lvalue(tv,pp,fcn, re);
+ mir_visit.visit_lvalue(re);
),
(Constant,
+ mir_visit.visit_const(re);
),
(SizedArray,
- H::visit_param(tv,pp,fcn, re.val);
+ mir_visit.visit_param(re.val);
),
(Borrow,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(Cast,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(BinOp,
- H::visit_param(tv,pp,fcn, re.val_l);
- H::visit_param(tv,pp,fcn, re.val_l);
+ mir_visit.visit_param(re.val_l);
+ mir_visit.visit_param(re.val_r);
),
(UniOp,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(DstMeta,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(DstPtr,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(MakeDst,
- H::visit_param(tv,pp,fcn, re.ptr_val);
- H::visit_param(tv,pp,fcn, re.meta_val);
+ mir_visit.visit_param(re.ptr_val);
+ mir_visit.visit_param(re.meta_val);
),
(Tuple,
for(const auto& v : re.vals)
- H::visit_param(tv,pp,fcn, v);
+ mir_visit.visit_param(v);
),
(Array,
for(const auto& v : re.vals)
- H::visit_param(tv,pp,fcn, v);
+ mir_visit.visit_param(v);
),
(Variant,
- H::visit_param(tv,pp,fcn, re.val);
+ mir_visit.visit_param(re.val);
),
(Struct,
for(const auto& v : re.vals)
- H::visit_param(tv,pp,fcn, v);
+ mir_visit.visit_param(v);
)
)
)
@@ -983,32 +922,65 @@ void Trans_Enumerate_Types(EnumState& state)
(Goto, ),
(Panic, ),
(If,
- H::visit_lvalue(tv,pp,fcn, te.cond);
+ mir_visit.visit_lvalue(te.cond);
),
(Switch,
- H::visit_lvalue(tv,pp,fcn, te.val);
+ mir_visit.visit_lvalue(te.val);
),
(SwitchValue,
- H::visit_lvalue(tv,pp,fcn, te.val);
+ mir_visit.visit_lvalue(te.val);
),
(Call,
- if( te.fcn.is_Value() )
- H::visit_lvalue(tv,pp,fcn, te.fcn.as_Value());
- else if( te.fcn.is_Intrinsic() )
+ if(const auto* e = te.fcn.opt_Value() )
+ {
+ mir_visit.visit_lvalue(*e);
+ }
+ else if(const auto* e = te.fcn.opt_Intrinsic())
{
- for(const auto& ty : te.fcn.as_Intrinsic().params.m_types)
+ for(const auto& ty : e->params.m_types)
tv.visit_type(monomorph(ty));
}
- H::visit_lvalue(tv,pp,fcn, te.ret_val);
+ else
+ {
+ // Paths don't need visiting?
+ }
+ mir_visit.visit_lvalue(te.ret_val);
for(const auto& arg : te.args)
- H::visit_param(tv,pp,fcn, arg);
+ mir_visit.visit_param(arg);
)
)
}
}
}
+ }; // struct TypeVisitor
+} // namespace <empty>
+
+// Enumerate types required for the enumerated items
+void Trans_Enumerate_Types(EnumState& state)
+{
+ static Span sp;
+ TypeVisitor tv { state.crate, state.rv.m_types };
+
+ unsigned int types_count = 0;
+ bool constructors_added;
+ do
+ {
+ // Visit all functions that haven't been type-visited yet
+ for(unsigned int i = 0; i < state.fcns_to_type_visit.size(); i++)
+ {
+ auto* p = state.fcns_to_type_visit[i];
+ assert(p->path);
+ assert(p->ptr);
+ auto& fcn_path = *p->path;
+ const auto& fcn = *p->ptr;
+ const auto& pp = p->pp;
+
+ TRACE_FUNCTION_F("Function " << fcn_path);
+ tv.visit_function(fcn_path, fcn, pp);
+ }
state.fcns_to_type_visit.clear();
// TODO: Similarly restrict revisiting of statics.
+ // - Challenging, as they're stored as a std::map
for(const auto& ent : state.rv.m_statics)
{
TRACE_FUNCTION_F("Enumerate static " << ent.first);
@@ -1024,8 +996,7 @@ void Trans_Enumerate_Types(EnumState& state)
const auto& gpath = ent.first.m_data.as_UfcsKnown().trait;
const auto& trait = state.crate.get_trait_by_path(sp, gpath.m_path);
- auto vtable_ty_spath = gpath.m_path;
- vtable_ty_spath.m_components.back() += "#vtable";
+ const auto& vtable_ty_spath = trait.m_vtable_path;
const auto& vtable_ref = state.crate.get_struct_by_path(sp, vtable_ty_spath);
// Copy the param set from the trait in the trait object
::HIR::PathParams vtable_params = gpath.m_params.clone();
@@ -1056,27 +1027,16 @@ void Trans_Enumerate_Types(EnumState& state)
if( ty.m_data.is_Path() )
{
const auto& te = ty.m_data.as_Path();
- const ::HIR::TraitMarkings* markings_ptr = nullptr;
- TU_MATCHA( (te.binding), (tpb),
- (Unbound, ),
- (Opaque, ),
- (Struct,
- markings_ptr = &tpb->m_markings;
- ),
- (Union,
- markings_ptr = &tpb->m_markings;
- ),
- (Enum,
- markings_ptr = &tpb->m_markings;
- )
- )
- ASSERT_BUG(Span(), markings_ptr, "Path binding not set correctly - " << ty);
+ ASSERT_BUG(sp, te.path.m_data.is_Generic(), "Non-Generic type path after enumeration - " << ty);
+ const auto& gp = te.path.m_data.as_Generic();
+ const ::HIR::TraitMarkings* markings_ptr = te.binding.get_trait_markings();
+ ASSERT_BUG(sp, markings_ptr, "Path binding not set correctly - " << ty);
// If the type has a drop impl, and it's either defined in this crate or has params (and thus was monomorphised)
- if( markings_ptr->has_drop_impl && (te.path.m_data.as_Generic().m_path.m_crate_name == state.crate.m_crate_name || te.path.m_data.as_Generic().m_params.has_params()) )
+ if( markings_ptr->has_drop_impl && (gp.m_path.m_crate_name == state.crate.m_crate_name || gp.m_params.has_params()) )
{
// Add the Drop impl to the codegen list
- Trans_Enumerate_FillFrom_Path(state, ::HIR::Path( ty.clone(), state.crate.get_lang_item_path(sp, "drop"), "drop"), {});
+ Trans_Enumerate_FillFrom_PathMono(state, ::HIR::Path( ty.clone(), state.crate.get_lang_item_path(sp, "drop"), "drop"));
constructors_added = true;
}
}
@@ -1086,7 +1046,7 @@ void Trans_Enumerate_Types(EnumState& state)
// Reqire drop glue for inner type.
// - Should that already exist?
// Requires box_free lang item
- Trans_Enumerate_FillFrom_Path(state, ::HIR::GenericPath( state.crate.get_lang_item_path(sp, "box_free"), { ity->clone() } ), {});;
+ Trans_Enumerate_FillFrom_PathMono(state, ::HIR::GenericPath( state.crate.get_lang_item_path(sp, "box_free"), { ity->clone() } ));
}
}
types_count = state.rv.m_types.size();
@@ -1180,14 +1140,14 @@ namespace {
return true;
}
}
- //{
- // auto it = impl.m_constants.find(e.item);
- // if( it != impl.m_constants.end() )
- // {
- // rv = EntPtr { &it->second.data };
- // return true;
- // }
- //}
+ {
+ auto it = impl.m_constants.find(pe->item);
+ if( it != impl.m_constants.end() )
+ {
+ rv = EntPtr { &it->second.data };
+ return true;
+ }
+ }
return false;
});
return rv;
@@ -1203,23 +1163,24 @@ namespace {
const auto& trait_vi = trait_vi_it->second;
bool is_dynamic = false;
+ bool any_impl = false;
::std::vector<::HIR::TypeRef> best_impl_params;
const ::HIR::TraitImpl* best_impl = nullptr;
resolve.find_impl(sp, pe->trait.m_path, pe->trait.m_params, *pe->type, [&](auto impl_ref, auto is_fuzz) {
DEBUG("[get_ent_fullpath] Found " << impl_ref);
//ASSERT_BUG(sp, !is_fuzz, "Fuzzy match not allowed here");
if( ! impl_ref.m_data.is_TraitImpl() ) {
- DEBUG("Trans impl search found an invalid impl type");
+ DEBUG("Trans impl search found an invalid impl type - " << impl_ref.m_data.tag_str());
is_dynamic = true;
// TODO: This can only really happen if it's a trait object magic impl, which should become a vtable lookup.
return true;
}
+ any_impl = true;
const auto& impl_ref_e = impl_ref.m_data.as_TraitImpl();
const auto& impl = *impl_ref_e.impl;
ASSERT_BUG(sp, impl.m_trait_args.m_types.size() == pe->trait.m_params.m_types.size(), "Trait parameter count mismatch " << impl.m_trait_args << " vs " << pe->trait.m_params);
if( best_impl == nullptr || impl.more_specific_than(*best_impl) ) {
- best_impl = &impl;
bool is_spec = false;
TU_MATCHA( (trait_vi), (ve),
(Constant,
@@ -1233,7 +1194,8 @@ namespace {
(Static,
if( pe->item == "vtable#" ) {
is_spec = true;
- break;
+ DEBUG("VTable, quick return");
+ return true;
}
auto it = impl.m_statics.find(pe->item);
if( it == impl.m_statics.end() ) {
@@ -1251,6 +1213,7 @@ namespace {
is_spec = fit->second.is_specialisable;
)
)
+ best_impl = &impl;
best_impl_params.clear();
for(unsigned int i = 0; i < impl_ref_e.params.size(); i ++)
{
@@ -1269,50 +1232,62 @@ namespace {
});
if( is_dynamic )
return EntPtr::make_AutoGenerate( {} );
- if( !best_impl )
+ if( !any_impl )
return EntPtr {};
- const auto& impl = *best_impl;
+ if( best_impl )
+ {
+ const auto& impl = *best_impl;
- impl_pp.m_types = mv$(best_impl_params);
+ impl_pp.m_types = mv$(best_impl_params);
- TU_MATCHA( (trait_vi), (ve),
- (Constant,
- auto it = impl.m_constants.find(pe->item);
- if( it != impl.m_constants.end() )
- {
+ // Fallback on default/provided items
+ TU_MATCH_HDRA( (trait_vi), {)
+ TU_ARMA(Constant, ve) {
+ auto it = impl.m_constants.find(pe->item);
+ ASSERT_BUG(sp, it != impl.m_constants.end(), "best_impl set, but item not found - " << path);
DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type);
return EntPtr { &it->second.data };
- }
- TODO(sp, "Associated constant - " << path);
- ),
- (Static,
- if( pe->item == "vtable#" )
- {
- DEBUG("VTable, autogen");
- return EntPtr::make_AutoGenerate( {} );
- }
- auto it = impl.m_statics.find(pe->item);
- if( it != impl.m_statics.end() )
- {
+ }
+ TU_ARMA(Static, ve) {
+ assert(pe->item != "vtable#");
+ auto it = impl.m_statics.find(pe->item);
+ ASSERT_BUG(sp, it != impl.m_statics.end(), "best_impl set, but item not found - " << path);
DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type);
return EntPtr { &it->second.data };
- }
- TODO(sp, "Associated static - " << path);
- ),
- (Function,
- auto fit = impl.m_methods.find(pe->item);
- if( fit != impl.m_methods.end() )
- {
+ }
+ TU_ARMA(Function, ve) {
+ auto fit = impl.m_methods.find(pe->item);
+ ASSERT_BUG(sp, fit != impl.m_methods.end(), "best_impl set, but item not found - " << path);
DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type);
return EntPtr { &fit->second.data };
+ }
}
- impl_pp = pe->trait.m_params.clone();
- // HACK! By adding a new parameter here, the MIR will always be monomorphised
- impl_pp.m_types.push_back( ::HIR::TypeRef() );
- return EntPtr { &ve };
- )
- )
- BUG(sp, "");
+ }
+ else
+ {
+ // Fallback on default/provided items
+ TU_MATCH_HDRA( (trait_vi), {)
+ TU_ARMA(Constant, ve) {
+ TODO(sp, "Associated constant - " << path);
+ }
+ TU_ARMA(Static, ve) {
+ if( pe->item == "vtable#" )
+ {
+ DEBUG("VTable, autogen");
+ return EntPtr::make_AutoGenerate( {} );
+ }
+ TODO(sp, "Associated static - " << path);
+ }
+ TU_ARMA(Function, ve) {
+ ASSERT_BUG(sp, ve.m_code.m_mir, "Attempting to use default method with no body MIR - " << path);
+ impl_pp = pe->trait.m_params.clone();
+ // HACK! By adding a new parameter here, the MIR will always be monomorphised
+ impl_pp.m_types.push_back( ::HIR::TypeRef() );
+ return EntPtr { &ve };
+ }
+ }
+ }
+ throw "unreachable";
}
else
{
@@ -1323,12 +1298,75 @@ namespace {
}
}
+namespace MIR {
+ struct EnumCache
+ {
+ ::std::vector<const ::HIR::Path*> paths;
+ ::std::vector<const ::HIR::TypeRef*> typeids;
+ EnumCache()
+ {
+ }
+ void insert_path(const ::HIR::Path& new_path)
+ {
+ for(const auto* p : this->paths)
+ if( *p == new_path )
+ return ;
+ this->paths.push_back(&new_path);
+ }
+ void insert_typeid(const ::HIR::TypeRef& new_ty)
+ {
+ for(const auto* p : this->typeids)
+ if( *p == new_ty )
+ return ;
+ this->typeids.push_back(&new_ty);
+ }
+
+ void apply(EnumState& state, const Trans_Params& pp) const
+ {
+ for(const auto* ty_p : this->typeids)
+ {
+ state.rv.m_typeids.insert( pp.monomorph(state.crate, *ty_p) );
+ }
+ for(const auto& path : this->paths)
+ {
+ Trans_Enumerate_FillFrom_Path(state, *path, pp);
+ }
+ }
+ };
+ EnumCachePtr::~EnumCachePtr()
+ {
+ delete this->p;
+ this->p = nullptr;
+ }
+}
+
void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, const Trans_Params& pp)
{
- TRACE_FUNCTION_F(path);
- Span sp;
auto path_mono = pp.monomorph(state.crate, path);
- DEBUG("- " << path_mono);
+ Trans_Enumerate_FillFrom_PathMono(state, mv$(path_mono));
+}
+void Trans_Enumerate_FillFrom_PathMono(EnumState& state, ::HIR::Path path_mono)
+{
+ TRACE_FUNCTION_F(path_mono);
+ Span sp;
+ // TODO: If already in the list, return early
+ if( state.rv.m_functions.count(path_mono) ) {
+ DEBUG("> Already done function");
+ return ;
+ }
+ if( state.rv.m_statics.count(path_mono) ) {
+ DEBUG("> Already done static");
+ return ;
+ }
+ if( state.rv.m_constants.count(path_mono) ) {
+ DEBUG("> Already done constant");
+ return ;
+ }
+ if( state.rv.m_vtables.count(path_mono) ) {
+ DEBUG("> Already done vtable");
+ return ;
+ }
+
Trans_Params sub_pp(sp);
TU_MATCHA( (path_mono.m_data), (pe),
(Generic,
@@ -1344,17 +1382,17 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co
sub_pp.self_type = pe.type->clone();
),
(UfcsUnknown,
- BUG(sp, "UfcsUnknown - " << path);
+ BUG(sp, "UfcsUnknown - " << path_mono);
)
)
// Get the item type
// - Valid types are Function and Static
auto item_ref = get_ent_fullpath(sp, state.crate, path_mono, sub_pp.pp_impl);
- TU_MATCHA( (item_ref), (e),
- (NotFound,
+ TU_MATCH_HDRA( (item_ref), {)
+ TU_ARMA(NotFound, e) {
BUG(sp, "Item not found for " << path_mono);
- ),
- (AutoGenerate,
+ }
+ TU_ARMA(AutoGenerate, e) {
if( path_mono.m_data.is_Generic() )
{
// Leave generation of struct/enum constructors to codgen
@@ -1376,58 +1414,102 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co
// Must have been a dynamic dispatch request, just leave as-is
}
// - <fn(...) as Fn*>::call*
- else if( path_mono.m_data.is_UfcsKnown() && path_mono.m_data.as_UfcsKnown().type->m_data.is_Function() )
+ else if( path_mono.m_data.is_UfcsKnown() && path_mono.m_data.as_UfcsKnown().type->m_data.is_Function() && (
+ path_mono.m_data.as_UfcsKnown().trait.m_path == state.crate.get_lang_item_path_opt("fn")
+ || path_mono.m_data.as_UfcsKnown().trait.m_path == state.crate.get_lang_item_path_opt("fn_mut")
+ || path_mono.m_data.as_UfcsKnown().trait.m_path == state.crate.get_lang_item_path_opt("fn_once")
+ ) )
{
// Must have been a dynamic dispatch request, just leave as-is
}
+ // <* as Clone>::clone
+ else if( TARGETVER_1_29 && path_mono.m_data.is_UfcsKnown() && path_mono.m_data.as_UfcsKnown().trait == state.crate.get_lang_item_path_opt("clone") )
+ {
+ const auto& pe = path_mono.m_data.as_UfcsKnown();
+ ASSERT_BUG(sp, pe.item == "clone" || pe.item == "clone_from", "Unexpected Clone method called, " << path_mono);
+ const auto& inner_ty = *pe.type;
+ // If this is !Copy, then we need to ensure that the inner type's clone impls are also available
+ ::StaticTraitResolve resolve { state.crate };
+ if( !resolve.type_is_copy(sp, inner_ty) )
+ {
+ auto enum_impl = [&](const ::HIR::TypeRef& ity) {
+ if( !resolve.type_is_copy(sp, ity) )
+ {
+ Trans_Enumerate_FillFrom_PathMono(state, ::HIR::Path(ity.clone(), pe.trait.clone(), pe.item));
+ }
+ };
+ if( const auto* te = inner_ty.m_data.opt_Tuple() ) {
+ for(const auto& ity : *te)
+ {
+ enum_impl(ity);
+ }
+ }
+ else if( const auto* te = inner_ty.m_data.opt_Array() ) {
+ enum_impl(*te->inner);
+ }
+ else if( TU_TEST2(inner_ty.m_data, Path, .path.m_data, Generic, .m_path.m_components.back().compare(0, 8, "closure#") == 0) ) {
+ const auto& gp = inner_ty.m_data.as_Path().path.m_data.as_Generic();
+ const auto& str = state.crate.get_struct_by_path(sp, gp.m_path);
+ Trans_Params p;
+ p.sp = sp;
+ p.pp_impl = gp.m_params.clone();
+ for(const auto& fld : str.m_data.as_Tuple())
+ {
+ ::HIR::TypeRef tmp;
+ const auto& ty_m = monomorphise_type_needed(fld.ent) ? (tmp = p.monomorph(resolve, fld.ent)) : fld.ent;
+ enum_impl(ty_m);
+ }
+ }
+ else {
+ BUG(sp, "Unhandled magic clone in enumerate - " << inner_ty);
+ }
+ }
+ // Add this type to a list of types that will have the impl auto-generated
+ state.rv.auto_clone_impls.insert( inner_ty.clone() );
+ }
else
{
BUG(sp, "AutoGenerate returned for unknown path type - " << path_mono);
}
- ),
- (Function,
+ }
+ TU_ARMA(Function, e) {
// Add this path (monomorphised) to the queue
state.enum_fcn(mv$(path_mono), *e, mv$(sub_pp));
- ),
- (Static,
+ }
+ TU_ARMA(Static, e) {
if( auto* ptr = state.rv.add_static(mv$(path_mono)) )
{
Trans_Enumerate_FillFrom(state, *e, *ptr, mv$(sub_pp));
}
- ),
- (Constant,
- Trans_Enumerate_FillFrom_Literal(state, e->m_value_res, sub_pp);
- )
- )
+ }
+ TU_ARMA(Constant, e) {
+ if( e->m_value_res.is_Defer() )
+ {
+ if( auto* slot = state.rv.add_const(mv$(path_mono)) )
+ {
+ MIR::EnumCache es;
+ Trans_Enumerate_FillFrom_MIR(es, *e->m_value.m_mir);
+ es.apply(state, sub_pp);
+ slot->ptr = e;
+ slot->pp = ::std::move(sub_pp);
+ }
+ }
+ else
+ {
+ Trans_Enumerate_FillFrom_Literal(state, e->m_value_res, sub_pp);
+ }
+ }
+ }
}
-void Trans_Enumerate_FillFrom_MIR_LValue(EnumState& state, const ::MIR::LValue& lv, const Trans_Params& pp)
+
+void Trans_Enumerate_FillFrom_MIR_LValue(MIR::EnumCache& state, const ::MIR::LValue& lv)
{
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Argument,
- ),
- (Local,
- ),
- (Static,
- Trans_Enumerate_FillFrom_Path(state, e, pp);
- ),
- (Field,
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp);
- ),
- (Deref,
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp);
- ),
- (Index,
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp);
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.idx, pp);
- ),
- (Downcast,
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp);
- )
- )
+ if( lv.m_root.is_Static() )
+ {
+ state.insert_path(lv.m_root.as_Static());
+ }
}
-void Trans_Enumerate_FillFrom_MIR_Constant(EnumState& state, const ::MIR::Constant& c, const Trans_Params& pp)
+void Trans_Enumerate_FillFrom_MIR_Constant(MIR::EnumCache& state, const ::MIR::Constant& c)
{
TU_MATCHA( (c), (ce),
(Int, ),
@@ -1437,21 +1519,22 @@ void Trans_Enumerate_FillFrom_MIR_Constant(EnumState& state, const ::MIR::Consta
(Bytes, ),
(StaticString, ), // String
(Const,
- //Trans_Enumerate_FillFrom_Path(state, ce.p, pp);
+ // - Check if this constant has a value of Defer
+ state.insert_path(*ce.p);
),
(ItemAddr,
- Trans_Enumerate_FillFrom_Path(state, ce, pp);
+ state.insert_path(*ce);
)
)
}
-void Trans_Enumerate_FillFrom_MIR_Param(EnumState& state, const ::MIR::Param& p, const Trans_Params& pp)
+void Trans_Enumerate_FillFrom_MIR_Param(MIR::EnumCache& state, const ::MIR::Param& p)
{
TU_MATCHA( (p), (e),
- (LValue, Trans_Enumerate_FillFrom_MIR_LValue(state, e, pp); ),
- (Constant, Trans_Enumerate_FillFrom_MIR_Constant(state, e, pp); )
+ (LValue, Trans_Enumerate_FillFrom_MIR_LValue(state, e); ),
+ (Constant, Trans_Enumerate_FillFrom_MIR_Constant(state, e); )
)
}
-void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, const Trans_Params& pp)
+void Trans_Enumerate_FillFrom_MIR(MIR::EnumCache& state, const ::MIR::Function& code)
{
for(const auto& bb : code.blocks)
{
@@ -1460,63 +1543,63 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code,
TU_MATCHA((stmt), (se),
(Assign,
DEBUG("- " << se.dst << " = " << se.src);
- Trans_Enumerate_FillFrom_MIR_LValue(state, se.dst, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, se.dst);
TU_MATCHA( (se.src), (e),
(Use,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e);
),
(Constant,
- Trans_Enumerate_FillFrom_MIR_Constant(state, e, pp);
+ Trans_Enumerate_FillFrom_MIR_Constant(state, e);
),
(SizedArray,
- Trans_Enumerate_FillFrom_MIR_Param(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, e.val);
),
(Borrow,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(Cast,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(BinOp,
- Trans_Enumerate_FillFrom_MIR_Param(state, e.val_l, pp);
- Trans_Enumerate_FillFrom_MIR_Param(state, e.val_r, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, e.val_l);
+ Trans_Enumerate_FillFrom_MIR_Param(state, e.val_r);
),
(UniOp,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(DstMeta,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(DstPtr,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(MakeDst,
- Trans_Enumerate_FillFrom_MIR_Param(state, e.ptr_val, pp);
- Trans_Enumerate_FillFrom_MIR_Param(state, e.meta_val, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, e.ptr_val);
+ Trans_Enumerate_FillFrom_MIR_Param(state, e.meta_val);
),
(Tuple,
for(const auto& val : e.vals)
- Trans_Enumerate_FillFrom_MIR_Param(state, val, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, val);
),
(Array,
for(const auto& val : e.vals)
- Trans_Enumerate_FillFrom_MIR_Param(state, val, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, val);
),
(Variant,
- Trans_Enumerate_FillFrom_MIR_Param(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, e.val);
),
(Struct,
for(const auto& val : e.vals)
- Trans_Enumerate_FillFrom_MIR_Param(state, val, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, val);
)
)
),
(Asm,
DEBUG("- asm! ...");
for(const auto& v : se.inputs)
- Trans_Enumerate_FillFrom_MIR_LValue(state, v.second, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, v.second);
for(const auto& v : se.outputs)
- Trans_Enumerate_FillFrom_MIR_LValue(state, v.second, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, v.second);
),
(SetDropFlag,
),
@@ -1524,7 +1607,7 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code,
),
(Drop,
DEBUG("- DROP " << se.slot);
- Trans_Enumerate_FillFrom_MIR_LValue(state, se.slot, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, se.slot);
// TODO: Ensure that the drop glue for this type is generated
)
)
@@ -1537,32 +1620,32 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code,
(Goto, ),
(Panic, ),
(If,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.cond, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.cond);
),
(Switch,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(SwitchValue,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val);
),
(Call,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e.ret_val, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.ret_val);
TU_MATCHA( (e.fcn), (e2),
(Value,
- Trans_Enumerate_FillFrom_MIR_LValue(state, e2, pp);
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e2);
),
(Path,
- Trans_Enumerate_FillFrom_Path(state, e2, pp);
+ state.insert_path(e2);
),
(Intrinsic,
if( e2.name == "type_id" ) {
// Add <T>::#type_id to the enumerate list
- state.rv.m_typeids.insert( pp.monomorph(state.crate, e2.params.m_types.at(0)) );
+ state.insert_typeid(e2.params.m_types.at(0));
}
)
)
for(const auto& arg : e.args)
- Trans_Enumerate_FillFrom_MIR_Param(state, arg, pp);
+ Trans_Enumerate_FillFrom_MIR_Param(state, arg);
)
)
}
@@ -1582,7 +1665,7 @@ void Trans_Enumerate_FillFrom_VTable(EnumState& state, ::HIR::Path vtable_path,
{
DEBUG("- " << m.second.first << " = " << m.second.second << " :: " << m.first);
auto gpath = monomorphise_genericpath_with(sp, m.second.second, monomorph_cb_trait, false);
- Trans_Enumerate_FillFrom_Path(state, ::HIR::Path(type.clone(), mv$(gpath), m.first), {});
+ Trans_Enumerate_FillFrom_PathMono(state, ::HIR::Path(type.clone(), mv$(gpath), m.first));
}
}
@@ -1591,6 +1674,9 @@ void Trans_Enumerate_FillFrom_Literal(EnumState& state, const ::HIR::Literal& li
TU_MATCHA( (lit), (e),
(Invalid,
),
+ (Defer,
+ // TODO: Bug?
+ ),
(List,
for(const auto& v : e)
Trans_Enumerate_FillFrom_Literal(state, v, pp);
@@ -1621,7 +1707,7 @@ namespace {
TU_IFLET( ::HIR::ValueItem, vi.second->ent, Function, i,
if( i.m_code.m_mir && i.m_linkage.name != "" && i.m_linkage.name == name )
{
- out_path = (mod_path + vi.first.c_str()).get_simple_path();
+ out_path = (mod_path + vi.first).get_simple_path();
return &i;
}
)
@@ -1630,7 +1716,7 @@ namespace {
for(const auto& ti : mod.m_mod_items)
{
TU_IFLET( ::HIR::TypeItem, ti.second->ent, Module, i,
- if( auto rv = find_function_by_link_name(i, mod_path + ti.first.c_str(), name, out_path) )
+ if( auto rv = find_function_by_link_name(i, mod_path + ti.first, name, out_path) )
return rv;
)
}
@@ -1658,7 +1744,15 @@ void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Function& function,
TRACE_FUNCTION_F("Function pp=" << pp.pp_method<<"+"<<pp.pp_impl);
if( function.m_code.m_mir )
{
- Trans_Enumerate_FillFrom_MIR(state, *function.m_code.m_mir, pp);
+ const auto& mir_fcn = *function.m_code.m_mir;
+ if( !mir_fcn.trans_enum_state )
+ {
+ auto* esp = new MIR::EnumCache();
+ Trans_Enumerate_FillFrom_MIR(*esp, *function.m_code.m_mir);
+ mir_fcn.trans_enum_state = ::MIR::EnumCachePtr(esp);
+ }
+ // TODO: Ensure that all types have drop glue generated too? (Iirc this is unconditional currently)
+ mir_fcn.trans_enum_state->apply(state, pp);
}
else
{
@@ -1692,4 +1786,3 @@ void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Static& item, Trans
out_stat.ptr = &item;
out_stat.pp = mv$(pp);
}
-
diff --git a/src/trans/main_bindings.hpp b/src/trans/main_bindings.hpp
index b938e8bf..af33ef35 100644
--- a/src/trans/main_bindings.hpp
+++ b/src/trans/main_bindings.hpp
@@ -38,6 +38,8 @@ extern TransList Trans_Enumerate_Public(::HIR::Crate& crate);
/// Re-run enumeration on monomorphised functions, removing now-unused items
extern void Trans_Enumerate_Cleanup(const ::HIR::Crate& crate, TransList& list);
+extern void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list);
+
extern void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list);
-extern void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const ::HIR::Crate& crate, const TransList& list, bool is_executable);
+extern void Trans_Codegen(const ::std::string& outfile, CodegenOutput out_ty, const TransOptions& opt, const ::HIR::Crate& crate, const TransList& list, const ::std::string& hir_file);
diff --git a/src/trans/mangling.cpp b/src/trans/mangling.cpp
index 741d13dd..0b5d61d6 100644
--- a/src/trans/mangling.cpp
+++ b/src/trans/mangling.cpp
@@ -2,7 +2,7 @@
* MRustC - Rust Compiler
* - By John Hodge (Mutabah/thePowersGang)
*
- * trans/mangling.hpp
+ * trans/mangling.cpp
* - Name mangling support
*
*
@@ -22,18 +22,27 @@
#include <hir/path.hpp>
namespace {
- ::std::string escape_str(const ::std::string& s) {
+ ::std::string escape_str(const char* s, size_t len) {
::std::string output;
- output.reserve(s.size() + 1);
- for(auto v : s)
+ output.reserve(len + 1);
+ for(auto vp = s; vp != s + len; vp ++)
+ {
+ auto v= *vp;
if( v == '#' )
output += "$H";
else if( v == '-' )
output += "_";
else
output += v;
+ }
return output;
}
+ ::std::string escape_str(const RcString& s) {
+ return escape_str(s.c_str(), s.size());
+ }
+ ::std::string escape_str(const ::std::string& s) {
+ return escape_str(s.c_str(), s.size());
+ }
::FmtLambda emit_params(const ::HIR::PathParams& params)
{
return FMT_CB(ss,
diff --git a/src/trans/mangling_v2.cpp b/src/trans/mangling_v2.cpp
new file mode 100644
index 00000000..f907a6e3
--- /dev/null
+++ b/src/trans/mangling_v2.cpp
@@ -0,0 +1,292 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * trans/mangling_v2.cpp
+ * - Name mangling (encoding of rust paths into symbols)
+ */
+#include <debug.hpp>
+#include <string_view.hpp>
+#include <hir/hir.hpp> // ABI_RUST
+#include <hir/type.hpp>
+
+class Mangler
+{
+ ::std::ostream& m_os;
+public:
+ Mangler(::std::ostream& os):
+ m_os(os)
+ {
+ }
+
+ // Item names:
+ // - These can have a single '#' in them (either leading or in the middle)
+ // TODO: Some other invalid characters can appear:
+ // - '-' (crate names)
+ void fmt_name(const RcString& s)
+ {
+ this->fmt_name(s.c_str());
+ }
+ void fmt_name(const char* const s)
+ {
+ size_t size = strlen(s);
+ const char* hash_pos = nullptr;
+ // - Search the string for the '#' character
+ for(const auto* p = s; *p; p++)
+ {
+ if( p == s ) {
+ ASSERT_BUG(Span(), !isdigit(*p), "Leading digit not valid in '" << s << "'");
+ }
+
+ if( isalnum(*p) ) {
+ }
+ else if( *p == '_' ) {
+ }
+ else if( *p == '#' || *p == '-' ) { // HACK: Treat '-' and '#' as the same in encoding
+ // Multiple hash characters? abort/error
+ ASSERT_BUG(Span(), hash_pos == nullptr, "Multiple '#' characters in '" << s << "'");
+ hash_pos = p;
+ }
+ else {
+ BUG(Span(), "Encounteded invalid character '" << *p << "' in '" << s << "'");
+ }
+ }
+
+ // If there's a hash, then prefix with a letter indicating its location?
+ // - Using a 3 character overhead currently (but a letter could work really well)
+ if( hash_pos != nullptr )
+ {
+ auto pre_hash_len = static_cast<int>(hash_pos - s);
+#if 0
+ assert(pre_hash_len < 26);
+ // <posletter> <full_len> <body1> <body2>
+ m_os << 'a' + pre_hash_len;
+ m_os << size - 1;
+ m_os << ::stdx::string_view(s, s + pre_hash_len);
+ m_os << hash_pos + 1;;
+#else
+ // 'h' <len1> <body1> <len2> <body2>
+ m_os << "h";
+ m_os << pre_hash_len;
+ m_os << ::stdx::string_view(s, s + pre_hash_len);
+ m_os << size - pre_hash_len - 1;
+ m_os << hash_pos + 1;;
+#endif
+ }
+ else
+ {
+ m_os << size;
+ m_os << s;
+ }
+ }
+ // SimplePath : <ncomp> 'c' [<RcString> ...]
+ void fmt_simple_path(const ::HIR::SimplePath& sp)
+ {
+ m_os << sp.m_components.size();
+ m_os << "c"; // Needed to separate the component count from the crate name
+ this->fmt_name(sp.m_crate_name);
+ for(const auto& c : sp.m_components)
+ {
+ this->fmt_name(c);
+ }
+ }
+
+ // PathParams : <ntys> 'g' [<TypeRef> ...]
+ void fmt_path_params(const ::HIR::PathParams& pp)
+ {
+ // Type Parameter count
+ m_os << pp.m_types.size();
+ m_os << "g";
+ for(const auto& ty : pp.m_types)
+ {
+ fmt_type(ty);
+ }
+ }
+ // GenericPath : <SimplePath> <PathParams>
+ void fmt_generic_path(const ::HIR::GenericPath& gp)
+ {
+ this->fmt_simple_path(gp.m_path);
+ this->fmt_path_params(gp.m_params);
+ }
+
+ void fmt_path(const ::HIR::Path& p)
+ {
+ // Path type
+ // - Generic: starts with `G`
+ // - Inherent: Starts with `I`
+ // - Trait: Starts with `Q` (qualified)
+ // - bare type: Starts with `T` (see Trans_MangleType)
+ TU_MATCH_HDRA( (p.m_data), {)
+ TU_ARMA(Generic, e) {
+ m_os << "G";
+ this->fmt_generic_path(e);
+ }
+ TU_ARMA(UfcsInherent, e) {
+ m_os << "I";
+ this->fmt_type(*e.type);
+ this->fmt_name(e.item);
+ this->fmt_path_params(e.params);
+ }
+ TU_ARMA(UfcsKnown, e) {
+ m_os << "Q";
+ this->fmt_type(*e.type);
+ this->fmt_generic_path(e.trait);
+ this->fmt_name(e.item);
+ this->fmt_path_params(e.params);
+ }
+ TU_ARMA(UfcsUnknown, e)
+ BUG(Span(), "Non-encodable path " << p);
+ }
+ }
+
+ // Type
+ // - Tuple: 'T' <nelem> [<TypeRef> ...]
+ // - Slice: 'S' <TypeRef>
+ // - Array: 'A' <size> <TypeRef>
+ // - Path: 'N' <Path>
+ // - TraitObject: 'D' <data:GenericPath> <nmarker> [markers: <GenericPath> ...] <naty> [<TypeRef> ...] TODO: Does this need to include the ATY name?
+ // - Borrow: 'B' ('s'|'u'|'o') <TypeRef>
+ // - RawPointer: 'P' ('s'|'u'|'o') <TypeRef>
+ // - Function: 'F' <abi:RcString> <nargs> [args: <TypeRef> ...] <ret:TypeRef>
+ // - Primitives::
+ // - u8 : 'C' 'a'
+ // - i8 : 'C' 'b'
+ // - u16 : 'C' 'c'
+ // - i16 : 'C' 'd'
+ // - u32 : 'C' 'e'
+ // - i32 : 'C' 'f'
+ // - u64 : 'C' 'g'
+ // - i64 : 'C' 'h'
+ // - u128: 'C' 'i'
+ // - i128: 'C' 'j'
+ // --
+ // - f32 : 'C' 'n'
+ // - f64 : 'C' 'o'
+ // --
+ // - usize: 'C' 'u'
+ // - isize: 'C' 'v'
+ // - bool : 'C' 'x'
+ // - char : 'C' 'x'
+ // - str : 'C' 'y'
+ // - Diverge: 'C' 'z'
+ void fmt_type(const ::HIR::TypeRef& ty)
+ {
+ TU_MATCH_HDRA( (ty.m_data), { )
+ case ::HIR::TypeRef::Data::TAG_Infer:
+ case ::HIR::TypeRef::Data::TAG_Generic:
+ case ::HIR::TypeRef::Data::TAG_ErasedType:
+ case ::HIR::TypeRef::Data::TAG_Closure:
+ BUG(Span(), "Non-encodable type " << ty);
+ TU_ARMA(Tuple, e) {
+ m_os << "T" << e.size();
+ for(const auto& sty : e)
+ this->fmt_type(sty);
+ }
+ TU_ARMA(Slice, e) {
+ m_os << "S";
+ this->fmt_type(*e.inner);
+ }
+ TU_ARMA(Array, e) {
+ m_os << "A" << e.size_val;
+ this->fmt_type(*e.inner);
+ }
+ TU_ARMA(Path, e) {
+ m_os << "N";
+ this->fmt_path(e.path);
+ }
+ TU_ARMA(TraitObject, e) {
+ // - TraitObject: 'D' <data:GenericPath> <naty> [<TypeRef> ...] <nmarker> [markers: <GenericPath> ...]
+ m_os << "D";
+ this->fmt_generic_path(e.m_trait.m_path);
+ m_os << e.m_trait.m_type_bounds.size();
+ // HACK: Assume all TraitObject types have the same aty set (std::map is deterministic)
+ for(const auto& aty : e.m_trait.m_type_bounds)
+ this->fmt_type(aty.second);
+ m_os << e.m_markers.size();
+ for(const auto& p : e.m_markers)
+ this->fmt_generic_path(p);
+ }
+ TU_ARMA(Function, e) {
+ // - Function: 'F' <abi:RcString> <nargs> [args: <TypeRef> ...] <ret:TypeRef>
+ m_os << "F";
+ m_os << (e.is_unsafe ? "u" : ""); // Optional allowed, next is a number
+ if( e.m_abi != ABI_RUST )
+ {
+ m_os << "e";
+ this->fmt_name(e.m_abi.c_str());
+ }
+ m_os << e.m_arg_types.size();
+ for(const auto& t : e.m_arg_types)
+ this->fmt_type(t);
+ this->fmt_type(*e.m_rettype);
+ }
+ TU_ARMA(Borrow, e) {
+ m_os << "B";
+ switch(e.type)
+ {
+ case ::HIR::BorrowType::Shared: m_os << "s"; break;
+ case ::HIR::BorrowType::Unique: m_os << "u"; break;
+ case ::HIR::BorrowType::Owned: m_os << "o"; break;
+ }
+ this->fmt_type(*e.inner);
+ }
+ TU_ARMA(Pointer, e) {
+ m_os << "P";
+ switch(e.type)
+ {
+ case ::HIR::BorrowType::Shared: m_os << "s"; break;
+ case ::HIR::BorrowType::Unique: m_os << "u"; break;
+ case ::HIR::BorrowType::Owned: m_os << "o"; break;
+ }
+ this->fmt_type(*e.inner);
+ }
+ TU_ARMA(Primitive, e) {
+ switch(e)
+ {
+ case ::HIR::CoreType::U8 : m_os << 'C' << 'a'; break;
+ case ::HIR::CoreType::I8 : m_os << 'C' << 'b'; break;
+ case ::HIR::CoreType::U16 : m_os << 'C' << 'c'; break;
+ case ::HIR::CoreType::I16 : m_os << 'C' << 'd'; break;
+ case ::HIR::CoreType::U32 : m_os << 'C' << 'e'; break;
+ case ::HIR::CoreType::I32 : m_os << 'C' << 'f'; break;
+ case ::HIR::CoreType::U64 : m_os << 'C' << 'g'; break;
+ case ::HIR::CoreType::I64 : m_os << 'C' << 'h'; break;
+ case ::HIR::CoreType::U128: m_os << 'C' << 'i'; break;
+ case ::HIR::CoreType::I128: m_os << 'C' << 'j'; break;
+ case ::HIR::CoreType::F32 : m_os << 'C' << 'n'; break;
+ case ::HIR::CoreType::F64 : m_os << 'C' << 'o'; break;
+ case ::HIR::CoreType::Usize: m_os << 'C' << 'u'; break;
+ case ::HIR::CoreType::Isize: m_os << 'C' << 'v'; break;
+ case ::HIR::CoreType::Bool: m_os << 'C' << 'w'; break;
+ case ::HIR::CoreType::Char: m_os << 'C' << 'x'; break;
+ case ::HIR::CoreType::Str : m_os << 'C' << 'y'; break;
+ }
+ }
+ TU_ARMA(Diverge, _e) {
+ m_os << 'C' << 'z';
+ }
+ }
+ }
+};
+
+::FmtLambda Trans_ManglePath(const ::HIR::Path& p)
+{
+ return FMT_CB(os, os << "ZR"; Mangler(os).fmt_path(p));
+}
+::FmtLambda Trans_MangleSimplePath(const ::HIR::SimplePath& p)
+{
+ return FMT_CB(os, os << "ZRG"; Mangler(os).fmt_simple_path(p); Mangler(os).fmt_path_params({}););
+}
+::FmtLambda Trans_MangleGenericPath(const ::HIR::GenericPath& p)
+{
+ return FMT_CB(os, os << "ZRG"; Mangler(os).fmt_generic_path(p));
+}
+::FmtLambda Trans_MangleType(const ::HIR::TypeRef& p)
+{
+ return FMT_CB(os, os << "ZRT"; Mangler(os).fmt_type(p));
+}
+
+::FmtLambda Trans_Mangle(const ::HIR::SimplePath& path) { return Trans_MangleSimplePath(path); }
+::FmtLambda Trans_Mangle(const ::HIR::GenericPath& path) { return Trans_MangleGenericPath(path); }
+::FmtLambda Trans_Mangle(const ::HIR::Path& path) { return Trans_ManglePath(path); }
+::FmtLambda Trans_Mangle(const ::HIR::TypeRef& ty) { return Trans_MangleType(ty); }
diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp
index 892cb730..b5099918 100644
--- a/src/trans/monomorphise.cpp
+++ b/src/trans/monomorphise.cpp
@@ -10,42 +10,19 @@
#include <mir/mir.hpp>
#include <hir/hir.hpp>
#include <mir/operations.hpp> // Needed for post-monomorph checks and optimisations
+#include <hir_conv/constant_evaluation.hpp>
namespace {
::MIR::LValue monomorph_LValue(const ::StaticTraitResolve& resolve, const Trans_Params& params, const ::MIR::LValue& tpl)
{
- TU_MATCHA( (tpl), (e),
- (Return, return e; ),
- (Argument, return e; ),
- (Local, return e; ),
- (Static,
- return params.monomorph(resolve, e);
- ),
- (Field,
- return ::MIR::LValue::make_Field({
- box$(monomorph_LValue(resolve, params, *e.val)),
- e.field_index
- });
- ),
- (Deref,
- return ::MIR::LValue::make_Deref({
- box$(monomorph_LValue(resolve, params, *e.val))
- });
- ),
- (Index,
- return ::MIR::LValue::make_Index({
- box$(monomorph_LValue(resolve, params, *e.val)),
- box$(monomorph_LValue(resolve, params, *e.idx))
- });
- ),
- (Downcast,
- return ::MIR::LValue::make_Downcast({
- box$(monomorph_LValue(resolve, params, *e.val)),
- e.variant_index
- });
- )
- )
- throw "";
+ if( tpl.m_root.is_Static() )
+ {
+ return ::MIR::LValue( ::MIR::LValue::Storage::new_Static(params.monomorph(resolve, tpl.m_root.as_Static())), tpl.m_wrappers );
+ }
+ else
+ {
+ return tpl.clone();
+ }
}
::MIR::Constant monomorph_Constant(const ::StaticTraitResolve& resolve, const Trans_Params& params, const ::MIR::Constant& tpl)
{
@@ -70,15 +47,15 @@ namespace {
),
(Const,
return ::MIR::Constant::make_Const({
- params.monomorph(resolve, ce.p)
+ box$(params.monomorph(resolve, *ce.p))
});
),
(ItemAddr,
- auto p = params.monomorph(resolve, ce);
+ auto p = params.monomorph(resolve, *ce);
// TODO: If this is a pointer to a function on a trait object, replace with the address loaded from the vtable.
// - Requires creating a new temporary for the vtable pointer.
// - Also requires knowing what the receiver is.
- return ::MIR::Constant( mv$(p) );
+ return ::MIR::Constant( box$(p) );
)
)
throw "";
@@ -117,6 +94,7 @@ namespace {
{
static Span sp;
TRACE_FUNCTION;
+ assert(tpl);
::MIR::Function output;
@@ -350,6 +328,7 @@ void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list)
const auto& path = fcn_ent.first;
const auto& pp = fcn_ent.second->pp;
TRACE_FUNCTION_FR(path, path);
+ ASSERT_BUG(Span(), fcn.m_code.m_mir, "No code for " << path);
auto mir = Trans_Monomorphise(resolve, fcn_ent.second->pp, fcn.m_code.m_mir);
@@ -359,8 +338,8 @@ void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list)
for(const auto& a : fcn.m_args)
args.push_back(::std::make_pair( ::HIR::Pattern{}, pp.monomorph(resolve, a.second) ));
- ::std::string s = FMT(path);
- ::HIR::ItemPath ip(s);
+ //::std::string s = FMT(path);
+ ::HIR::ItemPath ip(path);
MIR_Validate(resolve, ip, *mir, args, ret_type);
MIR_Cleanup(resolve, ip, *mir, args, ret_type);
MIR_Optimise(resolve, ip, *mir, args, ret_type);
@@ -371,5 +350,32 @@ void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list)
fcn_ent.second->monomorphised.code = ::std::move(mir);
}
}
+
+ // Also do constants and statics (stored in where?)
+ // - NOTE: Done in reverse order, because consteval needs used constants to be evaluated
+ for(auto& ent : reverse(list.m_constants))
+ {
+ const auto& path = ent.first;
+ const auto& pp = ent.second->pp;
+ const auto& c = *ent.second->ptr;
+ TRACE_FUNCTION_FR(path, path);
+ auto ty = pp.monomorph(resolve, c.m_type);
+ // 1. Evaluate the constant
+ struct Nvs: public ::HIR::Evaluator::Newval
+ {
+ ::HIR::Path new_static(::HIR::TypeRef type, ::HIR::Literal value) override {
+ TODO(Span(), "Create new static in monomorph pass - " << value << " : " << type);
+ }
+ } nvs;
+ auto eval = ::HIR::Evaluator { pp.sp, crate, nvs };
+ MonomorphState ms;
+ ms.self_ty = &pp.self_type;
+ ms.pp_impl = &pp.pp_impl;
+ ms.pp_method = &pp.pp_method;
+ auto new_lit = eval.evaluate_constant(path, c.m_value, ::std::move(ty), ::std::move(ms));
+ ASSERT_BUG(Span(), !new_lit.is_Defer(), "Result of evaluating " << path << " was still Defer");
+ // 2. Store evaluated HIR::Literal in c.m_monomorph_cache
+ c.m_monomorph_cache.insert(::std::make_pair( path.clone(), ::std::move(new_lit) ));
+ }
}
diff --git a/src/trans/target.cpp b/src/trans/target.cpp
index 70996fb0..de5492a8 100644
--- a/src/trans/target.cpp
+++ b/src/trans/target.cpp
@@ -404,21 +404,21 @@ namespace
ARCH_M68K
};
}
- else if(target_name == "i586-windows-gnu")
+ else if(target_name == "i586-pc-windows-gnu")
{
return TargetSpec {
"windows", "windows", "gnu", {CodegenMode::Gnu11, true, "mingw32", BACKEND_C_OPTS_GNU},
ARCH_X86
};
}
- else if(target_name == "x86_64-windows-gnu")
+ else if(target_name == "x86_64-pc-windows-gnu")
{
return TargetSpec {
"windows", "windows", "gnu", {CodegenMode::Gnu11, false, "x86_64-w64-mingw32", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
- else if (target_name == "x86-windows-msvc")
+ else if (target_name == "x86-pc-windows-msvc")
{
// TODO: Should this include the "kernel32.lib" inclusion?
return TargetSpec {
@@ -426,7 +426,7 @@ namespace
ARCH_X86
};
}
- else if (target_name == "x86_64-windows-msvc")
+ else if (target_name == "x86_64-pc-windows-msvc")
{
return TargetSpec {
"windows", "windows", "msvc", {CodegenMode::Msvc, true, "amd64", {}, {}},
@@ -595,6 +595,7 @@ void Target_SetCfg(const ::std::string& target_name)
if(s == "32") return g_target.m_arch.m_atomics.u32;
if(s == "64") return g_target.m_arch.m_atomics.u64;
if(s == "ptr") return g_target.m_arch.m_atomics.ptr; // Has an atomic pointer-sized value
+ if(s == "cas") return g_target.m_arch.m_atomics.ptr; // TODO: Atomic compare-and-set option
return false;
});
Cfg_SetValueCb("target_feature", [](const ::std::string& s) {
@@ -602,139 +603,6 @@ void Target_SetCfg(const ::std::string& target_name)
});
}
-namespace {
- // Returns NULL when the repr can't be determined
- ::std::unique_ptr<StructRepr> make_struct_repr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty)
- {
- TRACE_FUNCTION_F(ty);
- ::std::vector<StructRepr::Ent> ents;
- bool packed = false;
- bool allow_sort = false;
- if( const auto* te = ty.m_data.opt_Path() )
- {
- const auto& str = *te->binding.as_Struct();
- auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &te->path.m_data.as_Generic().m_params, nullptr);
- auto monomorph = [&](const auto& tpl) {
- auto rv = monomorphise_type_with(sp, tpl, monomorph_cb);
- resolve.expand_associated_types(sp, rv);
- return rv;
- };
- TU_MATCHA( (str.m_data), (se),
- (Unit,
- ),
- (Tuple,
- unsigned int idx = 0;
- for(const auto& e : se)
- {
- auto ty = monomorph(e.ent);
- size_t size, align;
- if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) )
- return nullptr;
- if( size == SIZE_MAX )
- BUG(sp, "Unsized type in tuple struct");
- ents.push_back(StructRepr::Ent { idx++, size, align, mv$(ty) });
- }
- ),
- (Named,
- unsigned int idx = 0;
- for(const auto& e : se)
- {
- auto ty = monomorph(e.second.ent);
- size_t size, align;
- if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) )
- return nullptr;
- if( size == SIZE_MAX )
- BUG(sp, "Unsized type in struct");
- ents.push_back(StructRepr::Ent { idx++, size, align, mv$(ty) });
- }
- )
- )
- switch(str.m_repr)
- {
- case ::HIR::Struct::Repr::Packed:
- packed = true;
- TODO(sp, "make_struct_repr - repr(packed)"); // needs codegen to know to pack the structure
- break;
- case ::HIR::Struct::Repr::Simd:
- case ::HIR::Struct::Repr::C:
- // No sorting, no packing
- break;
- case ::HIR::Struct::Repr::Rust:
- allow_sort = true;
- break;
- }
- }
- else if( const auto* te = ty.m_data.opt_Tuple() )
- {
- unsigned int idx = 0;
- for(const auto& t : *te)
- {
- size_t size, align;
- if( !Target_GetSizeAndAlignOf(sp, resolve, t, size,align) )
- return nullptr;
- if( size == SIZE_MAX )
- BUG(sp, "Unsized type in tuple");
- ents.push_back(StructRepr::Ent { idx++, size, align, t.clone() });
- }
- }
- else
- {
- BUG(sp, "Unexpected type in creating struct repr");
- }
-
-
- if( allow_sort )
- {
- // TODO: Sort by alignment then size (largest first)
- // - Requires codegen to use this information
- }
-
- StructRepr rv;
- size_t cur_ofs = 0;
- size_t max_align = 1;
- for(auto& e : ents)
- {
- // Increase offset to fit alignment
- if( !packed )
- {
- while( cur_ofs % e.align != 0 )
- {
- rv.ents.push_back({ ~0u, 1, 1, ::HIR::TypeRef( ::HIR::CoreType::U8 ) });
- cur_ofs ++;
- }
- }
- max_align = ::std::max(max_align, e.align);
-
- rv.ents.push_back(mv$(e));
- cur_ofs += e.size;
- }
- if( !packed )
- {
- while( cur_ofs % max_align != 0 )
- {
- rv.ents.push_back({ ~0u, 1, 1, ::HIR::TypeRef( ::HIR::CoreType::U8 ) });
- cur_ofs ++;
- }
- }
- return box$(rv);
- }
-}
-const StructRepr* Target_GetStructRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty)
-{
- // TODO: Thread safety
- // Map of generic paths to struct representations.
- static ::std::map<::HIR::TypeRef, ::std::unique_ptr<StructRepr>> s_cache;
-
- auto it = s_cache.find(ty);
- if( it != s_cache.end() )
- {
- return it->second.get();
- }
-
- auto ires = s_cache.insert(::std::make_pair( ty.clone(), make_struct_repr(sp, resolve, ty) ));
- return ires.first->second.get();
-}
-
bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align)
{
TRACE_FUNCTION_FR(ty, "size=" << out_size << ", align=" << out_align);
@@ -802,6 +670,15 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve,
}
),
(Path,
+ if( te.binding.is_Opaque() )
+ return false;
+ if( te.binding.is_ExternType() )
+ {
+ DEBUG("sizeof on extern type - unsized");
+ out_align = 0;
+ out_size = SIZE_MAX;
+ return true;
+ }
const auto* repr = Target_GetTypeRepr(sp, resolve, ty);
if( !repr )
{
@@ -865,26 +742,39 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve,
// - Alignment is machine native
out_align = g_target.m_arch.m_pointer_bits / 8;
// - Size depends on Sized-nes of the parameter
- if( resolve.type_is_sized(sp, *te.inner) )
+ // TODO: Handle different types of Unsized (ones with different pointer sizes)
+ switch(resolve.metadata_type(sp, *te.inner))
{
+ case MetadataType::Unknown:
+ return false;
+ case MetadataType::None:
+ case MetadataType::Zero:
out_size = g_target.m_arch.m_pointer_bits / 8;
- return true;
+ break;
+ case MetadataType::Slice:
+ case MetadataType::TraitObject:
+ out_size = g_target.m_arch.m_pointer_bits / 8 * 2;
+ break;
}
- // TODO: Handle different types of Unsized (ones with different pointer sizes)
- out_size = g_target.m_arch.m_pointer_bits / 8 * 2;
return true;
),
(Pointer,
// - Alignment is machine native
out_align = g_target.m_arch.m_pointer_bits / 8;
// - Size depends on Sized-nes of the parameter
- if( resolve.type_is_sized(sp, *te.inner) )
+ switch(resolve.metadata_type(sp, *te.inner))
{
+ case MetadataType::Unknown:
+ return false;
+ case MetadataType::None:
+ case MetadataType::Zero:
out_size = g_target.m_arch.m_pointer_bits / 8;
- return true;
+ break;
+ case MetadataType::Slice:
+ case MetadataType::TraitObject:
+ out_size = g_target.m_arch.m_pointer_bits / 8 * 2;
+ break;
}
- // TODO: Handle different types of Unsized (ones with different pointer sizes)
- out_size = g_target.m_arch.m_pointer_bits / 8 * 2;
return true;
),
(Function,
@@ -911,7 +801,7 @@ bool Target_GetAlignOf(const Span& sp, const StaticTraitResolve& resolve, const
{
size_t ignore_size;
bool rv = Target_GetSizeAndAlignOf(sp, resolve, ty, ignore_size, out_align);
- if( ignore_size == SIZE_MAX )
+ if( rv && ignore_size == SIZE_MAX )
BUG(sp, "Getting alignment of Unsized type - " << ty);
return rv;
}
@@ -986,6 +876,9 @@ namespace {
case ::HIR::Struct::Repr::Simd:
// No sorting, no packing
break;
+ case ::HIR::Struct::Repr::Aligned:
+ // TODO: Update the minimum alignment
+ case ::HIR::Struct::Repr::Transparent:
case ::HIR::Struct::Repr::Rust:
allow_sort = true;
break;
@@ -1058,7 +951,7 @@ namespace {
cur_ofs ++;
}
}
- rv.align = max_align;
+ rv.align = packed ? 1 : max_align;
rv.size = cur_ofs;
rv.fields = ::std::move(fields);
DEBUG("size = " << rv.size << ", align = " << rv.align);
@@ -1368,6 +1261,11 @@ namespace {
{
return make_type_repr_enum(sp, resolve, ty);
}
+ else if( TU_TEST1(ty.m_data, Path, .binding.is_ExternType()) )
+ {
+ // TODO: Do extern types need anything?
+ return nullptr;
+ }
else if( ty.m_data.is_Primitive() )
{
return nullptr;
diff --git a/src/trans/target.hpp b/src/trans/target.hpp
index 4e0309dd..3433483b 100644
--- a/src/trans/target.hpp
+++ b/src/trans/target.hpp
@@ -78,18 +78,6 @@ struct TargetSpec
TargetArch m_arch;
};
-struct StructRepr
-{
- struct Ent {
- unsigned int field_idx;
- size_t size;
- size_t align;
- ::HIR::TypeRef ty;
- };
- // List of types, including padding (indicated by a UINT_MAX field idx)
- // Ordered as they would be emitted
- ::std::vector<Ent> ents;
-};
struct TypeRepr
{
size_t align = 0;
@@ -137,7 +125,6 @@ extern void Target_ExportCurSpec(const ::std::string& filename);
extern bool Target_GetSizeOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size);
extern bool Target_GetAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_align);
extern bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align);
-extern const StructRepr* Target_GetStructRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& struct_ty);
extern const TypeRepr* Target_GetTypeRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty);
diff --git a/src/trans/trans_list.cpp b/src/trans/trans_list.cpp
index 04e1e9a1..3d8aa86f 100644
--- a/src/trans/trans_list.cpp
+++ b/src/trans/trans_list.cpp
@@ -15,7 +15,7 @@ TransList_Function* TransList::add_function(::HIR::Path p)
{
DEBUG("Function " << rv.first->first);
assert( !rv.first->second );
- rv.first->second.reset( new TransList_Function {} );
+ rv.first->second.reset( new TransList_Function(rv.first->first) );
return &*rv.first->second;
}
else
@@ -38,6 +38,21 @@ TransList_Static* TransList::add_static(::HIR::Path p)
return nullptr;
}
}
+TransList_Const* TransList::add_const(::HIR::Path p)
+{
+ auto rv = m_constants.insert( ::std::make_pair(mv$(p), nullptr) );
+ if( rv.second )
+ {
+ DEBUG("Const " << rv.first->first);
+ assert( !rv.first->second );
+ rv.first->second.reset( new TransList_Const {} );
+ return &*rv.first->second;
+ }
+ else
+ {
+ return nullptr;
+ }
+}
t_cb_generic Trans_Params::get_cb() const
{
diff --git a/src/trans/trans_list.hpp b/src/trans/trans_list.hpp
index 48274f87..7009111f 100644
--- a/src/trans/trans_list.hpp
+++ b/src/trans/trans_list.hpp
@@ -18,6 +18,7 @@ class Function;
class Static;
}
+// TODO: This is very similar to "hir_typeck/common.hpp" MonomorphState
struct Trans_Params
{
Span sp;
@@ -48,16 +49,27 @@ struct CachedFunction {
};
struct TransList_Function
{
+ const ::HIR::Path* path; // Pointer into the list (std::map pointers are stable)
const ::HIR::Function* ptr;
Trans_Params pp;
// If `pp.has_types` is true, the below is valid
CachedFunction monomorphised;
+
+ TransList_Function(const ::HIR::Path& path):
+ path(&path),
+ ptr(nullptr)
+ {}
};
struct TransList_Static
{
const ::HIR::Static* ptr;
Trans_Params pp;
};
+struct TransList_Const
+{
+ const ::HIR::Constant* ptr;
+ Trans_Params pp;
+};
class TransList
{
@@ -70,17 +82,22 @@ public:
::std::map< ::HIR::Path, ::std::unique_ptr<TransList_Function> > m_functions;
::std::map< ::HIR::Path, ::std::unique_ptr<TransList_Static> > m_statics;
+ /// Constants that are still Defer
+ ::std::map< ::HIR::Path, ::std::unique_ptr<TransList_Const> > m_constants;
::std::map< ::HIR::Path, Trans_Params> m_vtables;
/// Required type_id values
::std::set< ::HIR::TypeRef> m_typeids;
/// Required struct/enum constructor impls
::std::set< ::HIR::GenericPath> m_constructors;
+ // Automatic Clone impls
+ ::std::set< ::HIR::TypeRef> auto_clone_impls;
// .second is `true` if this is a from a reference to the type
::std::vector< ::std::pair<::HIR::TypeRef, bool> > m_types;
TransList_Function* add_function(::HIR::Path p);
TransList_Static* add_static(::HIR::Path p);
+ TransList_Const* add_const(::HIR::Path p);
bool add_vtable(::HIR::Path p, Trans_Params pp) {
return m_vtables.insert( ::std::make_pair( mv$(p), mv$(pp) ) ).second;
}
diff --git a/src/version.cpp b/src/version.cpp
index af5ff552..9f62d5a5 100644
--- a/src/version.cpp
+++ b/src/version.cpp
@@ -14,10 +14,10 @@
#ifdef _WIN32
# define VERSION_GIT_ISDIRTY 1
-# define VERSION_GIT_FULLHASH ""
-# define VERSION_GIT_SHORTHASH ""
-# define VERSION_BUILDTIME ""
-# define VERSION_GIT_BRANCH ""
+# define VERSION_GIT_FULLHASH "unknown"
+# define VERSION_GIT_SHORTHASH "msvc"
+# define VERSION_BUILDTIME "unknown"
+# define VERSION_GIT_BRANCH "unknown"
#endif
unsigned int giVersion_Major = VERSION_MAJOR;
diff --git a/test_smiri.sh b/test_smiri.sh
index a275420a..88aae504 100755
--- a/test_smiri.sh
+++ b/test_smiri.sh
@@ -1,9 +1,10 @@
#!/bin/sh
set -e
cd $(dirname $0)
-make -f minicargo.mk MMIR=1 LIBS
-make -C tools/standalone_miri
+make all
+make -C tools/standalone_miri || exit 1
+make -f minicargo.mk MMIR=1 LIBS V= || exit 1
echo "--- mrustc -o output-mmir/hello"
-./bin/mrustc rustc-1.19.0-src/src/test/run-pass/hello.rs -O -C codegen-type=monomir -o output-mmir/hello -L output-mmir/ > output-mmir/hello_dbg.txt
+time ./bin/mrustc rustc-1.19.0-src/src/test/run-pass/hello.rs -O -C codegen-type=monomir -o output-mmir/hello -L output-mmir/ > output-mmir/hello_dbg.txt || exit 1
echo "--- standalone_miri output-mmir/hello.mir"
time ./tools/bin/standalone_miri output-mmir/hello.mir --logfile smiri_hello.log
diff --git a/tools/common/debug.cpp b/tools/common/debug.cpp
index 94d8ed99..3884d651 100644
--- a/tools/common/debug.cpp
+++ b/tools/common/debug.cpp
@@ -41,6 +41,10 @@ void Debug_EnablePhase(const char* phase_name)
{
gmDisabledDebug.erase(it);
}
+ else
+ {
+ ::std::cerr << "Unknown debug phase: " << phase_name << ::std::endl;
+ }
}
void Debug_Print(::std::function<void(::std::ostream& os)> cb)
{
diff --git a/tools/common/target_detect.h b/tools/common/target_detect.h
index 1bfc7dd9..dda4bc31 100644
--- a/tools/common/target_detect.h
+++ b/tools/common/target_detect.h
@@ -10,9 +10,9 @@
// - Windows (MSVC)
#ifdef _MSC_VER
# if defined(_WIN64)
-# define DEFAULT_TARGET_NAME "x86_64-windows-msvc"
+# define DEFAULT_TARGET_NAME "x86_64-pc-windows-msvc"
# else
-# define DEFAULT_TARGET_NAME "x86-windows-msvc"
+# define DEFAULT_TARGET_NAME "x86-pc-windows-msvc"
# endif
// - Linux
#elif defined(__linux__)
@@ -32,9 +32,9 @@
// - MinGW
#elif defined(__MINGW32__)
# if defined(_WIN64)
-# define DEFAULT_TARGET_NAME "x86_64-windows-gnu"
+# define DEFAULT_TARGET_NAME "x86_64-pc-windows-gnu"
# else
-# define DEFAULT_TARGET_NAME "i586-windows-gnu"
+# define DEFAULT_TARGET_NAME "i586-pc-windows-gnu"
# endif
// - FreeBSD
#elif defined(__FreeBSD__)
diff --git a/tools/common/toml.cpp b/tools/common/toml.cpp
index 285d22a4..4e8e6da6 100644
--- a/tools/common/toml.cpp
+++ b/tools/common/toml.cpp
@@ -264,8 +264,7 @@ TomlKeyValue TomlFile::get_next_value()
}
if( m_current_composite.empty() )
{
- // TODO: Allow EOF?
- if(t.m_type != Token::Type::Newline)
+ if(t.m_type != Token::Type::Newline && t.m_type != Token::Type::Eof)
throw ::std::runtime_error(::format(m_lexer, ": Unexpected token in TOML file after entry - ", t));
}
else
diff --git a/tools/common/toml.h b/tools/common/toml.h
index 17e05142..5e031803 100644
--- a/tools/common/toml.h
+++ b/tools/common/toml.h
@@ -58,7 +58,7 @@ public:
// Obtain the next value in the file
TomlKeyValue get_next_value();
- const TomlLexer& lexer() const;
+ const TomlLexer& lexer() const { return m_lexer; }
};
struct TomlValue
diff --git a/tools/dump_hirfile/Makefile b/tools/dump_hirfile/Makefile
new file mode 100644
index 00000000..c0ae0513
--- /dev/null
+++ b/tools/dump_hirfile/Makefile
@@ -0,0 +1,56 @@
+#
+ifeq ($(OS),Windows_NT)
+ EXESUF ?= .exe
+endif
+EXESUF ?=
+
+V ?= @
+
+OBJDIR := .obj/
+
+BIN := ../bin/dump_hirfile$(EXESUF)
+OBJS := main.o
+OBJS += debug.o rc_string.o span.o ident.o
+OBJS += parse/parseerror.o # Why is this needed? ast/path.cpp uses it in binding
+OBJS += hir/hir.o hir/type.o hir/deserialise.o hir/serialise_lowlevel.o
+OBJS += hir/crate_ptr.o hir/generic_params.o hir/path.o hir/pattern.o hir/expr_ptr.o
+OBJS += hir/expr.o # Why is this needed?
+OBJS += parse/token.o parse/tokentree.o parse/tokenstream.o
+OBJS += ast/ast.o ast/expr.o ast/path.o ast/types.o ast/pattern.o
+OBJS += mir/mir.o mir/mir_ptr.o mir/dump.o hir/visitor.o
+OBJS += macro_rules/mod.o
+
+LINKFLAGS := -g -lpthread -lz
+CXXFLAGS := -Wall -std=c++14 -g -O2
+CXXFLAGS += -I ../common -I ../../src -I ../../src/include
+
+OBJS := $(OBJS:%=$(OBJDIR)%)
+
+.PHONY: all clean
+
+all: $(BIN)
+
+clean:
+ rm $(BIN) $(OBJS)
+
+$(BIN): $(OBJS) ../bin/common_lib.a
+ @mkdir -p $(dir $@)
+ @echo [CXX] -o $@
+ $V$(CXX) -o $@ $(OBJS) ../bin/common_lib.a $(LINKFLAGS)
+
+$(OBJDIR)%.o: %.cpp
+ @mkdir -p $(dir $@)
+ @echo [CXX] $<
+ $V$(CXX) -o $@ -c $< $(CXXFLAGS) -MMD -MP -MF $@.dep
+
+$(OBJDIR)%.o: ../../src/%.cpp
+ @mkdir -p $(dir $@)
+ @echo [CXX] $<
+ $V$(CXX) -o $@ -c $< $(CXXFLAGS) -MMD -MP -MF $@.dep
+
+../bin/common_lib.a: $(wildcard ../common/*.* ../common/Makefile)
+ make -C ../common
+
+-include $(OBJS:%.o=%.o.dep)
+
+
diff --git a/tools/dump_hirfile/main.cpp b/tools/dump_hirfile/main.cpp
new file mode 100644
index 00000000..47436950
--- /dev/null
+++ b/tools/dump_hirfile/main.cpp
@@ -0,0 +1,327 @@
+#include <hir/hir.hpp>
+#include <hir/item_path.hpp>
+#include <hir/main_bindings.hpp>
+#include <macro_rules/macro_rules.hpp>
+#include <mir/mir.hpp>
+#include <mir/operations.hpp> // MIR_Dump_Fcn
+
+int g_debug_indent_level = 0;
+
+struct Args
+{
+ Args(int argc, const char* const argv[]);
+
+ ::std::string infile;
+};
+
+struct Dumper
+{
+ struct Filters {
+ struct Types {
+ bool macros = true;
+ bool functions = true;
+ bool statics = true;
+ bool types = true;
+ bool traits = true;
+ } types;
+ bool public_only = false;
+ bool no_body = false;
+ } filters;
+
+ void dump_crate(const char* name, const ::HIR::Crate& crate) const;
+ void dump_module(::HIR::ItemPath ip, const ::HIR::Publicity& pub, const ::HIR::Module& mod) const;
+ void dump_function(::HIR::ItemPath ip, const ::HIR::Publicity& pub, const ::HIR::Function& fcn, int indent=0) const;
+ void dump_trait(::HIR::ItemPath ip, const ::HIR::Publicity& pub, const ::HIR::Trait& trait, int indent=0) const;
+};
+
+int main(int argc, const char* argv[])
+{
+ Args args(argc, argv);
+ Dumper dumper;
+
+ dumper.filters.types.functions = true;
+
+ auto hir = HIR_Deserialise(args.infile);
+ dumper.dump_crate("", *hir);
+}
+namespace {
+ template<typename T, typename Fcn>
+ void dump_impl_group(const ::HIR::Crate::ImplGroup<T>& ig, Fcn cb)
+ {
+ for(const auto& named_il : ig.named)
+ {
+ for(const auto& impl : named_il.second)
+ {
+ cb(*impl);
+ }
+ }
+ for(const auto& impl : ig.non_named)
+ {
+ cb(*impl);
+ }
+ for(const auto& impl : ig.generic)
+ {
+ cb(*impl);
+ }
+ }
+}
+void Dumper::dump_crate(const char* name, const ::HIR::Crate& crate) const
+{
+ // Dump macros
+ for(const auto& mac : crate.m_exported_macros)
+ {
+ ::std::cout << "macro_rules! " << mac.first << "{" << std::endl;
+ for(const auto& arm : mac.second->m_rules)
+ {
+ ::std::cout << " (";
+ for(const auto& pat : arm.m_pattern)
+ {
+ TU_MATCH_HDRA( (pat), {)
+ TU_ARMA(End, e)
+ ::std::cout << " EOS";
+ TU_ARMA(LoopStart, e)
+ ::std::cout << " (";
+ TU_ARMA(LoopNext, e)
+ ::std::cout << " ^";
+ TU_ARMA(LoopEnd, e)
+ ::std::cout << " )";
+ TU_ARMA(Jump, e)
+ ::std::cout << " <" << e.jump_target;
+ TU_ARMA(ExpectTok, e)
+ ::std::cout << " =" << e;
+ TU_ARMA(ExpectPat, e)
+ ::std::cout << " " << e.idx << "=" << e.type;
+ TU_ARMA(If, e) {
+ ::std::cout << " ?" << (e.is_equal ? "" : "!") << "{";
+ for(const auto& ent : e.ents) {
+ if(ent.ty == MacroPatEnt::PAT_TOKEN)
+ ::std::cout << " =" << ent.tok;
+ else
+ ::std::cout << " " << ent.ty;
+ }
+ ::std::cout << "}->" << e.jump_target;
+ }
+ }
+ }
+ ::std::cout << " ) => {\n";
+ // TODO: Macro expansion
+ ::std::cout << " }\n";
+ }
+ ::std::cout << "}\n";
+ ::std::cout << ::std::endl;
+ }
+
+ this->dump_module(::HIR::ItemPath(name), ::HIR::Publicity::new_global(), crate.m_root_module);
+
+ for(const auto& i : crate.m_trait_impls)
+ {
+ dump_impl_group(i.second, [&](const ::HIR::TraitImpl& ti) {
+ auto root_ip = ::HIR::ItemPath(ti.m_type, i.first, ti.m_trait_args);
+ ::std::cout << "impl" << ti.m_params.fmt_args() << " " << i.first << ti.m_trait_args << " for " << ti.m_type << "\n";
+ ::std::cout << " where" << ti.m_params.fmt_bounds() << "\n";
+ ::std::cout << "{" << ::std::endl;
+ if( this->filters.types.functions )
+ {
+ for(const auto& m : ti.m_methods)
+ {
+ this->dump_function(root_ip + m.first, ::HIR::Publicity::new_global(), m.second.data, 1);
+ }
+ }
+ ::std::cout << "}" << ::std::endl;
+ });
+ }
+
+ dump_impl_group(crate.m_type_impls, [&](const auto& i) {
+ auto root_ip = ::HIR::ItemPath(i.m_type);
+ ::std::cout << "impl" << i.m_params.fmt_args() << " " << i.m_type << "\n";
+ ::std::cout << " where" << i.m_params.fmt_bounds() << "\n";
+ ::std::cout << "{" << ::std::endl;
+ if( this->filters.types.functions )
+ {
+ for(const auto& m : i.m_methods)
+ {
+ this->dump_function(root_ip + m.first, ::HIR::Publicity::new_global(), m.second.data, 1);
+ }
+ }
+ ::std::cout << "}" << ::std::endl;
+ });
+}
+void Dumper::dump_module(::HIR::ItemPath ip, const ::HIR::Publicity& pub, const ::HIR::Module& mod) const
+{
+ if( filters.public_only && !pub.is_global() )
+ {
+ return ;
+ }
+ ::std::cout << "// mod " << ip << ::std::endl;
+ for(const auto& i : mod.m_mod_items)
+ {
+ auto sub_ip = ip + i.first;
+ //::std::cout << "// " << i.second->ent.tagstr() << " " << sub_ip << "\n";
+ TU_MATCH_HDRA( (i.second->ent), {)
+ TU_ARMA(Module, e) {
+ this->dump_module(sub_ip, i.second->publicity, e);
+ }
+ TU_ARMA(Import, e) {
+ //this->dump_mod_import(sub_ip, e);
+ }
+ TU_ARMA(TypeAlias, e) {
+ //this->dump_type_alias(sub_ip, e);
+ }
+ TU_ARMA(ExternType, e) {
+ //this->dump_ext_type(sub_ip, e);
+ }
+ TU_ARMA(Enum, e) {
+ //this->dump_enum(sub_ip, e);
+ }
+ TU_ARMA(Struct, e) {
+ //this->dump_enum(sub_ip, e);
+ }
+ TU_ARMA(Union, e) {
+ //this->dump_trait(sub_ip, e);
+ }
+ TU_ARMA(Trait, e) {
+ this->dump_trait(sub_ip, i.second->publicity, e);
+ }
+ }
+ }
+ for(const auto& i : mod.m_value_items)
+ {
+ auto sub_ip = ip + i.first;
+ //::std::cout << "// " << i.second->ent.tagstr() << " " << sub_ip << "\n";
+ TU_MATCH_HDRA( (i.second->ent), {)
+ TU_ARMA(Import, e) {
+ //this->dump_val_import(sub_ip, e);
+ }
+ TU_ARMA(Constant, e) {
+ //this->dump_constant(sub_ip, e);
+ }
+ TU_ARMA(Static, e) {
+ //this->dump_constant(sub_ip, e);
+ }
+ TU_ARMA(StructConstant, e) {
+ //this->dump_constant(sub_ip, e);
+ }
+ TU_ARMA(StructConstructor, e) {
+ //this->dump_constant(sub_ip, e);
+ }
+ TU_ARMA(Function, e) {
+ this->dump_function(sub_ip, i.second->publicity, e);
+ }
+ }
+ }
+}
+void Dumper::dump_function(::HIR::ItemPath ip, const ::HIR::Publicity& pub, const ::HIR::Function& fcn, int nindent/*=0*/) const
+{
+ auto indent = RepeatLitStr { " ", nindent };
+ if( !this->filters.types.functions ) {
+ return ;
+ }
+ if( filters.public_only && !pub.is_global() ) {
+ return ;
+ }
+ ::std::cout << indent << "fn " << ip << fcn.m_params.fmt_args() << "(";
+ ::std::cout << " )";
+ if( fcn.m_code.m_mir )
+ {
+ ::std::cout << "\n";
+ ::std::cout << indent << "{\n";
+ if( filters.no_body ) {
+ ::std::cout << indent << "...\n";
+ }
+ else {
+ MIR_Dump_Fcn(::std::cout, *fcn.m_code.m_mir, nindent+1);
+ }
+ ::std::cout << indent << "}\n";
+ ::std::cout << ::std::endl;
+ }
+ else
+ {
+ ::std::cout << ";" << ::std::endl;
+ }
+}
+void Dumper::dump_trait(::HIR::ItemPath ip, const ::HIR::Publicity& pub, const ::HIR::Trait& trait, int nindent/*=0*/) const
+{
+ auto indent = RepeatLitStr { " ", nindent };
+ if( !this->filters.types.functions ) {
+ return ;
+ }
+ if( !filters.public_only && !pub.is_global() ) {
+ return ;
+ }
+ ::std::cout << indent << "trait " << ip << trait.m_params.fmt_args() << "\n";
+ ::std::cout << indent << "{\n";
+ auto indent2 = RepeatLitStr { " ", nindent+1 };
+ // ...
+ ::std::cout << indent << "}\n";
+ ::std::cout << ::std::endl;
+}
+
+bool debug_enabled()
+{
+ return false;
+}
+::std::ostream& debug_output(int indent, const char* function)
+{
+ return ::std::cout << "- " << RepeatLitStr { " ", indent } << function << ": ";
+}
+
+Args::Args(int argc, const char* const argv[])
+{
+ this->infile = argv[1];
+}
+
+// TODO: This is copy-pasted from src/main.cpp, should live somewhere better
+::std::ostream& operator<<(::std::ostream& os, const FmtEscaped& x)
+{
+ os << ::std::hex;
+ for(auto s = x.s; *s != '\0'; s ++)
+ {
+ switch(*s)
+ {
+ case '\0': os << "\\0"; break;
+ case '\n': os << "\\n"; break;
+ case '\\': os << "\\\\"; break;
+ case '"': os << "\\\""; break;
+ default:
+ uint8_t v = *s;
+ if( v < 0x80 )
+ {
+ if( v < ' ' || v > 0x7F )
+ os << "\\u{" << ::std::hex << (unsigned int)v << "}";
+ else
+ os << v;
+ }
+ else if( v < 0xC0 )
+ ;
+ else if( v < 0xE0 )
+ {
+ uint32_t val = (uint32_t)(v & 0x1F) << 6;
+ v = (uint8_t)*++s; if( (v & 0xC0) != 0x80 ) { s--; continue ; } val |= (uint32_t)v << 6;
+ os << "\\u{" << ::std::hex << val << "}";
+ }
+ else if( v < 0xF0 )
+ {
+ uint32_t val = (uint32_t)(v & 0x0F) << 12;
+ v = (uint8_t)*++s; if( (v & 0xC0) != 0x80 ) { s--; continue ; } val |= (uint32_t)v << 12;
+ v = (uint8_t)*++s; if( (v & 0xC0) != 0x80 ) { s--; continue ; } val |= (uint32_t)v << 6;
+ os << "\\u{" << ::std::hex << val << "}";
+ }
+ else if( v < 0xF8 )
+ {
+ uint32_t val = (uint32_t)(v & 0x07) << 18;
+ v = (uint8_t)*++s; if( (v & 0xC0) != 0x80 ) { s--; continue ; } val |= (uint32_t)v << 18;
+ v = (uint8_t)*++s; if( (v & 0xC0) != 0x80 ) { s--; continue ; } val |= (uint32_t)v << 12;
+ v = (uint8_t)*++s; if( (v & 0xC0) != 0x80 ) { s--; continue ; } val |= (uint32_t)v << 6;
+ os << "\\u{" << ::std::hex << val << "}";
+ }
+ break;
+ }
+ }
+ os << ::std::dec;
+ return os;
+}
+
+MIR::EnumCachePtr::~EnumCachePtr()
+{
+ assert(!this->p);
+}
diff --git a/tools/minicargo/Makefile b/tools/minicargo/Makefile
index 363ef4b9..862f6b3c 100644
--- a/tools/minicargo/Makefile
+++ b/tools/minicargo/Makefile
@@ -13,7 +13,7 @@ V ?= @
OBJDIR := .obj/
BIN := ../bin/minicargo$(EXESUF)
-OBJS := main.o build.o manifest.o repository.o
+OBJS := main.o build.o manifest.o repository.o cfg.o
LINKFLAGS := -g -lpthread
CXXFLAGS := -Wall -std=c++14 -g -O2
diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp
index 53fa1a16..efacb6f8 100644
--- a/tools/minicargo/build.cpp
+++ b/tools/minicargo/build.cpp
@@ -24,6 +24,7 @@ extern int _putenv_s(const char*, const char*);
#include <vector>
#include <algorithm>
#include <sstream> // stringstream
+#include <fstream> // ifstream
#include <cstdlib> // setenv
#ifndef DISABLE_MULTITHREAD
# include <thread>
@@ -52,8 +53,10 @@ extern int _putenv_s(const char*, const char*);
#ifdef _WIN32
# define EXESUF ".exe"
+# define DLLSUF ".dll"
#else
# define EXESUF ""
+# define DLLSUF ".so"
#endif
#include <target_detect.h> // tools/common/target_detect.h
#define HOST_TARGET DEFAULT_TARGET_NAME
@@ -61,17 +64,19 @@ extern int _putenv_s(const char*, const char*);
/// Class abstracting access to the compiler
class Builder
{
- BuildOptions m_opts;
+ const BuildOptions& m_opts;
::helpers::path m_compiler_path;
+ size_t m_total_targets;
+ mutable size_t m_targets_built;
#ifndef _WIN32
mutable ::std::mutex chdir_mutex;
#endif
public:
- Builder(BuildOptions opts);
+ Builder(const BuildOptions& opts, size_t total_targets);
- bool build_target(const PackageManifest& manifest, const PackageTarget& target, bool is_for_host) const;
- bool build_library(const PackageManifest& manifest, bool is_for_host) const;
+ bool build_target(const PackageManifest& manifest, const PackageTarget& target, bool is_for_host, size_t index) const;
+ bool build_library(const PackageManifest& manifest, bool is_for_host, size_t index) const;
::helpers::path build_build_script(const PackageManifest& manifest, bool is_for_host, bool* out_is_rebuilt) const;
private:
@@ -217,6 +222,18 @@ BuildList::BuildList(const PackageManifest& manifest, const BuildOptions& opts):
{
b.m_list.push_back({ &manifest, !cross_compiling, 0 });
}
+ if( opts.mode != BuildOptions::Mode::Normal)
+ {
+ for(const auto& dep : manifest.dev_dependencies())
+ {
+ if( dep.is_disabled() )
+ {
+ continue ;
+ }
+ DEBUG(manifest.name() << ": Dependency " << dep.name());
+ b.add_package(dep.get_package(), 1, !opts.build_script_overrides.is_valid(), !cross_compiling);
+ }
+ }
// TODO: Add the binaries too?
// - They need slightly different treatment.
@@ -260,7 +277,7 @@ BuildList::BuildList(const PackageManifest& manifest, const BuildOptions& opts):
bool BuildList::build(BuildOptions opts, unsigned num_jobs)
{
bool include_build = !opts.build_script_overrides.is_valid();
- Builder builder { ::std::move(opts) };
+ Builder builder { opts, m_list.size() };
// Pre-count how many dependencies are remaining for each package
struct BuildState
@@ -413,7 +430,7 @@ bool BuildList::build(BuildOptions opts, unsigned num_jobs)
}
DEBUG("Thread " << my_idx << ": Starting " << cur << " - " << list[cur].package->name());
- if( ! builder->build_library(*list[cur].package, list[cur].is_host) )
+ if( ! builder->build_library(*list[cur].package, list[cur].is_host, cur) )
{
queue.failure = true;
queue.signal_all();
@@ -474,7 +491,7 @@ bool BuildList::build(BuildOptions opts, unsigned num_jobs)
{
auto cur = state.get_next();
- if( ! builder.build_library(*m_list[cur].package, m_list[cur].is_host) )
+ if( ! builder.build_library(*m_list[cur].package, m_list[cur].is_host, cur) )
{
return false;
}
@@ -488,7 +505,7 @@ bool BuildList::build(BuildOptions opts, unsigned num_jobs)
{
auto cur = state.get_next();
- if( ! builder.build_library(*m_list[cur].package, m_list[cur].is_host) )
+ if( ! builder.build_library(*m_list[cur].package, m_list[cur].is_host, cur) )
{
return false;
}
@@ -532,14 +549,26 @@ bool BuildList::build(BuildOptions opts, unsigned num_jobs)
}
// Now that all libraries are done, build the binaries (if present)
- return this->m_root_manifest.foreach_binaries([&](const auto& bin_target) {
- return builder.build_target(this->m_root_manifest, bin_target, /*is_for_host=*/false);
- });
+ switch(opts.mode)
+ {
+ case BuildOptions::Mode::Normal:
+ return this->m_root_manifest.foreach_binaries([&](const auto& bin_target) {
+ return builder.build_target(this->m_root_manifest, bin_target, /*is_for_host=*/false, ~0u);
+ });
+ case BuildOptions::Mode::Test:
+ // TODO: What about unit tests?
+ return this->m_root_manifest.foreach_ty(PackageTarget::Type::Test, [&](const auto& test_target) {
+ return builder.build_target(this->m_root_manifest, test_target, /*is_for_host=*/true, ~0u);
+ });
+ }
+ throw "unreachable";
}
-Builder::Builder(BuildOptions opts):
- m_opts(::std::move(opts))
+Builder::Builder(const BuildOptions& opts, size_t total_targets):
+ m_opts(opts),
+ m_total_targets(total_targets),
+ m_targets_built(0)
{
if( const char* override_path = getenv("MRUSTC_PATH") ) {
m_compiler_path = override_path;
@@ -614,16 +643,44 @@ Builder::Builder(BuildOptions opts):
switch(target.m_type)
{
case PackageTarget::Type::Lib:
- if(crate_type) {
- *crate_type = target.m_is_proc_macro ? "proc-macro" : "rlib";
+ switch( target.m_crate_types.size() > 0
+ ? target.m_crate_types.front()
+ : (target.m_is_proc_macro
+ ? PackageTarget::CrateType::proc_macro
+ : PackageTarget::CrateType::rlib
+ )
+ )
+ {
+ case PackageTarget::CrateType::proc_macro:
+ if(crate_type) *crate_type = "proc-macro";
+ outfile /= ::format("lib", target.m_name, crate_suffix, "-plugin" EXESUF);
+ break;
+ case PackageTarget::CrateType::dylib:
+ if( getenv("MINICARGO_DYLIB") )
+ {
+ // TODO: Enable this once mrustc can set rpath or absolute paths
+ if(crate_type) *crate_type = "dylib";
+ outfile /= ::format("lib", target.m_name, crate_suffix, DLLSUF);
+ break;
+ }
+ case PackageTarget::CrateType::rlib:
+ if(crate_type) *crate_type = "rlib";
+ outfile /= ::format("lib", target.m_name, crate_suffix, ".rlib");
+ break;
+ default:
+ throw "";
}
- outfile /= ::format("lib", target.m_name, crate_suffix, ".hir");
break;
case PackageTarget::Type::Bin:
if(crate_type)
*crate_type = "bin";
outfile /= ::format(target.m_name, EXESUF);
break;
+ case PackageTarget::Type::Test:
+ if(crate_type)
+ *crate_type = "bin";
+ outfile /= ::format(target.m_name, EXESUF);
+ break;
default:
throw ::std::runtime_error("Unknown target type being built");
}
@@ -632,11 +689,117 @@ Builder::Builder(BuildOptions opts):
return outfile;
}
-bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& target, bool is_for_host) const
+namespace {
+ ::std::map< ::std::string, ::std::vector<helpers::path> > load_depfile(const helpers::path& depfile_path)
+ {
+ ::std::map< ::std::string, ::std::vector<helpers::path> > rv;
+ ::std::ifstream ifp(depfile_path);
+ if( ifp.good() )
+ {
+ // Load space-separated (backslash-escaped) paths
+ struct Lexer {
+ ::std::ifstream ifp;
+ char m_c;
+
+ Lexer(::std::ifstream ifp)
+ :ifp(::std::move(ifp))
+ ,m_c(0)
+ {
+ nextc();
+ }
+
+ bool nextc() {
+ int v = ifp.get();
+ if( v == EOF ) {
+ m_c = '\0';
+ return false;
+ }
+ else {
+ m_c = (char)v;
+ return true;
+ }
+ }
+ ::std::string get_token() {
+ auto t = get_token_int();
+ //DEBUG("get_token '" << t << "'");
+ return t;
+ }
+ ::std::string get_token_int() {
+ if( ifp.eof() )
+ return "";
+ while( m_c == ' ' )
+ {
+ if( !nextc() )
+ return "";
+ }
+ if( m_c == '\n' ) {
+ nextc();
+ return "\n";
+ }
+ if( m_c == '\t' ) {
+ nextc();
+ return "\t";
+ }
+ ::std::string rv;
+ do {
+ if( m_c == '\\' )
+ {
+ nextc();
+ if( m_c == ' ' ) {
+ rv += m_c;
+ }
+ else if( m_c == ':' ) {
+ rv += m_c;
+ }
+ // HACK: Only spaces are escaped this way?
+ else {
+ rv += '\\';
+ rv += m_c;
+ }
+ }
+ else
+ {
+ rv += m_c;
+ }
+ } while( nextc() && m_c != ' ' && m_c != ':' && m_c != '\n' );
+ return rv;
+ }
+ } lexer(::std::move(ifp));
+
+ // Look for <string> ":" [<string>]* "\n"
+ do {
+ auto t = lexer.get_token();
+ if( t == "" )
+ break;
+ if( t == "\n" )
+ continue ;
+
+ auto v = rv.insert(::std::make_pair(t, ::std::vector<helpers::path>()));
+ auto& list = v.first->second;
+ auto target = t;
+ t = lexer.get_token();
+ assert(t == ":");
+
+ do {
+ t = lexer.get_token();
+ if( t == "\n" || t == "" )
+ break ;
+ list.push_back(t);
+ } while(1);
+ } while(1);
+ }
+ return rv;
+ }
+}
+
+bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& target, bool is_for_host, size_t index) const
{
const char* crate_type;
::std::string crate_suffix;
auto outfile = this->get_crate_path(manifest, target, is_for_host, &crate_type, &crate_suffix);
+ auto depfile = outfile + ".d";
+
+ size_t this_target_idx = (index != ~0u ? m_targets_built++ : ~0u);
// TODO: Determine if it needs re-running
// Rerun if:
@@ -658,22 +821,58 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget&
DEBUG("Building " << outfile << " - Older than mrustc ( " << ts_result << " < " << Timestamp::for_file(m_compiler_path) << ")");
}
else {
- // TODO: Check dependencies. (from depfile)
- // Don't rebuild (no need to)
- DEBUG("Not building " << outfile << " - not out of date");
- return true;
+ // Check dependencies. (from depfile)
+ auto depfile_ents = load_depfile(depfile);
+ auto it = depfile_ents.find(outfile);
+ bool has_new_file = false;
+ if( it != depfile_ents.end() )
+ {
+ for(const auto& f : it->second)
+ {
+ auto dep_ts = Timestamp::for_file(f);
+ if( ts_result < dep_ts )
+ {
+ has_new_file = true;
+ DEBUG("Rebuilding " << outfile << ", older than " << f);
+ break;
+ }
+ }
+ }
+
+ if( !has_new_file )
+ {
+ // Don't rebuild (no need to)
+ DEBUG("Not building " << outfile << " - not out of date");
+ return true;
+ }
}
for(const auto& cmd : manifest.build_script_output().pre_build_commands)
{
// TODO: Run commands specified by build script (override)
+ TODO("Run command `" << cmd << "` from build script override");
}
- ::std::cout << "BUILDING " << target.m_name << " from " << manifest.name() << " v" << manifest.version() << " with features [" << manifest.active_features() << "]" << ::std::endl;
+ {
+ // TODO: Determine what number and total targets there are
+ if( index != ~0u ) {
+ //::std::cout << "(" << index << "/" << m_total_targets << ") ";
+ ::std::cout << "(" << this_target_idx << "/" << m_total_targets << ") ";
+ }
+ ::std::cout << "BUILDING ";
+ if(target.m_name != manifest.name())
+ ::std::cout << target.m_name << " from ";
+ ::std::cout << manifest.name() << " v" << manifest.version();
+ if( !manifest.active_features().empty() )
+ ::std::cout << " with features [" << manifest.active_features() << "]";
+ ::std::cout << ::std::endl;
+ }
StringList args;
args.push_back(::helpers::path(manifest.manifest_path()).parent() / ::helpers::path(target.m_path));
+ args.push_back("-o"); args.push_back(outfile);
args.push_back("--crate-name"); args.push_back(target.m_name.c_str());
args.push_back("--crate-type"); args.push_back(crate_type);
+ args.push_back("-C"); args.push_back(format("emit-depfile=",depfile));
if( !crate_suffix.empty() ) {
args.push_back("--crate-tag"); args.push_back(crate_suffix.c_str() + 1);
}
@@ -699,7 +898,11 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget&
args.push_back("-C"); args.push_back("codegen-type=monomir");
}
- args.push_back("-o"); args.push_back(outfile);
+ for(const auto& d : m_opts.lib_search_dirs)
+ {
+ args.push_back("-L");
+ args.push_back(d.str().c_str());
+ }
args.push_back("-L"); args.push_back(this->get_output_dir(is_for_host).str());
for(const auto& dir : manifest.build_script_output().rustc_link_search) {
args.push_back("-L"); args.push_back(dir.second.c_str());
@@ -725,6 +928,10 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget&
args.push_back("--extern");
args.push_back(::format(m.get_library().m_name, "=", path));
}
+ if( target.m_type == PackageTarget::Type::Test )
+ {
+ args.push_back("--test");
+ }
for(const auto& dep : manifest.dependencies())
{
if( ! dep.is_disabled() )
@@ -735,10 +942,18 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget&
args.push_back(::format(m.get_library().m_name, "=", path));
}
}
- for(const auto& d : m_opts.lib_search_dirs)
+ if( target.m_type == PackageTarget::Type::Test )
{
- args.push_back("-L");
- args.push_back(d.str().c_str());
+ for(const auto& dep : manifest.dev_dependencies())
+ {
+ if( ! dep.is_disabled() )
+ {
+ const auto& m = dep.get_package();
+ auto path = this->get_crate_path(m, m.get_library(), is_for_host, nullptr, nullptr);
+ args.push_back("--extern");
+ args.push_back(::format(m.get_library().m_name, "=", path));
+ }
+ }
}
// TODO: Environment variables (rustc_env)
@@ -867,13 +1082,13 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget&
StringListKV env;
env.push_back("CARGO_MANIFEST_DIR", manifest.directory().to_absolute());
//env.push_back("CARGO_MANIFEST_LINKS", manifest.m_links);
- //for(const auto& feat : manifest.m_active_features)
- //{
- // ::std::string fn = "CARGO_FEATURE_";
- // for(char c : feat)
- // fn += c == '-' ? '_' : tolower(c);
- // env.push_back(fn, manifest.m_links);
- //}
+ for(const auto& feat : manifest.active_features())
+ {
+ ::std::string fn = "CARGO_FEATURE_";
+ for(char c : feat)
+ fn += c == '-' ? '_' : toupper(c);
+ env.push_back(fn, "1");
+ }
//env.push_back("CARGO_CFG_RELEASE", "");
env.push_back("OUT_DIR", out_dir);
env.push_back("TARGET", m_opts.target_name ? m_opts.target_name : HOST_TARGET);
@@ -882,6 +1097,11 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget&
env.push_back("OPT_LEVEL", "2");
env.push_back("DEBUG", "0");
env.push_back("PROFILE", "release");
+ // TODO: All cfg(foo_bar) become CARGO_CFG_FOO_BAR
+ env.push_back("CARGO_CFG_TARGET_POINTER_WIDTH", "32");
+ // - Needed for `regex`'s build script, make mrustc pretend to be rustc
+ env.push_back("RUSTC", this->m_compiler_path);
+
for(const auto& dep : manifest.dependencies())
{
if( ! dep.is_disabled() )
@@ -922,7 +1142,7 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget&
return out_file;
}
-bool Builder::build_library(const PackageManifest& manifest, bool is_for_host) const
+bool Builder::build_library(const PackageManifest& manifest, bool is_for_host, size_t index) const
{
if( manifest.build_script() != "" )
{
@@ -948,7 +1168,7 @@ bool Builder::build_library(const PackageManifest& manifest, bool is_for_host) c
}
}
- return this->build_target(manifest, manifest.get_library(), is_for_host);
+ return this->build_target(manifest, manifest.get_library(), is_for_host, index);
}
bool Builder::spawn_process_mrustc(const StringList& args, StringListKV env, const ::helpers::path& logfile) const
{
@@ -986,6 +1206,7 @@ bool Builder::spawn_process(const char* exe_name, const StringList& args, const
#else
for(auto kv : env)
{
+ DEBUG("putenv " << kv.first << "=" << kv.second);
_putenv_s(kv.first, kv.second);
}
#endif
diff --git a/tools/minicargo/build.h b/tools/minicargo/build.h
index bba22964..83af88d6 100644
--- a/tools/minicargo/build.h
+++ b/tools/minicargo/build.h
@@ -20,7 +20,15 @@ struct BuildOptions
::helpers::path build_script_overrides;
::std::vector<::helpers::path> lib_search_dirs;
bool emit_mmir = false;
- const char* target_name = nullptr; // if null, host is used
+ const char* target_name = nullptr; // if null, host is used
+ enum class Mode {
+ /// Build the binary/library
+ Normal,
+ /// Build tests
+ Test,
+ /// Build examples
+ Examples,
+ } mode = Mode::Normal;
};
class BuildList
diff --git a/tools/minicargo/cfg.cpp b/tools/minicargo/cfg.cpp
new file mode 100644
index 00000000..85bff327
--- /dev/null
+++ b/tools/minicargo/cfg.cpp
@@ -0,0 +1,269 @@
+/*
+ * mrustc "minicargo" (minimal cargo clone)
+ * - By John Hodge (Mutabah)
+ *
+ * cfg.cpp
+ * - Handling of target configuration (in manifest nodes)
+ */
+#include <iostream> // cerr
+#include "debug.h"
+#include <cassert>
+#include <algorithm>
+#include <string>
+#include <cstring>
+#include "cfg.hpp"
+
+// TODO: Extract this from the target at runtime (by invoking the compiler on the passed target)
+#ifdef _WIN32
+//# define TARGET_NAME "i586-windows-msvc"
+# define CFG_UNIX false
+# define CFG_WINDOWS true
+#elif defined(__NetBSD__)
+//# define TARGET_NAME "x86_64-unknown-netbsd"
+# define CFG_UNIX true
+# define CFG_WINDOWS false
+#else
+//# define TARGET_NAME "x86_64-unknown-linux-gnu"
+# define CFG_UNIX true
+# define CFG_WINDOWS false
+#endif
+
+class CfgParseLexer
+{
+public:
+ class Tok
+ {
+ friend class CfgParseLexer;
+ public:
+ enum Type {
+ EndOfStream,
+ Operator,
+ Ident,
+ String,
+ };
+ private:
+ Type m_ty;
+ const char* s;
+ const char* e;
+ ::std::string m_val;
+ Tok():
+ m_ty(EndOfStream), s(nullptr),e(nullptr)
+ {
+ }
+ Tok(const char* s):
+ m_ty(Operator), s(s), e(s+1), m_val()
+ {
+ }
+ Tok(const char* s, const char* e):
+ m_ty(Ident), s(s), e(e), m_val()
+ {
+ }
+ Tok(const char* s, const char* e, ::std::string val):
+ m_ty(String), s(s), e(e), m_val(::std::move(val))
+ {
+ }
+ public:
+ bool operator==(char c) const {
+ return (m_ty == Operator && *s == c);
+ }
+ bool operator!=(char c) const { return !(*this == c); }
+ bool operator==(const char* v) const {
+ return strlen(v) == static_cast<unsigned>(e - s) && memcmp(s, v, e-s) == 0;
+ }
+ bool operator!=(const char* v) const { return !(*this == v); }
+
+ const Type ty() const { return m_ty; }
+ const ::std::string& str() const {
+ return m_val;
+ }
+ ::std::string to_string() const {
+ return ::std::string(s, e);
+ }
+ };
+private:
+ const char* m_pos;
+ Tok m_cur;
+
+public:
+ CfgParseLexer(const char* s):
+ m_pos(s),
+ m_cur(nullptr,nullptr)
+ {
+ consume();
+ }
+ const Tok& cur() const {
+ return m_cur;
+ }
+
+ Tok consume() {
+ auto rv = m_cur;
+ m_cur = get_next();
+ //::std::cout << "consume: " << rv.to_string() << " => " << m_cur.to_string() << ::std::endl;
+ return rv;
+ }
+ bool consume_if(char c) {
+ if( cur() == c ) {
+ consume();
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ bool consume_if(const char* s) {
+ if( cur() == s ) {
+ consume();
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+private:
+ Tok get_next();
+};
+
+struct CfgChecker
+{
+ const char* target_env;
+ const char* target_os;
+ const char* target_arch;
+
+ bool check_cfg(CfgParseLexer& p) const;
+};
+
+CfgChecker gCfgChecker {
+ (CFG_WINDOWS ? "msvc" : "gnu"),
+ (CFG_WINDOWS ? "windows" : "linux"),
+ "x86"
+ };
+
+CfgParseLexer::Tok CfgParseLexer::get_next()
+{
+ while(*m_pos == ' ')
+ m_pos ++;
+ if(*m_pos == 0)
+ return Tok();
+ switch(*m_pos)
+ {
+ case '(': case ')':
+ case ',': case '=':
+ return Tok(m_pos++);
+ case '"': {
+ ::std::string str;
+ auto s = m_pos;
+ m_pos ++;
+ while( *m_pos != '"' )
+ {
+ if( *m_pos == '\\' )
+ {
+ TODO("Escape sequences in cfg parser");
+ }
+ str += *m_pos;
+ m_pos ++;
+ }
+ m_pos ++;
+ return Tok(s, m_pos, str); }
+ default:
+ if( isalnum(*m_pos) || *m_pos == '_' )
+ {
+ auto s = m_pos;
+ while(isalnum(*m_pos) || *m_pos == '_')
+ m_pos ++;
+ return Tok(s, m_pos);
+ }
+ else
+ {
+ throw ::std::runtime_error(format("Unexpected character in cfg() - ", *m_pos));
+ }
+ }
+}
+
+bool Cfg_Check(const char* cfg_string)
+{
+ CfgParseLexer p { cfg_string + 4 };
+
+ if( gCfgChecker.target_os == nullptr )
+ {
+ // TODO: If the checker isn't initialised, invoke the compiler and ask it to dump the current target
+ // - It's pre-initialised above currently
+ }
+
+ bool success = gCfgChecker.check_cfg(p);
+ if( !p.consume_if(")") )
+ throw ::std::runtime_error(format("Expected ')' after cfg condition - got", p.cur().to_string()));
+ return success;
+}
+
+bool CfgChecker::check_cfg(CfgParseLexer& p) const
+{
+ auto name = p.consume();
+ if( name.ty() != CfgParseLexer::Tok::Ident )
+ throw ::std::runtime_error("Expected an identifier");
+ // Combinators
+ if( p.consume_if('(') ) {
+ bool rv;
+ if( false ) {
+ }
+ else if( name == "not" ) {
+ rv = !check_cfg(p);
+ }
+ else if( name == "all" ) {
+ rv = true;
+ do
+ {
+ rv &= check_cfg(p);
+ } while(p.consume_if(','));
+ }
+ else if( name == "any" ) {
+ rv = false;
+ do
+ {
+ rv |= check_cfg(p);
+ } while(p.consume_if(','));
+ }
+ else {
+ TODO("Unknown fragment in cfg - " << name.to_string());
+ }
+ if( !p.consume_if(')') )
+ throw ::std::runtime_error("Expected ')' after combinator content");
+ return rv;
+ }
+ // Values
+ else if( p.consume_if('=') ) {
+ auto t = p.consume();
+ if( t.ty() != CfgParseLexer::Tok::String )
+ throw ::std::runtime_error("Expected a string after `=`");
+ const auto& val = t.str();
+
+ if( false ) {
+ }
+ else if( name == "target_env" )
+ return val == this->target_env;
+ else if( name == "target_os" )
+ return val == this->target_os;
+ else if( name == "target_arch" )
+ return val == this->target_arch;
+ else {
+ TODO("Unknown fragment in cfg - " << name.to_string());
+ }
+ }
+ // Flags
+ else {
+ if( false ) {
+ }
+ else if( name == "unix" ) {
+ return CFG_UNIX;
+ }
+ else if( name == "windows" ) {
+ return CFG_WINDOWS;
+ }
+ else if( name == "stage0" ) {
+ return false;
+ }
+ else {
+ TODO("Unknown fragment in cfg - " << name.to_string());
+ }
+ }
+ throw ::std::runtime_error("Hit end of check_cfg");
+}
diff --git a/tools/minicargo/cfg.hpp b/tools/minicargo/cfg.hpp
new file mode 100644
index 00000000..907c8079
--- /dev/null
+++ b/tools/minicargo/cfg.hpp
@@ -0,0 +1,9 @@
+/*
+ * mrustc "minicargo" (minimal cargo clone)
+ * - By John Hodge (Mutabah)
+ *
+ * cfg.cpp
+ * - Handling of target configuration (in manifest nodes)
+ */
+#pragma once
+extern bool Cfg_Check(const char* cfg_string);
diff --git a/tools/minicargo/main.cpp b/tools/minicargo/main.cpp
index ec6b8b45..4e929653 100644
--- a/tools/minicargo/main.cpp
+++ b/tools/minicargo/main.cpp
@@ -44,6 +44,11 @@ struct ProgramOptions
// Pause for user input before quitting (useful for MSVC debugging)
bool pause_before_quit = false;
+ /// Build and run tests?
+ bool test = false;
+
+ ::std::vector<::std::string> features;
+
int parse(int argc, const char* argv[]);
void usage() const;
void help() const;
@@ -97,10 +102,11 @@ int main(int argc, const char* argv[])
Debug_SetPhase("Load Root");
auto dir = ::helpers::path(opts.directory ? opts.directory : ".");
auto m = PackageManifest::load_from_toml( dir / "Cargo.toml" );
+ m.set_features(opts.features, opts.features.empty());
// 2. Load all dependencies
Debug_SetPhase("Load Dependencies");
- m.load_dependencies(repo, !bs_override_dir.is_valid());
+ m.load_dependencies(repo, !bs_override_dir.is_valid(), /*include_dev=*/opts.test);
// 3. Build dependency tree and build program.
BuildOptions build_opts;
@@ -111,6 +117,11 @@ int main(int argc, const char* argv[])
build_opts.target_name = opts.target;
for(const auto* d : opts.lib_search_dirs)
build_opts.lib_search_dirs.push_back( ::helpers::path(d) );
+ // Indicate desire to build tests (or examples) instead of the primary target
+ build_opts.mode =
+ opts.test ? BuildOptions::Mode::Test :
+ BuildOptions::Mode::Normal
+ ;
Debug_SetPhase("Enumerate Build");
auto build_list = BuildList(m, build_opts);
Debug_SetPhase("Run Build");
@@ -251,9 +262,25 @@ int ProgramOptions::parse(int argc, const char* argv[])
}
this->target = argv[++i];
}
+ else if( ::std::strcmp(arg, "--features") == 0 ) {
+ if(i+1 == argc) {
+ ::std::cerr << "Flag " << arg << " takes an argument" << ::std::endl;
+ return 1;
+ }
+ const auto* a = argv[++i];
+ while(const char* e = strchr(a, ','))
+ {
+ this->features.push_back( ::std::string(a, e) );
+ a = e + 1;
+ }
+ this->features.push_back( ::std::string(a) );
+ }
else if( ::std::strcmp(arg, "--pause") == 0 ) {
this->pause_before_quit = true;
}
+ else if( ::std::strcmp(arg, "--test") == 0 ) {
+ this->test = true;
+ }
else {
::std::cerr << "Unknown flag " << arg << ::std::endl;
return 1;
diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp
index e47da1bc..ac9c9cb2 100644
--- a/tools/minicargo/manifest.cpp
+++ b/tools/minicargo/manifest.cpp
@@ -13,20 +13,15 @@
#include <algorithm>
#include <cctype> // toupper
#include "repository.h"
+#include "cfg.hpp"
// TODO: Extract this from the target at runtime (by invoking the compiler on the passed target)
#ifdef _WIN32
# define TARGET_NAME "i586-windows-msvc"
-# define CFG_UNIX false
-# define CFG_WINDOWS true
#elif defined(__NetBSD__)
# define TARGET_NAME "x86_64-unknown-netbsd"
-# define CFG_UNIX true
-# define CFG_WINDOWS false
#else
# define TARGET_NAME "x86_64-unknown-linux-gnu"
-# define CFG_UNIX true
-# define CFG_WINDOWS false
#endif
static ::std::vector<::std::shared_ptr<PackageManifest>> g_loaded_manifests;
@@ -135,6 +130,16 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path)
}
rv.m_links = key_val.value.as_string();
}
+ else if( key == "autotests" )
+ {
+ // TODO: Fix the outer makefile so it doesn't need `foo-test`
+ // to be created.
+ //rv.m_create_auto_test = key_val.value.as_bool();
+ }
+ else if( key == "autobenches" )
+ {
+ //rv.m_create_auto_bench = key_val.value.as_bool();
+ }
else
{
// Unknown value in `package`
@@ -184,42 +189,28 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path)
target_edit_from_kv(*it, key_val, 2);
}
- else if( section == "dependencies" )
+ else if( section == "dependencies" || section == "build-dependencies" || section == "dev-dependencies" )
{
+ ::std::vector<PackageRef>& dep_list =
+ section == "dependencies" ? rv.m_dependencies :
+ section == "build-dependencies" ? rv.m_build_dependencies :
+ /*section == "dev-dependencies" ? */ rv.m_dev_dependencies /*:
+ throw ""*/
+ ;
assert(key_val.path.size() > 1);
const auto& depname = key_val.path[1];
// Find/create dependency descriptor
- auto it = ::std::find_if(rv.m_dependencies.begin(), rv.m_dependencies.end(), [&](const auto& x) { return x.m_name == depname; });
- bool was_added = (it == rv.m_dependencies.end());
+ auto it = ::std::find_if(dep_list.begin(), dep_list.end(), [&](const auto& x) { return x.m_name == depname; });
+ bool was_added = (it == dep_list.end());
if( was_added )
{
- it = rv.m_dependencies.insert(it, PackageRef{ depname });
+ it = dep_list.insert(it, PackageRef{ depname });
}
it->fill_from_kv(was_added, key_val, 2);
}
- else if( section == "build-dependencies" )
- {
- assert(key_val.path.size() > 1);
-
- const auto& depname = key_val.path[1];
-
- // Find/create dependency descriptor
- auto it = ::std::find_if(rv.m_build_dependencies.begin(), rv.m_build_dependencies.end(), [&](const auto& x) { return x.m_name == depname; });
- bool was_added = (it == rv.m_build_dependencies.end());
- if(was_added)
- {
- it = rv.m_build_dependencies.insert(it, PackageRef{ depname });
- }
-
- it->fill_from_kv(was_added, key_val, 2);
- }
- else if( section == "dev-dependencies" )
- {
- // TODO: Developemnt (test/bench) deps
- }
else if( section == "patch" )
{
//const auto& repo = key_val.path[1];
@@ -241,169 +232,7 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path)
// - It can be a target spec, or a cfg(foo) same as rustc
bool success;
if( cfg.substr(0, 4) == "cfg(" ) {
- class Parser
- {
- public:
- class Tok
- {
- friend class Parser;
- const char* s;
- const char* e;
- Tok(const char* s, const char* e):
- s(s), e(e)
- {
- }
- public:
- bool operator==(const char* v) const {
- return (strlen(v) == e - s) && memcmp(s, v, e-s) == 0;
- }
- bool operator!=(const char* v) const {
- return (strlen(v) != e - s) || memcmp(s, v, e-s) != 0;
- }
- ::std::string to_string() const {
- return ::std::string(s, e);
- }
- };
- private:
- const char* m_pos;
- Tok m_cur;
-
- public:
- Parser(const char* s):
- m_pos(s),
- m_cur(nullptr,nullptr)
- {
- consume();
- }
- const Tok& cur() const {
- return m_cur;
- }
-
- Tok consume() {
- auto rv = m_cur;
- m_cur = get_next();
- //::std::cout << "consume: " << rv.to_string() << " => " << m_cur.to_string() << ::std::endl;
- return rv;
- }
- bool consume_if(const char* s) {
- if( cur() == s ) {
- consume();
- return true;
- }
- else {
- return false;
- }
- }
- private:
- Tok get_next() {
- while(*m_pos == ' ')
- m_pos ++;
- if(*m_pos == 0)
- return Tok { m_pos, m_pos };
- switch(*m_pos)
- {
- case '(': case ')':
- case ',': case '=':
- return Tok { m_pos++, m_pos };
- case '"': {
- auto s = m_pos;
- m_pos ++;
- while( *m_pos != '"' )
- {
- if( *m_pos == '\\' )
- {
- TODO("Escape sequences in cfg parser");
- }
- m_pos ++;
- }
- m_pos ++;
- return Tok { s, m_pos }; }
- default:
- if( isalnum(*m_pos) || *m_pos == '_' )
- {
- auto s = m_pos;
- while(isalnum(*m_pos) || *m_pos == '_')
- m_pos ++;
- return Tok { s, m_pos };
- }
- else
- {
- throw ::std::runtime_error(format("Unexpected character in cfg() - ", *m_pos));
- }
- }
- }
- };
-
- struct H {
- static bool check_cfg(Parser& p)
- {
- if( p.consume_if("not") ) {
- if( !p.consume_if("(") )
- throw ::std::runtime_error("Expected '(' after `not`");
- auto rv = !check_cfg(p);
- if( !p.consume_if(")") )
- throw ::std::runtime_error("Expected ')' after `not` content");
- return rv;
- }
- else if( p.consume_if("all") ) {
- if( !p.consume_if("(") )
- throw ::std::runtime_error("Expected '(' after `all`");
- bool rv = true;
- do
- {
- rv &= check_cfg(p);
- } while(p.consume_if(","));
- if( !p.consume_if(")") )
- throw ::std::runtime_error("Expected ')' after `all` content");
- return rv;
- }
- // Strings
- else if( p.consume_if("target_os") ) {
- if( !p.consume_if("=") )
- throw ::std::runtime_error("Expected '=' after target_os");
- auto t = p.consume();
- if( t == "\"emscripten\"" ) {
- return false;
- }
- else if( t == "\"macos\"" ) {
- return false;
- }
- else {
- TODO("Handle target_os string - " << t.to_string());
- }
- }
- else if( p.consume_if("target_arch") ) {
- if( !p.consume_if("=") )
- throw ::std::runtime_error("Expected '=' after target");
- auto t = p.consume();
- if( t == "\"wasm32\"" ) {
- return false;
- }
- else{
- TODO("Handle target_arch string - " << t.to_string());
- }
- }
- // Flags
- else if( p.consume_if("unix") ) {
- return CFG_UNIX;
- }
- else if( p.consume_if("windows") ) {
- return CFG_WINDOWS;
- }
- else if( p.consume_if("stage0") ) {
- return false;
- }
- else {
- TODO("Unknown fragment in cfg - " << p.cur().to_string());
- throw ::std::runtime_error("");
- }
- }
- };
-
- Parser p { cfg.data() + 4 };
- success = H::check_cfg(p);
- if( !p.consume_if(")") )
- throw ::std::runtime_error(format("Expected ')' after cfg condition - got", p.cur().to_string()));
+ success = Cfg_Check(cfg.c_str());
}
else {
// It's a target name
@@ -412,25 +241,34 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path)
// If so, parse as if the path was `real_section....`
if( success )
{
- if( real_section == "dependencies" )
+ if( real_section == "dependencies"
+ || real_section == "dev-dependencies"
+ || real_section == "build-dependencies"
+ )
{
+ ::std::vector<PackageRef>& dep_list =
+ real_section == "dependencies" ? rv.m_dependencies :
+ real_section == "build-dependencies" ? rv.m_build_dependencies :
+ /*real_section == "dev-dependencies" ? */ rv.m_dev_dependencies /*:
+ throw ""*/
+ ;
assert(key_val.path.size() > 3);
const auto& depname = key_val.path[3];
// Find/create dependency descriptor
- auto it = ::std::find_if(rv.m_dependencies.begin(), rv.m_dependencies.end(), [&](const auto& x) { return x.m_name == depname; });
- bool was_added = (it == rv.m_dependencies.end());
+ auto it = ::std::find_if(dep_list.begin(), dep_list.end(), [&](const auto& x) { return x.m_name == depname; });
+ bool was_added = (it == dep_list.end());
if( was_added )
{
- it = rv.m_dependencies.insert(it, PackageRef{ depname });
+ it = dep_list.insert(it, PackageRef{ depname });
}
it->fill_from_kv(was_added, key_val, 4);
}
else
{
- TODO("Unknown manifest section for target - " << real_section);
+ TODO(toml_file.lexer() << ": Unknown manifest section '" << real_section << "' in `target`");
}
}
}
@@ -514,10 +352,21 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path)
tgt.m_path = "src/main.rs";
}
else {
- // TODO: What about src/bin/foo/main.rs?
+ // TODO: Error if both exist
+ // TODO: More complex search rules
tgt.m_path = ::helpers::path("src") / "bin" / tgt.m_name.c_str() + ".rs";
+ if( !::std::ifstream(package_dir / tgt.m_path).good() )
+ tgt.m_path = ::helpers::path("src") / "bin" / tgt.m_name.c_str() / "main.rs";
+ //if( !::std::ifstream(package_dir / tgt.m_path).good() )
+ // throw ::std::runtime_error(format("Unable to find source file for ", tgt.m_name, " - ", package_dir / tgt.m_path));
}
break;
+ case PackageTarget::Type::Test:
+ case PackageTarget::Type::Bench:
+ // no defaults
+ break;
+ case PackageTarget::Type::Example:
+ TODO("Default/implicit path for examples");
}
}
if(tgt.m_name == "")
@@ -528,6 +377,19 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path)
}
}
+ // If there's a lib target, add a test target using the same path
+ {
+ auto it = ::std::find_if(rv.m_targets.begin(), rv.m_targets.end(), [&](const auto& t) { return t.m_type == PackageTarget::Type::Lib; });
+ if( it != rv.m_targets.end() )
+ {
+ auto path = it->m_path;
+ auto name = it->m_name + "-test";
+ rv.m_targets.push_back(PackageTarget { PackageTarget::Type::Test });
+ rv.m_targets.back().m_name = name;
+ rv.m_targets.back().m_path = path;
+ }
+ }
+
for(const auto& dep : rv.m_dependencies)
{
if( dep.m_optional )
@@ -542,7 +404,7 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path)
// Explicitly disabled `[package] build = false`
rv.m_build_script = "";
}
- else if( rv.m_build_script != "" )
+ else if( rv.m_build_script == "" )
{
// Not set, check for a "build.rs" file
if( ::std::ifstream( package_dir / "build.rs").good() )
@@ -611,7 +473,26 @@ namespace
}
else if( key == "crate-type" )
{
- // TODO: Support crate types
+ //assert_kv_size(kv, base_idx + 1);
+ //assert_type(kv, base_idx + 1);
+ assert(kv.path.size() == base_idx + 1);
+ if( !target.m_crate_types.empty() ) {
+ // TODO: Error, multiple instances
+ }
+ for(const auto& sv : kv.value.m_sub_values)
+ {
+ const auto& s = sv.as_string();
+ if(s == "rlib") {
+ target.m_crate_types.push_back(PackageTarget::CrateType::rlib);
+ }
+ else if(s == "dylib") {
+ target.m_crate_types.push_back(PackageTarget::CrateType::dylib);
+ }
+ // TODO: Other crate types
+ else {
+ throw ::std::runtime_error(format("Unknown crate type - ", s));
+ }
+ }
}
else if( key == "required-features" )
{
@@ -798,12 +679,19 @@ void PackageManifest::set_features(const ::std::vector<::std::string>& features,
it2->m_optional_enabled = true;
}
}
+ {
+ auto it2 = ::std::find_if(m_dev_dependencies.begin(), m_dev_dependencies.end(), [&](const auto& x){ return x.m_name == featname; });
+ if(it2 != m_dev_dependencies.end())
+ {
+ it2->m_optional_enabled = true;
+ }
+ }
}
// Return true if any features were activated
//return start < m_active_features.size();
}
-void PackageManifest::load_dependencies(Repository& repo, bool include_build)
+void PackageManifest::load_dependencies(Repository& repo, bool include_build, bool include_dev)
{
TRACE_FUNCTION_F(m_name);
DEBUG("Loading depencencies for " << m_name);
@@ -819,16 +707,30 @@ void PackageManifest::load_dependencies(Repository& repo, bool include_build)
dep.load_manifest(repo, base_path, include_build);
}
- // TODO: Only enable if build script overrides aren't enabled.
+ // Load build deps if there's a build script AND build scripts are enabled
if( m_build_script != "" && include_build )
{
+ DEBUG("- Build dependencies");
for(auto& dep : m_build_dependencies)
{
if( dep.m_optional && !dep.m_optional_enabled )
{
continue ;
}
- dep.load_manifest(repo, base_path, true);
+ dep.load_manifest(repo, base_path, include_build);
+ }
+ }
+ // Load dev dependencies if the caller has indicated they should be
+ if( include_dev )
+ {
+ DEBUG("- Dev dependencies");
+ for(auto& dep : m_dev_dependencies)
+ {
+ if( dep.m_optional && !dep.m_optional_enabled )
+ {
+ continue ;
+ }
+ dep.load_manifest(repo, base_path, include_build);
}
}
}
@@ -1042,6 +944,10 @@ PackageVersionSpec PackageVersionSpec::from_string(const ::std::string& s)
// Default, compatible
pos ++;
break;
+ case '~':
+ ty = PackageVersionSpec::Bound::Type::MinorCompatible;
+ pos ++;
+ break;
case '=':
ty = PackageVersionSpec::Bound::Type::Equal;
pos ++;
@@ -1090,6 +996,17 @@ PackageVersionSpec PackageVersionSpec::from_string(const ::std::string& s)
{
pos ++;
v.patch = H::parse_i(s, pos);
+
+ if( pos < s.size() && s[pos] == '-' )
+ {
+ // Save tag (sequence of dot-seprated alpha-numeric identifiers)
+ auto tag_start = pos+1;
+ do {
+ // Could check the format, but meh.
+ pos ++;
+ } while(pos < s.size() && !isblank(s[pos]) && s[pos] != ',' );
+ //v.tag = ::std::string(s.c_str() + tag_start, s.c_str() + pos);
+ }
}
else
{
@@ -1098,6 +1015,9 @@ PackageVersionSpec PackageVersionSpec::from_string(const ::std::string& s)
}
else
{
+ // NOTE: This changes the behaviour of ~ rules to be bounded on the major version instead
+ if( ty == PackageVersionSpec::Bound::Type::MinorCompatible )
+ ty = PackageVersionSpec::Bound::Type::Compatible;
v.minor = 0;
v.patch = 0;
}
@@ -1110,7 +1030,7 @@ PackageVersionSpec PackageVersionSpec::from_string(const ::std::string& s)
break ;
} while(pos < s.size() && s[pos++] == ',');
if( pos != s.size() )
- throw ::std::runtime_error(::format( "Bad version string, pos=", pos ));
+ throw ::std::runtime_error(::format( "Bad version string '", s, "', pos=", pos ));
return rv;
}
bool PackageVersionSpec::accepts(const PackageVersion& v) const
@@ -1120,13 +1040,19 @@ bool PackageVersionSpec::accepts(const PackageVersion& v) const
switch(b.ty)
{
case Bound::Type::Compatible:
- // To be compatible, it has to be higher?
- // - TODO: Isn't a patch version compatible?
+ // ^ rules are >= specified, and < next major/breaking
if( !(v >= b.ver) )
return false;
if( !(v < b.ver.next_breaking()) )
return false;
break;
+ case Bound::Type::MinorCompatible:
+ // ~ rules are >= specified, and < next minor
+ if( !(v >= b.ver) )
+ return false;
+ if( !(v < b.ver.next_minor()) )
+ return false;
+ break;
case Bound::Type::GreaterEqual:
if( !(v >= b.ver) )
return false;
diff --git a/tools/minicargo/manifest.h b/tools/minicargo/manifest.h
index 4bb8b843..d0c537e5 100644
--- a/tools/minicargo/manifest.h
+++ b/tools/minicargo/manifest.h
@@ -26,6 +26,14 @@ struct PackageVersion
static PackageVersion from_string(const ::std::string& s);
+ PackageVersion next_minor() const {
+ if(major == 0) {
+ return PackageVersion { 0, minor, patch+1 };
+ }
+ else {
+ return PackageVersion { major, minor+1, 0 };
+ }
+ }
PackageVersion next_breaking() const {
if(major == 0) {
return PackageVersion { 0, minor + 1, 0 };
@@ -87,7 +95,8 @@ struct PackageVersionSpec
{
enum class Type
{
- Compatible,
+ Compatible, // "^" - Allows anything up to the next major version
+ MinorCompatible, // "~X.Y" - Allows anything up to the next minor version
Greater,
GreaterEqual,
Equal,
@@ -116,6 +125,7 @@ struct PackageVersionSpec
switch(b.ty)
{
case Bound::Type::Compatible: os << "^"; break;
+ case Bound::Type::MinorCompatible: os << "~"; break;
case Bound::Type::Greater: os << ">"; break;
case Bound::Type::GreaterEqual: os << ">="; break;
case Bound::Type::Equal: os << "="; break;
@@ -180,6 +190,14 @@ struct PackageTarget
Bench,
Example,
};
+ enum class CrateType
+ {
+ dylib,
+ rlib,
+ staticlib,
+ cdylib,
+ proc_macro,
+ };
Type m_type;
::std::string m_name;
@@ -192,6 +210,7 @@ struct PackageTarget
bool m_is_proc_macro = false;
bool m_is_own_harness = false;
+ ::std::vector<CrateType> m_crate_types;
::std::vector<::std::string> m_required_features;
PackageTarget(Type ty):
@@ -245,6 +264,7 @@ class PackageManifest
::std::vector<PackageRef> m_dependencies;
::std::vector<PackageRef> m_build_dependencies;
+ ::std::vector<PackageRef> m_dev_dependencies;
::std::vector<PackageTarget> m_targets;
@@ -263,15 +283,18 @@ public:
bool has_library() const;
const PackageTarget& get_library() const;
- bool foreach_binaries(::std::function<bool(const PackageTarget&)> cb) const {
+ bool foreach_ty(PackageTarget::Type ty, ::std::function<bool(const PackageTarget&)> cb) const {
for(const auto& t : m_targets ) {
- if( t.m_type == PackageTarget::Type::Bin ) {
+ if( t.m_type == ty ) {
if( !cb(t) )
return false;
}
}
return true;
}
+ bool foreach_binaries(::std::function<bool(const PackageTarget&)> cb) const {
+ return foreach_ty(PackageTarget::Type::Bin, cb);
+ }
const ::helpers::path directory() const {
return ::helpers::path(m_manifest_path).parent();
@@ -294,12 +317,15 @@ public:
const ::std::vector<PackageRef>& build_dependencies() const {
return m_build_dependencies;
}
+ const ::std::vector<PackageRef>& dev_dependencies() const {
+ return m_dev_dependencies;
+ }
const ::std::vector<::std::string>& active_features() const {
return m_active_features;
}
void set_features(const ::std::vector<::std::string>& features, bool enable_default);
- void load_dependencies(Repository& repo, bool include_build);
+ void load_dependencies(Repository& repo, bool include_build, bool include_dev=false);
void load_build_script(const ::std::string& path);
};
diff --git a/tools/minicargo/repository.cpp b/tools/minicargo/repository.cpp
index f5ff5ea8..060c5207 100644
--- a/tools/minicargo/repository.cpp
+++ b/tools/minicargo/repository.cpp
@@ -75,7 +75,7 @@ void Repository::load_vendored(const ::helpers::path& path)
}
}
- //DEBUG("Package '" << name << "' v" << ver);
+ DEBUG("Vendored package '" << name << "' v" << ver);
if(name == "")
continue ;
@@ -91,6 +91,7 @@ void Repository::load_vendored(const ::helpers::path& path)
} while( FindNextFile(find_handle, &find_data) );
FindClose(find_handle);
#endif
+ DEBUG("Loaded " << m_cache.size() << " vendored packages");
}
::std::shared_ptr<PackageManifest> Repository::from_path(::helpers::path in_path)
diff --git a/tools/minicargo/stringlist.h b/tools/minicargo/stringlist.h
index 4381121b..08b74c4b 100644
--- a/tools/minicargo/stringlist.h
+++ b/tools/minicargo/stringlist.h
@@ -78,7 +78,7 @@ public:
};
class StringListKV: private StringList
{
- ::std::vector<const char*> m_keys;
+ StringList m_keys;
public:
StringListKV()
{
@@ -99,6 +99,16 @@ public:
m_keys.push_back(k);
StringList::push_back(v);
}
+ void push_back(::std::string k, ::std::string v)
+ {
+ m_keys.push_back(k);
+ StringList::push_back(v);
+ }
+ void push_back(::std::string k, const char* v)
+ {
+ m_keys.push_back(k);
+ StringList::push_back(v);
+ }
struct Iter {
const StringListKV& v;
@@ -108,7 +118,7 @@ public:
this->i++;
}
::std::pair<const char*,const char*> operator*() {
- return ::std::make_pair(this->v.m_keys[this->i], this->v.get_vec()[this->i]);
+ return ::std::make_pair(this->v.m_keys.get_vec()[this->i], this->v.get_vec()[this->i]);
}
bool operator!=(const Iter& x) const {
return this->i != x.i;
@@ -118,7 +128,7 @@ public:
return Iter { *this, 0 };
}
Iter end() const {
- return Iter { *this, m_keys.size() };
+ return Iter { *this, m_keys.get_vec().size() };
}
friend ::std::ostream& operator<<(::std::ostream& os, const StringListKV& x) {
diff --git a/tools/standalone_miri/Makefile b/tools/standalone_miri/Makefile
index f4dc0d0d..0a8bd672 100644
--- a/tools/standalone_miri/Makefile
+++ b/tools/standalone_miri/Makefile
@@ -11,7 +11,7 @@ V ?= @
OBJDIR := .obj/
BIN := ../bin/standalone_miri$(EXESUF)
-OBJS := main.o debug.o mir.o lex.o value.o module_tree.o hir_sim.o miri.o
+OBJS := main.o debug.o mir.o lex.o value.o module_tree.o hir_sim.o miri.o rc_string.o
LINKFLAGS := -g -lpthread
CXXFLAGS := -Wall -std=c++14 -g -O2
@@ -37,6 +37,11 @@ $(OBJDIR)%.o: %.cpp
@echo [CXX] $<
$V$(CXX) -o $@ -c $< $(CXXFLAGS) -MMD -MP -MF $@.dep
+$(OBJDIR)%.o: ../../src/%.cpp
+ @mkdir -p $(dir $@)
+ @echo [CXX] $<
+ $V$(CXX) -o $@ -c $< $(CXXFLAGS) -MMD -MP -MF $@.dep
+
../bin/common_lib.a:
make -C ../common
diff --git a/tools/standalone_miri/debug.cpp b/tools/standalone_miri/debug.cpp
index c49df960..534790cd 100644
--- a/tools/standalone_miri/debug.cpp
+++ b/tools/standalone_miri/debug.cpp
@@ -11,14 +11,20 @@
unsigned DebugSink::s_indent = 0;
::std::unique_ptr<std::ofstream> DebugSink::s_out_file;
-DebugSink::DebugSink(::std::ostream& inner):
- m_inner(inner)
+DebugSink::DebugSink(::std::ostream& inner, bool stderr_too):
+ m_inner(inner),
+ m_stderr_too(stderr_too)
{
}
DebugSink::~DebugSink()
{
m_inner << "\n";
m_inner.flush();
+ m_inner.flags({});
+ if( m_stderr_too )
+ {
+ ::std::cerr << ::std::endl;
+ }
}
void DebugSink::set_output_file(const ::std::string& s)
{
@@ -30,6 +36,7 @@ bool DebugSink::enabled(const char* fcn_name)
}
DebugSink DebugSink::get(const char* fcn_name, const char* file, unsigned line, DebugLevel lvl)
{
+ bool stderr_too = false;
auto& sink = s_out_file ? *s_out_file : ::std::cout;
for(size_t i = s_indent; i--;)
sink << " ";
@@ -49,15 +56,18 @@ DebugSink DebugSink::get(const char* fcn_name, const char* file, unsigned line,
break;
case DebugLevel::Error:
sink << "ERROR: ";
+ stderr_too = true;
break;
case DebugLevel::Fatal:
sink << "FATAL: ";
+ stderr_too = true;
break;
case DebugLevel::Bug:
sink << "BUG: " << file << ":" << line << ": ";
+ stderr_too = true;
break;
}
- return DebugSink(sink);
+ return DebugSink(sink, stderr_too);
}
void DebugSink::inc_indent()
{
diff --git a/tools/standalone_miri/debug.hpp b/tools/standalone_miri/debug.hpp
index b3b0d76f..9de6231b 100644
--- a/tools/standalone_miri/debug.hpp
+++ b/tools/standalone_miri/debug.hpp
@@ -21,17 +21,26 @@ enum class DebugLevel {
Bug,
};
-class DebugSink
+class DebugSink//:
+ //public ::std::ostream
{
static unsigned s_indent;
static ::std::unique_ptr<std::ofstream> s_out_file;
::std::ostream& m_inner;
- DebugSink(::std::ostream& inner);
+ bool m_stderr_too;
+ DebugSink(::std::ostream& inner, bool stderr_too);
public:
~DebugSink();
template<typename T>
- ::std::ostream& operator<<(const T& v) { return m_inner << v; }
+ DebugSink& operator<<(const T& v) {
+ if( m_stderr_too )
+ {
+ ::std::cerr << v;
+ }
+ m_inner << v;
+ return *this;
+ }
static void set_output_file(const ::std::string& s);
static bool enabled(const char* fcn_name);
@@ -102,4 +111,6 @@ struct DebugExceptionError:
#define LOG_FATAL(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Fatal) << strm; exit(1); } while(0)
#define LOG_TODO(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Bug) << "TODO: " << strm; throw DebugExceptionTodo{}; } while(0)
#define LOG_BUG(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Bug) << "BUG: " << strm; abort(); } while(0)
-#define LOG_ASSERT(cnd,strm) do { if( !(cnd) ) { LOG_BUG("Assertion failure: " #cnd " - " << strm); } } while(0)
+#define LOG_ASSERT(cnd,strm) do { if( !(cnd) ) { LOG_ERROR("Assertion failure: " #cnd " - " << strm); } } while(0)
+
+#define FMT_STRING(...) (dynamic_cast<::std::stringstream&>(::std::stringstream() << __VA_ARGS__).str())
diff --git a/tools/standalone_miri/ffi.cpp b/tools/standalone_miri/ffi.cpp
new file mode 100644
index 00000000..827d862f
--- /dev/null
+++ b/tools/standalone_miri/ffi.cpp
@@ -0,0 +1,141 @@
+/*
+ * mrustc Standalone MIRI
+ * - by John Hodge (Mutabah)
+ *
+ * ffi.cpp
+ * - FFI wrappers
+ */
+
+/// Argument reference (for checking validity)
+struct ArgRef
+{
+ uint8_t idx; // if 255, it's not referencing anything
+
+ static ArgRef null() { return ArgRef { 255 }; }
+};
+
+/// Representation of a FFI type (defined by the .api file)
+/// - These specify various flags used to tag pointers in the MIR
+struct FfiType
+{
+ // Pointer:
+ // - Mutability
+ // - Nullability
+ // - Array size (number of allocated elements)
+ // > Can be either a number, or an argument name
+ // - Valid size (number of initialised elements)
+ // - Allocation source
+ struct Pointer {
+ bool is_mut;
+ bool is_nullable;
+ ArgOrCount alloc_size;
+ ArgOrCount valid_size;
+ ArgRef alloc_source; // Can be "null"
+ };
+ ::std::vector<Pointer> pointers; // Reverse list (last entry is the outermost pointer)
+
+ // Datatypes:
+ // - `void`
+ // - size/alignment
+ // - u8,u16,...
+ // - function
+ // - Name
+ enum class Datatype {
+ Void,
+ Signed,
+ Unsigned,
+ Float,
+ Function,
+ } datatype;
+ union Meta {
+ struct {
+ size_t size;
+ size_t align;
+ ::std::string tag;
+ } void_data;
+ unsigned bits;
+ struct {
+ ArgRef name_source;
+ } function;
+ } meta;
+};
+
+
+struct FfiShim
+{
+ class ValueRef
+ {
+ public:
+ static ValueRef new_global(std::string name);
+ static ValueRef new_local(std::string name);
+ static ValueRef new_deref(ValueRef target);
+ };
+ class Expr
+ {
+ enum {
+ LITERAL,
+ VALUE,
+ CALL,
+ } ty;
+ union {
+ } data;
+ public:
+ static Expr new_lit(uint64_t v);
+ static Expr new_value(ValueRef vr);
+ static Expr new_call_int(::std::vector<::std::string> path, ::std::vector<Expr> args);
+ };
+ struct Stmt;
+ struct Block
+ {
+ ::std::vector<Stmt> statements;
+ Expr val;
+ };
+ class Stmt
+ {
+ enum {
+ DEFINE, // `let foo = bar;`
+ ASSIGN, // `foo ?= bar;`
+ IF,
+ } ty;
+ union {
+ struct {
+ ::std::string slot;
+ Expr value;
+ } define;
+ struct {
+ ValueRef slot;
+ Expr value;
+ } assign;
+ struct {
+ Expr cond;
+ Block true_arm;
+ Block false_arm;
+ } if_block;
+ };
+ };
+};
+
+struct FfiFunction
+{
+ ::std::vector<FfiType> arg_types;
+ FfiType ret_type;
+ ::std::vector<std::string> arg_names;
+
+ // Either directly defers to a function
+ ::std::string library;
+ ::std::string function;
+
+ // Or, it has code for more advanced checking
+ //FfiShimExpr code;
+
+ bool call(Value& rv, ::std::vector<Value> args) const;
+};
+
+bool FfiFunction::call(Value& rv, ::std::vector<Value> args) const
+{
+
+}
+
+bool call_ffi(Value& rv, const ::std::string& link_name, const ::std::string& abi, ::std::vector<Value> args)
+{
+}
diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp
index 88739730..9d497054 100644
--- a/tools/standalone_miri/hir_sim.cpp
+++ b/tools/standalone_miri/hir_sim.cpp
@@ -42,18 +42,18 @@ size_t HIR::TypeRef::get_size(size_t ofs) const
// Need to look up the metadata type for the actual type
if( this->inner_type == RawType::Composite )
{
- if( this->composite_type->dst_meta == RawType::Unreachable )
+ if( this->composite_type().dst_meta == RawType::Unreachable )
{
return POINTER_SIZE;
}
// Special case: extern types (which appear when a type is only ever used by pointer)
- if( this->composite_type->dst_meta == RawType::Unit )
+ if( this->composite_type().dst_meta == RawType::Unit )
{
return POINTER_SIZE;
}
// TODO: Ideally, this inner type wouldn't be unsized itself... but checking that would be interesting.
- return POINTER_SIZE + this->composite_type->dst_meta.get_size();
+ return POINTER_SIZE + this->composite_type().dst_meta.get_size();
}
else if( this->inner_type == RawType::Str )
return POINTER_SIZE*2;
@@ -77,7 +77,8 @@ size_t HIR::TypeRef::get_size(size_t ofs) const
return 0;
case RawType::Composite:
// NOTE: Don't care if the type has metadata
- return this->composite_type->size;
+ LOG_ASSERT(this->composite_type().populated, "Getting size of non-defined type - " << *this);
+ return this->composite_type().size;
case RawType::Unreachable:
LOG_BUG("Attempting to get size of an unreachable type, " << *this);
case RawType::TraitObject:
@@ -111,6 +112,56 @@ size_t HIR::TypeRef::get_size(size_t ofs) const
throw "";
}
}
+size_t HIR::TypeRef::get_align(size_t ofs) const
+{
+ if( const auto* w = this->get_wrapper(ofs) )
+ {
+ LOG_TODO("get_align " << *this);
+ }
+ else
+ {
+ switch(this->inner_type)
+ {
+ case RawType::Unit:
+ return 1;
+ case RawType::Composite:
+ // NOTE: Don't care if the type has metadata
+ LOG_ASSERT(this->composite_type().populated, "Getting alignment of non-defined type - " << *this);
+ return this->composite_type().alignment;
+ case RawType::TraitObject:
+ case RawType::Str:
+ return 1;
+ case RawType::U8: case RawType::I8:
+ return 1;
+ case RawType::U16: case RawType::I16:
+ return 2;
+ case RawType::U32: case RawType::I32:
+ return 4;
+ case RawType::U64: case RawType::I64:
+ return 8;
+ case RawType::U128: case RawType::I128:
+ return 16;
+
+ case RawType::Bool:
+ return 1;
+ case RawType::Char:
+ return 4;
+
+ case RawType::F32:
+ return 4;
+ case RawType::F64:
+ return 8;
+
+ case RawType::Function: // This should probably be invalid?
+ case RawType::USize:
+ case RawType::ISize:
+ return POINTER_SIZE;
+ case RawType::Unreachable:
+ LOG_BUG("Getting alignment of unreachable type");
+ }
+ throw "";
+ }
+}
bool HIR::TypeRef::has_slice_meta(size_t& out_inner_size) const
{
if( const auto* w = this->get_wrapper() )
@@ -168,7 +219,7 @@ bool HIR::TypeRef::has_pointer() const
if( this->inner_type == RawType::Composite )
{
// Still not sure, check the inner for any pointers.
- for(const auto& fld : this->composite_type->fields)
+ for(const auto& fld : this->composite_type().fields)
{
if( fld.second.has_pointer() )
return true;
@@ -196,13 +247,13 @@ const HIR::TypeRef* HIR::TypeRef::get_unsized_type(size_t& running_inner_size) c
switch(this->inner_type)
{
case RawType::Composite:
- if(!this->composite_type->variants.empty())
+ if(!this->composite_type().variants.empty())
return nullptr;
- if(this->composite_type->fields.empty())
+ if(this->composite_type().fields.empty())
return nullptr;
- running_inner_size = this->composite_type->fields.back().first;
+ running_inner_size = this->composite_type().fields.back().first;
size_t tmp;
- return this->composite_type->fields.back().second.get_unsized_type(tmp);
+ return this->composite_type().fields.back().second.get_unsized_type(tmp);
case RawType::TraitObject:
case RawType::Str:
return this;
@@ -229,11 +280,12 @@ HIR::TypeRef HIR::TypeRef::get_meta_type() const
switch(this->inner_type)
{
case RawType::Composite:
- if( this->composite_type->dst_meta == RawType::Unreachable )
+ if( this->composite_type().dst_meta == RawType::Unreachable )
return TypeRef(RawType::Unreachable);
- return this->composite_type->dst_meta;
+ return this->composite_type().dst_meta;
case RawType::TraitObject:
- return ::HIR::TypeRef(this->composite_type).wrap( TypeWrapper::Ty::Pointer, static_cast<size_t>(BorrowType::Shared) );
+ LOG_ASSERT(this->ptr.composite_type, "get_meta_type - " << *this);
+ return ::HIR::TypeRef(this->ptr.composite_type).wrap( TypeWrapper::Ty::Pointer, static_cast<size_t>(BorrowType::Shared) );
case RawType::Str:
return TypeRef(RawType::USize);
default:
@@ -249,7 +301,7 @@ HIR::TypeRef HIR::TypeRef::get_field(size_t idx, size_t& ofs) const
if( w->type == TypeWrapper::Ty::Slice )
{
// TODO
- throw "TODO";
+ LOG_TODO("Field on slice - " << *this << " #" << idx);
}
else if( w->type == TypeWrapper::Ty::Array )
{
@@ -260,21 +312,20 @@ HIR::TypeRef HIR::TypeRef::get_field(size_t idx, size_t& ofs) const
}
else
{
- throw "ERROR";
+ LOG_ERROR("Field on unknown wrapper type - " << *this << " #" << idx);
}
}
else
{
if( this->inner_type == RawType::Composite )
{
- LOG_ASSERT(idx < this->composite_type->fields.size(), "Field " << idx << " out of bounds in type " << *this);
- ofs = this->composite_type->fields.at(idx).first;
- return this->composite_type->fields.at(idx).second;
+ LOG_ASSERT(idx < this->composite_type().fields.size(), "Field " << idx << " out of bounds in type " << *this);
+ ofs = this->composite_type().fields.at(idx).first;
+ return this->composite_type().fields.at(idx).second;
}
else
{
- ::std::cerr << *this << " doesn't have fields" << ::std::endl;
- throw "ERROR";
+ LOG_ERROR(*this << " doesn't have fields");
}
}
}
@@ -282,14 +333,14 @@ size_t HIR::TypeRef::get_field_ofs(size_t base_idx, const ::std::vector<size_t>&
{
assert(this->wrappers.size() == 0);
assert(this->inner_type == RawType::Composite);
- size_t ofs = this->composite_type->fields.at(base_idx).first;
- const auto* ty_p = &this->composite_type->fields.at(base_idx).second;
+ size_t ofs = this->composite_type().fields.at(base_idx).first;
+ const auto* ty_p = &this->composite_type().fields.at(base_idx).second;
for(auto idx : other_idx)
{
assert(ty_p->wrappers.size() == 0);
assert(ty_p->inner_type == RawType::Composite);
- ofs += ty_p->composite_type->fields.at(idx).first;
- ty_p = &ty_p->composite_type->fields.at(idx).second;
+ ofs += ty_p->composite_type().fields.at(idx).first;
+ ty_p = &ty_p->composite_type().fields.at(idx).second;
}
ty = *ty_p;
return ofs;
@@ -346,19 +397,30 @@ namespace HIR {
os << "()";
break;
case RawType::Composite:
- os << x.composite_type->my_path;
+ os << x.composite_type().my_path;
//os << "composite_" << x.composite_type;
break;
case RawType::Unreachable:
os << "!";
break;
- case RawType::Function:
- os << "function_?";
- break;
+ case RawType::Function: {
+ assert( x.ptr.function_type );
+ const auto& ft = *x.ptr.function_type;
+ if( ft.unsafe )
+ os << "unsafe ";
+ if( ft.abi != "Rust" )
+ os << "extern \"" << ft.abi << "\" ";
+ os << "fn( ";
+ for(const auto& a : ft.args)
+ os << a << ", ";
+ os << ")";
+ if( ft.ret != RawType::Unit )
+ os << "-> " << ft.ret;
+ } break;
case RawType::TraitObject:
os << "dyn ";
- if( x.composite_type )
- os << x.composite_type->my_path;
+ if( x.ptr.composite_type )
+ os << x.composite_type().my_path;
else
os << "?";
break;
diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp
index 62248fe9..81d3635a 100644
--- a/tools/standalone_miri/hir_sim.hpp
+++ b/tools/standalone_miri/hir_sim.hpp
@@ -9,20 +9,26 @@
#include <string>
#include <vector>
#include <memory>
+#include "../../src/include/rc_string.hpp"
const size_t POINTER_SIZE = 8;
+#define __ORD(fld) do { auto o = ::ord(this->fld, x.fld); if( o != OrdEqual ) return o; } while(0)
+#define __ORD_C(ty, fld) do { auto o = ::ord((ty)this->fld, (ty)x.fld); if( o != OrdEqual ) return o; } while(0)
#define __NE(fld) if(this->fld != x.fld) return true
#define __LT(fld) if(this->fld != x.fld) return this->fld < x.fld
+#if 0
enum Ordering
{
OrdLess,
OrdEqual,
OrdGreater,
};
+#endif
struct DataType;
+struct FunctionType;
enum class RawType
{
@@ -56,22 +62,22 @@ struct TypeWrapper
} type;
size_t size;
+ Ordering ord(const TypeWrapper& x) const {
+ __ORD_C(int, type);
+ __ORD(size);
+ return OrdEqual;
+ }
bool operator==(const TypeWrapper& x) const {
- return !(*this != x);
+ return this->ord(x) == OrdEqual;
}
bool operator!=(const TypeWrapper& x) const {
- __NE(type);
- __NE(size);
- return false;
+ return this->ord(x) != OrdEqual;
}
bool operator<(const TypeWrapper& x) const {
- __LT(type);
- __LT(size);
- return false;
+ return this->ord(x) == OrdLess;
}
};
-
namespace HIR {
enum class BorrowType
@@ -91,24 +97,35 @@ namespace HIR {
// Top to bottom list of wrappers (first entry is the outermost wrapper)
::std::vector<TypeWrapper> wrappers;
RawType inner_type = RawType::Unit;
- const DataType* composite_type = nullptr;
+ union {
+ const DataType* composite_type;
+ const FunctionType* function_type;
+ } ptr;
TypeRef()
{
+ ptr.composite_type = nullptr;
}
explicit TypeRef(const DataType* dt):
- inner_type(RawType::Composite),
- composite_type(dt)
+ inner_type(RawType::Composite)
+ {
+ ptr.composite_type = dt;
+ }
+ explicit TypeRef(const FunctionType* fp):
+ inner_type(RawType::Function)
{
+ ptr.function_type = fp;
}
explicit TypeRef(RawType rt):
inner_type(rt)
{
+ ptr.composite_type = nullptr;
}
explicit TypeRef(CoreType ct):
inner_type(ct.raw_type)
{
+ ptr.composite_type = nullptr;
}
static TypeRef diverge() {
TypeRef rv;
@@ -122,6 +139,7 @@ namespace HIR {
}
size_t get_size(size_t ofs=0) const;
+ size_t get_align(size_t ofs=0) const;
// Returns true if this (unsized) type is a wrapper around a slice
// - Fills `out_inner_size` with the size of the slice element
@@ -158,6 +176,17 @@ namespace HIR {
// Get the offset and type of a field (recursing using `other_idx`)
size_t get_field_ofs(size_t idx, const ::std::vector<size_t>& other_idx, TypeRef& ty) const;
+ const DataType& composite_type() const {
+ assert(inner_type == RawType::Composite || inner_type == RawType::TraitObject);
+ assert(ptr.composite_type);
+ return *ptr.composite_type;
+ }
+ const FunctionType& function_type() const {
+ assert(inner_type == RawType::Function);
+ assert(ptr.function_type);
+ return *ptr.function_type;
+ }
+
bool operator==(const RawType& x) const {
if( this->wrappers.size() != 0 )
return false;
@@ -166,20 +195,20 @@ namespace HIR {
bool operator!=(const RawType& x) const {
return !(*this == x);
}
+ Ordering ord(const TypeRef& x) const {
+ __ORD(wrappers);
+ __ORD_C(int, inner_type);
+ __ORD_C(uintptr_t, ptr.composite_type); // pointer comparison only
+ return OrdEqual;
+ }
bool operator==(const TypeRef& x) const {
- return !(*this != x);
+ return this->ord(x) == OrdEqual;
}
bool operator!=(const TypeRef& x) const {
- __NE(wrappers);
- __NE(inner_type);
- __NE(composite_type);
- return false;
+ return this->ord(x) != OrdEqual;
}
bool operator<(const TypeRef& x) const {
- __LT(wrappers);
- __LT(inner_type);
- __LT(composite_type);
- return false;
+ return this->ord(x) == OrdLess;
}
friend ::std::ostream& operator<<(::std::ostream& os, const TypeRef& x);
@@ -189,18 +218,19 @@ namespace HIR {
{
::std::string crate_name;
::std::vector<::std::string> ents;
+ Ordering ord(const SimplePath& x) const {
+ __ORD(crate_name);
+ __ORD(ents);
+ return OrdEqual;
+ }
bool operator==(const SimplePath& x) const {
- return !(*this != x);
+ return this->ord(x) == OrdEqual;
}
bool operator!=(const SimplePath& x) const {
- __NE(crate_name);
- __NE(ents);
- return false;
+ return this->ord(x) != OrdEqual;
}
bool operator<(const SimplePath& x) const {
- __LT(crate_name);
- __LT(ents);
- return false;
+ return this->ord(x) == OrdLess;
}
friend ::std::ostream& operator<<(::std::ostream& os, const SimplePath& x);
};
@@ -221,18 +251,19 @@ namespace HIR {
m_simplepath(sp)
{
}
+ Ordering ord(const GenericPath& x) const {
+ __ORD(m_simplepath);
+ __ORD(m_params.tys);
+ return OrdEqual;
+ }
bool operator==(const GenericPath& x) const {
- return !(*this != x);
+ return this->ord(x) == OrdEqual;
}
bool operator!=(const GenericPath& x) const {
- __NE(m_simplepath);
- __NE(m_params.tys);
- return false;
+ return this->ord(x) != OrdEqual;
}
bool operator<(const GenericPath& x) const {
- __LT(m_simplepath);
- __LT(m_params.tys);
- return false;
+ return this->ord(x) == OrdLess;
}
friend ::std::ostream& operator<<(::std::ostream& os, const GenericPath& x);
@@ -263,22 +294,21 @@ namespace HIR {
{
}
+ Ordering ord(const Path& x) const {
+ __ORD(m_type);
+ __ORD(m_trait);
+ __ORD(m_name);
+ __ORD(m_params.tys);
+ return OrdEqual;
+ }
bool operator==(const Path& x) const {
- return !(*this != x);
+ return this->ord(x) == OrdEqual;
}
bool operator!=(const Path& x) const {
- __NE(m_type);
- __NE(m_trait);
- __NE(m_name);
- __NE(m_params.tys);
- return false;
+ return this->ord(x) != OrdEqual;
}
bool operator<(const Path& x) const {
- __LT(m_type);
- __LT(m_trait);
- __LT(m_name);
- __LT(m_params.tys);
- return false;
+ return this->ord(x) == OrdLess;
}
friend ::std::ostream& operator<<(::std::ostream& os, const Path& x);
diff --git a/tools/standalone_miri/lex.cpp b/tools/standalone_miri/lex.cpp
index 07427bde..79e94224 100644
--- a/tools/standalone_miri/lex.cpp
+++ b/tools/standalone_miri/lex.cpp
@@ -7,6 +7,8 @@
*/
#include "lex.hpp"
#include <cctype>
+#include <sstream>
+#include "debug.hpp"
#include <iostream>
bool Token::operator==(TokenClass tc) const
@@ -25,7 +27,7 @@ bool Token::operator==(const char* s) const
uint64_t Token::integer() const
{
if( this->type != TokenClass::Integer )
- throw "";
+ throw ::std::runtime_error(FMT_STRING("Expected interger, got " << *this));
return this->numbers.int_val;
}
double Token::real() const
diff --git a/tools/standalone_miri/linux.api b/tools/standalone_miri/linux.api
new file mode 100644
index 00000000..a4b8dd36
--- /dev/null
+++ b/tools/standalone_miri/linux.api
@@ -0,0 +1,50 @@
+#
+# Expression grammar:
+# `let <name> = <expr>;`
+# `<slot> <op>= <expr>;`
+# `<expr>`
+
+# `signal` - Just ignore it
+fn signal(..) -> *const [null] void [size(0)] {
+ 0
+}
+fn memchr(ptr: *const [count(n)] u8, c: u8, n: usize) -> *const [null,alloc(ptr)] u8 = "":"memchr";
+fn memrchr(ptr: *const [count(n)] u8, c: u8, n: usize) -> *const [null,alloc(ptr)] u8 = "":"memrchr";
+fn strlen(ptr: *const [cstr] u8) -> usize = "":"strlen";
+
+
+#fn write(fd: i32, count: isize, buf: *const void [size(count)]) -> i32 = "":"write";
+fn write(fd: i32, count: isize, buf: *const void) -> i32 {
+ miri::assert("invalid fd passed", fd > 0);
+ miri::ensure_valid_read("source buffer invalid", buf, 0, count);
+ miri::call_i32("", "write", fd, count, buf)
+}
+fn sysconf(name: i32) -> usize = "":"sysconf";
+
+
+# 64-bit linux pthread_attr_t
+type pthread_attr_t = void [size(56),align(8)];
+fn pthread_attr_init(*mut pthread_attr_t) -> i32 = "":"pthread_attr_init";
+fn pthread_attr_destroy(*mut pthread_attr_t) -> i32 = "":"pthread_attr_destroy";
+
+type pthread_key_t = u32;
+static PTHREAD_NEXT_KEY: u32 = 1;
+static PTHREAD_TLS: Map<u32,u64>;
+fn pthread_key_create(ptr: *mut pthread_key_t) -> i32 {
+ let key = PTHREAD_NEXT_KEY;
+ PTHREAD_NEXT_KEY += 1;
+ *ptr = key;
+ 0
+}
+fn pthread_key_delete(key: pthread_key_t) -> i32 {
+ let _ = Map::remove(key);
+ 0
+}
+fn pthread_setspecific(key: pthread_key_t, val: u64) -> i32 {
+ Map::set(PTHREAD_TLS, key, val);
+ 0
+}
+fn pthread_getspecific(key: pthread_key_t) -> u64 {
+ let rv_opt = Map::get(PTHREAD_TLS, key);
+ Option::unwrap_or(rv_opt, 0)
+}
diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp
index deed08be..8ee118f7 100644
--- a/tools/standalone_miri/main.cpp
+++ b/tools/standalone_miri/main.cpp
@@ -51,6 +51,7 @@ int main(int argc, const char* argv[])
try
{
tree.load_file(opts.infile);
+ tree.validate();
}
catch(const DebugExceptionTodo& /*e*/)
{
@@ -71,26 +72,28 @@ int main(int argc, const char* argv[])
return 1;
}
+
// Create argc/argv based on input arguments
- auto argv_alloc = Allocation::new_alloc((1 + opts.args.size()) * POINTER_SIZE);
- argv_alloc->write_usize(0 * POINTER_SIZE, 0);
- argv_alloc->relocations.push_back({ 0 * POINTER_SIZE, RelocationPtr::new_ffi(FFIPointer { "", (void*)(opts.infile.c_str()), opts.infile.size() + 1 }) });
+ auto argv_alloc = Allocation::new_alloc((1 + opts.args.size()) * POINTER_SIZE, "argv");
+ argv_alloc->write_usize(0 * POINTER_SIZE, Allocation::PTR_BASE);
+ argv_alloc->relocations.push_back({ 0 * POINTER_SIZE, RelocationPtr::new_ffi(FFIPointer::new_const_bytes("argv0", opts.infile.c_str(), opts.infile.size() + 1)) });
for(size_t i = 0; i < opts.args.size(); i ++)
{
- argv_alloc->write_usize((1 + i) * POINTER_SIZE, 0);
- argv_alloc->relocations.push_back({ (1 + i) * POINTER_SIZE, RelocationPtr::new_ffi({ "", (void*)(opts.args[0]), ::std::strlen(opts.args[0]) + 1 }) });
+ argv_alloc->write_usize((1 + i) * POINTER_SIZE, Allocation::PTR_BASE);
+ argv_alloc->relocations.push_back({ (1 + i) * POINTER_SIZE, RelocationPtr::new_ffi(FFIPointer::new_const_bytes("argv", opts.args[i], ::std::strlen(opts.args[i]) + 1)) });
}
-
+ LOG_DEBUG("argv_alloc = " << *argv_alloc);
+
// Construct argc/argv values
auto val_argc = Value::new_isize(1 + opts.args.size());
auto argv_ty = ::HIR::TypeRef(RawType::I8).wrap(TypeWrapper::Ty::Pointer, 0 ).wrap(TypeWrapper::Ty::Pointer, 0);
- auto val_argv = Value::new_pointer(argv_ty, 0, RelocationPtr::new_alloc(argv_alloc));
+ auto val_argv = Value::new_pointer(argv_ty, Allocation::PTR_BASE, RelocationPtr::new_alloc(argv_alloc));
// Catch various exceptions from the interpreter
try
{
InterpreterThread root_thread(tree);
-
+
::std::vector<Value> args;
args.push_back(::std::move(val_argc));
args.push_back(::std::move(val_argv));
diff --git a/tools/standalone_miri/mir.cpp b/tools/standalone_miri/mir.cpp
index a0601823..bc456ca6 100644
--- a/tools/standalone_miri/mir.cpp
+++ b/tools/standalone_miri/mir.cpp
@@ -5,10 +5,13 @@
* mir/mir.cpp
* - MIR (Middle Intermediate Representation) definitions
*/
+#include "../../src/include/rc_string.hpp"
#include "../../src/mir/mir.hpp"
#include "hir_sim.hpp"
#include <iostream>
+#include <algorithm> // std::min
+#if 0
namespace std {
template <typename T>
inline ::std::ostream& operator<<(::std::ostream& os, const ::std::vector<T>& v) {
@@ -26,6 +29,7 @@ namespace std {
return os;
}
}
+#endif
namespace MIR {
::std::ostream& operator<<(::std::ostream& os, const Constant& v) {
@@ -62,44 +66,95 @@ namespace MIR {
os << "\"" << e << "\"";
),
(Const,
- os << e.p;
+ os << *e.p;
),
(ItemAddr,
- os << "&" << e;
+ os << "&" << *e;
)
)
return os;
}
- ::std::ostream& operator<<(::std::ostream& os, const LValue& x)
+ void LValue::RefCommon::fmt(::std::ostream& os) const
{
- TU_MATCHA( (x), (e),
+ TU_MATCHA( (m_lv->m_root), (e),
(Return,
- os << "Return";
+ os << "retval";
),
(Argument,
- os << "Argument(" << e.idx << ")";
+ os << "a" << e;
),
(Local,
- os << "Local(" << e << ")";
+ os << "_" << e;
),
(Static,
- os << "Static(" << e << ")";
- ),
- (Field,
- os << "Field(" << e.field_index << ", " << *e.val << ")";
- ),
- (Deref,
- os << "Deref(" << *e.val << ")";
- ),
- (Index,
- os << "Index(" << *e.val << ", " << *e.idx << ")";
- ),
- (Downcast,
- os << "Downcast(" << e.variant_index << ", " << *e.val << ")";
+ os << "(" << e << ")";
)
)
+ for(size_t i = 0; i < m_wrapper_count; i ++)
+ {
+ const LValue::Wrapper& w = m_lv->m_wrappers.at(i);
+ TU_MATCHA( (w), (e),
+ (Field,
+ os << "." << e;
+ ),
+ (Deref,
+ os << "*";
+ ),
+ (Index,
+ os << "[_" << e << "]";
+ ),
+ (Downcast,
+ os << "#" << e;
+ )
+ )
+ }
+ }
+
+ ::std::ostream& operator<<(::std::ostream& os, const LValue& x)
+ {
+ LValue::CRef(x).fmt(os);
return os;
}
+
+ Ordering LValue::Storage::ord(const LValue::Storage& x) const
+ {
+ if( x.is_Static() )
+ {
+ if( this->is_Static() )
+ return this->as_Static().ord( x.as_Static() );
+ else
+ return OrdLess;
+ }
+ else
+ {
+ if( this->is_Static() )
+ return OrdGreater;
+ }
+
+ return ::ord(this->val, x.val);
+ }
+ Ordering LValue::ord(const LValue& x) const
+ {
+ auto rv = m_root.ord(x.m_root);
+ if( rv != OrdEqual )
+ return rv;
+ return ::ord(m_wrappers, x.m_wrappers);
+ }
+ Ordering LValue::RefCommon::ord(const LValue::RefCommon& x) const
+ {
+ Ordering rv;
+ //TRACE_FUNCTION_FR(FMT_CB(ss, this->fmt(ss); ss << " ? "; x.fmt(ss);), rv);
+ rv = m_lv->m_root.ord(x.m_lv->m_root);
+ if( rv != OrdEqual )
+ return rv;
+ for(size_t i = 0; i < ::std::min(m_wrapper_count, x.m_wrapper_count); i ++)
+ {
+ rv = m_lv->m_wrappers[i].ord(x.m_lv->m_wrappers[i]);
+ if( rv != OrdEqual )
+ return rv;
+ }
+ return (rv = ::ord(m_wrapper_count, x.m_wrapper_count));
+ }
::std::ostream& operator<<(::std::ostream& os, const Param& x)
{
TU_MATCHA( (x), (e),
@@ -296,5 +351,10 @@ namespace MIR {
)
return os;
}
+
+ EnumCachePtr::~EnumCachePtr()
+ {
+ assert(!this->p);
+ }
}
diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp
index fd4d45d8..4eadac66 100644
--- a/tools/standalone_miri/miri.cpp
+++ b/tools/standalone_miri/miri.cpp
@@ -5,18 +5,26 @@
* miri.cpp
* - Interpreter core
*/
+#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include "module_tree.hpp"
#include "value.hpp"
+#include "string_view.hpp"
#include <algorithm>
#include <iomanip>
#include "debug.hpp"
#include "miri.hpp"
+// VVV FFI
#include <cstring> // memrchr
+#include <sys/stat.h>
+#include <fcntl.h>
#ifdef _WIN32
# define NOMINMAX
# include <Windows.h>
+#else
+# include <unistd.h>
#endif
+#undef DEBUG
unsigned ThreadState::s_next_tls_key = 1;
@@ -25,6 +33,7 @@ class PrimitiveValue
public:
virtual ~PrimitiveValue() {}
+ virtual bool is_zero() const = 0;
virtual bool add(const PrimitiveValue& v) = 0;
virtual bool subtract(const PrimitiveValue& v) = 0;
virtual bool multiply(const PrimitiveValue& v) = 0;
@@ -50,6 +59,9 @@ struct PrimitiveUInt:
PrimitiveUInt(T v): v(v) {}
~PrimitiveUInt() override {}
+ virtual bool is_zero() const {
+ return this->v == 0;
+ }
bool add(const PrimitiveValue& x) override {
const auto* xp = &x.check<Self>("add");
T newv = this->v + xp->v;
@@ -100,6 +112,20 @@ struct PrimitiveU32: public PrimitiveUInt<uint32_t>
tgt.write_u32(ofs, this->v);
}
};
+struct PrimitiveU16: public PrimitiveUInt<uint16_t>
+{
+ PrimitiveU16(uint16_t v): PrimitiveUInt(v) {}
+ void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override {
+ tgt.write_u16(ofs, this->v);
+ }
+};
+struct PrimitiveU8: public PrimitiveUInt<uint8_t>
+{
+ PrimitiveU8(uint8_t v): PrimitiveUInt(v) {}
+ void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override {
+ tgt.write_u8(ofs, this->v);
+ }
+};
template<typename T>
struct PrimitiveSInt:
public PrimitiveValue
@@ -110,6 +136,9 @@ struct PrimitiveSInt:
PrimitiveSInt(T v): v(v) {}
~PrimitiveSInt() override {}
+ virtual bool is_zero() const {
+ return this->v == 0;
+ }
// TODO: Make this correct.
bool add(const PrimitiveValue& x) override {
const auto* xp = &x.check<Self>("add");
@@ -179,6 +208,12 @@ public:
LOG_ASSERT(t.get_wrapper() == nullptr, "PrimitiveValueVirt::from_value: " << t);
switch(t.inner_type)
{
+ case RawType::U8:
+ new(&rv.buf) PrimitiveU8(v.read_u8(0));
+ break;
+ case RawType::U16:
+ new(&rv.buf) PrimitiveU16(v.read_u16(0));
+ break;
case RawType::U32:
new(&rv.buf) PrimitiveU32(v.read_u32(0));
break;
@@ -254,142 +289,166 @@ struct MirHelpers
{
}
- ValueRef get_value_and_type(const ::MIR::LValue& lv, ::HIR::TypeRef& ty)
+ ValueRef get_value_and_type_root(const ::MIR::LValue::Storage& lv_root, ::HIR::TypeRef& ty)
{
- switch(lv.tag())
+ switch(lv_root.tag())
{
- case ::MIR::LValue::TAGDEAD: throw "";
+ case ::MIR::LValue::Storage::TAGDEAD: throw "";
// --> Slots
- TU_ARM(lv, Return, _e) {
- ty = this->frame.fcn.ret_ty;
+ TU_ARM(lv_root, Return, _e) {
+ ty = this->frame.fcn->ret_ty;
return ValueRef(this->frame.ret);
} break;
- TU_ARM(lv, Local, e) {
- ty = this->frame.fcn.m_mir.locals.at(e);
+ TU_ARM(lv_root, Local, e) {
+ ty = this->frame.fcn->m_mir.locals.at(e);
return ValueRef(this->frame.locals.at(e));
} break;
- TU_ARM(lv, Argument, e) {
- ty = this->frame.fcn.args.at(e.idx);
- return ValueRef(this->frame.args.at(e.idx));
+ TU_ARM(lv_root, Argument, e) {
+ ty = this->frame.fcn->args.at(e);
+ return ValueRef(this->frame.args.at(e));
} break;
- TU_ARM(lv, Static, e) {
+ TU_ARM(lv_root, Static, e) {
/*const*/ auto& s = this->thread.m_modtree.get_static(e);
ty = s.ty;
return ValueRef(s.val);
} break;
- // --> Modifiers
- TU_ARM(lv, Index, e) {
- auto idx = get_value_ref(*e.idx).read_usize(0);
- ::HIR::TypeRef array_ty;
- auto base_val = get_value_and_type(*e.val, array_ty);
- const auto* wrapper = array_ty.get_wrapper();
- if( !wrapper )
- {
- LOG_ERROR("Indexing non-array/slice - " << array_ty);
- }
- else if( wrapper->type == TypeWrapper::Ty::Array )
+ }
+ throw "";
+ }
+ ValueRef get_value_and_type(const ::MIR::LValue& lv, ::HIR::TypeRef& ty)
+ {
+ auto vr = get_value_and_type_root(lv.m_root, ty);
+ for(const auto& w : lv.m_wrappers)
+ {
+ switch(w.tag())
{
- ty = array_ty.get_inner();
- // Check index against array size
- if( idx >= wrapper->size ) {
- LOG_ERROR("Index out of bounds on array " << array_ty << ", idx=" << idx);
+ case ::MIR::LValue::Wrapper::TAGDEAD: throw "";
+ // --> Modifiers
+ TU_ARM(w, Index, idx_var) {
+ auto idx = this->frame.locals.at(idx_var).read_usize(0);
+ const auto* wrapper = ty.get_wrapper();
+ if( !wrapper )
+ {
+ LOG_ERROR("Indexing non-array/slice - " << ty);
throw "ERROR";
}
- base_val.m_offset += static_cast<size_t>(ty.get_size() * idx);
- return base_val;
- }
- else if( wrapper->type == TypeWrapper::Ty::Slice )
- {
- LOG_TODO("Slice index");
- }
- else
- {
- LOG_ERROR("Indexing non-array/slice - " << array_ty);
- throw "ERROR";
- }
- } break;
- TU_ARM(lv, Field, e) {
- ::HIR::TypeRef composite_ty;
- auto base_val = get_value_and_type(*e.val, composite_ty);
- // TODO: if there's metadata present in the base, but the inner doesn't have metadata, clear the metadata
- size_t inner_ofs;
- ty = composite_ty.get_field(e.field_index, inner_ofs);
- LOG_DEBUG("Field - " << composite_ty << "#" << e.field_index << " = @" << inner_ofs << " " << ty);
- base_val.m_offset += inner_ofs;
- if( ty.get_meta_type() == HIR::TypeRef(RawType::Unreachable) )
- {
- LOG_ASSERT(base_val.m_size >= ty.get_size(), "Field didn't fit in the value - " << ty.get_size() << " required, but " << base_val.m_size << " avail");
- base_val.m_size = ty.get_size();
- }
- return base_val;
- }
- TU_ARM(lv, Downcast, e) {
- ::HIR::TypeRef composite_ty;
- auto base_val = get_value_and_type(*e.val, composite_ty);
- LOG_DEBUG("Downcast - " << composite_ty);
-
- size_t inner_ofs;
- ty = composite_ty.get_field(e.variant_index, inner_ofs);
- base_val.m_offset += inner_ofs;
- return base_val;
- }
- TU_ARM(lv, Deref, e) {
- ::HIR::TypeRef ptr_ty;
- auto val = get_value_and_type(*e.val, ptr_ty);
- ty = ptr_ty.get_inner();
- LOG_DEBUG("val = " << val << ", (inner) ty=" << ty);
-
- LOG_ASSERT(val.m_size >= POINTER_SIZE, "Deref of a value that doesn't fit a pointer - " << ty);
- size_t ofs = static_cast<size_t>( val.read_usize(0) ); // TODO: Limits?
-
- // There MUST be a relocation at this point with a valid allocation.
- auto alloc = val.get_relocation(val.m_offset);
- LOG_TRACE("Deref " << alloc << " + " << ofs << " to give value of type " << ty);
- // NOTE: No alloc can happen when dereferencing a zero-sized pointer
- if( alloc.is_alloc() )
- {
- LOG_DEBUG("> " << lv << " alloc=" << alloc.alloc());
- }
- size_t size;
+ else if( wrapper->type == TypeWrapper::Ty::Array )
+ {
+ ty = ty.get_inner();
+ vr.m_offset += ty.get_size() * idx;
+ }
+ else if( wrapper->type == TypeWrapper::Ty::Slice )
+ {
+ ty = ty.get_inner();
+ LOG_ASSERT(vr.m_metadata, "No slice metadata");
+ auto len = vr.m_metadata->read_usize(0);
+ LOG_ASSERT(idx < len, "Slice index out of range");
+ vr.m_offset += ty.get_size() * idx;
+ vr.m_metadata.reset();
+ }
+ else
+ {
+ LOG_ERROR("Indexing non-array/slice - " << ty);
+ throw "ERROR";
+ }
+ } break;
+ TU_ARM(w, Field, fld_idx) {
+ // TODO: if there's metadata present in the base, but the inner doesn't have metadata, clear the metadata
+ size_t inner_ofs;
+ auto inner_ty = ty.get_field(fld_idx, inner_ofs);
+ LOG_DEBUG("Field - " << ty << "#" << fld_idx << " = @" << inner_ofs << " " << inner_ty);
+ vr.m_offset += inner_ofs;
+ if( inner_ty.get_meta_type() == HIR::TypeRef(RawType::Unreachable) )
+ {
+ LOG_ASSERT(vr.m_size >= inner_ty.get_size(), "Field didn't fit in the value - " << inner_ty.get_size() << " required, but " << vr.m_size << " available");
+ vr.m_size = inner_ty.get_size();
+ }
+ ty = ::std::move(inner_ty);
+ }
+ TU_ARM(w, Downcast, variant_index) {
+ auto composite_ty = ::std::move(ty);
+ LOG_DEBUG("Downcast - " << composite_ty);
- const auto meta_ty = ty.get_meta_type();
- ::std::shared_ptr<Value> meta_val;
- // If the type has metadata, store it.
- if( meta_ty != RawType::Unreachable )
- {
- auto meta_size = meta_ty.get_size();
- LOG_ASSERT(val.m_size == POINTER_SIZE + meta_size, "Deref of " << ty << ", but pointer isn't correct size");
- meta_val = ::std::make_shared<Value>( val.read_value(POINTER_SIZE, meta_size) );
+ size_t inner_ofs;
+ ty = composite_ty.get_field(variant_index, inner_ofs);
+ vr.m_offset += inner_ofs;
+ }
+ TU_ARM(w, Deref, _) {
+ auto ptr_ty = ::std::move(ty);
+ ty = ptr_ty.get_inner();
+ LOG_DEBUG("Deref - " << vr << " into " << ty);
+
+ LOG_ASSERT(vr.m_size >= POINTER_SIZE, "Deref pointer isn't large enough to be a pointer");
+ // TODO: Move the metadata machinery into `deref` (or at least the logic needed to get the value size)
+ //auto inner_val = vr.deref(0, ty);
+ size_t ofs = vr.read_usize(0);
+ LOG_ASSERT(ofs != 0, "Dereferencing NULL pointer");
+ auto alloc = vr.get_relocation(0);
+ if( alloc )
+ {
+ // TODO: It's valid to dereference (but not read) a non-null invalid pointer.
+ LOG_ASSERT(ofs >= Allocation::PTR_BASE, "Dereferencing invalid pointer - " << ofs << " into " << alloc);
+ ofs -= Allocation::PTR_BASE;
+ }
+ else
+ {
+ }
- size_t slice_inner_size;
- if( ty.has_slice_meta(slice_inner_size) ) {
- size = (ty.get_wrapper() == nullptr ? ty.get_size() : 0) + static_cast<size_t>(meta_val->read_usize(0)) * slice_inner_size;
+ // There MUST be a relocation at this point with a valid allocation.
+ LOG_TRACE("Interpret " << alloc << " + " << ofs << " as value of type " << ty);
+ // NOTE: No alloc can happen when dereferencing a zero-sized pointer
+ if( alloc.is_alloc() )
+ {
+ //LOG_DEBUG("Deref - lvr=" << ::MIR::LValue::CRef(lv, &w - &lv.m_wrappers.front()) << " alloc=" << alloc.alloc());
}
- //else if( ty == RawType::TraitObject) {
- // // NOTE: Getting the size from the allocation is semi-valid, as you can't sub-slice trait objects
- // size = alloc.get_size() - ofs;
- //}
- else {
- LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs);
- size = alloc.get_size() - ofs;
+ else
+ {
+ LOG_ASSERT(ty.get_meta_type() != RawType::Unreachable || ty.get_size() >= 0, "Dereference (giving a non-ZST) with no allocation");
}
- }
- else
- {
- LOG_ASSERT(val.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value (size=" << val.m_size << ") - " << val << ": " << ptr_ty);
- size = ty.get_size();
- if( !alloc ) {
- LOG_ERROR("Deref of a value with no relocation - " << val);
+ size_t size;
+
+ const auto meta_ty = ty.get_meta_type();
+ ::std::shared_ptr<Value> meta_val;
+ // If the type has metadata, store it.
+ if( meta_ty != RawType::Unreachable )
+ {
+ auto meta_size = meta_ty.get_size();
+ LOG_ASSERT(vr.m_size == POINTER_SIZE + meta_size, "Deref of " << ty << ", but pointer isn't correct size");
+ meta_val = ::std::make_shared<Value>( vr.read_value(POINTER_SIZE, meta_size) );
+
+ size_t slice_inner_size;
+ if( ty.has_slice_meta(slice_inner_size) ) {
+ // Slice metadata, add the base size (if it's a struct) to the variable size
+ // - `get_wrapper` will return non-null for `[T]`, special-case `str`
+ size = (ty != RawType::Str && ty.get_wrapper() == nullptr ? ty.get_size() : 0) + meta_val->read_usize(0) * slice_inner_size;
+ }
+ //else if( ty == RawType::TraitObject) {
+ // // NOTE: Getting the size from the allocation is semi-valid, as you can't sub-slice trait objects
+ // size = alloc.get_size() - ofs;
+ //}
+ else {
+ LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs);
+ // TODO: if the inner type is a trait object, then check that it has an allocation.
+ size = alloc.get_size() - ofs;
+ }
+ }
+ else
+ {
+ LOG_DEBUG("sizeof(" << ty << ") = " << ty.get_size());
+ LOG_ASSERT(vr.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value (size=" << vr << ") - " << vr << ": " << ptr_ty);
+ size = ty.get_size();
+ if( !alloc && size > 0 ) {
+ LOG_ERROR("Deref of a non-ZST pointer with no relocation - " << vr);
+ }
}
- }
- LOG_DEBUG("alloc=" << alloc << ", ofs=" << ofs << ", size=" << size);
- auto rv = ValueRef(::std::move(alloc), ofs, size);
- rv.m_metadata = ::std::move(meta_val);
- return rv;
- } break;
+ LOG_DEBUG("Deref - New VR: alloc=" << alloc << ", ofs=" << ofs << ", size=" << size);
+ vr = ValueRef(::std::move(alloc), ofs, size);
+ vr.m_metadata = ::std::move(meta_val);
+ } break;
+ }
}
- throw "";
+ return vr;
}
ValueRef get_value_ref(const ::MIR::LValue& lv)
{
@@ -422,11 +481,14 @@ struct MirHelpers
::HIR::TypeRef ty;
auto base_value = get_value_and_type(lv, ty);
- if(base_value.m_alloc) {
- base_value.m_alloc.alloc().write_value(base_value.m_offset, ::std::move(val));
- }
- else {
- base_value.m_value->write_value(base_value.m_offset, ::std::move(val));
+ if( val.size() > 0 )
+ {
+ if(!base_value.m_value) {
+ base_value.m_alloc.alloc().write_value(base_value.m_offset, ::std::move(val));
+ }
+ else {
+ base_value.m_value->write_value(base_value.m_offset, ::std::move(val));
+ }
}
}
@@ -447,7 +509,11 @@ struct MirHelpers
ty = ::HIR::TypeRef(ce.t);
Value val = Value(ty);
val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian
- // TODO: i128/u128 need the upper bytes cleared+valid
+ // i128/u128 need the upper bytes cleared+valid
+ if( ce.t.raw_type == RawType::U128 ) {
+ uint64_t zero = 0;
+ val.write_bytes(8, &zero, 8);
+ }
return val;
} break;
TU_ARM(c, Bool, ce) {
@@ -474,12 +540,17 @@ struct MirHelpers
LOG_BUG("Constant::Const in mmir");
} break;
TU_ARM(c, Bytes, ce) {
- LOG_TODO("Constant::Bytes");
+ ty = ::HIR::TypeRef(RawType::U8).wrap(TypeWrapper::Ty::Slice, 0).wrap(TypeWrapper::Ty::Borrow, 0);
+ Value val = Value(ty);
+ val.write_ptr(0, Allocation::PTR_BASE + 0, RelocationPtr::new_ffi(FFIPointer::new_const_bytes("Constant::Bytes", ce.data(), ce.size())));
+ val.write_usize(POINTER_SIZE, ce.size());
+ LOG_DEBUG(c << " = " << val);
+ return val;
} break;
TU_ARM(c, StaticString, ce) {
ty = ::HIR::TypeRef(RawType::Str).wrap(TypeWrapper::Ty::Borrow, 0);
Value val = Value(ty);
- val.write_ptr(0, 0, RelocationPtr::new_string(&ce));
+ val.write_ptr(0, Allocation::PTR_BASE + 0, RelocationPtr::new_string(&ce));
val.write_usize(POINTER_SIZE, ce.size());
LOG_DEBUG(c << " = " << val);
return val;
@@ -487,15 +558,16 @@ struct MirHelpers
// --> Accessor
TU_ARM(c, ItemAddr, ce) {
// Create a value with a special backing allocation of zero size that references the specified item.
- if( /*const auto* fn =*/ this->thread.m_modtree.get_function_opt(ce) ) {
+ if( /*const auto* fn =*/ this->thread.m_modtree.get_function_opt(*ce) ) {
ty = ::HIR::TypeRef(RawType::Function);
- return Value::new_fnptr(ce);
+ return Value::new_fnptr(*ce);
}
- if( const auto* s = this->thread.m_modtree.get_static_opt(ce) ) {
+ if( const auto* s = this->thread.m_modtree.get_static_opt(*ce) ) {
ty = s->ty.wrapped(TypeWrapper::Ty::Borrow, 0);
- return Value::new_pointer(ty, 0, RelocationPtr::new_alloc(s->val.allocation));
+ LOG_ASSERT(s->val.m_inner.is_alloc, "Statics should already have an allocation assigned");
+ return Value::new_pointer(ty, Allocation::PTR_BASE + 0, RelocationPtr::new_alloc(s->val.m_inner.alloc.alloc));
}
- LOG_ERROR("Constant::ItemAddr - " << ce << " - not found");
+ LOG_ERROR("Constant::ItemAddr - " << *ce << " - not found");
} break;
}
throw "";
@@ -546,15 +618,15 @@ InterpreterThread::~InterpreterThread()
for(size_t i = 0; i < m_stack.size(); i++)
{
const auto& frame = m_stack[m_stack.size() - 1 - i];
- ::std::cout << "#" << i << ": ";
+ ::std::cout << "#" << i << ": F" << frame.frame_index << " ";
if( frame.cb )
{
::std::cout << "WRAPPER";
}
else
{
- ::std::cout << frame.fcn.my_path << " BB" << frame.bb_idx << "/";
- if( frame.stmt_idx == frame.fcn.m_mir.blocks.at(frame.bb_idx).statements.size() )
+ ::std::cout << frame.fcn->my_path << " BB" << frame.bb_idx << "/";
+ if( frame.stmt_idx == frame.fcn->m_mir.blocks.at(frame.bb_idx).statements.size() )
::std::cout << "TERM";
else
::std::cout << frame.stmt_idx;
@@ -576,10 +648,11 @@ bool InterpreterThread::step_one(Value& out_thread_result)
assert( !this->m_stack.empty() );
assert( !this->m_stack.back().cb );
auto& cur_frame = this->m_stack.back();
- TRACE_FUNCTION_R(cur_frame.fcn.my_path, "");
- const auto& bb = cur_frame.fcn.m_mir.blocks.at( cur_frame.bb_idx );
+ auto instr_idx = this->m_instruction_count++;
+ TRACE_FUNCTION_R("#" << instr_idx << " " << cur_frame.fcn->my_path << " BB" << cur_frame.bb_idx << "/" << cur_frame.stmt_idx, "#" << instr_idx);
+ const auto& bb = cur_frame.fcn->m_mir.blocks.at( cur_frame.bb_idx );
- const size_t MAX_STACK_DEPTH = 40;
+ const size_t MAX_STACK_DEPTH = 90;
if( this->m_stack.size() > MAX_STACK_DEPTH )
{
LOG_ERROR("Maximum stack depth of " << MAX_STACK_DEPTH << " exceeded");
@@ -590,7 +663,7 @@ bool InterpreterThread::step_one(Value& out_thread_result)
if( cur_frame.stmt_idx < bb.statements.size() )
{
const auto& stmt = bb.statements[cur_frame.stmt_idx];
- LOG_DEBUG("=== BB" << cur_frame.bb_idx << "/" << cur_frame.stmt_idx << ": " << stmt);
+ LOG_DEBUG("=== F" << cur_frame.frame_index << " BB" << cur_frame.bb_idx << "/" << cur_frame.stmt_idx << ": " << stmt);
switch(stmt.tag())
{
case ::MIR::Statement::TAGDEAD: throw "";
@@ -609,25 +682,24 @@ bool InterpreterThread::step_one(Value& out_thread_result)
::HIR::TypeRef src_ty;
ValueRef src_base_value = state.get_value_and_type(re.val, src_ty);
auto alloc = src_base_value.m_alloc;
+ // If the source doesn't yet have a relocation, give it a backing allocation so we can borrow
if( !alloc && src_base_value.m_value )
{
- if( !src_base_value.m_value->allocation )
- {
- src_base_value.m_value->create_allocation();
- }
- alloc = RelocationPtr::new_alloc( src_base_value.m_value->allocation );
+ LOG_DEBUG("Borrow - Creating allocation for " << src_base_value);
+ alloc = RelocationPtr::new_alloc( src_base_value.m_value->borrow("Borrow") );
}
if( alloc.is_alloc() )
- LOG_DEBUG("- alloc=" << alloc << " (" << alloc.alloc() << ")");
+ LOG_DEBUG("Borrow - alloc=" << alloc << " (" << alloc.alloc() << ")");
else
- LOG_DEBUG("- alloc=" << alloc);
+ LOG_DEBUG("Borrow - alloc=" << alloc);
size_t ofs = src_base_value.m_offset;
const auto meta = src_ty.get_meta_type();
auto dst_ty = src_ty.wrapped(TypeWrapper::Ty::Borrow, static_cast<size_t>(re.type));
+ LOG_DEBUG("Borrow - ofs=" << ofs << ", meta_ty=" << meta);
- // Create the pointer
+ // Create the pointer (can this just store into the target?)
new_val = Value(dst_ty);
- new_val.write_ptr(0, ofs, ::std::move(alloc));
+ new_val.write_ptr(0, Allocation::PTR_BASE + ofs, ::std::move(alloc));
// - Add metadata if required
if( meta != RawType::Unreachable )
{
@@ -687,13 +759,22 @@ bool InterpreterThread::step_one(Value& out_thread_result)
else if( const auto* src_w = src_ty.get_wrapper() )
{
if( src_w->type != TypeWrapper::Ty::Pointer && src_w->type != TypeWrapper::Ty::Borrow ) {
- LOG_ERROR("Attempting to cast to a non-pointer - " << src_ty);
+ LOG_ERROR("Attempting to cast from a non-pointer - " << src_ty);
}
// TODO: MUST be a thin pointer?
// TODO: MUST be an integer (usize only?)
- if( re.type != RawType::USize && re.type != RawType::ISize ) {
- LOG_ERROR("Casting from a pointer to non-usize - " << re.type << " to " << src_ty);
+ switch(re.type.wrappers.empty() ? re.type.inner_type : RawType::Unreachable)
+ {
+ case RawType::USize:
+ case RawType::ISize:
+ break;
+ case RawType::U64:
+ case RawType::I64:
+ // TODO: Only if 64-bit?
+ break;
+ default:
+ LOG_ERROR("Casting from a pointer to non-usize - " << src_ty << " to " << re.type);
throw "ERROR";
}
new_val = src_value.read_value(0, re.type.get_size());
@@ -726,8 +807,8 @@ bool InterpreterThread::step_one(Value& out_thread_result)
case RawType::Bool: throw "ERROR";
case RawType::F32: throw "BUG";
case RawType::F64: dst_val = static_cast<float>( src_value.read_f64(0) ); break;
- case RawType::USize: throw "TODO";// /*dst_val = src_value.read_usize();*/ break;
- case RawType::ISize: throw "TODO";// /*dst_val = src_value.read_isize();*/ break;
+ case RawType::USize: LOG_TODO("f32 from " << src_ty);// /*dst_val = src_value.read_usize();*/ break;
+ case RawType::ISize: LOG_TODO("f32 from " << src_ty);// /*dst_val = src_value.read_isize();*/ break;
case RawType::U8: dst_val = static_cast<float>( src_value.read_u8 (0) ); break;
case RawType::I8: dst_val = static_cast<float>( src_value.read_i8 (0) ); break;
case RawType::U16: dst_val = static_cast<float>( src_value.read_u16(0) ); break;
@@ -736,8 +817,8 @@ bool InterpreterThread::step_one(Value& out_thread_result)
case RawType::I32: dst_val = static_cast<float>( src_value.read_i32(0) ); break;
case RawType::U64: dst_val = static_cast<float>( src_value.read_u64(0) ); break;
case RawType::I64: dst_val = static_cast<float>( src_value.read_i64(0) ); break;
- case RawType::U128: throw "TODO";// /*dst_val = src_value.read_u128();*/ break;
- case RawType::I128: throw "TODO";// /*dst_val = src_value.read_i128();*/ break;
+ case RawType::U128: LOG_TODO("f32 from " << src_ty);// /*dst_val = src_value.read_u128();*/ break;
+ case RawType::I128: LOG_TODO("f32 from " << src_ty);// /*dst_val = src_value.read_i128();*/ break;
}
new_val.write_f32(0, dst_val);
} break;
@@ -774,7 +855,15 @@ bool InterpreterThread::step_one(Value& out_thread_result)
case RawType::Bool:
LOG_TODO("Cast to " << re.type);
case RawType::Char:
- LOG_TODO("Cast to " << re.type);
+ switch(src_ty.inner_type)
+ {
+ case RawType::Char: new_val.write_u32(0, src_value.read_u32(0) ); break;
+ case RawType::U8: new_val.write_u32(0, src_value.read_u8(0) ); break;
+ default:
+ LOG_ERROR("Cast from " << src_ty << " to char isn't valid");
+ break;
+ }
+ break;
case RawType::USize:
case RawType::U8:
case RawType::U16:
@@ -799,14 +888,30 @@ bool InterpreterThread::step_one(Value& out_thread_result)
LOG_ASSERT(re.type.inner_type == RawType::USize, "Function pointers can only be casted to usize, instead " << re.type);
new_val = src_value.read_value(0, re.type.get_size());
break;
- case RawType::Char:
- LOG_ASSERT(re.type.inner_type == RawType::U32, "Char can only be casted to u32, instead " << re.type);
- new_val = src_value.read_value(0, 4);
- break;
+ case RawType::Char: {
+ uint32_t v = src_value.read_u32(0);
+ switch(re.type.inner_type)
+ {
+ case RawType::U8:
+ if( v > 0xFF ) {
+ LOG_NOTICE("Casting to u8 from char above 255");
+ }
+ new_val.write_u8(0, v & 0xFF);
+ break;
+ case RawType::U32:
+ new_val = src_value.read_value(0, 4);
+ break;
+ case RawType::USize:
+ new_val.write_usize(0, v);
+ break;
+ default:
+ LOG_ERROR("Char can only be casted to u32/u8, instead " << re.type);
+ }
+ } break;
case RawType::Unit:
LOG_FATAL("Cast of unit");
case RawType::Composite: {
- const auto& dt = *src_ty.composite_type;
+ const auto& dt = src_ty.composite_type();
if( dt.variants.size() == 0 ) {
LOG_FATAL("Cast of composite - " << src_ty);
}
@@ -893,6 +998,13 @@ bool InterpreterThread::step_one(Value& out_thread_result)
if(0)
case RawType::I64:
dst_val = static_cast<uint64_t>( src_value.read_i64(0) );
+ if(0)
+ case RawType::U128:
+ dst_val = static_cast<uint64_t>( src_value.read_u128(0) );
+ if(0)
+ case RawType::I128:
+ LOG_TODO("Cast i128 to " << re.type);
+ //dst_val = static_cast<uint64_t>( src_value.read_i128(0) );
switch(re.type.inner_type)
{
@@ -930,13 +1042,20 @@ bool InterpreterThread::step_one(Value& out_thread_result)
throw "";
}
break;
- case RawType::U128: throw "TODO"; /*dst_val = src_value.read_u128();*/ break;
- case RawType::I128: throw "TODO"; /*dst_val = src_value.read_i128();*/ break;
}
} break;
case RawType::U128:
- case RawType::I128:
- LOG_TODO("Cast to " << re.type);
+ case RawType::I128: {
+ U128 dst_val;
+ switch(src_ty.inner_type)
+ {
+ case RawType::U8: dst_val = src_value.read_u8 (0); break;
+ case RawType::I8: dst_val = src_value.read_i8 (0); break;
+ default:
+ LOG_TODO("Cast " << src_ty << " to " << re.type);
+ }
+ new_val.write_u128(0, dst_val);
+ } break;
}
}
} break;
@@ -957,18 +1076,65 @@ bool InterpreterThread::step_one(Value& out_thread_result)
case ::MIR::eBinOp::LE: {
LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r);
int res = 0;
- // TODO: Handle comparison of the relocations too
- //const auto& alloc_l = v_l.m_value ? v_l.m_value->allocation : v_l.m_alloc;
- //const auto& alloc_r = v_r.m_value ? v_r.m_value->allocation : v_r.m_alloc;
- auto reloc_l = /*alloc_l ? */v_l.get_relocation(v_l.m_offset)/* : RelocationPtr()*/;
- auto reloc_r = /*alloc_r ? */v_r.get_relocation(v_r.m_offset)/* : RelocationPtr()*/;
+ auto reloc_l = v_l.get_relocation(0);
+ auto reloc_r = v_r.get_relocation(0);
- if( reloc_l != reloc_r )
+
+ // TODO: Handle comparison of the relocations too
+ // - If both sides have a relocation:
+ // > EQ/NE always valid
+ // > others require the same relocation
+ // - If one side has a relocation:
+ // > EQ/NE only allow zero on the non-reloc side
+ // > others are invalid?
+ if( reloc_l && reloc_r )
{
- res = (reloc_l < reloc_r ? -1 : 1);
+ // Both have relocations, check if they're equal
+ if( reloc_l != reloc_r )
+ {
+ switch(re.op)
+ {
+ case ::MIR::eBinOp::EQ:
+ case ::MIR::eBinOp::NE:
+ res = 1;
+ break;
+ default:
+ LOG_FATAL("Unable to compare " << v_l << " and " << v_r << " - different relocations (" << reloc_l << " != " << reloc_r << ")");
+ }
+ // - Equality will always fail
+ // - Ordering is a bug
+ }
+ else
+ {
+ // Equal: Allow all comparisons
+ }
+ }
+ else if( reloc_l || reloc_r )
+ {
+ // Only one side
+ // - Ordering is a bug
+ // - Equalities are allowed, but only for `0`?
+ // > TODO: If the side with no reloation doesn't have value `0` then error?
+ switch(re.op)
+ {
+ case ::MIR::eBinOp::EQ:
+ case ::MIR::eBinOp::NE:
+ // - Allow success, as addresses can be masked down
+ break;
+ default:
+ if( reloc_l )
+ res = 1;
+ else// if( reloc_r )
+ res = -1;
+ //LOG_FATAL("Unable to order " << v_l << " and " << v_r << " - different relocations");
+ break;
+ }
+ }
+ else
+ {
+ // No relocations, no need to check more
}
- LOG_DEBUG("res=" << res << ", " << reloc_l << " ? " << reloc_r);
if( const auto* w = ty_l.get_wrapper() )
{
@@ -1010,6 +1176,10 @@ bool InterpreterThread::step_one(Value& out_thread_result)
case RawType::I8 : res = res != 0 ? res : Ops::do_compare(v_l.read_i8 (0), v_r.read_i8 (0)); break;
case RawType::USize: res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0)); break;
case RawType::ISize: res = res != 0 ? res : Ops::do_compare(v_l.read_isize(0), v_r.read_isize(0)); break;
+ case RawType::Char: res = res != 0 ? res : Ops::do_compare(v_l.read_u32(0), v_r.read_u32(0)); break;
+ case RawType::Bool: res = res != 0 ? res : Ops::do_compare(v_l.read_u8(0), v_r.read_u8(0)); break; // TODO: `read_bool` that checks for bool values?
+ case RawType::U128: res = res != 0 ? res : Ops::do_compare(v_l.read_u128(0), v_r.read_u128(0)); break;
+ case RawType::I128: res = res != 0 ? res : Ops::do_compare(v_l.read_i128(0), v_r.read_i128(0)); break;
default:
LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l);
}
@@ -1034,36 +1204,40 @@ bool InterpreterThread::step_one(Value& out_thread_result)
case ::MIR::eBinOp::BIT_SHR: {
LOG_ASSERT(ty_l.get_wrapper() == nullptr, "Bitwise operator on non-primitive - " << ty_l);
LOG_ASSERT(ty_r.get_wrapper() == nullptr, "Bitwise operator with non-primitive - " << ty_r);
- size_t max_bits = ty_r.get_size() * 8;
+ size_t max_bits = ty_l.get_size() * 8;
uint8_t shift;
- auto check_cast = [&](uint64_t v){ LOG_ASSERT(0 <= v && v <= static_cast<decltype(v)>(max_bits), "Shift out of range - " << v); return static_cast<uint8_t>(v); };
+ auto check_cast_u = [&](auto v){ LOG_ASSERT(0 <= v && v <= max_bits, "Shift out of range - " << v); return static_cast<uint8_t>(v); };
+ auto check_cast_s = [&](auto v){ LOG_ASSERT(v <= static_cast<int64_t>(max_bits), "Shift out of range - " << v); return static_cast<uint8_t>(v); };
switch(ty_r.inner_type)
{
- case RawType::U64: shift = check_cast(v_r.read_u64(0)); break;
- case RawType::U32: shift = check_cast(v_r.read_u32(0)); break;
- case RawType::U16: shift = check_cast(v_r.read_u16(0)); break;
- case RawType::U8 : shift = check_cast(v_r.read_u8 (0)); break;
- case RawType::I64: shift = check_cast(v_r.read_i64(0)); break;
- case RawType::I32: shift = check_cast(v_r.read_i32(0)); break;
- case RawType::I16: shift = check_cast(v_r.read_i16(0)); break;
- case RawType::I8 : shift = check_cast(v_r.read_i8 (0)); break;
- case RawType::USize: shift = check_cast(v_r.read_usize(0)); break;
- case RawType::ISize: shift = check_cast(v_r.read_isize(0)); break;
+ case RawType::U64: shift = check_cast_u(v_r.read_u64(0)); break;
+ case RawType::U32: shift = check_cast_u(v_r.read_u32(0)); break;
+ case RawType::U16: shift = check_cast_u(v_r.read_u16(0)); break;
+ case RawType::U8 : shift = check_cast_u(v_r.read_u8 (0)); break;
+ case RawType::I64: shift = check_cast_s(v_r.read_i64(0)); break;
+ case RawType::I32: shift = check_cast_s(v_r.read_i32(0)); break;
+ case RawType::I16: shift = check_cast_s(v_r.read_i16(0)); break;
+ case RawType::I8 : shift = check_cast_s(v_r.read_i8 (0)); break;
+ case RawType::USize: shift = check_cast_u(v_r.read_usize(0)); break;
+ case RawType::ISize: shift = check_cast_s(v_r.read_isize(0)); break;
default:
- LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r);
+ LOG_TODO("BinOp shift RHS unknown type - " << se.src << " w/ " << ty_r);
}
new_val = Value(ty_l);
switch(ty_l.inner_type)
{
// TODO: U128
+ case RawType::U128: new_val.write_u128(0, Ops::do_bitwise(v_l.read_u128(0), U128(shift), re.op)); break;
case RawType::U64: new_val.write_u64(0, Ops::do_bitwise(v_l.read_u64(0), static_cast<uint64_t>(shift), re.op)); break;
case RawType::U32: new_val.write_u32(0, Ops::do_bitwise(v_l.read_u32(0), static_cast<uint32_t>(shift), re.op)); break;
case RawType::U16: new_val.write_u16(0, Ops::do_bitwise(v_l.read_u16(0), static_cast<uint16_t>(shift), re.op)); break;
case RawType::U8 : new_val.write_u8 (0, Ops::do_bitwise(v_l.read_u8 (0), static_cast<uint8_t >(shift), re.op)); break;
case RawType::USize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast<uint64_t>(shift), re.op)); break;
- // TODO: Is signed allowed?
+ // Is signed allowed? (yes)
+ // - What's the exact semantics? For now assuming it's unsigned+reinterpret
+ case RawType::ISize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast<uint64_t>(shift), re.op)); break;
default:
- LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r);
+ LOG_TODO("BinOp shift LHS unknown type - " << se.src << " w/ " << ty_l);
}
} break;
case ::MIR::eBinOp::BIT_AND:
@@ -1074,7 +1248,10 @@ bool InterpreterThread::step_one(Value& out_thread_result)
new_val = Value(ty_l);
switch(ty_l.inner_type)
{
- // TODO: U128/I128
+ case RawType::U128:
+ case RawType::I128:
+ new_val.write_u128( 0, Ops::do_bitwise(v_l.read_u128(0), v_r.read_u128(0), re.op) );
+ break;
case RawType::U64:
case RawType::I64:
new_val.write_u64( 0, Ops::do_bitwise(v_l.read_u64(0), v_r.read_u64(0), re.op) );
@@ -1089,6 +1266,7 @@ bool InterpreterThread::step_one(Value& out_thread_result)
break;
case RawType::U8:
case RawType::I8:
+ case RawType::Bool:
new_val.write_u8 ( 0, static_cast<uint8_t >(Ops::do_bitwise(v_l.read_u8 (0), v_r.read_u8 (0), re.op)) );
break;
case RawType::USize:
@@ -1098,16 +1276,44 @@ bool InterpreterThread::step_one(Value& out_thread_result)
default:
LOG_TODO("BinOp bitwise - " << se.src << " w/ " << ty_l);
}
+ // If the LHS had a relocation, propagate it over
+ if( auto r = v_l.get_relocation(0) )
+ {
+ LOG_DEBUG("- Restore relocation " << r);
+ new_val.set_reloc(0, ::std::min(POINTER_SIZE, new_val.size()), r);
+ }
break;
default:
LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r);
auto val_l = PrimitiveValueVirt::from_value(ty_l, v_l);
auto val_r = PrimitiveValueVirt::from_value(ty_r, v_r);
+ RelocationPtr new_val_reloc;
switch(re.op)
{
- case ::MIR::eBinOp::ADD: val_l.get().add( val_r.get() ); break;
- case ::MIR::eBinOp::SUB: val_l.get().subtract( val_r.get() ); break;
+ case ::MIR::eBinOp::ADD:
+ LOG_ASSERT(!v_r.get_relocation(0), "RHS of `+` has a relocation");
+ new_val_reloc = v_l.get_relocation(0);
+ val_l.get().add( val_r.get() );
+ break;
+ case ::MIR::eBinOp::SUB:
+ if( auto r = v_l.get_relocation(0) )
+ {
+ if( v_r.get_relocation(0) )
+ {
+ // Pointer difference, no relocation in output
+ }
+ else
+ {
+ new_val_reloc = ::std::move(r);
+ }
+ }
+ else
+ {
+ LOG_ASSERT(!v_r.get_relocation(0), "RHS of `-` has a relocation but LHS does not");
+ }
+ val_l.get().subtract( val_r.get() );
+ break;
case ::MIR::eBinOp::MUL: val_l.get().multiply( val_r.get() ); break;
case ::MIR::eBinOp::DIV: val_l.get().divide( val_r.get() ); break;
case ::MIR::eBinOp::MOD: val_l.get().modulo( val_r.get() ); break;
@@ -1117,6 +1323,10 @@ bool InterpreterThread::step_one(Value& out_thread_result)
}
new_val = Value(ty_l);
val_l.get().write_to_value(new_val, 0);
+ if( new_val_reloc )
+ {
+ new_val.set_reloc(0, ::std::min(POINTER_SIZE, new_val.size()), ::std::move(new_val_reloc));
+ }
break;
}
} break;
@@ -1216,10 +1426,18 @@ bool InterpreterThread::step_one(Value& out_thread_result)
state.get_value_and_type(se.dst, dst_ty);
new_val = Value(dst_ty);
- for(size_t i = 0; i < re.vals.size(); i++)
+ if( dst_ty.inner_type == RawType::Unit )
{
- auto fld_ofs = dst_ty.composite_type->fields.at(i).first;
- new_val.write_value(fld_ofs, state.param_to_value(re.vals[i]));
+ LOG_ASSERT(re.vals.size() == 0 , "");
+ }
+ else
+ {
+ LOG_ASSERT(dst_ty.inner_type == RawType::Composite, dst_ty);
+ for(size_t i = 0; i < re.vals.size(); i++)
+ {
+ auto fld_ofs = dst_ty.composite_type().fields.at(i).first;
+ new_val.write_value(fld_ofs, state.param_to_value(re.vals[i]));
+ }
}
} break;
TU_ARM(se.src, Array, re) {
@@ -1287,12 +1505,15 @@ bool InterpreterThread::step_one(Value& out_thread_result)
::HIR::TypeRef dst_ty;
state.get_value_and_type(se.dst, dst_ty);
new_val = Value(dst_ty);
- LOG_ASSERT(dst_ty.composite_type == &data_ty, "Destination type of RValue::Struct isn't the same as the input");
+ LOG_ASSERT(dst_ty.inner_type == RawType::Composite, dst_ty);
+ LOG_ASSERT(dst_ty.ptr.composite_type == &data_ty, "Destination type of RValue::Struct isn't the same as the input");
for(size_t i = 0; i < re.vals.size(); i++)
{
auto fld_ofs = data_ty.fields.at(i).first;
- new_val.write_value(fld_ofs, state.param_to_value(re.vals[i]));
+ auto v = state.param_to_value(re.vals[i]);
+ LOG_DEBUG("Struct - @" << fld_ofs << " = " << v);
+ new_val.write_value(fld_ofs, ::std::move(v));
}
} break;
}
@@ -1309,21 +1530,17 @@ bool InterpreterThread::step_one(Value& out_thread_result)
auto v = state.get_value_and_type(se.slot, ty);
// - Take a pointer to the inner
- auto alloc = v.m_alloc;
- if( !alloc )
- {
- if( !v.m_value->allocation )
- {
- v.m_value->create_allocation();
- }
- alloc = RelocationPtr::new_alloc( v.m_value->allocation );
- }
+ auto alloc = (v.m_value ? RelocationPtr::new_alloc(v.m_value->borrow("drop")) : v.m_alloc);
size_t ofs = v.m_offset;
- assert(ty.get_meta_type() == RawType::Unreachable);
+ //LOG_ASSERT(ty.get_meta_type() == RawType::Unreachable, "Dropping an unsized type with Statement::Drop - " << ty);
- auto ptr_ty = ty.wrapped(TypeWrapper::Ty::Borrow, 2);
+ auto ptr_ty = ty.wrapped(TypeWrapper::Ty::Borrow, /*BorrowTy::Unique*/2);
- auto ptr_val = Value::new_pointer(ptr_ty, ofs, ::std::move(alloc));
+ auto ptr_val = Value::new_pointer(ptr_ty, Allocation::PTR_BASE + ofs, ::std::move(alloc));
+ if( v.m_metadata )
+ {
+ ptr_val.write_value(POINTER_SIZE, *v.m_metadata);
+ }
if( !drop_value(ptr_val, ty, /*shallow=*/se.kind == ::MIR::eDropKind::SHALLOW) )
{
@@ -1345,14 +1562,17 @@ bool InterpreterThread::step_one(Value& out_thread_result)
}
else
{
- LOG_DEBUG("=== BB" << cur_frame.bb_idx << "/TERM: " << bb.terminator);
+ LOG_DEBUG("=== F" << cur_frame.frame_index << " BB" << cur_frame.bb_idx << "/TERM: " << bb.terminator);
switch(bb.terminator.tag())
{
case ::MIR::Terminator::TAGDEAD: throw "";
TU_ARM(bb.terminator, Incomplete, _te)
LOG_TODO("Terminator::Incomplete hit");
TU_ARM(bb.terminator, Diverge, _te)
- LOG_TODO("Terminator::Diverge hit");
+ LOG_DEBUG("DIVERGE (continue panic)");
+ assert(m_thread.panic_count > 0);
+ m_thread.panic_active = true;
+ return this->pop_stack(out_thread_result);
TU_ARM(bb.terminator, Panic, _te)
LOG_TODO("Terminator::Panic");
TU_ARM(bb.terminator, Goto, te)
@@ -1371,13 +1591,14 @@ bool InterpreterThread::step_one(Value& out_thread_result)
auto v = state.get_value_and_type(te.val, ty);
LOG_ASSERT(ty.get_wrapper() == nullptr, "Matching on wrapped value - " << ty);
LOG_ASSERT(ty.inner_type == RawType::Composite, "Matching on non-coposite - " << ty);
+ LOG_DEBUG("Switch v = " << v);
// TODO: Convert the variant list into something that makes it easier to switch on.
size_t found_target = SIZE_MAX;
size_t default_target = SIZE_MAX;
- for(size_t i = 0; i < ty.composite_type->variants.size(); i ++)
+ for(size_t i = 0; i < ty.composite_type().variants.size(); i ++)
{
- const auto& var = ty.composite_type->variants[i];
+ const auto& var = ty.composite_type().variants[i];
if( var.tag_data.size() == 0 )
{
// Save as the default, error for multiple defaults
@@ -1399,6 +1620,7 @@ bool InterpreterThread::step_one(Value& out_thread_result)
continue ;
if( ::std::memcmp(tmp.data(), var.tag_data.data(), tmp.size()) == 0 )
{
+ LOG_DEBUG("Explicit match " << i);
found_target = i;
break ;
}
@@ -1407,6 +1629,7 @@ bool InterpreterThread::step_one(Value& out_thread_result)
if( found_target == SIZE_MAX )
{
+ LOG_DEBUG("Default match " << default_target);
found_target = default_target;
}
if( found_target == SIZE_MAX )
@@ -1415,8 +1638,93 @@ bool InterpreterThread::step_one(Value& out_thread_result)
}
cur_frame.bb_idx = te.targets.at(found_target);
} break;
- TU_ARM(bb.terminator, SwitchValue, _te)
- LOG_TODO("Terminator::SwitchValue");
+ TU_ARM(bb.terminator, SwitchValue, te) {
+ ::HIR::TypeRef ty;
+ auto v = state.get_value_and_type(te.val, ty);
+ TU_MATCH_HDRA( (te.values), {)
+ TU_ARMA(Unsigned, vals) {
+ LOG_ASSERT(vals.size() == te.targets.size(), "Mismatch in SwitchValue target/value list lengths");
+ // Read an unsigned value
+ if( ty.get_wrapper() ) {
+ LOG_ERROR("Terminator::SwitchValue::Unsigned with wrapped type - " << ty);
+ }
+ uint64_t switch_val;
+ switch(ty.inner_type)
+ {
+ case RawType::U8: switch_val = v.read_u8(0); break;
+ case RawType::U16: switch_val = v.read_u16(0); break;
+ case RawType::U32: switch_val = v.read_u32(0); break;
+ case RawType::U64: switch_val = v.read_u64(0); break;
+ case RawType::U128: LOG_TODO("Terminator::SwitchValue::Unsigned with u128");
+ case RawType::USize: switch_val = v.read_usize(0); break;
+ case RawType::Char: switch_val = v.read_u32(0); break;
+ default:
+ LOG_ERROR("Terminator::SwitchValue::Unsigned with unexpected type - " << ty);
+ }
+
+ auto it = ::std::find(vals.begin(), vals.end(), switch_val);
+ if( it != vals.end() )
+ {
+ auto idx = it - vals.begin();
+ LOG_TRACE("- " << switch_val << " matched arm " << idx);
+ cur_frame.bb_idx = te.targets.at(idx);
+ }
+ else
+ {
+ LOG_TRACE("- " << switch_val << " not matched, taking default arm");
+ cur_frame.bb_idx = te.def_target;
+ }
+ }
+ TU_ARMA(Signed, vals) {
+ if( ty.get_wrapper() ) {
+ LOG_ERROR("Terminator::SwitchValue::Signed with wrapped type - " << ty);
+ }
+ int64_t switch_val;
+ switch(ty.inner_type)
+ {
+ case RawType::I8: switch_val = v.read_i8(0); break;
+ case RawType::I16: switch_val = v.read_i16(0); break;
+ case RawType::I32: switch_val = v.read_i32(0); break;
+ case RawType::I64: switch_val = v.read_i64(0); break;
+ case RawType::I128: LOG_TODO("Terminator::SwitchValue::Signed with i128");
+ case RawType::ISize: switch_val = v.read_isize(0); break;
+ default:
+ LOG_ERROR("Terminator::SwitchValue::Signed with unexpected type - " << ty);
+ }
+
+ auto it = ::std::find(vals.begin(), vals.end(), switch_val);
+ if( it != vals.end() )
+ {
+ auto idx = it - vals.begin();
+ LOG_TRACE("- " << switch_val << " matched arm " << idx);
+ cur_frame.bb_idx = te.targets.at(idx);
+ }
+ else
+ {
+ LOG_TRACE("- " << switch_val << " not matched, taking default arm");
+ cur_frame.bb_idx = te.def_target;
+ }
+ }
+ TU_ARMA(String, vals) {
+ auto size = v.read_usize(POINTER_SIZE);
+ const char* sv_ptr = reinterpret_cast<const char*>(v.read_pointer_const(0, size));
+ auto switch_val = ::stdx::string_view(sv_ptr, sv_ptr+size);
+
+ auto it = ::std::find_if(vals.begin(), vals.end(), [&](const ::std::string& x){ return switch_val == x; });
+ if( it != vals.end() )
+ {
+ auto idx = it - vals.begin();
+ LOG_TRACE("- '" << switch_val << "' matched arm " << idx);
+ cur_frame.bb_idx = te.targets.at(idx);
+ }
+ else
+ {
+ LOG_TRACE("- '" << switch_val << "' not matched, taking default arm");
+ cur_frame.bb_idx = te.def_target;
+ }
+ }
+ }
+ }
TU_ARM(bb.terminator, Call, te) {
::std::vector<Value> sub_args; sub_args.reserve(te.args.size());
for(const auto& a : te.args)
@@ -1447,10 +1755,9 @@ bool InterpreterThread::step_one(Value& out_thread_result)
LOG_DEBUG("> Indirect call " << v);
// TODO: Assert type
// TODO: Assert offset/content.
- assert(v.read_usize(0) == 0);
- fcn_alloc_ptr = v.get_relocation(v.m_offset);
- if( !fcn_alloc_ptr )
- LOG_FATAL("Calling value with no relocation - " << v);
+ LOG_ASSERT(v.read_usize(0) == Allocation::PTR_BASE, "Function pointer value invalid - " << v);
+ fcn_alloc_ptr = v.get_relocation(0);
+ LOG_ASSERT(fcn_alloc_ptr, "Calling value with no relocation - " << v);
LOG_ASSERT(fcn_alloc_ptr.get_ty() == RelocationPtr::Ty::Function, "Calling value that isn't a function pointer");
fcn_p = &fcn_alloc_ptr.fcn();
}
@@ -1459,12 +1766,23 @@ bool InterpreterThread::step_one(Value& out_thread_result)
if( !this->call_path(rv, *fcn_p, ::std::move(sub_args)) )
{
// Early return, don't want to update stmt_idx yet
+ LOG_DEBUG("- Non-immediate return, do not advance yet");
return false;
}
}
- LOG_DEBUG(te.ret_val << " = " << rv << " (resume " << cur_frame.fcn.my_path << ")");
- state.write_lvalue(te.ret_val, rv);
- cur_frame.bb_idx = te.ret_block;
+ // If a panic is in progress (in thread state), take the panic block instead
+ if( m_thread.panic_active )
+ {
+ m_thread.panic_active = false;
+ LOG_DEBUG("Panic into " << cur_frame.fcn->my_path);
+ cur_frame.bb_idx = te.panic_block;
+ }
+ else
+ {
+ LOG_DEBUG(te.ret_val << " = " << rv << " (resume " << cur_frame.fcn->my_path << ")");
+ state.write_lvalue(te.ret_val, rv);
+ cur_frame.bb_idx = te.ret_block;
+ }
} break;
}
cur_frame.stmt_idx = 0;
@@ -1502,41 +1820,56 @@ bool InterpreterThread::pop_stack(Value& out_thread_result)
auto& cur_frame = this->m_stack.back();
MirHelpers state { *this, cur_frame };
- const auto& blk = cur_frame.fcn.m_mir.blocks.at( cur_frame.bb_idx );
+ const auto& blk = cur_frame.fcn->m_mir.blocks.at( cur_frame.bb_idx );
if( cur_frame.stmt_idx < blk.statements.size() )
{
assert( blk.statements[cur_frame.stmt_idx].is_Drop() );
cur_frame.stmt_idx ++;
- LOG_DEBUG("DROP complete (resume " << cur_frame.fcn.my_path << ")");
+ LOG_DEBUG("DROP complete (resume " << cur_frame.fcn->my_path << ")");
}
else
{
assert( blk.terminator.is_Call() );
const auto& te = blk.terminator.as_Call();
- LOG_DEBUG(te.ret_val << " = " << res_v << " (resume " << cur_frame.fcn.my_path << ")");
+ LOG_DEBUG("Resume " << cur_frame.fcn->my_path);
+ LOG_DEBUG("F" << cur_frame.frame_index << " " << te.ret_val << " = " << res_v);
- state.write_lvalue(te.ret_val, res_v);
cur_frame.stmt_idx = 0;
- cur_frame.bb_idx = te.ret_block;
+ // If a panic is in progress (in thread state), take the panic block instead
+ if( m_thread.panic_active )
+ {
+ m_thread.panic_active = false;
+ LOG_DEBUG("Panic into " << cur_frame.fcn->my_path);
+ cur_frame.bb_idx = te.panic_block;
+ }
+ else
+ {
+ state.write_lvalue(te.ret_val, res_v);
+ cur_frame.bb_idx = te.ret_block;
+ }
}
return false;
}
}
+unsigned InterpreterThread::StackFrame::s_next_frame_index = 0;
InterpreterThread::StackFrame::StackFrame(const Function& fcn, ::std::vector<Value> args):
- fcn(fcn),
- ret( fcn.ret_ty ),
+ frame_index(s_next_frame_index++),
+ fcn(&fcn),
+ ret( fcn.ret_ty == RawType::Unreachable ? Value() : Value(fcn.ret_ty) ),
args( ::std::move(args) ),
locals( ),
drop_flags( fcn.m_mir.drop_flags ),
bb_idx(0),
stmt_idx(0)
{
+ LOG_DEBUG("F" << frame_index << " - Initializing " << fcn.m_mir.locals.size() << " locals");
this->locals.reserve( fcn.m_mir.locals.size() );
for(const auto& ty : fcn.m_mir.locals)
{
+ LOG_DEBUG("_" << (&ty - &fcn.m_mir.locals.front()) << ": " << ty);
if( ty == RawType::Unreachable ) {
// HACK: Locals can be !, but they can NEVER be accessed
this->locals.push_back( Value() );
@@ -1557,7 +1890,9 @@ bool InterpreterThread::call_path(Value& ret, const ::HIR::Path& path, ::std::ve
}
// - No guard page needed
- if( path == ::HIR::SimplePath { "std", {"sys", "imp", "thread", "guard", "init" } } )
+ if( path == ::HIR::SimplePath { "std", {"sys", "imp", "thread", "guard", "init" } }
+ || path == ::HIR::SimplePath { "std", {"sys", "unix", "thread", "guard", "init" } }
+ )
{
ret = Value::with_size(16, false);
ret.write_u64(0, 0);
@@ -1576,8 +1911,17 @@ bool InterpreterThread::call_path(Value& ret, const ::HIR::Path& path, ::std::ve
if( fcn.external.link_name != "" )
{
- // External function!
- return this->call_extern(ret, fcn.external.link_name, fcn.external.link_abi, ::std::move(args));
+ // TODO: Search for a function with both code and this link name
+ if(const auto* ext_fcn = m_modtree.get_ext_function(fcn.external.link_name.c_str()))
+ {
+ this->m_stack.push_back(StackFrame(*ext_fcn, ::std::move(args)));
+ return false;
+ }
+ else
+ {
+ // External function!
+ return this->call_extern(ret, fcn.external.link_name, fcn.external.link_abi, ::std::move(args));
+ }
}
this->m_stack.push_back(StackFrame(fcn, ::std::move(args)));
@@ -1603,42 +1947,73 @@ extern "C" {
#endif
bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, const ::std::string& abi, ::std::vector<Value> args)
{
- if( link_name == "__rust_allocate" )
+ struct FfiHelpers {
+ static const char* read_cstr(const Value& v, size_t ptr_ofs, size_t* out_strlen=nullptr)
+ {
+ bool _is_mut;
+ size_t size;
+ // Get the base pointer and allocation size (checking for at least one valid byte to start with)
+ const char* ptr = reinterpret_cast<const char*>( v.read_pointer_unsafe(0, 1, /*out->*/ size, _is_mut) );
+ size_t len = 0;
+ // Seek until either out of space, or a NUL is found
+ while(size -- && *ptr)
+ {
+ ptr ++;
+ len ++;
+ }
+ if( out_strlen )
+ {
+ *out_strlen = len;
+ }
+ return reinterpret_cast<const char*>(v.read_pointer_const(0, len + 1)); // Final read will trigger an error if the NUL isn't there
+ }
+ };
+ if( link_name == "__rust_allocate" || link_name == "__rust_alloc" || link_name == "__rust_alloc_zeroed" )
{
+ static unsigned s_alloc_count = 0;
+
+ auto alloc_idx = s_alloc_count ++;
+ auto alloc_name = FMT_STRING("__rust_alloc#" << alloc_idx);
auto size = args.at(0).read_usize(0);
auto align = args.at(1).read_usize(0);
- LOG_DEBUG("__rust_allocate(size=" << size << ", align=" << align << ")");
- auto rty = ::HIR::TypeRef(RawType::Unit).wrap( TypeWrapper::Ty::Pointer, 0 );
+ LOG_DEBUG(link_name << "(size=" << size << ", align=" << align << "): name=" << alloc_name);
// TODO: Use the alignment when making an allocation?
- rv = Value::new_pointer(rty, 0, RelocationPtr::new_alloc(Allocation::new_alloc(size)));
+ auto alloc = Allocation::new_alloc(size, ::std::move(alloc_name));
+ LOG_TRACE("- alloc=" << alloc << " (" << alloc->size() << " bytes)");
+ auto rty = ::HIR::TypeRef(RawType::Unit).wrap( TypeWrapper::Ty::Pointer, 0 );
+
+ if( link_name == "__rust_alloc_zeroed" )
+ {
+ alloc->mark_bytes_valid(0, size);
+ }
+
+ rv = Value::new_pointer(rty, Allocation::PTR_BASE, RelocationPtr::new_alloc(::std::move(alloc)));
}
- else if( link_name == "__rust_reallocate" )
+ else if( link_name == "__rust_reallocate" || link_name == "__rust_realloc" )
{
- LOG_ASSERT(args.at(0).allocation, "__rust_reallocate first argument doesn't have an allocation");
auto alloc_ptr = args.at(0).get_relocation(0);
auto ptr_ofs = args.at(0).read_usize(0);
- LOG_ASSERT(ptr_ofs == 0, "__rust_reallocate with offset pointer");
auto oldsize = args.at(1).read_usize(0);
- auto newsize = args.at(2).read_usize(0);
- auto align = args.at(3).read_usize(0);
+ // NOTE: The ordering here depends on the rust version (1.19 has: old, new, align - 1.29 has: old, align, new)
+ auto align = args.at(true /*1.29*/ ? 2 : 3).read_usize(0);
+ auto newsize = args.at(true /*1.29*/ ? 3 : 2).read_usize(0);
LOG_DEBUG("__rust_reallocate(ptr=" << alloc_ptr << ", oldsize=" << oldsize << ", newsize=" << newsize << ", align=" << align << ")");
+ LOG_ASSERT(ptr_ofs == Allocation::PTR_BASE, "__rust_reallocate with offset pointer");
LOG_ASSERT(alloc_ptr, "__rust_reallocate with no backing allocation attached to pointer");
LOG_ASSERT(alloc_ptr.is_alloc(), "__rust_reallocate with no backing allocation attached to pointer");
auto& alloc = alloc_ptr.alloc();
// TODO: Check old size and alignment against allocation.
- alloc.data.resize( (newsize + 8-1) / 8 );
- alloc.mask.resize( (newsize + 8-1) / 8 );
+ alloc.resize(newsize);
// TODO: Should this instead make a new allocation to catch use-after-free?
rv = ::std::move(args.at(0));
}
- else if( link_name == "__rust_deallocate" )
+ else if( link_name == "__rust_deallocate" || link_name == "__rust_dealloc" )
{
- LOG_ASSERT(args.at(0).allocation, "__rust_deallocate first argument doesn't have an allocation");
auto alloc_ptr = args.at(0).get_relocation(0);
auto ptr_ofs = args.at(0).read_usize(0);
- LOG_ASSERT(ptr_ofs == 0, "__rust_deallocate with offset pointer");
+ LOG_ASSERT(ptr_ofs == Allocation::PTR_BASE, "__rust_deallocate with offset pointer");
LOG_DEBUG("__rust_deallocate(ptr=" << alloc_ptr << ")");
LOG_ASSERT(alloc_ptr, "__rust_deallocate with no backing allocation attached to pointer");
@@ -1675,6 +2050,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
return false;
}
}
+ else if( link_name == "panic_impl" )
+ {
+ LOG_TODO("panic_impl");
+ }
else if( link_name == "__rust_start_panic" )
{
LOG_TODO("__rust_start_panic");
@@ -1683,6 +2062,19 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
{
LOG_TODO("rust_begin_unwind");
}
+ // libunwind
+ else if( link_name == "_Unwind_RaiseException" )
+ {
+ LOG_DEBUG("_Unwind_RaiseException(" << args.at(0) << ")");
+ // Save the first argument in TLS, then return a status that indicates unwinding should commence.
+ m_thread.panic_active = true;
+ m_thread.panic_count += 1;
+ m_thread.panic_value = ::std::move(args.at(0));
+ }
+ else if( link_name == "_Unwind_DeleteException" )
+ {
+ LOG_DEBUG("_Unwind_DeleteException(" << args.at(0) << ")");
+ }
#ifdef _WIN32
// WinAPI functions used by libstd
else if( link_name == "AddVectoredExceptionHandler" )
@@ -1692,7 +2084,6 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
}
else if( link_name == "GetModuleHandleW" )
{
- LOG_ASSERT(args.at(0).allocation, "");
const auto& tgt_alloc = args.at(0).get_relocation(0);
const void* arg0 = (tgt_alloc ? tgt_alloc.alloc().data_ptr() : nullptr);
//extern void* GetModuleHandleW(const void* s);
@@ -1706,7 +2097,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
auto ret = GetModuleHandleW(static_cast<LPCWSTR>(arg0));
if(ret)
{
- rv = Value::new_ffiptr(FFIPointer { "GetModuleHandleW", ret, 0 });
+ rv = Value::new_ffiptr(FFIPointer::new_void("GetModuleHandleW", ret));
}
else
{
@@ -1731,7 +2122,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
if( ret )
{
- rv = Value::new_ffiptr(FFIPointer { "GetProcAddress", ret, 0 });
+ rv = Value::new_ffiptr(FFIPointer::new_void("GetProcAddress", ret));
}
else
{
@@ -1752,6 +2143,96 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
rv = Value::new_isize(val);
}
+ else if( link_name == "read" )
+ {
+ auto fd = args.at(0).read_i32(0);
+ auto count = args.at(2).read_isize(0);
+ auto buf_vr = args.at(1).read_pointer_valref_mut(0, count);
+
+ LOG_DEBUG("read(" << fd << ", " << buf_vr.data_ptr_mut() << ", " << count << ")");
+ ssize_t val = read(fd, buf_vr.data_ptr_mut(), count);
+ LOG_DEBUG("= " << val);
+
+ if( val > 0 )
+ {
+ buf_vr.mark_bytes_valid(0, val);
+ }
+
+ rv = Value::new_isize(val);
+ }
+ else if( link_name == "close" )
+ {
+ auto fd = args.at(0).read_i32(0);
+ LOG_DEBUG("close(" << fd << ")");
+ // TODO: Ensure that this FD is from the set known by the FFI layer
+ close(fd);
+ }
+ else if( link_name == "isatty" )
+ {
+ auto fd = args.at(0).read_i32(0);
+ LOG_DEBUG("isatty(" << fd << ")");
+ int rv_i = isatty(fd);
+ LOG_DEBUG("= " << rv_i);
+ rv = Value::new_i32(rv_i);
+ }
+ else if( link_name == "fcntl" )
+ {
+ // `fcntl` has custom handling for the third argument, as some are pointers
+ int fd = args.at(0).read_i32(0);
+ int command = args.at(1).read_i32(0);
+
+ int rv_i;
+ const char* name;
+ switch(command)
+ {
+ // - No argument
+ case F_GETFD: name = "F_GETFD"; if(0)
+ ;
+ {
+ LOG_DEBUG("fcntl(" << fd << ", " << name << ")");
+ rv_i = fcntl(fd, command);
+ } break;
+ // - Integer arguments
+ case F_DUPFD: name = "F_DUPFD"; if(0)
+ case F_DUPFD_CLOEXEC: name = "F_DUPFD_CLOEXEC"; if(0)
+ case F_SETFD: name = "F_SETFD"; if(0)
+ ;
+ {
+ int arg = args.at(2).read_i32(0);
+ LOG_DEBUG("fcntl(" << fd << ", " << name << ", " << arg << ")");
+ rv_i = fcntl(fd, command, arg);
+ } break;
+ default:
+ if( args.size() > 2 )
+ {
+ LOG_TODO("fnctl(..., " << command << ", " << args[2] << ")");
+ }
+ else
+ {
+ LOG_TODO("fnctl(..., " << command << ")");
+ }
+ }
+
+ LOG_DEBUG("= " << rv_i);
+ rv = Value(::HIR::TypeRef(RawType::I32));
+ rv.write_i32(0, rv_i);
+ }
+ else if( link_name == "prctl" )
+ {
+ auto option = args.at(0).read_i32(0);
+ int rv_i;
+ switch(option)
+ {
+ case 15: { // PR_SET_NAME - set thread name
+ auto name = FfiHelpers::read_cstr(args.at(1), 0);
+ LOG_DEBUG("prctl(PR_SET_NAME, \"" << name << "\"");
+ rv_i = 0;
+ } break;
+ default:
+ LOG_TODO("prctl(" << option << ", ...");
+ }
+ rv = Value::new_i32(rv_i);
+ }
else if( link_name == "sysconf" )
{
auto name = args.at(0).read_i32(0);
@@ -1761,6 +2242,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
rv = Value::new_usize(val);
}
+ else if( link_name == "pthread_self" )
+ {
+ rv = Value::new_i32(0);
+ }
else if( link_name == "pthread_mutex_init" || link_name == "pthread_mutex_lock" || link_name == "pthread_mutex_unlock" || link_name == "pthread_mutex_destroy" )
{
rv = Value::new_i32(0);
@@ -1769,6 +2254,11 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
{
rv = Value::new_i32(0);
}
+ else if( link_name == "pthread_rwlock_unlock" )
+ {
+ // TODO: Check that this thread holds the lock?
+ rv = Value::new_i32(0);
+ }
else if( link_name == "pthread_mutexattr_init" || link_name == "pthread_mutexattr_settype" || link_name == "pthread_mutexattr_destroy" )
{
rv = Value::new_i32(0);
@@ -1777,6 +2267,75 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
{
rv = Value::new_i32(0);
}
+ else if( link_name == "pthread_attr_init" || link_name == "pthread_attr_destroy" || link_name == "pthread_getattr_np" )
+ {
+ rv = Value::new_i32(0);
+ }
+ else if( link_name == "pthread_attr_setstacksize" )
+ {
+ // Lie and return succeess
+ rv = Value::new_i32(0);
+ }
+ else if( link_name == "pthread_attr_getguardsize" )
+ {
+ const auto attr_p = args.at(0).read_pointer_const(0, 1);
+ auto out_size = args.at(1).deref(0, HIR::TypeRef(RawType::USize));
+
+ out_size.m_alloc.alloc().write_usize(out_size.m_offset, 0x1000);
+
+ rv = Value::new_i32(0);
+ }
+ else if( link_name == "pthread_attr_getstack" )
+ {
+ const auto attr_p = args.at(0).read_pointer_const(0, 1);
+ auto out_ptr = args.at(2).deref(0, HIR::TypeRef(RawType::USize));
+ auto out_size = args.at(2).deref(0, HIR::TypeRef(RawType::USize));
+
+ out_size.m_alloc.alloc().write_usize(out_size.m_offset, 0x4000);
+
+ rv = Value::new_i32(0);
+ }
+ else if( link_name == "pthread_create" )
+ {
+ auto thread_handle_out = args.at(0).read_pointer_valref_mut(0, sizeof(pthread_t));
+ auto attrs = args.at(1).read_pointer_const(0, sizeof(pthread_attr_t));
+ auto fcn_path = args.at(2).get_relocation(0).fcn();
+ LOG_ASSERT(args.at(2).read_usize(0) == Allocation::PTR_BASE, "");
+ auto arg = args.at(3);
+ LOG_NOTICE("TODO: pthread_create(" << thread_handle_out << ", " << attrs << ", " << fcn_path << ", " << arg << ")");
+ // TODO: Create a new interpreter context with this thread, use co-operative scheduling
+ // HACK: Just run inline
+ if( true )
+ {
+ auto tls = ::std::move(m_thread.tls_values);
+ this->m_stack.push_back(StackFrame::make_wrapper([=](Value& out_rv, Value /*rv*/)mutable ->bool {
+ out_rv = Value::new_i32(0);
+ m_thread.tls_values = ::std::move(tls);
+ return true;
+ }));
+
+ // TODO: Catch the panic out of this.
+ if( this->call_path(rv, fcn_path, { ::std::move(arg) }) )
+ {
+ bool v = this->pop_stack(rv);
+ assert( v == false );
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else {
+ //this->m_parent.create_thread(fcn_path, arg);
+ rv = Value::new_i32(EPERM);
+ }
+ }
+ else if( link_name == "pthread_detach" )
+ {
+ // "detach" - Prevent the need to explitly join a thread
+ rv = Value::new_i32(0);
+ }
else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" )
{
rv = Value::new_i32(0);
@@ -1795,20 +2354,32 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
auto key = args.at(0).read_u32(0);
// Get a pointer-sized value from storage
- uint64_t v = key < m_thread.tls_values.size() ? m_thread.tls_values[key] : 0;
-
- rv = Value::new_usize(v);
+ if( key < m_thread.tls_values.size() )
+ {
+ const auto& e = m_thread.tls_values[key];
+ rv = Value::new_usize(e.first);
+ if( e.second )
+ {
+ rv.set_reloc(0, POINTER_SIZE, e.second);
+ }
+ }
+ else
+ {
+ // Return zero until populated
+ rv = Value::new_usize(0);
+ }
}
else if( link_name == "pthread_setspecific" )
{
auto key = args.at(0).read_u32(0);
auto v = args.at(1).read_u64(0);
+ auto v_reloc = args.at(1).get_relocation(0);
- // Get a pointer-sized value from storage
+ // Store a pointer-sized value in storage
if( key >= m_thread.tls_values.size() ) {
m_thread.tls_values.resize(key+1);
}
- m_thread.tls_values[key] = v;
+ m_thread.tls_values[key] = ::std::make_pair(v, v_reloc);
rv = Value::new_i32(0);
}
@@ -1816,6 +2387,72 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
{
rv = Value::new_i32(0);
}
+ // - Time
+ else if( link_name == "clock_gettime" )
+ {
+ // int clock_gettime(clockid_t clk_id, struct timespec *tp);
+ auto clk_id = args.at(0).read_u32(0);
+ auto tp_vr = args.at(1).read_pointer_valref_mut(0, sizeof(struct timespec));
+
+ LOG_DEBUG("clock_gettime(" << clk_id << ", " << tp_vr);
+ int rv_i = clock_gettime(clk_id, reinterpret_cast<struct timespec*>(tp_vr.data_ptr_mut()));
+ if(rv_i == 0)
+ tp_vr.mark_bytes_valid(0, tp_vr.m_size);
+ LOG_DEBUG("= " << rv_i << " (" << tp_vr << ")");
+ rv = Value::new_i32(rv_i);
+ }
+ // - Linux extensions
+ else if( link_name == "open64" )
+ {
+ const auto* path = FfiHelpers::read_cstr(args.at(0), 0);
+ auto flags = args.at(1).read_i32(0);
+ auto mode = (args.size() > 2 ? args.at(2).read_i32(0) : 0);
+
+ LOG_DEBUG("open64(\"" << path << "\", " << flags << ")");
+ int rv_i = open(path, flags, mode);
+ LOG_DEBUG("= " << rv_i);
+
+ rv = Value(::HIR::TypeRef(RawType::I32));
+ rv.write_i32(0, rv_i);
+ }
+ else if( link_name == "stat64" )
+ {
+ const auto* path = FfiHelpers::read_cstr(args.at(0), 0);
+ auto outbuf_vr = args.at(1).read_pointer_valref_mut(0, sizeof(struct stat));
+
+ LOG_DEBUG("stat64(\"" << path << "\", " << outbuf_vr << ")");
+ int rv_i = stat(path, reinterpret_cast<struct stat*>(outbuf_vr.data_ptr_mut()));
+ LOG_DEBUG("= " << rv_i);
+
+ if( rv_i == 0 )
+ {
+ // TODO: Mark the buffer as valid?
+ }
+
+ rv = Value(::HIR::TypeRef(RawType::I32));
+ rv.write_i32(0, rv_i);
+ }
+ else if( link_name == "__errno_location" )
+ {
+ rv = Value::new_ffiptr(FFIPointer::new_const_bytes("errno", &errno, sizeof(errno)));
+ }
+ else if( link_name == "syscall" )
+ {
+ auto num = args.at(0).read_u32(0);
+
+ LOG_DEBUG("syscall(" << num << ", ...) - hack return ENOSYS");
+ errno = ENOSYS;
+ rv = Value::new_i64(-1);
+ }
+ else if( link_name == "dlsym" )
+ {
+ auto handle = args.at(0).read_usize(0);
+ const char* name = FfiHelpers::read_cstr(args.at(1), 0);
+
+ LOG_DEBUG("dlsym(0x" << ::std::hex << handle << ", '" << name << "')");
+ LOG_NOTICE("dlsym stubbed to zero");
+ rv = Value::new_usize(0);
+ }
#endif
// std C
else if( link_name == "signal" )
@@ -1824,6 +2461,31 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
rv = Value(::HIR::TypeRef(RawType::USize));
rv.write_usize(0, 1);
}
+ else if( link_name == "sigaction" )
+ {
+ rv = Value::new_i32(-1);
+ }
+ else if( link_name == "sigaltstack" ) // POSIX: Set alternate signal stack
+ {
+ rv = Value::new_i32(-1);
+ }
+ else if( link_name == "memcmp" )
+ {
+ auto n = args.at(2).read_usize(0);
+ int rv_i;
+ if( n > 0 )
+ {
+ const void* ptr_b = args.at(1).read_pointer_const(0, n);
+ const void* ptr_a = args.at(0).read_pointer_const(0, n);
+
+ rv_i = memcmp(ptr_a, ptr_b, n);
+ }
+ else
+ {
+ rv_i = 0;
+ }
+ rv = Value::new_i32(rv_i);
+ }
// - `void *memchr(const void *s, int c, size_t n);`
else if( link_name == "memchr" )
{
@@ -1835,11 +2497,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
const void* ret = memchr(ptr, c, n);
rv = Value(::HIR::TypeRef(RawType::USize));
- rv.create_allocation();
if( ret )
{
- rv.write_usize(0, args.at(0).read_usize(0) + ( static_cast<const uint8_t*>(ret) - static_cast<const uint8_t*>(ptr) ));
- rv.allocation->relocations.push_back({ 0, ptr_alloc });
+ auto rv_ofs = args.at(0).read_usize(0) + ( static_cast<const uint8_t*>(ret) - static_cast<const uint8_t*>(ptr) );
+ rv.write_ptr(0, rv_ofs, ptr_alloc);
}
else
{
@@ -1856,11 +2517,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
const void* ret = memrchr(ptr, c, n);
rv = Value(::HIR::TypeRef(RawType::USize));
- rv.create_allocation();
if( ret )
{
- rv.write_usize(0, args.at(0).read_usize(0) + ( static_cast<const uint8_t*>(ret) - static_cast<const uint8_t*>(ptr) ));
- rv.allocation->relocations.push_back({ 0, ptr_alloc });
+ auto rv_ofs = args.at(0).read_usize(0) + ( static_cast<const uint8_t*>(ret) - static_cast<const uint8_t*>(ptr) );
+ rv.write_ptr(0, rv_ofs, ptr_alloc);
}
else
{
@@ -1870,21 +2530,35 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
else if( link_name == "strlen" )
{
// strlen - custom implementation to ensure validity
- bool _is_mut;
- size_t size;
- const char* ptr = reinterpret_cast<const char*>( args.at(0).read_pointer_unsafe(0, 1, size, _is_mut) );
size_t len = 0;
- while(size -- && *ptr)
- {
- ptr ++;
- len ++;
- }
- args.at(0).read_pointer_const(0, len + 1);
+ FfiHelpers::read_cstr(args.at(0), 0, &len);
//rv = Value::new_usize(len);
rv = Value(::HIR::TypeRef(RawType::USize));
rv.write_usize(0, len);
}
+ else if( link_name == "getenv" )
+ {
+ const auto* name = FfiHelpers::read_cstr(args.at(0), 0);
+ LOG_DEBUG("getenv(\"" << name << "\")");
+ const auto* ret_ptr = getenv(name);
+ if( ret_ptr )
+ {
+ LOG_DEBUG("= \"" << ret_ptr << "\"");
+ rv = Value::new_ffiptr(FFIPointer::new_const_bytes("getenv", ret_ptr, strlen(ret_ptr)+1));
+ }
+ else
+ {
+ LOG_DEBUG("= NULL");
+ rv = Value(::HIR::TypeRef(RawType::USize));
+ rv.create_allocation();
+ rv.write_usize(0,0);
+ }
+ }
+ else if( link_name == "setenv" )
+ {
+ LOG_TODO("Allow `setenv` without incurring thread unsafety");
+ }
// Allocators!
else
{
@@ -1893,7 +2567,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
return true;
}
-bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector<Value> args)
+bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const ::HIR::PathParams& ty_params, ::std::vector<Value> args)
{
TRACE_FUNCTION_R(name, rv);
for(const auto& a : args)
@@ -1907,15 +2581,69 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
{
it = type_ids.insert(it, ty_T);
}
-
+
rv = Value::with_size(POINTER_SIZE, false);
rv.write_usize(0, it - type_ids.begin());
}
+ else if( name == "type_name" )
+ {
+ const auto& ty_T = ty_params.tys.at(0);
+
+ static ::std::map<HIR::TypeRef, ::std::string> s_type_names;
+ auto it = s_type_names.find(ty_T);
+ if( it == s_type_names.end() )
+ {
+ it = s_type_names.insert( ::std::make_pair(ty_T, FMT_STRING(ty_T)) ).first;
+ }
+
+ rv = Value::with_size(2*POINTER_SIZE, /*needs_alloc=*/true);
+ rv.write_ptr(0*POINTER_SIZE, Allocation::PTR_BASE, RelocationPtr::new_string(&it->second));
+ rv.write_usize(1*POINTER_SIZE, 0);
+ }
+ else if( name == "discriminant_value" )
+ {
+ const auto& ty = ty_params.tys.at(0);
+ ValueRef val = args.at(0).deref(0, ty);
+
+ size_t fallback = SIZE_MAX;
+ size_t found_index = SIZE_MAX;
+ LOG_ASSERT(ty.inner_type == RawType::Composite, "discriminant_value " << ty);
+ for(size_t i = 0; i < ty.composite_type().variants.size(); i ++)
+ {
+ const auto& var = ty.composite_type().variants[i];
+ if( var.tag_data.size() == 0 )
+ {
+ // Only seen in Option<NonNull>
+ assert(fallback == SIZE_MAX);
+ fallback = i;
+ }
+ else
+ {
+ // Get offset to the tag
+ ::HIR::TypeRef tag_ty;
+ size_t tag_ofs = ty.get_field_ofs(var.base_field, var.field_path, tag_ty);
+ // Compare
+ if( val.compare(tag_ofs, var.tag_data.data(), var.tag_data.size()) == 0 )
+ {
+ found_index = i;
+ break ;
+ }
+ }
+ }
+
+ if( found_index == SIZE_MAX )
+ {
+ LOG_ASSERT(fallback != SIZE_MAX, "Can't find variant of " << ty << " for " << val);
+ found_index = fallback;
+ }
+
+ rv = Value::new_usize(found_index);
+ }
else if( name == "atomic_fence" || name == "atomic_fence_acq" )
{
rv = Value();
}
- else if( name == "atomic_store" )
+ else if( name == "atomic_store" || name == "atomic_store_relaxed" || name == "atomic_store_rel" )
{
auto& ptr_val = args.at(0);
auto& data_val = args.at(1);
@@ -1927,20 +2655,20 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
LOG_ASSERT(alloc, "Deref of a value with no relocation");
// TODO: Atomic side of this?
- size_t ofs = ptr_val.read_usize(0);
+ size_t ofs = ptr_val.read_usize(0) - Allocation::PTR_BASE;
alloc.alloc().write_value(ofs, ::std::move(data_val));
}
- else if( name == "atomic_load" || name == "atomic_load_relaxed" )
+ else if( name == "atomic_load" || name == "atomic_load_relaxed" || name == "atomic_load_acq" )
{
auto& ptr_val = args.at(0);
- LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "atomic_store of a value that isn't a pointer-sized value");
+ LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "atomic_load of a value that isn't a pointer-sized value");
// There MUST be a relocation at this point with a valid allocation.
auto alloc = ptr_val.get_relocation(0);
LOG_ASSERT(alloc, "Deref of a value with no relocation");
// TODO: Atomic lock the allocation.
- size_t ofs = ptr_val.read_usize(0);
+ size_t ofs = ptr_val.read_usize(0) - Allocation::PTR_BASE;
const auto& ty = ty_params.tys.at(0);
rv = alloc.alloc().read_value(ofs, ty.get_size());
@@ -1948,7 +2676,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
else if( name == "atomic_xadd" || name == "atomic_xadd_relaxed" )
{
const auto& ty_T = ty_params.tys.at(0);
- auto ptr_ofs = args.at(0).read_usize(0);
+ auto ptr_ofs = args.at(0).read_usize(0) - Allocation::PTR_BASE;
auto ptr_alloc = args.at(0).get_relocation(0);
auto v = args.at(1).read_value(0, ty_T.get_size());
@@ -1969,7 +2697,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
else if( name == "atomic_xsub" || name == "atomic_xsub_relaxed" || name == "atomic_xsub_rel" )
{
const auto& ty_T = ty_params.tys.at(0);
- auto ptr_ofs = args.at(0).read_usize(0);
+ auto ptr_ofs = args.at(0).read_usize(0) - Allocation::PTR_BASE;
auto ptr_alloc = args.at(0).get_relocation(0);
auto v = args.at(1).read_value(0, ty_T.get_size());
@@ -1987,7 +2715,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
val_l.get().write_to_value( ptr_alloc.alloc(), ptr_ofs );
}
- else if( name == "atomic_xchg" )
+ else if( name == "atomic_xchg" || name == "atomic_xchg_acqrel" )
{
const auto& ty_T = ty_params.tys.at(0);
auto data_ref = args.at(0).read_pointer_valref_mut(0, ty_T.get_size());
@@ -2006,7 +2734,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
rv = Value::with_size( ty_T.get_size() + 1, false );
rv.write_value(0, data_ref.read_value(0, old_v.size()));
LOG_DEBUG("> *ptr = " << data_ref);
- if( data_ref.compare(old_v.data_ptr(), old_v.size()) == true ) {
+ if( data_ref.compare(0, old_v.data_ptr(), old_v.size()) == true ) {
data_ref.m_alloc.alloc().write_value( data_ref.m_offset, new_v );
rv.write_u8( old_v.size(), 1 );
}
@@ -2027,6 +2755,27 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
{
auto ptr_alloc = args.at(0).get_relocation(0);
auto ptr_ofs = args.at(0).read_usize(0);
+ LOG_ASSERT(ptr_ofs >= Allocation::PTR_BASE, "`offset` with invalid pointer - " << args.at(0));
+ auto& ofs_val = args.at(1);
+
+ auto delta_counts = ofs_val.read_usize(0);
+ auto ty_size = ty_params.tys.at(0).get_size();
+ LOG_DEBUG("\"offset\": 0x" << ::std::hex << ptr_ofs << " + 0x" << delta_counts << " * 0x" << ty_size);
+ ptr_ofs -= Allocation::PTR_BASE;
+ auto new_ofs = ptr_ofs + delta_counts * ty_size;
+ if(POINTER_SIZE != 8) {
+ new_ofs &= 0xFFFFFFFF;
+ }
+
+ rv = ::std::move(args.at(0));
+ rv.write_ptr(0, Allocation::PTR_BASE + new_ofs, ptr_alloc);
+ }
+ else if( name == "arith_offset" ) // Doesn't check validity, and allows wrapping
+ {
+ auto ptr_alloc = args.at(0).get_relocation(0);
+ auto ptr_ofs = args.at(0).read_usize(0);
+ //LOG_ASSERT(ptr_ofs >= Allocation::PTR_BASE, "`offset` with invalid pointer - " << args.at(0));
+ //ptr_ofs -= Allocation::PTR_BASE;
auto& ofs_val = args.at(1);
auto delta_counts = ofs_val.read_usize(0);
@@ -2034,11 +2783,16 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
if(POINTER_SIZE != 8) {
new_ofs &= 0xFFFFFFFF;
}
+ //new_ofs += Allocation::PTR_BASE;
rv = ::std::move(args.at(0));
- rv.write_usize(0, new_ofs);
- if( ptr_alloc ) {
- rv.allocation->relocations.push_back({ 0, ptr_alloc });
+ if( ptr_alloc )
+ {
+ rv.write_ptr(0, new_ofs, ptr_alloc);
+ }
+ else
+ {
+ rv.write_usize(0, new_ofs);
}
}
// effectively ptr::write
@@ -2047,18 +2801,13 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
auto& ptr_val = args.at(0);
auto& data_val = args.at(1);
- LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "move_val_init of an address that isn't a pointer-sized value");
-
// There MUST be a relocation at this point with a valid allocation.
- LOG_ASSERT(ptr_val.allocation, "Deref of a value with no allocation (hence no relocations)");
- LOG_TRACE("Deref " << ptr_val << " and store " << data_val);
-
- auto ptr_alloc = ptr_val.get_relocation(0);
- LOG_ASSERT(ptr_alloc, "Deref of a value with no relocation");
+ // - TODO: What about FFI? (can't be a string or function though)
+ auto dst_vr = ptr_val.deref(0, ty_params.tys.at(0));
+ LOG_ASSERT(dst_vr.m_alloc, "Deref didn't yeild an allocation (error?)");
+ LOG_ASSERT(dst_vr.m_alloc.is_alloc(), "Deref didn't yield an allocation");
- size_t ofs = ptr_val.read_usize(0);
- ptr_alloc.alloc().write_value(ofs, ::std::move(data_val));
- LOG_DEBUG(ptr_alloc.alloc());
+ dst_vr.m_alloc.alloc().write_value(dst_vr.m_offset, ::std::move(data_val));
}
else if( name == "uninit" )
{
@@ -2069,6 +2818,22 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
rv = Value(ty_params.tys.at(0));
rv.mark_bytes_valid(0, rv.size());
}
+ else if( name == "write_bytes" )
+ {
+ auto& dst_ptr_v = args.at(0);
+ auto byte = args.at(1).read_u8(0);
+ auto count = args.at(2).read_usize(0);
+ auto bytes = count * ty_params.tys.at(0).get_size();
+
+ LOG_DEBUG("'write_bytes'(" << dst_ptr_v << ", " << (int)byte << ", " << count << "): bytes=" << bytes);
+
+ if( count > 0 )
+ {
+ auto dst_vr = dst_ptr_v.read_pointer_valref_mut(0, bytes);
+ memset(dst_vr.data_ptr_mut(), byte, bytes);
+ dst_vr.mark_bytes_valid(0, bytes);
+ }
+ }
// - Unsized stuff
else if( name == "size_of_val" )
{
@@ -2097,7 +2862,12 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
}
else if( ity->inner_type == RawType::TraitObject )
{
- LOG_TODO("size_of_val - Trait Object - " << ty);
+ auto vtable_ty = meta_ty.get_inner();
+ LOG_DEBUG("> vtable_ty = " << vtable_ty << " (size= " << vtable_ty.get_size() << ")");
+ auto vtable = val.deref(POINTER_SIZE, vtable_ty);
+ LOG_DEBUG("> vtable = " << vtable);
+ auto size = vtable.read_usize(1*POINTER_SIZE);
+ flex_size = size;
}
else
{
@@ -2111,12 +2881,86 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
rv.write_usize(0, ty.get_size());
}
}
+ else if( name == "min_align_of_val" )
+ {
+ /*const*/ auto& val = args.at(0);
+ const auto& ty = ty_params.tys.at(0);
+ rv = Value(::HIR::TypeRef(RawType::USize));
+ size_t fixed_size = 0; // unused
+ size_t flex_align = 0;
+ if( const auto* ity = ty.get_unsized_type(fixed_size) )
+ {
+ if( const auto* w = ity->get_wrapper() )
+ {
+ LOG_ASSERT(w->type == TypeWrapper::Ty::Slice, "align_of_val on wrapped type that isn't a slice - " << *ity);
+ flex_align = ity->get_inner().get_align();
+ }
+ else if( ity->inner_type == RawType::Str )
+ {
+ flex_align = 1;
+ }
+ else if( ity->inner_type == RawType::TraitObject )
+ {
+ const auto meta_ty = ty.get_meta_type();
+ auto vtable_ty = meta_ty.get_inner();
+ LOG_DEBUG("> vtable_ty = " << vtable_ty << " (size= " << vtable_ty.get_size() << ")");
+ auto vtable = val.deref(POINTER_SIZE, vtable_ty);
+ LOG_DEBUG("> vtable = " << vtable);
+ flex_align = vtable.read_usize(2*POINTER_SIZE);
+ }
+ else
+ {
+ LOG_BUG("Inner unsized type unknown - " << *ity);
+ }
+ }
+ rv.write_usize(0, ::std::max( ty.get_align(), flex_align ));
+ }
else if( name == "drop_in_place" )
{
auto& val = args.at(0);
const auto& ty = ty_params.tys.at(0);
return drop_value(val, ty);
}
+ else if( name == "try" )
+ {
+ auto fcn_path = args.at(0).get_relocation(0).fcn();
+ auto arg = args.at(1);
+ auto out_panic_value = args.at(2).read_pointer_valref_mut(0, POINTER_SIZE);
+
+ ::std::vector<Value> sub_args;
+ sub_args.push_back( ::std::move(arg) );
+
+ this->m_stack.push_back(StackFrame::make_wrapper([=](Value& out_rv, Value /*rv*/)mutable->bool{
+ if( m_thread.panic_active )
+ {
+ assert(m_thread.panic_count > 0);
+ m_thread.panic_active = false;
+ m_thread.panic_count --;
+ LOG_ASSERT(m_thread.panic_value.size() == out_panic_value.m_size, "Panic value " << m_thread.panic_value << " doesn't fit in " << out_panic_value);
+ out_panic_value.m_alloc.alloc().write_value( out_panic_value.m_offset, ::std::move(m_thread.panic_value) );
+ out_rv = Value::new_u32(1);
+ return true;
+ }
+ else
+ {
+ LOG_ASSERT(m_thread.panic_count == 0, "Panic count non-zero, but previous function returned non-panic");
+ out_rv = Value::new_u32(0);
+ return true;
+ }
+ }));
+
+ // TODO: Catch the panic out of this.
+ if( this->call_path(rv, fcn_path, ::std::move(sub_args)) )
+ {
+ bool v = this->pop_stack(rv);
+ assert( v == false );
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
// ----------------------------------------------------------------
// Checked arithmatic
else if( name == "add_with_overflow" )
@@ -2158,7 +3002,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
else if( name == "mul_with_overflow" )
{
const auto& ty = ty_params.tys.at(0);
-
+
auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
bool didnt_overflow = lhs.get().multiply( rhs.get() );
@@ -2173,6 +3017,24 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
lhs.get().write_to_value(rv, dty.fields[0].first);
rv.write_u8( dty.fields[1].first, didnt_overflow ? 0 : 1 ); // Returns true if overflow happened
}
+ // - "exact_div" :: Normal divide, but UB if not an exact multiple
+ else if( name == "exact_div" )
+ {
+ const auto& ty = ty_params.tys.at(0);
+
+ auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
+ auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
+
+ LOG_ASSERT(!rhs.get().is_zero(), "`exact_div` with zero divisor: " << args.at(0) << " / " << args.at(1));
+ auto rem = lhs;
+ rem.get().modulo( rhs.get() );
+ LOG_ASSERT(rem.get().is_zero(), "`exact_div` with yielded non-zero remainder: " << args.at(0) << " / " << args.at(1));
+ bool didnt_overflow = lhs.get().divide( rhs.get() );
+ LOG_ASSERT(didnt_overflow, "`exact_div` failed for unknown reason: " << args.at(0) << " /" << args.at(1));
+
+ rv = Value(ty);
+ lhs.get().write_to_value(rv, 0);
+ }
// Overflowing artithmatic
else if( name == "overflowing_sub" )
{
@@ -2181,6 +3043,18 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
lhs.get().subtract( rhs.get() );
+ // TODO: Overflowing part
+
+ rv = Value(ty);
+ lhs.get().write_to_value(rv, 0);
+ }
+ else if( name == "overflowing_add" )
+ {
+ const auto& ty = ty_params.tys.at(0);
+
+ auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
+ auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
+ lhs.get().add( rhs.get() );
rv = Value(ty);
lhs.get().write_to_value(rv, 0);
@@ -2189,40 +3063,29 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
// memcpy
else if( name == "copy_nonoverlapping" )
{
- auto src_ofs = args.at(0).read_usize(0);
- auto src_alloc = args.at(0).get_relocation(0);
- auto dst_ofs = args.at(1).read_usize(0);
- auto dst_alloc = args.at(1).get_relocation(0);
+ //auto src_ofs = args.at(0).read_usize(0);
+ //auto src_alloc = args.at(0).get_relocation(0);
+ //auto dst_ofs = args.at(1).read_usize(0);
+ //auto dst_alloc = args.at(1).get_relocation(0);
size_t ent_count = args.at(2).read_usize(0);
size_t ent_size = ty_params.tys.at(0).get_size();
auto byte_count = ent_count * ent_size;
+ LOG_DEBUG("`copy_nonoverlapping`: byte_count=" << byte_count);
- LOG_ASSERT(src_alloc, "Source of copy* must have an allocation");
- LOG_ASSERT(dst_alloc, "Destination of copy* must be a memory allocation");
- LOG_ASSERT(dst_alloc.is_alloc(), "Destination of copy* must be a memory allocation");
-
- switch(src_alloc.get_ty())
+ // A count of zero doesn't need to do any of the checks (TODO: Validate this rule)
+ if( byte_count > 0 )
{
- case RelocationPtr::Ty::Allocation: {
- auto v = src_alloc.alloc().read_value(src_ofs, byte_count);
- LOG_DEBUG("v = " << v);
- dst_alloc.alloc().write_value(dst_ofs, ::std::move(v));
- } break;
- case RelocationPtr::Ty::StdString:
- LOG_ASSERT(src_ofs <= src_alloc.str().size(), "");
- LOG_ASSERT(byte_count <= src_alloc.str().size(), "");
- LOG_ASSERT(src_ofs + byte_count <= src_alloc.str().size(), "");
- dst_alloc.alloc().write_bytes(dst_ofs, src_alloc.str().data() + src_ofs, byte_count);
- break;
- case RelocationPtr::Ty::Function:
- LOG_FATAL("Attempt to copy* a function");
- break;
- case RelocationPtr::Ty::FfiPointer:
- LOG_ASSERT(src_ofs <= src_alloc.ffi().size, "");
- LOG_ASSERT(byte_count <= src_alloc.ffi().size, "");
- LOG_ASSERT(src_ofs + byte_count <= src_alloc.ffi().size, "");
- dst_alloc.alloc().write_bytes(dst_ofs, reinterpret_cast<const char*>(src_alloc.ffi().ptr_value) + src_ofs, byte_count);
- break;
+ auto src_vr = args.at(0).read_pointer_valref_mut(0, byte_count);
+ auto dst_vr = args.at(1).read_pointer_valref_mut(0, byte_count);
+
+ auto& dst_alloc = dst_vr.m_alloc;
+ LOG_ASSERT(dst_alloc, "Destination of copy* must be a memory allocation");
+ LOG_ASSERT(dst_alloc.is_alloc(), "Destination of copy* must be a memory allocation");
+
+ // TODO: is this inefficient?
+ auto src_val = src_vr.read_value(0, byte_count);
+ LOG_DEBUG("src_val = " << src_val);
+ dst_alloc.alloc().write_value(dst_vr.m_offset, ::std::move(src_val));
}
}
else
@@ -2235,6 +3098,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con
// TODO: Use a ValueRef instead?
bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_shallow/*=false*/)
{
+ TRACE_FUNCTION_R(ptr << ": " << ty << (is_shallow ? " (shallow)" : ""), "");
// TODO: After the drop is done, flag the backing allocation for `ptr` as freed
if( is_shallow )
{
@@ -2242,7 +3106,7 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_
auto box_ptr_vr = ptr.read_pointer_valref_mut(0, POINTER_SIZE);
auto ofs = box_ptr_vr.read_usize(0);
auto alloc = box_ptr_vr.get_relocation(0);
- if( ofs != 0 || !alloc || !alloc.is_alloc() ) {
+ if( ofs != Allocation::PTR_BASE || !alloc || !alloc.is_alloc() ) {
LOG_ERROR("Attempting to shallow drop with invalid pointer (no relocation or non-zero offset) - " << box_ptr_vr);
}
@@ -2273,6 +3137,7 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_
case TypeWrapper::Ty::Slice: {
// - Get thin pointer and count
auto ofs = ptr.read_usize(0);
+ LOG_ASSERT(ofs >= Allocation::PTR_BASE, "");
auto ptr_reloc = ptr.get_relocation(0);
auto count = ptr.read_usize(POINTER_SIZE);
@@ -2281,8 +3146,28 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_
for(uint64_t i = 0; i < count; i ++)
{
auto ptr = Value::new_pointer(pty, ofs, ptr_reloc);
- if( !drop_value(ptr, ity) ) {
- LOG_TODO("Handle closure looping when dropping a slice");
+ if( !drop_value(ptr, ity) )
+ {
+ // - This is trying to invoke custom drop glue, need to suspend this operation and come back later
+
+ // > insert a new frame shim BEFORE the current top (which would be the frame created by
+ // `drop_value` calling a function)
+ m_stack.insert( m_stack.end() - 1, StackFrame::make_wrapper([this,pty,ity,ptr_reloc,count, i,ofs](Value& rv, Value drop_rv) mutable {
+ assert(i < count);
+ i ++;
+ ofs += ity.get_size();
+ if( i < count )
+ {
+ auto ptr = Value::new_pointer(pty, ofs, ptr_reloc);
+ assert(!drop_value(ptr, ity));
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }) );
+ return false;
}
ofs += ity.get_size();
}
@@ -2297,12 +3182,12 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_
{
if( ty.inner_type == RawType::Composite )
{
- if( ty.composite_type->drop_glue != ::HIR::Path() )
+ if( ty.composite_type().drop_glue != ::HIR::Path() )
{
LOG_DEBUG("Drop - " << ty);
Value tmp;
- return this->call_path(tmp, ty.composite_type->drop_glue, { ptr });
+ return this->call_path(tmp, ty.composite_type().drop_glue, { ptr });
}
else
{
@@ -2311,7 +3196,21 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_
}
else if( ty.inner_type == RawType::TraitObject )
{
- LOG_TODO("Drop - " << ty << " - trait object");
+ // Get the drop glue from the vtable (first entry)
+ auto inner_ptr = ptr.read_value(0, POINTER_SIZE);
+ auto vtable = ptr.deref(POINTER_SIZE, ty.get_meta_type().get_inner());
+ auto drop_r = vtable.get_relocation(0);
+ if( drop_r )
+ {
+ LOG_ASSERT(drop_r.get_ty() == RelocationPtr::Ty::Function, "");
+ auto fcn = drop_r.fcn();
+ static Value tmp;
+ return this->call_path(tmp, fcn, { ::std::move(inner_ptr) });
+ }
+ else
+ {
+ // None
+ }
}
else
{
diff --git a/tools/standalone_miri/miri.hpp b/tools/standalone_miri/miri.hpp
index 6f02ffee..f835fedb 100644
--- a/tools/standalone_miri/miri.hpp
+++ b/tools/standalone_miri/miri.hpp
@@ -13,10 +13,16 @@ struct ThreadState
{
static unsigned s_next_tls_key;
unsigned call_stack_depth;
- ::std::vector<uint64_t> tls_values;
+ ::std::vector< ::std::pair<uint64_t, RelocationPtr> > tls_values;
+
+ unsigned panic_count;
+ bool panic_active;
+ Value panic_value;
ThreadState():
call_stack_depth(0)
+ ,panic_count(0)
+ ,panic_active(false)
{
}
@@ -35,8 +41,11 @@ class InterpreterThread
friend struct MirHelpers;
struct StackFrame
{
+ static unsigned s_next_frame_index;
+ unsigned frame_index;
+
::std::function<bool(Value&,Value)> cb;
- const Function& fcn;
+ const Function* fcn;
Value ret;
::std::vector<Value> args;
::std::vector<Value> locals;
@@ -56,11 +65,13 @@ class InterpreterThread
ModuleTree& m_modtree;
ThreadState m_thread;
+ size_t m_instruction_count;
::std::vector<StackFrame> m_stack;
public:
InterpreterThread(ModuleTree& modtree):
- m_modtree(modtree)
+ m_modtree(modtree),
+ m_instruction_count(0)
{
}
~InterpreterThread();
@@ -77,7 +88,7 @@ private:
// Returns true if the call was resolved instantly
bool call_extern(Value& ret_val, const ::std::string& name, const ::std::string& abi, ::std::vector<Value> args);
// Returns true if the call was resolved instantly
- bool call_intrinsic(Value& ret_val, const ::std::string& name, const ::HIR::PathParams& pp, ::std::vector<Value> args);
+ bool call_intrinsic(Value& ret_val, const RcString& name, const ::HIR::PathParams& pp, ::std::vector<Value> args);
// Returns true if the call was resolved instantly
bool drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_shallow=false);
diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp
index 8e0a231a..91d82d85 100644
--- a/tools/standalone_miri/module_tree.cpp
+++ b/tools/standalone_miri/module_tree.cpp
@@ -57,6 +57,24 @@ void ModuleTree::load_file(const ::std::string& path)
// Keep going!
}
}
+void ModuleTree::validate()
+{
+ TRACE_FUNCTION_R("", "");
+ for(const auto& dt : this->data_types)
+ {
+ //LOG_ASSERT(dt.second->populated, "Type " << dt.first << " never defined");
+ }
+
+ for(const auto& fcn : this->functions)
+ {
+ // TODO: This doesn't actually happen yet (this combination can't be parsed)
+ if( fcn.second.external.link_name != "" && !fcn.second.m_mir.blocks.empty() )
+ {
+ LOG_DEBUG(fcn.first << " = '" << fcn.second.external.link_name << "'");
+ ext_functions.insert(::std::make_pair( fcn.second.external.link_name, &fcn.second ));
+ }
+ }
+}
// Parse a single item from a .mir file
bool Parser::parse_one()
{
@@ -99,25 +117,26 @@ bool Parser::parse_one()
rv_ty = parse_type();
}
+ Function::ExtInfo ext;
if( lex.consume_if('=') )
{
- auto link_name = ::std::move(lex.check_consume(TokenClass::String).strval);
+ ext.link_name = ::std::move(lex.check_consume(TokenClass::String).strval);
lex.check_consume(':');
- auto abi = ::std::move(lex.check_consume(TokenClass::String).strval);
- lex.check_consume(';');
-
+ ext.link_abi = ::std::move(lex.check_consume(TokenClass::String).strval);
+ }
+ ::MIR::Function body;
+ if( lex.consume_if(';') )
+ {
LOG_DEBUG(lex << "extern fn " << p);
- auto p2 = p;
- tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, {link_name, abi}, {} }) );
}
else
{
- auto body = parse_body();
+ body = parse_body();
LOG_DEBUG(lex << "fn " << p);
- auto p2 = p;
- tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, {}, ::std::move(body) }) );
}
+ auto p2 = p;
+ tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, ::std::move(ext), ::std::move(body) }) );
}
else if( lex.consume_if("static") )
{
@@ -133,8 +152,7 @@ bool Parser::parse_one()
Static s;
s.val = Value(ty);
// - Statics need to always have an allocation (for references)
- if( !s.val.allocation )
- s.val.create_allocation();
+ s.val.ensure_allocation();
s.val.write_bytes(0, data.data(), data.size());
s.ty = ty;
@@ -153,15 +171,14 @@ bool Parser::parse_one()
{
auto reloc_str = ::std::move(lex.consume().strval);
- auto a = Allocation::new_alloc( reloc_str.size() );
- //a.alloc().set_tag();
+ auto a = Allocation::new_alloc( reloc_str.size(), FMT_STRING("static " << p) );
a->write_bytes(0, reloc_str.data(), reloc_str.size());
- s.val.allocation->relocations.push_back({ static_cast<size_t>(ofs), /*size,*/ RelocationPtr::new_alloc(::std::move(a)) });
+ s.val.set_reloc( ofs, size, RelocationPtr::new_alloc(::std::move(a)) );
}
else if( lex.next() == "::" || lex.next() == "<" )
{
auto reloc_path = parse_path();
- s.val.allocation->relocations.push_back({ static_cast<size_t>(ofs), /*size,*/ RelocationPtr::new_fcn(reloc_path) });
+ s.val.set_reloc( ofs, size, RelocationPtr::new_fcn(reloc_path) );
}
else
{
@@ -185,6 +202,7 @@ bool Parser::parse_one()
//LOG_TRACE("type " << p);
auto rv = DataType {};
+ rv.populated = true;
rv.my_path = p;
lex.check_consume('{');
@@ -332,9 +350,6 @@ bool Parser::parse_one()
struct H
{
- static ::std::unique_ptr<::MIR::LValue> make_lvp(::MIR::LValue&& lv) {
- return ::std::unique_ptr<::MIR::LValue>(new ::MIR::LValue(::std::move(lv)));
- }
//
// Parse a LValue
//
@@ -357,7 +372,7 @@ bool Parser::parse_one()
if( name.substr(0,3) == "arg" ) {
try {
auto idx = static_cast<unsigned>( ::std::stol(name.substr(3)) );
- lv = ::MIR::LValue::make_Argument({ idx });
+ lv = ::MIR::LValue::new_Argument( idx );
}
catch(const ::std::exception& e) {
LOG_ERROR(lex << "Invalid argument name - " << name << " - " << e.what());
@@ -365,7 +380,7 @@ bool Parser::parse_one()
}
// Hard-coded "RETURN" lvalue
else if( name == "RETURN" ) {
- lv = ::MIR::LValue::make_Return({});
+ lv = ::MIR::LValue::new_Return();
}
// Otherwise, look up variable names
else {
@@ -373,13 +388,13 @@ bool Parser::parse_one()
if( it == var_names.end() ) {
LOG_ERROR(lex << "Cannot find variable named '" << name << "'");
}
- lv = ::MIR::LValue::make_Local(static_cast<unsigned>(it - var_names.begin()));
+ lv = ::MIR::LValue::new_Local(static_cast<unsigned>(it - var_names.begin()));
}
}
else if( lex.next() == "::" || lex.next() == '<' )
{
auto path = p.parse_path();
- lv = ::MIR::LValue( ::std::move(path) );
+ lv = ::MIR::LValue::new_Static( ::std::move(path) );
}
else {
LOG_ERROR(lex << "Unexpected token in LValue - " << lex.next());
@@ -390,19 +405,19 @@ bool Parser::parse_one()
{
lex.check(TokenClass::Integer);
auto idx = static_cast<unsigned>( lex.consume().integer() );
- lv = ::MIR::LValue::make_Downcast({ make_lvp(::std::move(lv)), idx });
+ lv = ::MIR::LValue::new_Downcast(::std::move(lv), idx);
}
else if( lex.consume_if('.') )
{
lex.check(TokenClass::Integer);
auto idx = static_cast<unsigned>( lex.consume().integer() );
- lv = ::MIR::LValue::make_Field({ make_lvp(::std::move(lv)), idx });
+ lv = ::MIR::LValue::new_Field( ::std::move(lv), idx );
}
else if( lex.next() == '[' )
{
lex.consume();
auto idx_lv = parse_lvalue(p, var_names);
- lv = ::MIR::LValue::make_Index({ make_lvp(::std::move(lv)), make_lvp(::std::move(idx_lv)) });
+ lv = ::MIR::LValue::new_Index(::std::move(lv), idx_lv.as_Local());
lex.check_consume(']');
}
else
@@ -412,7 +427,7 @@ bool Parser::parse_one()
}
while(deref --)
{
- lv = ::MIR::LValue::make_Deref({ make_lvp(::std::move(lv)) });
+ lv = ::MIR::LValue::new_Deref( ::std::move(lv) );
}
return lv;
}
@@ -464,7 +479,7 @@ bool Parser::parse_one()
else if( p.lex.consume_if("ADDROF") ) {
auto path = p.parse_path();
- return ::MIR::Constant::make_ItemAddr({ ::std::move(path) });
+ return ::MIR::Constant::make_ItemAddr({ ::std::make_unique<HIR::Path>(::std::move(path)) });
}
else {
LOG_BUG(p.lex << "BUG? " << p.lex.next());
@@ -867,7 +882,7 @@ bool Parser::parse_one()
::std::vector<unsigned> targets;
while(lex.next() != '{')
{
- targets.push_back( static_cast<unsigned>(lex.consume().integer()) );
+ targets.push_back( static_cast<unsigned>(lex.check_consume(TokenClass::Integer).integer()) );
if( !lex.consume_if(',') )
break;
}
@@ -936,7 +951,7 @@ bool Parser::parse_one()
lex.check_consume(')');
}
else if( lex.next() == TokenClass::String ) {
- auto name = ::std::move(lex.consume().strval);
+ auto name = RcString::new_interned(lex.consume().strval);
auto params = parse_pathparams();
ct = ::MIR::CallTarget::make_Intrinsic({ ::std::move(name), ::std::move(params) });
}
@@ -1214,7 +1229,14 @@ RawType Parser::parse_core_type()
{
ret_ty = ::HIR::TypeRef::unit();
}
- return ::HIR::TypeRef(RawType::Function);
+ auto ft = FunctionType {
+ is_unsafe,
+ ::std::move(abi),
+ ::std::move(args),
+ ::std::move(ret_ty)
+ };
+ const auto* ft_p = &*tree.function_types.insert(::std::move(ft)).first;
+ return ::HIR::TypeRef(ft_p);
// TODO: Use abi/ret_ty/args as part of that
}
else if( lex.consume_if("dyn") )
@@ -1262,14 +1284,28 @@ RawType Parser::parse_core_type()
}
lex.consume_if(')');
+ // Ignore marker traits.
+
auto rv = ::HIR::TypeRef(RawType::TraitObject);
if( base_trait != ::HIR::GenericPath() )
{
// Generate vtable path
auto vtable_path = base_trait;
vtable_path.m_simplepath.ents.back() += "#vtable";
- // - TODO: Associated types?
- rv.composite_type = this->get_composite( ::std::move(vtable_path) );
+ if( atys.size() > 1 )
+ {
+ LOG_TODO("Handle multiple ATYs in vtable path");
+ }
+ else if( atys.size() == 1 )
+ {
+ vtable_path.m_params.tys.push_back( ::std::move(atys[0].second) );
+ }
+ // - TODO: Associated types? (Need to ensure ordering is correct)
+ rv.ptr.composite_type = this->get_composite( ::std::move(vtable_path) );
+ }
+ else
+ {
+ // TODO: vtable for empty trait?
}
return rv;
}
@@ -1289,6 +1325,7 @@ const DataType* Parser::get_composite(::HIR::GenericPath gp)
{
// TODO: Later on need to check if the type is valid.
auto v = ::std::make_unique<DataType>(DataType {});
+ v->populated = false;
v->my_path = gp;
auto ir = tree.data_types.insert(::std::make_pair( ::std::move(gp), ::std::move(v)) );
it = ir.first;
@@ -1318,6 +1355,15 @@ const Function* ModuleTree::get_function_opt(const ::HIR::Path& p) const
}
return &it->second;
}
+const Function* ModuleTree::get_ext_function(const char* name) const
+{
+ auto it = ext_functions.find(name);
+ if( it == ext_functions.end() )
+ {
+ return nullptr;
+ }
+ return it->second;
+}
Static& ModuleTree::get_static(const ::HIR::Path& p)
{
auto it = statics.find(p);
diff --git a/tools/standalone_miri/module_tree.hpp b/tools/standalone_miri/module_tree.hpp
index efa0a034..299aa51c 100644
--- a/tools/standalone_miri/module_tree.hpp
+++ b/tools/standalone_miri/module_tree.hpp
@@ -11,6 +11,7 @@
#include <map>
#include <set>
+#include "../../src/include/rc_string.hpp"
#include "../../src/mir/mir.hpp"
#include "hir_sim.hpp"
#include "value.hpp"
@@ -22,7 +23,7 @@ struct Function
::HIR::TypeRef ret_ty;
// If `link_name` is non-empty, then the function is an external
- struct {
+ struct ExtInfo {
::std::string link_name;
::std::string link_abi;
} external;
@@ -47,14 +48,20 @@ class ModuleTree
// Hack: Tuples are stored as `::""::<A,B,C,...>`
::std::map<::HIR::GenericPath, ::std::unique_ptr<DataType>> data_types;
+
+ ::std::set<FunctionType> function_types; // note: insertion doesn't invaliate pointers.
+
+ ::std::map<::std::string, const Function*> ext_functions;
public:
ModuleTree();
void load_file(const ::std::string& path);
+ void validate();
::HIR::SimplePath find_lang_item(const char* name) const;
const Function& get_function(const ::HIR::Path& p) const;
const Function* get_function_opt(const ::HIR::Path& p) const;
+ const Function* get_ext_function(const char* name) const;
Static& get_static(const ::HIR::Path& p);
Static* get_static_opt(const ::HIR::Path& p);
@@ -66,16 +73,15 @@ public:
// struct/union/enum
struct DataType
{
+ bool populated;
::HIR::GenericPath my_path;
- // TODO: Store the name of this type for logging?
-
- // TODO: Metadata type! (indicates an unsized wrapper)
- // TODO: Drop glue
size_t alignment;
size_t size;
+ // Drop glue
::HIR::Path drop_glue;
+ // Metadata type! (indicates an unsized wrapper)
::HIR::TypeRef dst_meta;
// Offset and datatype
@@ -91,3 +97,21 @@ struct DataType
};
::std::vector<VariantValue> variants;
};
+
+struct FunctionType
+{
+ bool unsafe;
+ ::std::string abi;
+ ::std::vector<HIR::TypeRef> args;
+ HIR::TypeRef ret;
+
+ bool operator<(const FunctionType& x) const {
+ #define _(f) if(f != x.f) return f < x.f
+ _(unsafe);
+ _(abi);
+ _(args);
+ _(ret);
+ #undef _
+ return false;
+ }
+};
diff --git a/tools/standalone_miri/u128.hpp b/tools/standalone_miri/u128.hpp
new file mode 100644
index 00000000..8403b94a
--- /dev/null
+++ b/tools/standalone_miri/u128.hpp
@@ -0,0 +1,170 @@
+#pragma once
+
+class U128
+{
+ friend class I128;
+ uint64_t lo, hi;
+public:
+ U128(): lo(0), hi(0) {}
+
+ U128(uint8_t v): lo(v), hi(0) {}
+ U128(int8_t v): lo(v), hi(v < 0 ? -1 : 0) {}
+
+ void fmt(::std::ostream& os) const { os << hi << ":" << lo; }
+
+ int cmp(U128 v) const {
+ if( hi != v.hi ) {
+ return (hi < v.hi ? -1 : 1);
+ }
+ if( lo != v.lo ) {
+ return (lo < v.lo ? -1 : 1);
+ }
+ return 0;
+ }
+ int cmp(unsigned v) const {
+ if(hi)
+ return 1;
+ if(lo < v)
+ return -1;
+ if(lo > v)
+ return 1;
+ return 0;
+ }
+
+ template<typename T> bool operator< (const T& v) const { return this->cmp(v) < 0; }
+ template<typename T> bool operator<=(const T& v) const { return this->cmp(v) <= 0; }
+ template<typename T> bool operator> (const T& v) const { return this->cmp(v) > 0; }
+ template<typename T> bool operator>=(const T& v) const { return this->cmp(v) >= 0; }
+ template<typename T> bool operator==(const T& v) const { return this->cmp(v) == 0; }
+ template<typename T> bool operator!=(const T& v) const { return this->cmp(v) != 0; }
+
+ operator uint8_t() const { return static_cast<uint8_t>(lo); }
+
+ U128 operator&(U128 x) const {
+ U128 rv;
+ rv.lo = this->lo & x.lo;
+ rv.hi = this->hi & x.hi;
+ return rv;
+ }
+ U128 operator|(U128 x) const {
+ U128 rv;
+ rv.lo = this->lo | x.lo;
+ rv.hi = this->hi | x.hi;
+ return rv;
+ }
+ U128 operator^(U128 x) const {
+ U128 rv;
+ rv.lo = this->lo ^ x.lo;
+ rv.hi = this->hi ^ x.hi;
+ return rv;
+ }
+
+ U128 operator<<(U128 n) const
+ {
+ if( n < 128 )
+ {
+ return *this << static_cast<uint8_t>(n);
+ }
+ else
+ {
+ return U128();
+ }
+ }
+ U128 operator<<(uint8_t n) const
+ {
+ if(n == 0)
+ {
+ return *this;
+ }
+ else if( n < 64 )
+ {
+ U128 rv;
+ rv.lo = lo << n;
+ rv.hi = (hi << n) | (lo >> (64-n));
+ return rv;
+ }
+ else if( n < 128 )
+ {
+ U128 rv;
+ rv.lo = 0;
+ rv.hi = (lo << (n-64));
+ return rv;
+ }
+ else
+ {
+ return U128();
+ }
+ }
+ U128 operator>>(uint8_t n) const
+ {
+ if(n == 0)
+ {
+ return *this;
+ }
+ else if( n < 64 )
+ {
+ U128 rv;
+ rv.lo = (lo >> n) | (hi << (64-n));
+ rv.hi = (hi >> n);
+ return rv;
+ }
+ else if( n < 128 )
+ {
+ U128 rv;
+ rv.lo = (hi >> (n-64));
+ rv.hi = 0;
+ return rv;
+ }
+ else
+ {
+ return U128();
+ }
+ }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const U128& x) { x.fmt(os); return os; }
+};
+
+class I128
+{
+ U128 v;
+public:
+ I128() {}
+
+ int cmp(I128 x) const {
+ if(v.hi != x.v.hi)
+ return (static_cast<int64_t>(v.hi) < static_cast<int64_t>(x.v.hi) ? -1 : 1);
+ if(v.lo != x.v.lo)
+ {
+ if( static_cast<int64_t>(v.hi) < 0 )
+ {
+ // Negative, so larger raw value is the smaller
+ return (v.lo > x.v.lo ? -1 : 1);
+ }
+ else
+ {
+ return (v.lo < x.v.lo ? -1 : 1);
+ }
+ }
+ return 0;
+ }
+ //int cmp(int v) const {
+ // if(hi)
+ // return 1;
+ // if(lo < v)
+ // return -1;
+ // if(lo > v)
+ // return 1;
+ // return 0;
+ //}
+
+ template<typename T> bool operator< (const T& v) const { return this->cmp(v) < 0; }
+ template<typename T> bool operator<=(const T& v) const { return this->cmp(v) <= 0; }
+ template<typename T> bool operator> (const T& v) const { return this->cmp(v) > 0; }
+ template<typename T> bool operator>=(const T& v) const { return this->cmp(v) >= 0; }
+ template<typename T> bool operator==(const T& v) const { return this->cmp(v) == 0; }
+ template<typename T> bool operator!=(const T& v) const { return this->cmp(v) != 0; }
+
+ void fmt(::std::ostream& os) const { os << v.hi << ":" << v.lo; }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const I128& x) { x.fmt(os); return os; }
+};
diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp
index 5974a172..a497f0bd 100644
--- a/tools/standalone_miri/value.cpp
+++ b/tools/standalone_miri/value.cpp
@@ -13,13 +13,98 @@
#include <algorithm>
#include "debug.hpp"
-AllocationHandle Allocation::new_alloc(size_t size)
+namespace {
+ static bool in_bounds(size_t ofs, size_t size, size_t max_size) {
+ if( !(ofs < max_size) )
+ return false;
+ if( !(size <= max_size) )
+ return false;
+ return ofs + size <= max_size;
+ }
+
+ void set_bit(uint8_t* p, size_t i, bool v)
+ {
+ if(v) {
+ p[i/8] |= 1 << (i%8);
+ }
+ else {
+ p[i/8] &= ~(1 << (i%8));
+ }
+ }
+ bool get_bit(const uint8_t* p, size_t i) {
+ return (p[i/8] & (1 << (i%8))) != 0;
+ }
+ void copy_bits(uint8_t* dst, size_t dst_ofs, const uint8_t* src, size_t src_ofs, size_t len)
+ {
+ // Even number of bytes, fast copy
+ if( dst_ofs % 8 == 0 && src_ofs % 8 == 0 && len % 8 == 0 )
+ {
+ for(size_t i = 0; i < len/8; i ++)
+ {
+ dst[dst_ofs/8 + i] = src[src_ofs/8 + i];
+ }
+ }
+ else
+ {
+ for(size_t i = 0; i < len; i ++)
+ {
+ set_bit( dst, dst_ofs+i, get_bit(src, src_ofs+i) );
+ }
+ }
+ }
+};
+
+::std::ostream& operator<<(::std::ostream& os, const Allocation* x)
+{
+ os << "A(#" << x->m_index << " " << x->tag() /*<< " +" << x->size()*/ << ")";
+ return os;
+}
+
+FfiLayout FfiLayout::new_const_bytes(size_t s)
+{
+ return FfiLayout {
+ { Range {s, true, false} }
+ };
+}
+bool FfiLayout::is_valid_read(size_t o, size_t s) const
+{
+ for(const auto& r : ranges)
+ {
+ if( o < r.len ) {
+ if( !r.is_valid )
+ return false;
+ if( o + s <= r.len )
+ {
+ s = 0;
+ break;
+ }
+ s -= (r.len - o);
+ o = 0;
+ }
+ else {
+ o -= r.len;
+ }
+ }
+ if( s > 0 )
+ {
+ return false;
+ }
+ return true;
+}
+
+uint64_t Allocation::s_next_index = 0;
+
+AllocationHandle Allocation::new_alloc(size_t size, ::std::string tag)
{
Allocation* rv = new Allocation();
+ rv->m_index = s_next_index++;
+ rv->m_tag = ::std::move(tag);
rv->refcount = 1;
- rv->data.resize( (size + 8-1) / 8 ); // QWORDS
- rv->mask.resize( (size + 8-1) / 8 ); // bitmap bytes
+ rv->m_size = size;
+ rv->m_data.resize( (size + 8-1) / 8 ); // QWORDS
+ rv->m_mask.resize( (size + 8-1) / 8 ); // bitmap bytes
//LOG_DEBUG(rv << " ALLOC");
+ LOG_DEBUG(rv);
return AllocationHandle(rv);
}
AllocationHandle::AllocationHandle(const AllocationHandle& x):
@@ -167,7 +252,7 @@ size_t RelocationPtr::get_size() const
os << "\"" << x.str() << "\"";
break;
case RelocationPtr::Ty::FfiPointer:
- os << "FFI " << x.ffi().source_function << " " << x.ffi().ptr_value;
+ os << "FFI '" << x.ffi().tag_name << "' " << x.ffi().ptr_value;
break;
}
}
@@ -191,6 +276,8 @@ void ValueCommonWrite::write_usize(size_t ofs, uint64_t v)
void* ValueCommonRead::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& out_size, bool& out_is_mut) const
{
auto ofs = read_usize(rd_ofs);
+ LOG_ASSERT(ofs >= Allocation::PTR_BASE, "Deref of invalid pointer");
+ ofs -= Allocation::PTR_BASE;
auto reloc = get_relocation(rd_ofs);
if( !reloc )
{
@@ -210,22 +297,16 @@ void* ValueCommonRead::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size
{
case RelocationPtr::Ty::Allocation: {
auto& a = reloc.alloc();
- if( ofs > a.size() )
- LOG_FATAL("Out-of-bounds pointer");
- if( ofs + req_valid > a.size() )
- LOG_FATAL("Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << a.size());
- a.check_bytes_valid( static_cast<size_t>(ofs), req_valid );
- out_size = a.size() - static_cast<size_t>(ofs);
+ LOG_ASSERT(in_bounds(ofs, req_valid, a.size()), "Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << a.size() << ")");
+ a.check_bytes_valid( ofs, req_valid );
+ out_size = a.size() - ofs;
out_is_mut = true;
return a.data_ptr() + ofs;
}
case RelocationPtr::Ty::StdString: {
const auto& s = reloc.str();
- if( ofs > s.size() )
- LOG_FATAL("Out-of-bounds pointer");
- if( ofs + req_valid > s.size() )
- LOG_FATAL("Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << s.size());
- out_size = s.size() - static_cast<size_t>(ofs);
+ LOG_ASSERT(in_bounds(ofs, req_valid, s.size()), "Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << s.size() << ")");
+ out_size = s.size() - ofs;
out_is_mut = false;
return const_cast<void*>( static_cast<const void*>(s.data() + ofs) );
}
@@ -233,11 +314,13 @@ void* ValueCommonRead::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size
LOG_FATAL("read_pointer w/ function");
case RelocationPtr::Ty::FfiPointer: {
const auto& f = reloc.ffi();
+ size_t size = f.get_size();
+ LOG_ASSERT(in_bounds(ofs, req_valid, size), "Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << size << ")");
// TODO: Validity?
//if( req_valid )
// LOG_FATAL("Can't request valid data from a FFI pointer");
// TODO: Have an idea of mutability and available size from FFI
- out_size = f.size - static_cast<size_t>(ofs);
+ out_size = size - ofs;
out_is_mut = false;
return reinterpret_cast<char*>(reloc.ffi().ptr_value) + ofs;
}
@@ -248,17 +331,38 @@ void* ValueCommonRead::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size
ValueRef ValueCommonRead::read_pointer_valref_mut(size_t rd_ofs, size_t size)
{
auto ofs = read_usize(rd_ofs);
+ LOG_ASSERT(ofs >= Allocation::PTR_BASE, "Invalid pointer read");
+ ofs -= Allocation::PTR_BASE;
auto reloc = get_relocation(rd_ofs);
+ LOG_DEBUG("ValueCommonRead::read_pointer_valref_mut(" << ofs << "+" << size << ", reloc=" << reloc << ")");
if( !reloc )
{
LOG_ERROR("Getting ValRef to null pointer (no relocation)");
}
else
{
- // TODO: Validate size
- return ValueRef(reloc, static_cast<size_t>(ofs), size);
+ // Validate size and offset are in bounds
+ switch(reloc.get_ty())
+ {
+ case RelocationPtr::Ty::Allocation:
+ LOG_ASSERT( in_bounds(ofs, size, reloc.alloc().size()), "Deref with OOB size - " << ofs << "+" << size << " > " << reloc.alloc().size() );
+ break;
+ case RelocationPtr::Ty::StdString:
+ LOG_ASSERT( in_bounds(ofs, size, reloc.str().size()), "Deref with OOB size - " << ofs << "+" << size << " > " << reloc.str().size() );
+ break;
+ case RelocationPtr::Ty::Function:
+ LOG_FATAL("read_pointer_valref_mut w/ function");
+ case RelocationPtr::Ty::FfiPointer:
+ LOG_ASSERT( in_bounds(ofs, size, reloc.ffi().get_size()), "Deref with OOB size - " << ofs << "+" << size << " > " << reloc.ffi().get_size() );
+ break;
+ }
+ return ValueRef(reloc, ofs, size);
}
}
+ValueRef ValueCommonRead::deref(size_t ofs, const ::HIR::TypeRef& ty)
+{
+ return read_pointer_valref_mut(ofs, ty.get_size());
+}
void Allocation::resize(size_t new_size)
@@ -268,18 +372,19 @@ void Allocation::resize(size_t new_size)
//size_t old_size = this->size();
//size_t extra_bytes = (new_size > old_size ? new_size - old_size : 0);
- this->data.resize( (new_size + 8-1) / 8 );
- this->mask.resize( (new_size + 8-1) / 8 );
+ this->m_size = new_size;
+ this->m_data.resize( (new_size + 8-1) / 8 );
+ this->m_mask.resize( (new_size + 8-1) / 8 );
}
void Allocation::check_bytes_valid(size_t ofs, size_t size) const
{
- if( !(ofs + size <= this->size()) ) {
+ if( !in_bounds(ofs, size, this->size()) ) {
LOG_FATAL("Out of range - " << ofs << "+" << size << " > " << this->size());
}
for(size_t i = ofs; i < ofs + size; i++)
{
- if( !(this->mask[i/8] & (1 << (i%8))) )
+ if( !(this->m_mask[i/8] & (1 << (i%8))) )
{
LOG_ERROR("Invalid bytes in value - " << ofs << "+" << size << " - " << *this);
throw "ERROR";
@@ -288,19 +393,20 @@ void Allocation::check_bytes_valid(size_t ofs, size_t size) const
}
void Allocation::mark_bytes_valid(size_t ofs, size_t size)
{
- assert( ofs+size <= this->mask.size() * 8 );
+ assert( ofs+size <= this->m_mask.size() * 8 );
for(size_t i = ofs; i < ofs + size; i++)
{
- this->mask[i/8] |= (1 << (i%8));
+ this->m_mask[i/8] |= (1 << (i%8));
}
}
Value Allocation::read_value(size_t ofs, size_t size) const
{
Value rv;
- TRACE_FUNCTION_R("Allocation::read_value " << this << " " << ofs << "+" << size, *this << " | " << rv);
+ //TRACE_FUNCTION_R("Allocation::read_value " << this << " " << ofs << "+" << size, *this << " | " << size << "=" << rv);
if( this->is_freed )
LOG_ERROR("Use of freed memory " << this);
LOG_DEBUG(*this);
+ LOG_ASSERT( in_bounds(ofs, size, this->size()), "Read out of bounds (" << ofs << "+" << size << " > " << this->size() << ")" );
// Determine if this can become an inline allocation.
bool has_reloc = false;
@@ -308,57 +414,25 @@ Value Allocation::read_value(size_t ofs, size_t size) const
{
if( ofs <= r.slot_ofs && r.slot_ofs < ofs + size )
{
+ // NOTE: A relocation at offset zero is allowed
+ if( r.slot_ofs == ofs )
+ continue ;
has_reloc = true;
}
}
- if( has_reloc || size > sizeof(rv.direct_data.data) )
- {
- rv.allocation = Allocation::new_alloc(size);
-
- rv.write_bytes(0, this->data_ptr() + ofs, size);
-
- for(const auto& r : this->relocations)
- {
- if( ofs <= r.slot_ofs && r.slot_ofs < ofs + size )
- {
- rv.allocation->relocations.push_back({ r.slot_ofs - ofs, r.backing_alloc });
- }
- }
+ rv = Value::with_size(size, has_reloc);
+ rv.write_bytes(0, this->data_ptr() + ofs, size);
- // Copy the mask bits
- for(size_t i = 0; i < size; i ++)
- {
- size_t j = ofs + i;
- const uint8_t test_mask = (1 << (j%8));
- const uint8_t set_mask = (1 << (i%8));
- bool v = (this->mask[j/8] & test_mask) != 0;
- if( v )
- {
- rv.allocation->mask[i/8] |= set_mask;
- }
- }
- }
- else
+ for(const auto& r : this->relocations)
{
- rv.direct_data.size = static_cast<uint8_t>(size);
-
- rv.write_bytes(0, this->data_ptr() + ofs, size);
- rv.direct_data.mask[0] = 0;
- rv.direct_data.mask[1] = 0;
-
- // Copy the mask bits
- for(size_t i = 0; i < size; i ++)
+ if( ofs <= r.slot_ofs && r.slot_ofs < ofs + size )
{
- size_t j = ofs + i;
- const uint8_t tst_mask = 1 << (j%8);
- const uint8_t set_mask = 1 << (i%8);
- bool v = (this->mask[j/8] & tst_mask) != 0;
- if( v )
- {
- rv.direct_data.mask[i/8] |= set_mask;
- }
+ rv.set_reloc(r.slot_ofs - ofs, /*r.size*/POINTER_SIZE, r.backing_alloc);
}
}
+ // Copy the mask bits
+ copy_bits(rv.get_mask_mut(), 0, m_mask.data(), ofs, size);
+
return rv;
}
void Allocation::read_bytes(size_t ofs, void* dst, size_t count) const
@@ -366,19 +440,11 @@ void Allocation::read_bytes(size_t ofs, void* dst, size_t count) const
if( this->is_freed )
LOG_ERROR("Use of freed memory " << this);
- LOG_DEBUG("Allocation::read_bytes " << this << " " << ofs << "+" << count);
+ //LOG_DEBUG("Allocation::read_bytes " << this << " " << ofs << "+" << count);
if(count == 0)
return ;
- if(ofs >= this->size() ) {
- LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size());
- throw "ERROR";
- }
- if(count > this->size() ) {
- LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size());
- throw "ERROR";
- }
- if(ofs+count > this->size() ) {
+ if( !in_bounds(ofs, count, this->size()) ) {
LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size());
throw "ERROR";
}
@@ -394,14 +460,15 @@ void Allocation::write_value(size_t ofs, Value v)
LOG_ERROR("Use of freed memory " << this);
//if( this->is_read_only )
// LOG_ERROR("Writing to read-only allocation " << this);
- if( v.allocation )
+ if( v.m_inner.is_alloc )
{
- size_t v_size = v.allocation->size();
- const auto& src_alloc = *v.allocation;
- // Take a copy of the source mask
- auto s_mask = src_alloc.mask;
+ const auto& src_alloc = *v.m_inner.alloc.alloc;
+ size_t v_size = src_alloc.size();
+ assert(&src_alloc != this); // Shouldn't happen?
- // Save relocations first, because `Foo = Foo` is valid.
+ // Take a copy of the source mask
+ auto s_mask = src_alloc.m_mask;
+ // Save relocations first, because `Foo = Foo` is valid?
::std::vector<Relocation> new_relocs = src_alloc.relocations;
// - write_bytes removes any relocations in this region.
write_bytes(ofs, src_alloc.data_ptr(), v_size);
@@ -420,39 +487,16 @@ void Allocation::write_value(size_t ofs, Value v)
}
// Set mask in destination
- if( ofs % 8 != 0 || v_size % 8 != 0 )
- {
- // Lazy way, sets/clears individual bits
- for(size_t i = 0; i < v_size; i ++)
- {
- uint8_t dbit = 1 << ((ofs+i) % 8);
- if( s_mask[i/8] & (1 << (i %8)) )
- this->mask[ (ofs+i) / 8 ] |= dbit;
- else
- this->mask[ (ofs+i) / 8 ] &= ~dbit;
- }
- }
- else
- {
- // Copy the mask bytes directly
- for(size_t i = 0; i < v_size / 8; i ++)
- {
- this->mask[ofs/8+i] = s_mask[i];
- }
- }
+ copy_bits(m_mask.data(), ofs, s_mask.data(), 0, v_size);
}
else
{
- this->write_bytes(ofs, v.direct_data.data, v.direct_data.size);
-
- // Lazy way, sets/clears individual bits
- for(size_t i = 0; i < v.direct_data.size; i ++)
+ this->write_bytes(ofs, v.data_ptr(), v.size());
+ copy_bits(m_mask.data(), ofs, v.get_mask(), 0, v.size());
+ // TODO: Copy relocation
+ if( v.m_inner.direct.reloc_0 )
{
- uint8_t dbit = 1 << ((ofs+i) % 8);
- if( v.direct_data.mask[i/8] & (1 << (i %8)) )
- this->mask[ (ofs+i) / 8 ] |= dbit;
- else
- this->mask[ (ofs+i) / 8 ] &= ~dbit;
+ this->set_reloc(ofs, POINTER_SIZE, ::std::move(v.m_inner.direct.reloc_0));
}
}
}
@@ -466,16 +510,8 @@ void Allocation::write_bytes(size_t ofs, const void* src, size_t count)
if(count == 0)
return ;
- TRACE_FUNCTION_R("Allocation::write_bytes " << this << " " << ofs << "+" << count, *this);
- if(ofs >= this->size() ) {
- LOG_ERROR("Out of bounds write, " << ofs << "+" << count << " > " << this->size());
- throw "ERROR";
- }
- if(count > this->size() ) {
- LOG_ERROR("Out of bounds write, " << ofs << "+" << count << " > " << this->size());
- throw "ERROR";
- }
- if(ofs+count > this->size() ) {
+ //TRACE_FUNCTION_R("Allocation::write_bytes " << this << " " << ofs << "+" << count, *this);
+ if( !in_bounds(ofs, count, this->size()) ) {
LOG_ERROR("Out of bounds write, " << ofs << "+" << count << " > " << this->size());
throw "ERROR";
}
@@ -501,8 +537,29 @@ void Allocation::write_bytes(size_t ofs, const void* src, size_t count)
}
void Allocation::write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc)
{
+ LOG_ASSERT(ptr_ofs >= Allocation::PTR_BASE, "Invalid pointer being written");
this->write_usize(ofs, ptr_ofs);
- this->relocations.push_back(Relocation { ofs, /*POINTER_SIZE,*/ ::std::move(reloc) });
+ this->set_reloc(ofs, POINTER_SIZE, ::std::move(reloc));
+}
+void Allocation::set_reloc(size_t ofs, size_t len, RelocationPtr reloc)
+{
+ LOG_ASSERT(ofs % POINTER_SIZE == 0, "");
+ LOG_ASSERT(len == POINTER_SIZE, "");
+ // Delete any existing relocation at this position
+ for(auto it = this->relocations.begin(); it != this->relocations.end();)
+ {
+ if( ofs <= it->slot_ofs && it->slot_ofs < ofs + len )
+ {
+ // Slot starts in this updated region
+ // - TODO: Split in half?
+ it = this->relocations.erase(it);
+ continue ;
+ }
+ // TODO: What if the slot ends in the new region?
+ // What if the new region is in the middle of the slot
+ ++ it;
+ }
+ this->relocations.push_back(Relocation { ofs, /*len,*/ ::std::move(reloc) });
}
::std::ostream& operator<<(::std::ostream& os, const Allocation& x)
{
@@ -513,7 +570,7 @@ void Allocation::write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc)
if( i != 0 )
os << " ";
- if( x.mask[i/8] & (1 << (i%8)) )
+ if( x.m_mask[i/8] & (1 << (i%8)) )
{
os << ::std::setw(2) << ::std::setfill('0') << (int)x.data_ptr()[i];
}
@@ -538,72 +595,62 @@ void Allocation::write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc)
Value::Value()
{
- this->direct_data.size = 0;
- this->direct_data.mask[0] = 0;
- this->direct_data.mask[1] = 0;
+ memset(&m_inner, 0, sizeof(m_inner));
}
Value::Value(::HIR::TypeRef ty)
{
size_t size = ty.get_size();
// Support inline data if the data will fit within the inline region (which is the size of the metadata)
- if( ty.get_size() <= sizeof(this->direct_data.data) )
+ if( size <= sizeof(m_inner.direct.data) )
{
// AND the type doesn't contain a pointer (of any kind)
- if( ! ty.has_pointer() )
+ // TODO: Pointers _are_ allowed now (but only one)
+ if( true || ! ty.has_pointer() )
{
// Will fit in a inline allocation, nice.
//LOG_TRACE("No pointers in " << ty << ", storing inline");
- this->direct_data.size = static_cast<uint8_t>(size);
- this->direct_data.mask[0] = 0;
- this->direct_data.mask[1] = 0;
+ new(&m_inner.direct) Inner::Direct(size);
return ;
}
}
// Fallback: Make a new allocation
//LOG_TRACE(" Creating allocation for " << ty);
- this->allocation = Allocation::new_alloc(size);
+ new(&m_inner.alloc) Inner::Alloc( Allocation::new_alloc(size, FMT_STRING(ty)) );
+ assert(m_inner.is_alloc);
}
Value Value::with_size(size_t size, bool have_allocation)
{
Value rv;
- if(have_allocation)
+ if(have_allocation || size > sizeof(m_inner.direct.data))
{
- rv.allocation = Allocation::new_alloc(size);
+ new(&rv.m_inner.alloc) Inner::Alloc( Allocation::new_alloc(size, FMT_STRING("with_size(" << size << ")")) );
}
else
{
- rv.direct_data.size = static_cast<uint8_t>(size);
- rv.direct_data.mask[0] = 0;
- rv.direct_data.mask[1] = 0;
+ new(&rv.m_inner.direct) Inner::Direct(size);
}
return rv;
}
Value Value::new_fnptr(const ::HIR::Path& fn_path)
{
Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::Function }) );
- assert(rv.allocation);
- rv.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_fcn(fn_path) });
- rv.allocation->data.at(0) = 0;
- rv.allocation->mask.at(0) = (1 << POINTER_SIZE)-1;
+ rv.write_ptr(0, Allocation::PTR_BASE, RelocationPtr::new_fcn(fn_path));
return rv;
}
Value Value::new_ffiptr(FFIPointer ffi)
{
Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::USize }) );
- rv.create_allocation();
- rv.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_ffi(ffi) });
- rv.allocation->data.at(0) = 0;
- rv.allocation->mask.at(0) = (1 << POINTER_SIZE)-1;
+ assert( !rv.m_inner.is_alloc );
+ rv.write_ptr(0, Allocation::PTR_BASE, RelocationPtr::new_ffi(ffi));
return rv;
}
Value Value::new_pointer(::HIR::TypeRef ty, uint64_t v, RelocationPtr r) {
assert(ty.get_wrapper());
assert(ty.get_wrapper()->type == TypeWrapper::Ty::Borrow || ty.get_wrapper()->type == TypeWrapper::Ty::Pointer);
Value rv(ty);
- rv.write_usize(0, v);
- rv.allocation->relocations.push_back(Relocation { 0, /*POINTER_SIZE,*/ ::std::move(r) });
+ rv.write_ptr(0, v, ::std::move(r));
return rv;
}
Value Value::new_usize(uint64_t v) {
@@ -626,59 +673,57 @@ Value Value::new_i32(int32_t v) {
rv.write_i32(0, v);
return rv;
}
+Value Value::new_i64(int64_t v) {
+ auto rv = Value( ::HIR::TypeRef(RawType::I64) );
+ rv.write_i64(0, v);
+ return rv;
+}
void Value::create_allocation()
{
- assert(!this->allocation);
- this->allocation = Allocation::new_alloc(this->direct_data.size);
- if( this->direct_data.size > 0 )
- this->allocation->mask[0] = this->direct_data.mask[0];
- if( this->direct_data.size > 8 )
- this->allocation->mask[1] = this->direct_data.mask[1];
- ::std::memcpy(this->allocation->data.data(), this->direct_data.data, this->direct_data.size);
+ assert(!m_inner.is_alloc);
+ auto new_alloc = Allocation::new_alloc(m_inner.direct.size, "create_allocation"); // TODO: Provide a better name?
+ auto& direct = m_inner.direct;
+ if( direct.size > 0 )
+ new_alloc->m_mask[0] = direct.mask[0];
+ if( direct.size > 8 )
+ new_alloc->m_mask[1] = direct.mask[1];
+ ::std::memcpy(new_alloc->data_ptr(), direct.data, direct.size);
+ if( direct.reloc_0 )
+ {
+ new_alloc->set_reloc(0, POINTER_SIZE, ::std::move(direct.reloc_0));
+ }
+
+ new(&m_inner.alloc) Inner::Alloc(::std::move(new_alloc));
}
void Value::check_bytes_valid(size_t ofs, size_t size) const
{
if( size == 0 )
return ;
- if( this->allocation )
- {
- this->allocation->check_bytes_valid(ofs, size);
+ if( !in_bounds(ofs, size, this->size()) ) {
+ LOG_ERROR("Read out of bounds " << ofs+size << " >= " << this->size());
+ throw "ERROR";
}
- else
+ const auto* mask = this->get_mask();
+ for(size_t i = ofs; i < ofs + size; i++)
{
- if( size == 0 && this->direct_data.size > 0 ) {
- return ;
- }
- if( ofs >= this->direct_data.size ) {
- LOG_ERROR("Read out of bounds " << ofs << "+" << size << " > " << int(this->direct_data.size));
- throw "ERROR";
- }
- if( ofs+size > this->direct_data.size ) {
- LOG_ERROR("Read out of bounds " << ofs+size << " >= " << int(this->direct_data.size));
- throw "ERROR";
- }
- for(size_t i = ofs; i < ofs + size; i++)
+ if( !get_bit(mask, i) )
{
- if( !(this->direct_data.mask[i/8] & (1 << i%8)) )
- {
- LOG_ERROR("Accessing invalid bytes in value");
- throw "ERROR";
- }
+ LOG_ERROR("Accessing invalid bytes in value, offset " << i << " of " << *this);
}
}
}
void Value::mark_bytes_valid(size_t ofs, size_t size)
{
- if( this->allocation )
+ if( m_inner.is_alloc )
{
- this->allocation->mark_bytes_valid(ofs, size);
+ m_inner.alloc.alloc->mark_bytes_valid(ofs, size);
}
else
{
for(size_t i = ofs; i < ofs+size; i++)
{
- this->direct_data.mask[i/8] |= (1 << i%8);
+ m_inner.direct.mask[i/8] |= (1 << i%8);
}
}
}
@@ -686,18 +731,28 @@ void Value::mark_bytes_valid(size_t ofs, size_t size)
Value Value::read_value(size_t ofs, size_t size) const
{
Value rv;
- //TRACE_FUNCTION_R(ofs << ", " << size << ") - " << *this, rv);
- if( this->allocation )
+ TRACE_FUNCTION_R(ofs << ", " << size << " - " << *this, rv);
+ if( m_inner.is_alloc )
{
- rv = this->allocation->read_value(ofs, size);
+ rv = m_inner.alloc.alloc->read_value(ofs, size);
}
else
{
- // Inline can become inline.
- rv.direct_data.size = static_cast<uint8_t>(size);
- rv.write_bytes(0, this->direct_data.data+ofs, size);
- rv.direct_data.mask[0] = this->direct_data.mask[0];
- rv.direct_data.mask[1] = this->direct_data.mask[1];
+ // Inline always fits in inline.
+ if( ofs == 0 && size == this->size() )
+ {
+ rv = Value(*this);
+ }
+ else
+ {
+ rv.m_inner.direct.size = static_cast<uint8_t>(size);
+ memcpy(rv.m_inner.direct.data, this->data_ptr() + ofs, size);
+ copy_bits(rv.m_inner.direct.mask, 0, this->get_mask(), ofs, size);
+ if( ofs == 0 )
+ {
+ rv.m_inner.direct.reloc_0 = RelocationPtr(m_inner.direct.reloc_0);
+ }
+ }
}
return rv;
}
@@ -705,27 +760,14 @@ void Value::read_bytes(size_t ofs, void* dst, size_t count) const
{
if(count == 0)
return ;
- if( this->allocation )
+ if( m_inner.is_alloc )
{
- this->allocation->read_bytes(ofs, dst, count);
+ m_inner.alloc.alloc->read_bytes(ofs, dst, count);
}
else
{
check_bytes_valid(ofs, count);
-
- if(ofs >= this->direct_data.size ) {
- LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size());
- throw "ERROR";
- }
- if(count > this->direct_data.size ) {
- LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size());
- throw "ERROR";
- }
- if(ofs+count > this->direct_data.size ) {
- LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size());
- throw "ERROR";
- }
- ::std::memcpy(dst, this->direct_data.data + ofs, count);
+ ::std::memcpy(dst, m_inner.direct.data + ofs, count);
}
}
@@ -733,88 +775,65 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count)
{
if( count == 0 )
return ;
- if( this->allocation )
+ if( m_inner.is_alloc )
{
- this->allocation->write_bytes(ofs, src, count);
+ m_inner.alloc.alloc->write_bytes(ofs, src, count);
}
else
{
- if(ofs >= this->direct_data.size ) {
- LOG_BUG("Write to offset outside value size (" << ofs << "+" << count << " >= " << (int)this->direct_data.size << ")");
+ auto& direct = m_inner.direct;
+ if( !in_bounds(ofs, count, direct.size) ) {
+ LOG_ERROR("Write extends outside value size (" << ofs << "+" << count << " >= " << (int)direct.size << ")");
}
- if(count > this->direct_data.size ){
- LOG_BUG("Write larger than value size (" << ofs << "+" << count << " >= " << (int)this->direct_data.size << ")");
- }
- if(ofs+count > this->direct_data.size ) {
- LOG_BUG("Write extends outside value size (" << ofs << "+" << count << " >= " << (int)this->direct_data.size << ")");
- }
- ::std::memcpy(this->direct_data.data + ofs, src, count);
+ ::std::memcpy(direct.data + ofs, src, count);
mark_bytes_valid(ofs, count);
+ if( 0 <= ofs && ofs < POINTER_SIZE ) {
+ direct.reloc_0 = RelocationPtr();
+ }
}
}
void Value::write_value(size_t ofs, Value v)
{
- if( this->allocation )
+ if( m_inner.is_alloc )
{
- this->allocation->write_value(ofs, ::std::move(v));
+ m_inner.alloc.alloc->write_value(ofs, ::std::move(v));
}
else
{
- if( v.allocation && !v.allocation->relocations.empty() )
- {
- this->create_allocation();
- this->allocation->write_value(ofs, ::std::move(v));
- }
- else
- {
- write_bytes(ofs, v.direct_data.data, v.direct_data.size);
+ write_bytes(ofs, v.data_ptr(), v.size());
+ // - Copy mask
+ copy_bits(this->get_mask_mut(), ofs, v.get_mask(), 0, v.size());
- // Lazy way, sets/clears individual bits
- for(size_t i = 0; i < v.direct_data.size; i ++)
+ // TODO: Faster way of knowing where there are relocations
+ for(size_t i = 0; i < v.size(); i ++)
+ {
+ if( auto r = v.get_relocation(i) )
{
- uint8_t dbit = 1 << ((ofs+i) % 8);
- if( v.direct_data.mask[i/8] & (1 << (i %8)) )
- this->direct_data.mask[ (ofs+i) / 8 ] |= dbit;
- else
- this->direct_data.mask[ (ofs+i) / 8 ] &= ~dbit;
+ this->set_reloc(ofs + i, POINTER_SIZE, r);
}
}
}
}
void Value::write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc)
{
- if( !this->allocation )
- {
- LOG_ERROR("Writing a pointer with no allocation");
- }
- this->allocation->write_ptr(ofs, ptr_ofs, ::std::move(reloc));
-}
-
-::std::ostream& operator<<(::std::ostream& os, const Value& v)
-{
- if( v.allocation )
+ if( m_inner.is_alloc )
{
- os << *v.allocation;
+ m_inner.alloc.alloc->write_ptr(ofs, ptr_ofs, ::std::move(reloc));
}
else
{
- auto flags = os.flags();
- os << ::std::hex;
- for(size_t i = 0; i < v.direct_data.size; i++)
+ write_usize(ofs, ptr_ofs);
+ if( ofs != 0 )
{
- if( i != 0 )
- os << " ";
- if( v.direct_data.mask[i/8] & (1 << i%8) )
- {
- os << ::std::setw(2) << ::std::setfill('0') << (int)v.direct_data.data[i];
- }
- else
- {
- os << "--";
- }
+ LOG_ERROR("Writing a pointer with no allocation");
}
- os.setf(flags);
+ m_inner.direct.reloc_0 = ::std::move(reloc);
}
+}
+
+::std::ostream& operator<<(::std::ostream& os, const Value& v)
+{
+ os << ValueRef(const_cast<Value&>(v), 0, v.size());
return os;
}
extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
@@ -830,6 +849,8 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
case RelocationPtr::Ty::Allocation: {
const auto& alloc = alloc_ptr.alloc();
+ os << &alloc << "@" << v.m_offset << "+" << v.m_size << " ";
+
auto flags = os.flags();
os << ::std::hex;
for(size_t i = v.m_offset; i < ::std::min(alloc.size(), v.m_offset + v.m_size); i++)
@@ -837,7 +858,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
if( i != 0 )
os << " ";
- if( alloc.mask[i/8] & (1 << i%8) )
+ if( alloc.m_mask[i/8] & (1 << i%8) )
{
os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[i];
}
@@ -863,9 +884,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
break;
case RelocationPtr::Ty::StdString: {
const auto& s = alloc_ptr.str();
- assert(v.m_offset < s.size());
- assert(v.m_size < s.size());
- assert(v.m_offset + v.m_size <= s.size());
+ assert( in_bounds(v.m_offset, v.m_size, s.size()) );
auto flags = os.flags();
os << ::std::hex;
for(size_t i = v.m_offset; i < v.m_offset + v.m_size; i++)
@@ -879,9 +898,11 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
break;
}
}
- else if( v.m_value && v.m_value->allocation )
+ else if( v.m_value && v.m_value->m_inner.is_alloc )
{
- const auto& alloc = *v.m_value->allocation;
+ const auto& alloc = *v.m_value->m_inner.alloc.alloc;
+
+ os << &alloc << "@" << v.m_offset << "+" << v.m_size << " ";
auto flags = os.flags();
os << ::std::hex;
@@ -890,7 +911,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
if( i != 0 )
os << " ";
- if( alloc.mask[i/8] & (1 << i%8) )
+ if( alloc.m_mask[i/8] & (1 << i%8) )
{
os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[i];
}
@@ -913,7 +934,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
}
else if( v.m_value )
{
- const auto& direct = v.m_value->direct_data;
+ const auto& direct = v.m_value->m_inner.direct;
auto flags = os.flags();
os << ::std::hex;
@@ -931,6 +952,10 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
}
}
os.setf(flags);
+ if(direct.reloc_0)
+ {
+ os << " { " << direct.reloc_0 << " }";
+ }
}
else
{
@@ -939,11 +964,28 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v)
return os;
}
+void ValueRef::mark_bytes_valid(size_t ofs, size_t size)
+{
+ if( m_alloc ) {
+ switch(m_alloc.get_ty())
+ {
+ case RelocationPtr::Ty::Allocation:
+ m_alloc.alloc().mark_bytes_valid(m_offset + ofs, size);
+ break;
+ default:
+ LOG_TODO("mark_valid in " << m_alloc);
+ }
+ }
+ else {
+ m_value->mark_bytes_valid(m_offset + ofs, size);
+ }
+}
+
Value ValueRef::read_value(size_t ofs, size_t size) const
{
if( size == 0 )
return Value();
- if( !(ofs < m_size && size <= m_size && ofs + size <= m_size) ) {
+ if( !in_bounds(ofs, size, m_size) ) {
LOG_ERROR("Read exceeds bounds, " << ofs << " + " << size << " > " << m_size << " - from " << *this);
}
if( m_alloc ) {
@@ -952,25 +994,27 @@ Value ValueRef::read_value(size_t ofs, size_t size) const
case RelocationPtr::Ty::Allocation:
return m_alloc.alloc().read_value(m_offset + ofs, size);
case RelocationPtr::Ty::StdString: {
+ LOG_ASSERT(in_bounds(m_offset + ofs, size, m_alloc.str().size()), "");
auto rv = Value::with_size(size, false);
- //ASSERT_BUG(ofs <= m_alloc.str().size(), "");
- //ASSERT_BUG(size <= m_alloc.str().size(), "");
- //ASSERT_BUG(ofs+size <= m_alloc.str().size(), "");
- assert(m_offset+ofs <= m_alloc.str().size() && size <= m_alloc.str().size() && m_offset+ofs+size <= m_alloc.str().size());
rv.write_bytes(0, m_alloc.str().data() + m_offset + ofs, size);
return rv;
}
+ case RelocationPtr::Ty::FfiPointer: {
+ LOG_ASSERT(in_bounds(m_offset + ofs, size, m_alloc.ffi().get_size()), "");
+ auto rv = Value::with_size(size, false);
+ rv.write_bytes(0, reinterpret_cast<const char*>(m_alloc.ffi().ptr_value) + m_offset + ofs, size);
+ return rv;
+ }
default:
- //ASSERT_BUG(m_alloc.is_alloc(), "read_value on non-data backed Value - " << );
- throw "TODO";
+ LOG_TODO("read_value from " << m_alloc);
}
}
else {
return m_value->read_value(m_offset + ofs, size);
}
}
-bool ValueRef::compare(const void* other, size_t other_len) const
+bool ValueRef::compare(size_t offset, const void* other, size_t other_len) const
{
- check_bytes_valid(0, other_len);
- return ::std::memcmp(data_ptr(), other, other_len) == 0;
+ check_bytes_valid(offset, other_len);
+ return ::std::memcmp(data_ptr() + offset, other, other_len) == 0;
}
diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp
index b057b3c4..03a21970 100644
--- a/tools/standalone_miri/value.hpp
+++ b/tools/standalone_miri/value.hpp
@@ -13,6 +13,9 @@
#include <cstring> // memcpy
#include <cassert>
+#include "debug.hpp"
+#include "u128.hpp"
+
namespace HIR {
struct TypeRef;
struct Path;
@@ -21,11 +24,49 @@ class Allocation;
struct Value;
struct ValueRef;
+struct FfiLayout
+{
+ struct Range {
+ size_t len;
+ bool is_valid;
+ bool is_writable;
+ };
+ ::std::vector<Range> ranges;
+
+ static FfiLayout new_const_bytes(size_t s);
+
+ size_t get_size() const {
+ size_t rv = 0;
+ for(const auto& r : ranges)
+ rv += r.len;
+ return rv;
+ }
+ bool is_valid_read(size_t o, size_t s) const;
+};
struct FFIPointer
{
- const char* source_function;
+ // FFI pointers require the following:
+ // - A tag indicating where they're valid/from
+ // - A data format (e.g. size of allocation, internal data format)
+ // - If the data format is unspecified (null) then it's a void pointer
+ // - An actual pointer
+
+ // Pointer value, returned by the FFI
void* ptr_value;
- size_t size;
+ // Tag name, used for validty checking by FFI hooks
+ const char* tag_name;
+ ::std::shared_ptr<FfiLayout> layout;
+
+ static FFIPointer new_void(const char* name, const void* v) {
+ return FFIPointer { const_cast<void*>(v), name, ::std::make_shared<FfiLayout>() };
+ }
+ static FFIPointer new_const_bytes(const char* name, const void* s, size_t size) {
+ return FFIPointer { const_cast<void*>(s), name, ::std::make_shared<FfiLayout>(FfiLayout::new_const_bytes(size)) };
+ };
+
+ size_t get_size() const {
+ return (layout ? layout->get_size() : 0);
+ }
};
class AllocationHandle
@@ -83,7 +124,7 @@ public:
RelocationPtr(const RelocationPtr& x);
~RelocationPtr();
static RelocationPtr new_alloc(AllocationHandle h);
- static RelocationPtr new_fcn(::HIR::Path p);
+ static RelocationPtr new_fcn(::HIR::Path p); // TODO: What if it's a FFI function? Could be encoded in here.
static RelocationPtr new_string(const ::std::string* s); // NOTE: The string must have a stable pointer
static RelocationPtr new_ffi(FFIPointer info);
@@ -155,15 +196,20 @@ struct ValueCommonRead
uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; }
uint32_t read_u32(size_t ofs) const { uint32_t rv; read_bytes(ofs, &rv, 4); return rv; }
uint64_t read_u64(size_t ofs) const { uint64_t rv; read_bytes(ofs, &rv, 8); return rv; }
+ U128 read_u128(size_t ofs) const { U128 rv; read_bytes(ofs, &rv, 16); return rv; }
int8_t read_i8(size_t ofs) const { return static_cast<int8_t>(read_u8(ofs)); }
int16_t read_i16(size_t ofs) const { return static_cast<int16_t>(read_u16(ofs)); }
int32_t read_i32(size_t ofs) const { return static_cast<int32_t>(read_u32(ofs)); }
int64_t read_i64(size_t ofs) const { return static_cast<int64_t>(read_u64(ofs)); }
+ I128 read_i128(size_t ofs) const { I128 rv; read_bytes(ofs, &rv, 16); return rv; }
float read_f32(size_t ofs) const { float rv; read_bytes(ofs, &rv, 4); return rv; }
double read_f64(size_t ofs) const { double rv; read_bytes(ofs, &rv, 8); return rv; }
uint64_t read_usize(size_t ofs) const;
int64_t read_isize(size_t ofs) const { return static_cast<int64_t>(read_usize(ofs)); }
+ /// De-reference a pointer (of target type `ty`) at the given offset, and return a reference to it
+ ValueRef deref(size_t ofs, const ::HIR::TypeRef& ty);
+
/// Read a pointer from the value, requiring at least `req_valid` valid bytes, saves avaliable space in `size`
void* read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& size, bool& is_mut) const;
/// Read a pointer, requiring `req_len` valid bytes
@@ -177,8 +223,7 @@ struct ValueCommonRead
bool is_mut;
void* rv = read_pointer_unsafe(rd_ofs, 0, out_size, is_mut);
if(!is_mut)
- throw "";
- //LOG_FATAL("Attempting to get an uninit pointer to immutable data");
+ LOG_FATAL("Attempting to get an uninit pointer to immutable data");
return rv;
}
/// Read a pointer and return a ValueRef to it (mutable data)
@@ -193,10 +238,12 @@ struct ValueCommonWrite:
void write_u16(size_t ofs, uint16_t v) { write_bytes(ofs, &v, 2); }
void write_u32(size_t ofs, uint32_t v) { write_bytes(ofs, &v, 4); }
void write_u64(size_t ofs, uint64_t v) { write_bytes(ofs, &v, 8); }
+ void write_u128(size_t ofs, U128 v) { write_bytes(ofs, &v, 16); }
void write_i8 (size_t ofs, int8_t v) { write_u8 (ofs, static_cast<uint8_t >(v)); }
void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast<uint16_t>(v)); }
void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast<uint32_t>(v)); }
void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast<uint64_t>(v)); }
+ void write_i128(size_t ofs, I128 v) { write_bytes(ofs, &v, 16); }
void write_f32(size_t ofs, float v) { write_bytes(ofs, &v, 4); }
void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); }
void write_usize(size_t ofs, uint64_t v);
@@ -208,19 +255,31 @@ class Allocation:
public ValueCommonWrite
{
friend class AllocationHandle;
+
+ static uint64_t s_next_index;
+
+ ::std::string m_tag;
size_t refcount;
+ size_t m_size;
+ uint64_t m_index;
// TODO: Read-only flag?
bool is_freed = false;
+
+ ::std::vector<uint64_t> m_data;
+public:
+ ::std::vector<uint8_t> m_mask;
+ ::std::vector<Relocation> relocations;
public:
- static AllocationHandle new_alloc(size_t size);
+ virtual ~Allocation() {}
+ static AllocationHandle new_alloc(size_t size, ::std::string tag);
- const uint8_t* data_ptr() const { return reinterpret_cast<const uint8_t*>(this->data.data()); }
- uint8_t* data_ptr() { return reinterpret_cast< uint8_t*>(this->data.data()); }
- size_t size() const { return this->data.size() * 8; }
+ // NOTE: This should match the value in the MMIR backend
+ static const size_t PTR_BASE = 0x1000;
- ::std::vector<uint64_t> data;
- ::std::vector<uint8_t> mask;
- ::std::vector<Relocation> relocations;
+ const uint8_t* data_ptr() const { return reinterpret_cast<const uint8_t*>(this->m_data.data()); }
+ uint8_t* data_ptr() { return reinterpret_cast< uint8_t*>(this->m_data.data()); }
+ size_t size() const { return m_size; }
+ const ::std::string& tag() const { return m_tag; }
RelocationPtr get_relocation(size_t ofs) const override {
for(const auto& r : relocations) {
@@ -232,7 +291,7 @@ public:
void mark_as_freed() {
is_freed = true;
relocations.clear();
- for(auto& v : mask)
+ for(auto& v : m_mask)
v = 0;
}
@@ -247,23 +306,95 @@ public:
void write_value(size_t ofs, Value v);
void write_bytes(size_t ofs, const void* src, size_t count) override;
void write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc) override;
+
+ void set_reloc(size_t ofs, size_t len, RelocationPtr reloc);
+ friend ::std::ostream& operator<<(::std::ostream& os, const Allocation* x);
};
extern ::std::ostream& operator<<(::std::ostream& os, const Allocation& x);
+// TODO: Rename to be `StackSlot`
struct Value:
public ValueCommonWrite
{
- // If NULL, data is direct
- AllocationHandle allocation;
- struct {
- // NOTE: Can't pack the mask+size tighter, need 4 bits of size (8-15) leaving 12 bits of mask
- uint8_t data[2*8-3]; // 13 data bytes, plus 16bit mask, plus size = 16 bytes
- uint8_t mask[2];
- uint8_t size;
- } direct_data;
+//private:
+ union Inner {
+ bool is_alloc;
+ struct Alloc {
+ bool is_alloc;
+ AllocationHandle alloc;
+
+ Alloc(AllocationHandle alloc):
+ is_alloc(true),
+ alloc(::std::move(alloc))
+ {
+ }
+ } alloc;
+ // Sizeof = 4+8+8 = 20b (plus vtable?)
+ struct Direct {
+ bool is_alloc;
+ uint8_t size;
+ uint8_t mask[2];
+ uint8_t data[2*8];
+ RelocationPtr reloc_0; // Relocation only for 0+POINTER_SIZE
+
+ Direct(size_t size):
+ is_alloc(false),
+ size(static_cast<uint8_t>(size)),
+ mask{0,0}
+ {
+ }
+ } direct;
+
+ Inner():
+ direct(0)
+ {
+ }
+ ~Inner() {
+ if(is_alloc) {
+ alloc.~Alloc();
+ }
+ else {
+ direct.~Direct();
+ }
+ }
+ Inner(const Inner& x) {
+ if(x.is_alloc) {
+ new(&this->alloc) Alloc(x.alloc);
+ }
+ else {
+ new(&this->direct) Direct(x.direct);
+ }
+ }
+ Inner(Inner&& x) {
+ if(x.is_alloc) {
+ new(&this->alloc) Alloc(::std::move(x.alloc));
+ }
+ else {
+ new(&this->direct) Direct(::std::move(x.direct));
+ }
+ }
+ Inner& operator=(Inner&& x) {
+ this->~Inner();
+ new(this) Inner(x);
+ return *this;
+ }
+ Inner& operator=(const Inner& x) {
+ this->~Inner();
+ new(this) Inner(x);
+ return *this;
+ }
+ } m_inner;
+public:
Value();
Value(::HIR::TypeRef ty);
+ ~Value() {
+ }
+
+ Value(const Value&) = default;
+ Value(Value&&) = default;
+ Value& operator=(const Value& x) = delete;
+ Value& operator=(Value&& x) = default;
static Value with_size(size_t size, bool have_allocation);
static Value new_fnptr(const ::HIR::Path& fn_path);
@@ -273,17 +404,51 @@ struct Value:
static Value new_isize(int64_t v);
static Value new_u32(uint32_t v);
static Value new_i32(int32_t v);
+ static Value new_i64(int64_t v);
+ AllocationHandle borrow(::std::string loc) {
+ if( !m_inner.is_alloc )
+ create_allocation(/*loc*/);
+ return m_inner.alloc.alloc;
+ }
+ void ensure_allocation() {
+ if( !m_inner.is_alloc )
+ create_allocation();
+ }
void create_allocation();
- size_t size() const { return allocation ? allocation->size() : direct_data.size; }
- const uint8_t* data_ptr() const { return allocation ? allocation->data_ptr() : direct_data.data; }
- uint8_t* data_ptr() { return allocation ? allocation->data_ptr() : direct_data.data; }
+ size_t size() const { return m_inner.is_alloc ? m_inner.alloc.alloc->size() : m_inner.direct.size; }
+ const uint8_t* data_ptr() const { return m_inner.is_alloc ? m_inner.alloc.alloc->data_ptr() : m_inner.direct.data; }
+ uint8_t* data_ptr() { return m_inner.is_alloc ? m_inner.alloc.alloc->data_ptr() : m_inner.direct.data; }
+ const uint8_t* get_mask() const { return m_inner.is_alloc ? m_inner.alloc.alloc->m_mask.data() : m_inner.direct.mask; }
+ uint8_t* get_mask_mut() { return m_inner.is_alloc ? m_inner.alloc.alloc->m_mask.data() : m_inner.direct.mask; }
RelocationPtr get_relocation(size_t ofs) const override {
- if( this->allocation && this->allocation )
- return this->allocation->get_relocation(ofs);
+ if( m_inner.is_alloc )
+ return m_inner.alloc.alloc->get_relocation(ofs);
+ else if(ofs == 0)
+ {
+ return m_inner.direct.reloc_0;
+ }
else
+ {
return RelocationPtr();
+ }
+ }
+ void set_reloc(size_t ofs, size_t size, RelocationPtr p) /*override*/ {
+ if( m_inner.is_alloc )
+ {
+ m_inner.alloc.alloc->set_reloc(ofs, size, ::std::move(p));
+ }
+ else if( ofs == 0 /*&& size == POINTER_SIZE*/ )
+ {
+ m_inner.direct.reloc_0 = ::std::move(p);
+ }
+ else
+ {
+ this->create_allocation();
+ assert( m_inner.is_alloc );
+ m_inner.alloc.alloc->set_reloc(ofs, size, ::std::move(p));
+ }
}
void check_bytes_valid(size_t ofs, size_t size) const;
@@ -310,6 +475,17 @@ struct ValueRef:
size_t m_size; // Size in bytes of the referenced value
::std::shared_ptr<Value> m_metadata;
+ static bool in_bounds(size_t ofs, size_t size, size_t max_size) {
+ if( size == 0 ) {
+ return ofs <= max_size;
+ }
+ if( ofs > 0 && !(ofs < max_size) )
+ return false;
+ if( !(size <= max_size) )
+ return false;
+ return ofs + size <= max_size;
+ }
+
ValueRef(RelocationPtr ptr, size_t ofs, size_t size):
m_alloc(ptr),
m_value(nullptr),
@@ -321,22 +497,25 @@ struct ValueRef:
switch(m_alloc.get_ty())
{
case RelocationPtr::Ty::Allocation:
- assert(ofs < m_alloc.alloc().size());
- assert(size <= m_alloc.alloc().size());
- assert(ofs+size <= m_alloc.alloc().size());
+ if( !in_bounds(ofs, size, m_alloc.alloc().size()) )
+ {
+ LOG_NOTICE("ValueRef exceeds bounds of " << m_alloc << " - " << ofs << "+" << size << " > " << m_alloc.alloc().size());
+ }
break;
case RelocationPtr::Ty::StdString:
- assert(ofs < m_alloc.str().size());
- assert(size <= m_alloc.str().size());
- assert(ofs+size <= m_alloc.str().size());
+ if( !in_bounds(ofs, size, m_alloc.str().size()) )
+ {
+ LOG_NOTICE("ValueRef exceeds bounds of string - " << ofs << "+" << size << " > " << m_alloc.str().size());
+ }
break;
case RelocationPtr::Ty::FfiPointer:
- assert(ofs < m_alloc.ffi().size);
- assert(size <= m_alloc.ffi().size);
- assert(ofs+size <= m_alloc.ffi().size);
+ if( !in_bounds(ofs, size, m_alloc.ffi().get_size()) )
+ {
+ LOG_NOTICE("ValueRef exceeds bounds of FFI buffer - " << ofs << "+" << size << " > " << m_alloc.ffi().get_size());
+ }
break;
- default:
- throw "TODO";
+ case RelocationPtr::Ty::Function:
+ LOG_TODO("");
}
}
}
@@ -355,13 +534,13 @@ struct ValueRef:
if(m_alloc)
{
if( m_alloc.is_alloc() )
- return m_alloc.alloc().get_relocation(ofs);
+ return m_alloc.alloc().get_relocation(m_offset + ofs);
else
return RelocationPtr();
}
else if( m_value )
{
- return m_value->get_relocation(ofs);
+ return m_value->get_relocation(m_offset + ofs);
}
else
{
@@ -379,7 +558,27 @@ struct ValueRef:
case RelocationPtr::Ty::StdString:
return reinterpret_cast<const uint8_t*>(m_alloc.str().data() + m_offset);
default:
- throw "TODO";
+ LOG_TODO("");
+ }
+ }
+ else if( m_value ) {
+ return m_value->data_ptr() + m_offset;
+ }
+ else {
+ return nullptr;
+ }
+ }
+
+ // TODO: Remove these two (move to a helper?)
+ uint8_t* data_ptr_mut() {
+ if( m_alloc ) {
+ switch(m_alloc.get_ty())
+ {
+ case RelocationPtr::Ty::Allocation:
+ return m_alloc.alloc().data_ptr() + m_offset;
+ break;
+ default:
+ LOG_TODO("");
}
}
else if( m_value ) {
@@ -389,12 +588,12 @@ struct ValueRef:
return nullptr;
}
}
+ void mark_bytes_valid(size_t ofs, size_t size);
+
void read_bytes(size_t ofs, void* dst, size_t size) const {
if( size == 0 )
return ;
- assert(ofs < m_size);
- assert(size <= m_size);
- assert(ofs+size <= m_size);
+ LOG_ASSERT(in_bounds(ofs, size, m_size), "read_bytes(" << ofs << "+" << size << " > " << m_size <<")");
if( m_alloc ) {
switch(m_alloc.get_ty())
{
@@ -407,7 +606,7 @@ struct ValueRef:
break;
default:
//ASSERT_BUG(m_alloc.is_alloc(), "read_value on non-data backed Value - " << );
- throw "TODO";
+ LOG_TODO("");
}
}
else {
@@ -417,9 +616,7 @@ struct ValueRef:
void check_bytes_valid(size_t ofs, size_t size) const {
if( size == 0 )
return ;
- assert(ofs < m_size);
- assert(size <= m_size);
- assert(ofs+size <= m_size);
+ LOG_ASSERT(in_bounds(ofs, size, m_size), "check_bytes_valid(" << ofs << "+" << size << " > " << m_size <<")");
if( m_alloc ) {
switch(m_alloc.get_ty())
{
@@ -431,7 +628,7 @@ struct ValueRef:
break;
default:
//ASSERT_BUG(m_alloc.is_alloc(), "read_value on non-data backed Value - " << );
- throw "TODO";
+ LOG_TODO("");
}
}
else {
@@ -439,6 +636,10 @@ struct ValueRef:
}
}
- bool compare(const void* other, size_t other_len) const;
+ bool compare(size_t offset, const void* other, size_t other_len) const;
};
extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v);
+//struct ValueRefMut:
+// public ValueCommonWrite
+//{
+//};
diff --git a/tools/standalone_miri/win32.api b/tools/standalone_miri/win32.api
new file mode 100644
index 00000000..1f374c1e
--- /dev/null
+++ b/tools/standalone_miri/win32.api
@@ -0,0 +1,24 @@
+#
+# Windows API calls
+#
+
+type HMODULE = void [size(0), name("HMODULE")];
+
+#fn GetModuleHandleW(lpcwsName: *const [cstr,null] u16) -> *const [null] HMODULE = "Kernel32.dll":"GetModuleHandleW";
+fn GetModuleHandleW(lpcwsName: *const [cstr,null] u16) -> *const [null] HMODULE {
+ miri::ensure_valid_nulseq("lpcwsName", lpcwsName);
+ return miri::call_ptr("Kernel32.dll", "GetModuleHandleW", lpcwsName);
+}
+
+# - The returned function pointer is annotated with the passed name
+fn GetProcAddress(hModule: *const HMODULE, name: *const [cstr] u8) -> fn(?) [null] {
+ miri::ensure_valid_nulseq("name", name);
+ let rv = miri::call_ptr("Kernel32.dll", "GetProcAddress", hModule, name);
+ # Create a named function pointer from the raw pointer return, that will go though the .api file
+ return miri::make_named_fn_ptr(rv, miri::cstr8_to_string(name));
+}
+
+fn AddVectoredExceptionHandler(..) -> usize {
+ 1
+}
+
diff --git a/tools/testrunner/main.cpp b/tools/testrunner/main.cpp
index 3823215a..a634d87a 100644
--- a/tools/testrunner/main.cpp
+++ b/tools/testrunner/main.cpp
@@ -37,6 +37,9 @@ struct Options
const char* input_glob = nullptr;
::std::vector<::std::string> test_list;
+ bool debug_enabled;
+ ::std::vector<::std::string> lib_dirs;
+
int debug_level = 0;
const char* exceptions_file = nullptr;
@@ -55,6 +58,12 @@ struct TestDesc
::std::vector<::std::string> m_pre_build;
::std::vector<::std::string> m_extra_flags;
bool ignore;
+ bool no_run;
+ TestDesc()
+ :ignore(false)
+ ,no_run(false)
+ {
+ }
};
struct Timestamp
{
@@ -94,20 +103,27 @@ struct Timestamp
}
};
-bool run_executable(const ::helpers::path& file, const ::std::vector<const char*>& args, const ::helpers::path& outfile);
+bool run_executable(const ::helpers::path& file, const ::std::vector<const char*>& args, const ::helpers::path& outfile, unsigned timeout_seconds);
-bool run_compiler(const ::helpers::path& source_file, const ::helpers::path& output, const ::std::vector<::std::string>& extra_flags, ::helpers::path libdir={}, bool is_dep=false)
+bool run_compiler(const Options& opts, const ::helpers::path& source_file, const ::helpers::path& output, const ::std::vector<::std::string>& extra_flags, ::helpers::path libdir={}, bool is_dep=false)
{
::std::vector<const char*> args;
args.push_back("mrustc");
// Force optimised and debuggable
args.push_back("-O");
- // TODO: Only turn debug on when requested by the caller
- //args.push_back("-g");
- args.push_back("-L");
- args.push_back("output");
+ // Only turn debug on when requested by the caller
+ if( opts.debug_enabled )
+ {
+ args.push_back("-g");
+ }
+
+ for(const auto& d : opts.lib_dirs)
+ {
+ args.push_back("-L");
+ args.push_back(d.c_str());
+ }
if(libdir.is_valid())
{
args.push_back("-L");
@@ -134,7 +150,16 @@ bool run_compiler(const ::helpers::path& source_file, const ::helpers::path& out
for(const auto& s : extra_flags)
args.push_back(s.c_str());
- return run_executable(MRUSTC_PATH, args, logfile);
+ return run_executable(MRUSTC_PATH, args, logfile, 0);
+}
+
+static bool gTimeout = false;
+static bool gInterrupted = false;
+void sigalrm_handler(int) {
+ gTimeout = true;
+}
+void sigint_handler(int) {
+ gInterrupted = true;
}
int main(int argc, const char* argv[])
@@ -145,6 +170,16 @@ int main(int argc, const char* argv[])
return v;
}
+#ifdef _WIN32
+#else
+ {
+ struct sigaction sa = {0};
+ sa.sa_handler = sigalrm_handler;
+ sigaction(SIGALRM, &sa, NULL);
+ signal(SIGINT, sigint_handler);
+ }
+#endif
+
::std::vector<::std::string> skip_list;
// > Filter out tests listed in an exceptions file (newline separated, supports comments)
if( opts.exceptions_file )
@@ -247,6 +282,10 @@ int main(int argc, const char* argv[])
{
td.ignore = true;
}
+ else if( line.substr(start, 4+1+7) == "skip-codegen" )
+ {
+ td.no_run = true;
+ }
else if( line.substr(start, 14) == "compile-flags:" )
{
auto end = line.find(' ', 3+14);
@@ -290,13 +329,19 @@ int main(int argc, const char* argv[])
::std::sort(tests.begin(), tests.end(), [](const auto& a, const auto& b){ return a.m_name < b.m_name; });
// ---
- auto compiler_ts = getenv("TESTRUNNER_NOCOMPILERDEP") ? Timestamp::infinite_past() : Timestamp::for_file(MRUSTC_PATH);
+ const bool SKIP_PASS = (getenv("TESTRUNNER_SKIPPASS") != nullptr);
+ const bool NO_COMPILER_DEP = (getenv("TESTRUNNER_NOCOMPILERDEP") != nullptr);
+ const auto compiler_ts = Timestamp::for_file(MRUSTC_PATH);
unsigned n_skip = 0;
unsigned n_cfail = 0;
unsigned n_fail = 0;
unsigned n_ok = 0;
for(const auto& test : tests)
{
+ if( gInterrupted ) {
+ DEBUG(">> Interrupted");
+ return 1;
+ }
if( !opts.test_list.empty() && ::std::find(opts.test_list.begin(), opts.test_list.end(), test.m_name) == opts.test_list.end() )
{
if( opts.debug_level > 0 )
@@ -319,10 +364,23 @@ int main(int argc, const char* argv[])
//DEBUG(">> " << test.m_name);
auto depdir = outdir / "deps-" + test.m_name.c_str();
- auto outfile = outdir / test.m_name + ".exe";
-
- auto test_output_ts = Timestamp::for_file(outfile);
- if( test_output_ts == Timestamp::infinite_past() || test_output_ts < compiler_ts )
+ auto test_exe = outdir / test.m_name + ".exe";
+ auto test_output = outdir / test.m_name + ".out";
+
+ auto test_exe_ts = Timestamp::for_file(test_exe);
+ auto test_output_ts = Timestamp::for_file(test_output);
+ // (Optional) if the target file doesn't exist, force a re-compile IF the compiler is newer than the
+ // executable.
+ if( SKIP_PASS )
+ {
+ // If output is missing (the last run didn't succeed), and the compiler is newer than the executable
+ if( test_output_ts == Timestamp::infinite_past() && test_exe_ts < compiler_ts )
+ {
+ // Force a recompile
+ test_exe_ts = Timestamp::infinite_past();
+ }
+ }
+ if( test_exe_ts == Timestamp::infinite_past() || (!NO_COMPILER_DEP && !SKIP_PASS && test_exe_ts < compiler_ts) )
{
bool pre_build_failed = false;
for(const auto& file : test.m_pre_build)
@@ -333,7 +391,7 @@ int main(int argc, const char* argv[])
mkdir(depdir.str().c_str(), 0755);
#endif
auto infile = input_path / "auxiliary" / file;
- if( !run_compiler(infile, depdir, {}, depdir, true) )
+ if( !run_compiler(opts, infile, depdir, {}, depdir, true) )
{
DEBUG("COMPILE FAIL " << infile << " (dep of " << test.m_name << ")");
n_cfail ++;
@@ -355,30 +413,36 @@ int main(int argc, const char* argv[])
depdir = ::helpers::path();
}
- auto compile_logfile = outdir / test.m_name + "-build.log";
- if( !run_compiler(test.m_path, outfile, test.m_extra_flags, depdir) )
+ auto compile_logfile = test_exe + "-build.log";
+ if( !run_compiler(opts, test.m_path, test_exe, test.m_extra_flags, depdir) )
{
- DEBUG("COMPILE FAIL " << test.m_name);
+ DEBUG("COMPILE FAIL " << test.m_name << ", log in " << compile_logfile);
n_cfail ++;
if( opts.fail_fast )
return 1;
else
continue;
}
- test_output_ts = Timestamp::for_file(outfile);
+ test_exe_ts = Timestamp::for_file(test_exe);
}
// - Run the test
- auto run_out_file = outdir / test.m_name + ".out";
- if( Timestamp::for_file(run_out_file) < test_output_ts )
+ if( test.no_run )
{
- if( !run_executable(outfile, { outfile.str().c_str() }, run_out_file) )
+ ::std::ofstream(test_output.str()) << "";
+ if( opts.debug_level > 0 )
+ DEBUG("No run " << test.m_name);
+ }
+ else if( test_output_ts < test_exe_ts )
+ {
+ auto run_out_file_tmp = test_output + ".tmp";
+ if( !run_executable(test_exe, { test_exe.str().c_str() }, run_out_file_tmp, 10) )
{
DEBUG("RUN FAIL " << test.m_name);
// Move the failing output file
- auto fail_file = run_out_file + "_failed";
+ auto fail_file = test_output + "_failed";
remove(fail_file.str().c_str());
- rename(run_out_file.str().c_str(), fail_file.str().c_str());
+ rename(run_out_file_tmp.str().c_str(), fail_file.str().c_str());
DEBUG("- Output in " << fail_file);
n_fail ++;
@@ -387,6 +451,11 @@ int main(int argc, const char* argv[])
else
continue;
}
+ else
+ {
+ remove(test_output.str().c_str());
+ rename(run_out_file_tmp.str().c_str(), test_output.str().c_str());
+ }
}
else
{
@@ -442,6 +511,16 @@ int Options::parse(int argc, const char* argv[])
case 'v':
this->debug_level += 1;
break;
+ case 'g':
+ this->debug_enabled = true;
+ break;
+ case 'L':
+ if( i+1 == argc ) {
+ this->usage_short();
+ return 1;
+ }
+ this->lib_dirs.push_back( argv[++i] );
+ break;
default:
this->usage_short();
@@ -501,7 +580,7 @@ void Options::usage_full() const
}
///
-bool run_executable(const ::helpers::path& exe_name, const ::std::vector<const char*>& args, const ::helpers::path& outfile)
+bool run_executable(const ::helpers::path& exe_name, const ::std::vector<const char*>& args, const ::helpers::path& outfile, unsigned timeout_seconds)
{
#ifdef _WIN32
::std::stringstream cmdline;
@@ -530,6 +609,7 @@ bool run_executable(const ::helpers::path& exe_name, const ::std::vector<const c
CreateProcessA(exe_name.str().c_str(), (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
SetErrorMode(em);
CloseHandle(si.hStdOutput);
+ // TODO: Use timeout_seconds
WaitForSingleObject(pi.hProcess, INFINITE);
DWORD status = 1;
GetExitCodeProcess(pi.hProcess, &status);
@@ -567,15 +647,24 @@ bool run_executable(const ::helpers::path& exe_name, const ::std::vector<const c
posix_spawn_file_actions_destroy(&file_actions);
int status = -1;
- waitpid(pid, &status, 0);
+ // NOTE: `alarm(0)` clears any pending alarm, so no need to check before
+ // calling
+ alarm(timeout_seconds);
+ if( waitpid(pid, &status, 0) <= 0 )
+ {
+ DEBUG(exe_name << " timed out, killing it");
+ kill(pid, SIGKILL);
+ return false;
+ }
+ alarm(0);
if( status != 0 )
{
if( WIFEXITED(status) )
- DEBUG(exe_name << " exited with non-zero exit status " << WEXITSTATUS(status) << ", see log " << outfile_str);
+ DEBUG(exe_name << " exited with non-zero exit status " << WEXITSTATUS(status));
else if( WIFSIGNALED(status) )
- DEBUG(exe_name << " was terminated with signal " << WTERMSIG(status) << ", see log " << outfile_str);
+ DEBUG(exe_name << " was terminated with signal " << WTERMSIG(status));
else
- DEBUG(exe_name << " terminated for unknown reason, status=" << status << ", see log " << outfile_str);
+ DEBUG(exe_name << " terminated for unknown reason, status=" << status);
return false;
}
#endif
diff --git a/vsproject/build_cargo_minicargo.cmd b/vsproject/build_cargo_minicargo.cmd
index 33725f4e..ce878e48 100644
--- a/vsproject/build_cargo_minicargo.cmd
+++ b/vsproject/build_cargo_minicargo.cmd
@@ -1,7 +1,6 @@
-@echo off
-call build_std.cmd
-if %errorlevel% neq 0 exit /b %errorlevel%
+@call build_std.cmd
+@if %errorlevel% neq 0 exit /b %errorlevel%
-mkdir output\cargo-build
-x64\Release\minicargo.exe ..\rustc-1.19.0-src\src\tools\cargo -L output --output-dir output\cargo-build --vendor-dir ..\rustc-1.19.0-src\src\vendor
-if %errorlevel% neq 0 exit /b %errorlevel% \ No newline at end of file
+@mkdir %OUTDIR%\cargo-build
+x64\Release\minicargo.exe ..\rustc-%RUSTC_VERSION%-src\src\tools\cargo -L %OUTDIR% --output-dir %OUTDIR%\cargo-build --vendor-dir ..\rustc-%RUSTC_VERSION%-src\src\vendor
+@if %errorlevel% neq 0 exit /b %errorlevel% \ No newline at end of file
diff --git a/vsproject/build_rustc_minicargo.cmd b/vsproject/build_rustc_minicargo.cmd
index acaadf47..af4ffb7b 100644
--- a/vsproject/build_rustc_minicargo.cmd
+++ b/vsproject/build_rustc_minicargo.cmd
@@ -1,7 +1,6 @@
-@echo off
-call build_std.cmd
-if %errorlevel% neq 0 exit /b %errorlevel%
+@call build_std.cmd
+@if %errorlevel% neq 0 exit /b %errorlevel%
-mkdir output\rustc-build
-x64\Release\minicargo.exe ..\rustc-1.19.0-src\src\rustc -L output --output-dir output\rustc-build --vendor-dir ..\rustc-1.19.0-src\src\vendor
-if %errorlevel% neq 0 exit /b %errorlevel% \ No newline at end of file
+@mkdir output\rustc-build
+x64\Release\minicargo.exe ..\rustc-%RUSTC_VERSION%-src\src\rustc -L %OUTDIR% --output-dir %OUTDIR%\rustc-build --vendor-dir ..\rustc-%RUSTC_VERSION%-src\src\vendor
+@if %errorlevel% neq 0 exit /b %errorlevel% \ No newline at end of file
diff --git a/vsproject/build_std.cmd b/vsproject/build_std.cmd
index 0a360614..ff09a0b6 100644
--- a/vsproject/build_std.cmd
+++ b/vsproject/build_std.cmd
@@ -1,9 +1,11 @@
-@echo off
-x64\Release\minicargo.exe ..\rustc-1.19.0-src\src\libstd --script-overrides ..\script-overrides\stable-1.19.0
-if %errorlevel% neq 0 exit /b %errorlevel%
-x64\Release\minicargo.exe ..\rustc-1.19.0-src\src\libpanic_unwind --script-overrides ..\script-overrides\stable-1.19.0
-if %errorlevel% neq 0 exit /b %errorlevel%
-x64\Release\minicargo.exe ..\rustc-1.19.0-src\src\libtest --script-overrides ..\script-overrides\stable-1.19.0
-if %errorlevel% neq 0 exit /b %errorlevel%
-x64\Release\minicargo.exe ..\lib\libproc_macro
-if %errorlevel% neq 0 exit /b %errorlevel%
+@set RUSTC_VERSION=1.29.0
+@set OUTDIR=output-%RUSTC_VERSION%
+@mkdir %OUTDIR%
+x64\Release\minicargo.exe ..\rustc-%RUSTC_VERSION%-src\src\libstd --output-dir %OUTDIR% --script-overrides ..\script-overrides\stable-%RUSTC_VERSION%-windows
+@if %errorlevel% neq 0 exit /b %errorlevel%
+x64\Release\minicargo.exe ..\rustc-%RUSTC_VERSION%-src\src\libpanic_unwind --output-dir %OUTDIR% --script-overrides ..\script-overrides\stable-%RUSTC_VERSION%-windows
+@if %errorlevel% neq 0 exit /b %errorlevel%
+x64\Release\minicargo.exe ..\rustc-%RUSTC_VERSION%-src\src\libtest --vendor-dir ..\rustc-%RUSTC_VERSION%-src\src\vendor --output-dir %OUTDIR% --script-overrides ..\script-overrides\stable-%RUSTC_VERSION%-windows
+@if %errorlevel% neq 0 exit /b %errorlevel%
+x64\Release\minicargo.exe ..\lib\libproc_macro --output-dir %OUTDIR%
+@if %errorlevel% neq 0 exit /b %errorlevel%
diff --git a/vsproject/minicargo/minicargo.vcxproj b/vsproject/minicargo/minicargo.vcxproj
index 8694bc11..b62aad66 100644
--- a/vsproject/minicargo/minicargo.vcxproj
+++ b/vsproject/minicargo/minicargo.vcxproj
@@ -82,6 +82,8 @@
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\tools\common</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>
+ </DisableSpecificWarnings>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(OutDir)</AdditionalLibraryDirectories>
@@ -94,6 +96,8 @@
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\tools\common</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>
+ </DisableSpecificWarnings>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(OutDir)</AdditionalLibraryDirectories>
@@ -108,6 +112,8 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\tools\common</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>
+ </DisableSpecificWarnings>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -124,6 +130,8 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\..\tools\common</AdditionalIncludeDirectories>
+ <DisableSpecificWarnings>
+ </DisableSpecificWarnings>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -134,6 +142,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\tools\minicargo\build.cpp" />
+ <ClCompile Include="..\..\tools\minicargo\cfg.cpp" />
<ClCompile Include="..\..\tools\minicargo\main.cpp" />
<ClCompile Include="..\..\tools\minicargo\manifest.cpp" />
<ClCompile Include="..\..\tools\minicargo\repository.cpp" />
diff --git a/vsproject/minicargo/minicargo.vcxproj.filters b/vsproject/minicargo/minicargo.vcxproj.filters
index 8fcee797..b9066a85 100644
--- a/vsproject/minicargo/minicargo.vcxproj.filters
+++ b/vsproject/minicargo/minicargo.vcxproj.filters
@@ -27,6 +27,9 @@
<ClCompile Include="..\..\tools\minicargo\repository.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\tools\minicargo\cfg.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\tools\minicargo\manifest.h">
diff --git a/vsproject/mrustc.vcxproj b/vsproject/mrustc.vcxproj
index 234ce37b..6b73a8c8 100644
--- a/vsproject/mrustc.vcxproj
+++ b/vsproject/mrustc.vcxproj
@@ -157,6 +157,8 @@
<ProjectReference />
</ItemDefinitionGroup>
<ItemGroup>
+ <ClCompile Include="..\src\trans\auto_impls.cpp" />
+ <ClCompile Include="..\src\trans\mangling_v2.cpp" />
<ClCompile Include="..\src\ast\ast.cpp" />
<ClCompile Include="..\src\ast\crate.cpp" />
<ClCompile Include="..\src\ast\dump.cpp" />
@@ -166,6 +168,7 @@
<ClCompile Include="..\src\ast\types.cpp" />
<ClCompile Include="..\src\debug.cpp" />
<ClCompile Include="..\src\expand\asm.cpp" />
+ <ClCompile Include="..\src\expand\assert.cpp" />
<ClCompile Include="..\src\expand\cfg.cpp" />
<ClCompile Include="..\src\expand\concat.cpp" />
<ClCompile Include="..\src\expand\crate_tags.cpp" />
@@ -193,6 +196,7 @@
<ClCompile Include="..\src\hir\from_ast_expr.cpp" />
<ClCompile Include="..\src\hir\generic_params.cpp" />
<ClCompile Include="..\src\hir\hir.cpp" />
+ <ClCompile Include="..\src\hir\hir_ops.cpp" />
<ClCompile Include="..\src\hir\path.cpp" />
<ClCompile Include="..\src\hir\pattern.cpp" />
<ClCompile Include="..\src\hir\serialise.cpp" />
@@ -204,6 +208,7 @@
<ClCompile Include="..\src\hir_conv\expand_type.cpp" />
<ClCompile Include="..\src\hir_conv\markings.cpp" />
<ClCompile Include="..\src\hir_conv\resolve_ufcs.cpp" />
+ <ClCompile Include="..\src\hir_conv\resolve_ufcs_outer.cpp" />
<ClCompile Include="..\src\hir_expand\annotate_value_usage.cpp" />
<ClCompile Include="..\src\hir_expand\closures.cpp" />
<ClCompile Include="..\src\hir_expand\erased_types.cpp" />
@@ -258,7 +263,6 @@
<ClCompile Include="..\src\trans\codegen_c_structured.cpp" />
<ClCompile Include="..\src\trans\codegen_mmir.cpp" />
<ClCompile Include="..\src\trans\enumerate.cpp" />
- <ClCompile Include="..\src\trans\mangling.cpp" />
<ClCompile Include="..\src\trans\monomorphise.cpp" />
<ClCompile Include="..\src\trans\target.cpp" />
<ClCompile Include="..\src\trans\trans_list.cpp" />
diff --git a/vsproject/mrustc.vcxproj.filters b/vsproject/mrustc.vcxproj.filters
index cedc5fd1..d94cdca8 100644
--- a/vsproject/mrustc.vcxproj.filters
+++ b/vsproject/mrustc.vcxproj.filters
@@ -209,9 +209,6 @@
<ClCompile Include="..\src\trans\monomorphise.cpp">
<Filter>Source Files\trans</Filter>
</ClCompile>
- <ClCompile Include="..\src\trans\mangling.cpp">
- <Filter>Source Files\trans</Filter>
- </ClCompile>
<ClCompile Include="..\src\expand\lang_item.cpp">
<Filter>Source Files\expand</Filter>
</ClCompile>
@@ -389,6 +386,21 @@
<ClCompile Include="..\src\version.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\src\trans\auto_impls.cpp">
+ <Filter>Source Files\trans</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\trans\mangling_v2.cpp">
+ <Filter>Source Files\trans</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\hir_conv\resolve_ufcs_outer.cpp">
+ <Filter>Source Files\hir_conv</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\hir\hir_ops.cpp">
+ <Filter>Source Files\hir</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\expand\assert.cpp">
+ <Filter>Source Files\expand</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\common.hpp">
diff --git a/vsproject/run_hello.cmd b/vsproject/run_hello.cmd
index b419bbc1..894e8240 100644
--- a/vsproject/run_hello.cmd
+++ b/vsproject/run_hello.cmd
@@ -1,8 +1,7 @@
-@echo off
-call build_std.cmd
-if %errorlevel% neq 0 exit /b %errorlevel%
+@call build_std.cmd
+@if %errorlevel% neq 0 exit /b %errorlevel%
-x64\Release\mrustc.exe ..\rustc-1.19.0-src\src\test\run-pass\hello.rs -L output -o output\hello.exe -g
-if %errorlevel% neq 0 exit /b %errorlevel%
-output\hello.exe
-if %errorlevel% neq 0 exit /b %errorlevel% \ No newline at end of file
+x64\Release\mrustc.exe ..\rustc-%RUSTC_VERSION%-src\src\test\run-pass\hello.rs -L %OUTDIR% -o %OUTDIR%\hello.exe -g
+@if %errorlevel% neq 0 exit /b %errorlevel%
+%OUTDIR%\hello.exe
+@if %errorlevel% neq 0 exit /b %errorlevel% \ No newline at end of file
diff --git a/vsproject/standalone_miri/standalone_miri.vcxproj b/vsproject/standalone_miri/standalone_miri.vcxproj
index ad97ff69..6b3c317c 100644
--- a/vsproject/standalone_miri/standalone_miri.vcxproj
+++ b/vsproject/standalone_miri/standalone_miri.vcxproj
@@ -71,16 +71,12 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
- <IntDir>$(Platform)\$(Configuration)\</IntDir>
- <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
- <IntDir>$(Platform)\$(Configuration)\</IntDir>
- <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
@@ -95,6 +91,7 @@
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatSpecificWarningsAsErrors>4062;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
+ <DisableSpecificWarnings>4061</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -111,6 +108,7 @@
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatSpecificWarningsAsErrors>4062;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
+ <DisableSpecificWarnings>4061</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -129,6 +127,7 @@
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatSpecificWarningsAsErrors>4062;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
+ <DisableSpecificWarnings>4061</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -149,6 +148,7 @@
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<TreatSpecificWarningsAsErrors>4062;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
+ <DisableSpecificWarnings>4061</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -169,6 +169,7 @@
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="..\..\src\rc_string.cpp" />
<ClCompile Include="..\..\tools\standalone_miri\debug.cpp" />
<ClCompile Include="..\..\tools\standalone_miri\hir_sim.cpp" />
<ClCompile Include="..\..\tools\standalone_miri\lex.cpp" />
@@ -181,4 +182,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>
+</Project> \ No newline at end of file
diff --git a/vsproject/standalone_miri/standalone_miri.vcxproj.filters b/vsproject/standalone_miri/standalone_miri.vcxproj.filters
index 3b25bbfb..5e7af341 100644
--- a/vsproject/standalone_miri/standalone_miri.vcxproj.filters
+++ b/vsproject/standalone_miri/standalone_miri.vcxproj.filters
@@ -62,5 +62,8 @@
<ClCompile Include="..\..\tools\standalone_miri\miri.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\rc_string.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
</Project> \ No newline at end of file