Merge branch 'master' into kmath
Conflicts: src/libcore/cmath.rs
This commit is contained in:
commit
6284190ef9
113 changed files with 2814 additions and 766 deletions
|
|
@ -26,6 +26,7 @@ Jeffrey Yasskin <jyasskin@gmail.com>
|
|||
Jesse Ruderman <jruderman@gmail.com>
|
||||
Josh Matthews <josh@joshmatthews.net>
|
||||
Joshua Wise <joshua@joshuawise.com>
|
||||
Jyun-Yan You <jyyou@cs.nctu.edu.tw>
|
||||
Kelly Wilson <wilsonk@cpsc.ucalgary.ca>
|
||||
Lennart Kudling
|
||||
Lindsey Kuper <lkuper@mozilla.com>
|
||||
|
|
|
|||
2
configure
vendored
2
configure
vendored
|
|
@ -212,7 +212,7 @@ case $CFG_CPUTYPE in
|
|||
CFG_CPUTYPE=arm
|
||||
;;
|
||||
|
||||
x86_64 | x86-64 | x64)
|
||||
x86_64 | x86-64 | x64 | amd64)
|
||||
CFG_CPUTYPE=x86_64
|
||||
;;
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ de-initialized on the caller side, and give ownership of it to the
|
|||
called function. This is written `-`.
|
||||
|
||||
Finally, the default passing styles (by-value for non-structural
|
||||
types, by-reference for structural ones) are written `+` for by-value
|
||||
types, by-reference for structural ones) are written `++` for by-value
|
||||
and `&&` for by(-immutable)-reference. It is sometimes necessary to
|
||||
override the defaults. We'll talk more about this when discussing
|
||||
[generics][gens].
|
||||
|
|
|
|||
353
mk/libuv/x86_64/freebsd/Makefile
Normal file
353
mk/libuv/x86_64/freebsd/Makefile
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
# We borrow heavily from the kernel build setup, though we are simpler since
|
||||
# we don't have Kconfig tweaking settings on us.
|
||||
|
||||
# The implicit make rules have it looking for RCS files, among other things.
|
||||
# We instead explicitly write all the rules we care about.
|
||||
# It's even quicker (saves ~200ms) to pass -r on the command line.
|
||||
MAKEFLAGS=-r
|
||||
|
||||
# The source directory tree.
|
||||
srcdir := ../../../..
|
||||
|
||||
# The name of the builddir.
|
||||
builddir_name ?= out
|
||||
|
||||
# The V=1 flag on command line makes us verbosely print command lines.
|
||||
ifdef V
|
||||
quiet=
|
||||
else
|
||||
quiet=quiet_
|
||||
endif
|
||||
|
||||
# Specify BUILDTYPE=Release on the command line for a release build.
|
||||
BUILDTYPE ?= Default
|
||||
|
||||
# Directory all our build output goes into.
|
||||
# Note that this must be two directories beneath src/ for unit tests to pass,
|
||||
# as they reach into the src/ directory for data with relative paths.
|
||||
builddir ?= $(builddir_name)/$(BUILDTYPE)
|
||||
abs_builddir := $(abspath $(builddir))
|
||||
depsdir := $(builddir)/.deps
|
||||
|
||||
# Object output directory.
|
||||
obj := $(builddir)/obj
|
||||
abs_obj := $(abspath $(obj))
|
||||
|
||||
# We build up a list of every single one of the targets so we can slurp in the
|
||||
# generated dependency rule Makefiles in one pass.
|
||||
all_deps :=
|
||||
|
||||
|
||||
|
||||
# C++ apps need to be linked with g++.
|
||||
#
|
||||
# Note: flock is used to seralize linking. Linking is a memory-intensive
|
||||
# process so running parallel links can often lead to thrashing. To disable
|
||||
# the serialization, override LINK via an envrionment variable as follows:
|
||||
#
|
||||
# export LINK=g++
|
||||
#
|
||||
# This will allow make to invoke N linker processes as specified in -jN.
|
||||
LINK ?= lockf $(builddir)/linker.lock $(CXX)
|
||||
|
||||
CC.target ?= $(CC)
|
||||
CFLAGS.target ?= $(CFLAGS)
|
||||
CXX.target ?= $(CXX)
|
||||
CXXFLAGS.target ?= $(CXXFLAGS)
|
||||
LINK.target ?= $(LINK)
|
||||
LDFLAGS.target ?= $(LDFLAGS)
|
||||
AR.target ?= $(AR)
|
||||
ARFLAGS.target ?= crs
|
||||
|
||||
# N.B.: the logic of which commands to run should match the computation done
|
||||
# in gyp's make.py where ARFLAGS.host etc. is computed.
|
||||
# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
|
||||
# to replicate this environment fallback in make as well.
|
||||
CC.host ?= gcc
|
||||
CFLAGS.host ?=
|
||||
CXX.host ?= g++
|
||||
CXXFLAGS.host ?=
|
||||
LINK.host ?= g++
|
||||
LDFLAGS.host ?=
|
||||
AR.host ?= ar
|
||||
ARFLAGS.host := crs
|
||||
|
||||
# Define a dir function that can handle spaces.
|
||||
# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
|
||||
# "leading spaces cannot appear in the text of the first argument as written.
|
||||
# These characters can be put into the argument value by variable substitution."
|
||||
empty :=
|
||||
space := $(empty) $(empty)
|
||||
|
||||
# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
|
||||
replace_spaces = $(subst $(space),?,$1)
|
||||
unreplace_spaces = $(subst ?,$(space),$1)
|
||||
dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
|
||||
|
||||
# Flags to make gcc output dependency info. Note that you need to be
|
||||
# careful here to use the flags that ccache and distcc can understand.
|
||||
# We write to a dep file on the side first and then rename at the end
|
||||
# so we can't end up with a broken dep file.
|
||||
depfile = $(depsdir)/$(call replace_spaces,$@).d
|
||||
DEPFLAGS = -MMD -MF $(depfile).raw
|
||||
|
||||
# We have to fixup the deps output in a few ways.
|
||||
# (1) the file output should mention the proper .o file.
|
||||
# ccache or distcc lose the path to the target, so we convert a rule of
|
||||
# the form:
|
||||
# foobar.o: DEP1 DEP2
|
||||
# into
|
||||
# path/to/foobar.o: DEP1 DEP2
|
||||
# (2) we want missing files not to cause us to fail to build.
|
||||
# We want to rewrite
|
||||
# foobar.o: DEP1 DEP2 \
|
||||
# DEP3
|
||||
# to
|
||||
# DEP1:
|
||||
# DEP2:
|
||||
# DEP3:
|
||||
# so if the files are missing, they're just considered phony rules.
|
||||
# We have to do some pretty insane escaping to get those backslashes
|
||||
# and dollar signs past make, the shell, and sed at the same time.
|
||||
# Doesn't work with spaces, but that's fine: .d files have spaces in
|
||||
# their names replaced with other characters.
|
||||
define fixup_dep
|
||||
# The depfile may not exist if the input file didn't have any #includes.
|
||||
touch $(depfile).raw
|
||||
# Fixup path as in (1).
|
||||
sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
|
||||
# Add extra rules as in (2).
|
||||
# We remove slashes and replace spaces with new lines;
|
||||
# remove blank lines;
|
||||
# delete the first line and append a colon to the remaining lines.
|
||||
sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
|
||||
grep -v '^$$' |\
|
||||
sed -e 1d -e 's|$$|:|' \
|
||||
>> $(depfile)
|
||||
rm $(depfile).raw
|
||||
endef
|
||||
|
||||
# Command definitions:
|
||||
# - cmd_foo is the actual command to run;
|
||||
# - quiet_cmd_foo is the brief-output summary of the command.
|
||||
|
||||
quiet_cmd_cc = CC($(TOOLSET)) $@
|
||||
cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
|
||||
|
||||
quiet_cmd_cxx = CXX($(TOOLSET)) $@
|
||||
cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
|
||||
|
||||
quiet_cmd_touch = TOUCH $@
|
||||
cmd_touch = touch $@
|
||||
|
||||
quiet_cmd_copy = COPY $@
|
||||
# send stderr to /dev/null to ignore messages when linking directories.
|
||||
cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
|
||||
|
||||
quiet_cmd_alink = AR($(TOOLSET)) $@
|
||||
cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) $(ARFLAGS.$(TOOLSET)) $@ $(filter %.o,$^)
|
||||
|
||||
# Due to circular dependencies between libraries :(, we wrap the
|
||||
# special "figure out circular dependencies" flags around the entire
|
||||
# input list during linking.
|
||||
quiet_cmd_link = LINK($(TOOLSET)) $@
|
||||
cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
|
||||
|
||||
# We support two kinds of shared objects (.so):
|
||||
# 1) shared_library, which is just bundling together many dependent libraries
|
||||
# into a link line.
|
||||
# 2) loadable_module, which is generating a module intended for dlopen().
|
||||
#
|
||||
# They differ only slightly:
|
||||
# In the former case, we want to package all dependent code into the .so.
|
||||
# In the latter case, we want to package just the API exposed by the
|
||||
# outermost module.
|
||||
# This means shared_library uses --whole-archive, while loadable_module doesn't.
|
||||
# (Note that --whole-archive is incompatible with the --start-group used in
|
||||
# normal linking.)
|
||||
|
||||
# Other shared-object link notes:
|
||||
# - Set SONAME to the library filename so our binaries don't reference
|
||||
# the local, absolute paths used on the link command-line.
|
||||
quiet_cmd_solink = SOLINK($(TOOLSET)) $@
|
||||
cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
|
||||
|
||||
quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
|
||||
cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
|
||||
|
||||
|
||||
# Define an escape_quotes function to escape single quotes.
|
||||
# This allows us to handle quotes properly as long as we always use
|
||||
# use single quotes and escape_quotes.
|
||||
escape_quotes = $(subst ','\'',$(1))
|
||||
# This comment is here just to include a ' to unconfuse syntax highlighting.
|
||||
# Define an escape_vars function to escape '$' variable syntax.
|
||||
# This allows us to read/write command lines with shell variables (e.g.
|
||||
# $LD_LIBRARY_PATH), without triggering make substitution.
|
||||
escape_vars = $(subst $$,$$$$,$(1))
|
||||
# Helper that expands to a shell command to echo a string exactly as it is in
|
||||
# make. This uses printf instead of echo because printf's behaviour with respect
|
||||
# to escape sequences is more portable than echo's across different shells
|
||||
# (e.g., dash, bash).
|
||||
exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
|
||||
|
||||
# Helper to compare the command we're about to run against the command
|
||||
# we logged the last time we ran the command. Produces an empty
|
||||
# string (false) when the commands match.
|
||||
# Tricky point: Make has no string-equality test function.
|
||||
# The kernel uses the following, but it seems like it would have false
|
||||
# positives, where one string reordered its arguments.
|
||||
# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
|
||||
# $(filter-out $(cmd_$@), $(cmd_$(1))))
|
||||
# We instead substitute each for the empty string into the other, and
|
||||
# say they're equal if both substitutions produce the empty string.
|
||||
# .d files contain ? instead of spaces, take that into account.
|
||||
command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
|
||||
$(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
|
||||
|
||||
# Helper that is non-empty when a prerequisite changes.
|
||||
# Normally make does this implicitly, but we force rules to always run
|
||||
# so we can check their command lines.
|
||||
# $? -- new prerequisites
|
||||
# $| -- order-only dependencies
|
||||
prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
|
||||
|
||||
# Helper that executes all postbuilds, and deletes the output file when done
|
||||
# if any of the postbuilds failed.
|
||||
define do_postbuilds
|
||||
@E=0;\
|
||||
for p in $(POSTBUILDS); do\
|
||||
eval $$p;\
|
||||
F=$$?;\
|
||||
if [ $$F -ne 0 ]; then\
|
||||
E=$$F;\
|
||||
fi;\
|
||||
done;\
|
||||
if [ $$E -ne 0 ]; then\
|
||||
rm -rf "$@";\
|
||||
exit $$E;\
|
||||
fi
|
||||
endef
|
||||
|
||||
# do_cmd: run a command via the above cmd_foo names, if necessary.
|
||||
# Should always run for a given target to handle command-line changes.
|
||||
# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
|
||||
# Third argument, if non-zero, makes it do POSTBUILDS processing.
|
||||
# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
|
||||
# spaces already and dirx strips the ? characters.
|
||||
define do_cmd
|
||||
$(if $(or $(command_changed),$(prereq_changed)),
|
||||
@$(call exact_echo, $($(quiet)cmd_$(1)))
|
||||
@mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
|
||||
$(if $(findstring flock,$(word 1,$(cmd_$1))),
|
||||
@$(cmd_$(1))
|
||||
@echo " $(quiet_cmd_$(1)): Finished",
|
||||
@$(cmd_$(1))
|
||||
)
|
||||
@$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
|
||||
@$(if $(2),$(fixup_dep))
|
||||
$(if $(and $(3), $(POSTBUILDS)),
|
||||
$(call do_postbuilds)
|
||||
)
|
||||
)
|
||||
endef
|
||||
|
||||
# Declare the "all" target first so it is the default,
|
||||
# even though we don't have the deps yet.
|
||||
.PHONY: all
|
||||
all:
|
||||
|
||||
# Use FORCE_DO_CMD to force a target to run. Should be coupled with
|
||||
# do_cmd.
|
||||
.PHONY: FORCE_DO_CMD
|
||||
FORCE_DO_CMD:
|
||||
|
||||
TOOLSET := target
|
||||
# Suffix rules, putting all outputs into $(obj).
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
# Try building from generated source, too.
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
|
||||
@$(call do_cmd,cxx,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
|
||||
ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
|
||||
$(findstring $(join ^,$(prefix)),\
|
||||
$(join ^,src/libuv/run-benchmarks.target.mk)))),)
|
||||
include src/libuv/run-benchmarks.target.mk
|
||||
endif
|
||||
ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
|
||||
$(findstring $(join ^,$(prefix)),\
|
||||
$(join ^,src/libuv/run-tests.target.mk)))),)
|
||||
include src/libuv/run-tests.target.mk
|
||||
endif
|
||||
ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
|
||||
$(findstring $(join ^,$(prefix)),\
|
||||
$(join ^,src/libuv/uv.target.mk)))),)
|
||||
include src/libuv/uv.target.mk
|
||||
endif
|
||||
|
||||
quiet_cmd_regen_makefile = ACTION Regenerating $@
|
||||
cmd_regen_makefile = ./src/libuv/build/gyp/gyp -fmake --ignore-environment "--toplevel-dir=." "--depth=." "--generator-output=mk/libuv/x86_64/unix" "-Dlibrary=static_library" "-Dtarget_arch=x86_64" "-DOS=freebsd" src/libuv/uv.gyp
|
||||
Makefile: $(srcdir)/src/libuv/uv.gyp
|
||||
# $(call do_cmd,regen_makefile)
|
||||
|
||||
# "all" is a concatenation of the "all" targets from all the included
|
||||
# sub-makefiles. This is just here to clarify.
|
||||
all:
|
||||
|
||||
# Add in dependency-tracking rules. $(all_deps) is the list of every single
|
||||
# target in our tree. Only consider the ones with .d (dependency) info:
|
||||
d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
|
||||
ifneq ($(d_files),)
|
||||
# Rather than include each individual .d file, concatenate them into a
|
||||
# single file which make is able to load faster. We split this into
|
||||
# commands that take 1000 files at a time to avoid overflowing the
|
||||
# command line.
|
||||
$(shell cat $(wordlist 1,1000,$(d_files)) > $(depsdir)/all.deps)
|
||||
|
||||
ifneq ($(word 1001,$(d_files)),)
|
||||
$(error Found unprocessed dependency files (gyp didn't generate enough rules!))
|
||||
endif
|
||||
|
||||
# make looks for ways to re-generate included makefiles, but in our case, we
|
||||
# don't have a direct way. Explicitly telling make that it has nothing to do
|
||||
# for them makes it go faster.
|
||||
$(depsdir)/all.deps: ;
|
||||
|
||||
include $(depsdir)/all.deps
|
||||
endif
|
||||
83
mk/libuv/x86_64/freebsd/src/libuv/run-benchmarks.target.mk
Normal file
83
mk/libuv/x86_64/freebsd/src/libuv/run-benchmarks.target.mk
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# This file is generated by gyp; do not edit.
|
||||
|
||||
TOOLSET := target
|
||||
TARGET := run-benchmarks
|
||||
DEFS_Default := '-D_LARGEFILE_SOURCE' \
|
||||
'-D_FILE_OFFSET_BITS=64' \
|
||||
'-D_GNU_SOURCE' \
|
||||
'-DEIO_STACKSIZE=262144'
|
||||
|
||||
# Flags passed to all source files.
|
||||
CFLAGS_Default := -pthread
|
||||
|
||||
# Flags passed to only C files.
|
||||
CFLAGS_C_Default :=
|
||||
|
||||
# Flags passed to only C++ files.
|
||||
CFLAGS_CC_Default :=
|
||||
|
||||
INCS_Default := -I$(srcdir)/src/libuv/include
|
||||
|
||||
OBJS := $(obj).target/$(TARGET)/src/libuv/test/benchmark-ares.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/benchmark-getaddrinfo.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/benchmark-ping-pongs.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/benchmark-pound.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/benchmark-pump.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/benchmark-sizes.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/benchmark-spawn.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/benchmark-tcp-write-batch.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/benchmark-udp-packet-storm.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/dns-server.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/echo-server.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/blackhole-server.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/run-benchmarks.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/runner.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/runner-unix.o
|
||||
|
||||
# Add to the list of files we specially track dependencies for.
|
||||
all_deps += $(OBJS)
|
||||
|
||||
# Make sure our dependencies are built before any of us.
|
||||
$(OBJS): | $(obj).target/src/libuv/libuv.a
|
||||
|
||||
# CFLAGS et al overrides must be target-local.
|
||||
# See "Target-specific Variable Values" in the GNU Make manual.
|
||||
$(OBJS): TOOLSET := $(TOOLSET)
|
||||
$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
|
||||
$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
|
||||
|
||||
# Suffix rules, putting all outputs into $(obj).
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
# Try building from generated source, too.
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
# End of this set of suffix rules
|
||||
### Rules for final target.
|
||||
LDFLAGS_Default :=
|
||||
|
||||
LIBS :=
|
||||
|
||||
$(builddir)/run-benchmarks: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
|
||||
$(builddir)/run-benchmarks: LIBS := $(LIBS)
|
||||
$(builddir)/run-benchmarks: LD_INPUTS := $(OBJS) $(obj).target/src/libuv/libuv.a
|
||||
$(builddir)/run-benchmarks: TOOLSET := $(TOOLSET)
|
||||
$(builddir)/run-benchmarks: $(OBJS) $(obj).target/src/libuv/libuv.a FORCE_DO_CMD
|
||||
$(call do_cmd,link)
|
||||
|
||||
all_deps += $(builddir)/run-benchmarks
|
||||
# Add target alias
|
||||
.PHONY: run-benchmarks
|
||||
run-benchmarks: $(builddir)/run-benchmarks
|
||||
|
||||
# Add executable to "all" target.
|
||||
.PHONY: all
|
||||
all: $(builddir)/run-benchmarks
|
||||
|
||||
117
mk/libuv/x86_64/freebsd/src/libuv/run-tests.target.mk
Normal file
117
mk/libuv/x86_64/freebsd/src/libuv/run-tests.target.mk
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
# This file is generated by gyp; do not edit.
|
||||
|
||||
TOOLSET := target
|
||||
TARGET := run-tests
|
||||
DEFS_Default := '-D_LARGEFILE_SOURCE' \
|
||||
'-D_FILE_OFFSET_BITS=64' \
|
||||
'-D_GNU_SOURCE' \
|
||||
'-DEIO_STACKSIZE=262144'
|
||||
|
||||
# Flags passed to all source files.
|
||||
CFLAGS_Default := -pthread
|
||||
|
||||
# Flags passed to only C files.
|
||||
CFLAGS_C_Default :=
|
||||
|
||||
# Flags passed to only C++ files.
|
||||
CFLAGS_CC_Default :=
|
||||
|
||||
INCS_Default := -I$(srcdir)/src/libuv/include
|
||||
|
||||
OBJS := $(obj).target/$(TARGET)/src/libuv/test/blackhole-server.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/echo-server.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/run-tests.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/runner.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-get-loadavg.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-async.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-error.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-callback-stack.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-connection-fail.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-delayed-accept.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-fail-always.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-fs.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-fs-event.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-get-currentexe.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-get-memory.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-getaddrinfo.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-gethostbyname.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-getsockname.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-hrtime.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-idle.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-ipc.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-loop-handles.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-multiple-listen.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-pass-always.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-ping-pong.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-bind-error.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-pipe-connect-error.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-ref.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-shutdown-eof.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-spawn.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-stdio-over-pipes.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-bind-error.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-bind6-error.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-close.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-flags.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-connect-error.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-connect6-error.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-write-error.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-write-to-half-open-connection.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-tcp-writealot.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-threadpool.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-timer-again.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-timer.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-tty.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-udp-dgram-too-big.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-udp-ipv6.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-udp-send-and-recv.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/test-udp-multicast-join.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/test/runner-unix.o
|
||||
|
||||
# Add to the list of files we specially track dependencies for.
|
||||
all_deps += $(OBJS)
|
||||
|
||||
# Make sure our dependencies are built before any of us.
|
||||
$(OBJS): | $(obj).target/src/libuv/libuv.a
|
||||
|
||||
# CFLAGS et al overrides must be target-local.
|
||||
# See "Target-specific Variable Values" in the GNU Make manual.
|
||||
$(OBJS): TOOLSET := $(TOOLSET)
|
||||
$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
|
||||
$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
|
||||
|
||||
# Suffix rules, putting all outputs into $(obj).
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
# Try building from generated source, too.
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
# End of this set of suffix rules
|
||||
### Rules for final target.
|
||||
LDFLAGS_Default :=
|
||||
|
||||
LIBS :=
|
||||
|
||||
$(builddir)/run-tests: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
|
||||
$(builddir)/run-tests: LIBS := $(LIBS)
|
||||
$(builddir)/run-tests: LD_INPUTS := $(OBJS) $(obj).target/src/libuv/libuv.a
|
||||
$(builddir)/run-tests: TOOLSET := $(TOOLSET)
|
||||
$(builddir)/run-tests: $(OBJS) $(obj).target/src/libuv/libuv.a FORCE_DO_CMD
|
||||
$(call do_cmd,link)
|
||||
|
||||
all_deps += $(builddir)/run-tests
|
||||
# Add target alias
|
||||
.PHONY: run-tests
|
||||
run-tests: $(builddir)/run-tests
|
||||
|
||||
# Add executable to "all" target.
|
||||
.PHONY: all
|
||||
all: $(builddir)/run-tests
|
||||
|
||||
6
mk/libuv/x86_64/freebsd/src/libuv/uv.Makefile
Normal file
6
mk/libuv/x86_64/freebsd/src/libuv/uv.Makefile
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# This file is generated by gyp; do not edit.
|
||||
|
||||
export builddir_name ?= mk/libuv/x86_64/unix/./src/libuv/out
|
||||
.PHONY: all
|
||||
all:
|
||||
$(MAKE) -C ../.. uv run-benchmarks run-tests
|
||||
138
mk/libuv/x86_64/freebsd/src/libuv/uv.target.mk
Normal file
138
mk/libuv/x86_64/freebsd/src/libuv/uv.target.mk
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
# This file is generated by gyp; do not edit.
|
||||
|
||||
TOOLSET := target
|
||||
TARGET := uv
|
||||
DEFS_Default := '-D_LARGEFILE_SOURCE' \
|
||||
'-D_FILE_OFFSET_BITS=64' \
|
||||
'-D_GNU_SOURCE' \
|
||||
'-DEIO_STACKSIZE=262144' \
|
||||
'-DHAVE_CONFIG_H' \
|
||||
'-DEV_CONFIG_H="config_freebsd.h"' \
|
||||
'-DEIO_CONFIG_H="config_freebsd.h"'
|
||||
|
||||
# Flags passed to all source files.
|
||||
CFLAGS_Default := -pthread \
|
||||
-g \
|
||||
--std=gnu89 \
|
||||
-pedantic \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wno-unused-parameter
|
||||
|
||||
# Flags passed to only C files.
|
||||
CFLAGS_C_Default :=
|
||||
|
||||
# Flags passed to only C++ files.
|
||||
CFLAGS_CC_Default :=
|
||||
|
||||
INCS_Default := -I$(srcdir)/src/libuv/include \
|
||||
-I$(srcdir)/src/libuv/include/uv-private \
|
||||
-I$(srcdir)/src/libuv/src \
|
||||
-I$(srcdir)/src/libuv/src/unix/ev \
|
||||
-I$(srcdir)/src/libuv/src/ares/config_freebsd
|
||||
|
||||
OBJS := $(obj).target/$(TARGET)/src/libuv/src/uv-common.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_cancel.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares__close_sockets.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_data.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_destroy.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_expand_name.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_expand_string.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_fds.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_free_hostent.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_free_string.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_gethostbyaddr.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_gethostbyname.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares__get_hostent.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_getnameinfo.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_getopt.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_getsock.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_init.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_library_init.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_llist.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_mkquery.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_nowarn.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_options.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_aaaa_reply.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_a_reply.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_mx_reply.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_ns_reply.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_ptr_reply.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_srv_reply.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_parse_txt_reply.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_process.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_query.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares__read_line.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_search.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_send.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_strcasecmp.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_strdup.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_strerror.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_timeout.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares__timeval.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_version.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/ares_writev.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/bitncmp.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/inet_net_pton.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/inet_ntop.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/ares/windows_port.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/core.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/uv-eio.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/fs.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/udp.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/tcp.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/pipe.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/tty.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/stream.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/cares.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/dl.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/error.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/process.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/eio/eio.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/ev/ev.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/freebsd.o \
|
||||
$(obj).target/$(TARGET)/src/libuv/src/unix/kqueue.o
|
||||
|
||||
# Add to the list of files we specially track dependencies for.
|
||||
all_deps += $(OBJS)
|
||||
|
||||
# CFLAGS et al overrides must be target-local.
|
||||
# See "Target-specific Variable Values" in the GNU Make manual.
|
||||
$(OBJS): TOOLSET := $(TOOLSET)
|
||||
$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
|
||||
$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
|
||||
|
||||
# Suffix rules, putting all outputs into $(obj).
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
# Try building from generated source, too.
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
|
||||
@$(call do_cmd,cc,1)
|
||||
|
||||
# End of this set of suffix rules
|
||||
### Rules for final target.
|
||||
LDFLAGS_Default :=
|
||||
|
||||
LIBS := -lm
|
||||
|
||||
$(obj).target/src/libuv/libuv.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
|
||||
$(obj).target/src/libuv/libuv.a: LIBS := $(LIBS)
|
||||
$(obj).target/src/libuv/libuv.a: TOOLSET := $(TOOLSET)
|
||||
$(obj).target/src/libuv/libuv.a: $(OBJS) FORCE_DO_CMD
|
||||
$(call do_cmd,alink)
|
||||
|
||||
all_deps += $(obj).target/src/libuv/libuv.a
|
||||
# Add target alias
|
||||
.PHONY: uv
|
||||
uv: $(obj).target/src/libuv/libuv.a
|
||||
|
||||
# Add target alias to "all" target.
|
||||
.PHONY: all
|
||||
all: uv
|
||||
|
||||
|
|
@ -24,14 +24,15 @@ endif
|
|||
ifneq ($(findstring freebsd,$(CFG_OSTYPE)),)
|
||||
CFG_LIB_NAME=lib$(1).so
|
||||
CFG_LIB_GLOB=lib$(1)-*.so
|
||||
CFG_GCCISH_CFLAGS += -fPIC -march=i686 -I/usr/local/include
|
||||
CFG_GCCISH_CFLAGS += -fPIC -I/usr/local/include
|
||||
CFG_GCCISH_LINK_FLAGS += -shared -fPIC -lpthread -lrt
|
||||
ifeq ($(CFG_CPUTYPE), x86_64)
|
||||
CFG_GCCISH_CFLAGS_i386 += -m32
|
||||
CFG_GCCISH_LINK_FLAGS_i386 += -m32
|
||||
CFG_GCCISH_CFLAGS_x86_64 += -m32
|
||||
CFG_GCCISH_LINK_FLAGS_x86_64 += -m32
|
||||
endif
|
||||
CFG_GCCISH_DEF_FLAG := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS := -Wl,-no-whole-archive
|
||||
CFG_GCCISH_CFLAGS_i386 += -m32
|
||||
CFG_GCCISH_LINK_FLAGS_i386 += -m32
|
||||
CFG_GCCISH_CFLAGS_x86_64 += -m64
|
||||
CFG_GCCISH_LINK_FLAGS_x86_64 += -m64
|
||||
CFG_UNIXY := 1
|
||||
CFG_LDENV := LD_LIBRARY_PATH
|
||||
CFG_DEF_SUFFIX := .bsd.def
|
||||
|
|
@ -246,4 +247,4 @@ define CFG_MAKE_ASSEMBLER
|
|||
endef
|
||||
|
||||
$(foreach target,$(CFG_TARGET_TRIPLES),\
|
||||
$(eval $(call CFG_MAKE_ASSEMBLER,$(target))))
|
||||
$(eval $(call CFG_MAKE_ASSEMBLER,$(target))))
|
||||
|
|
|
|||
9
mk/rt.mk
9
mk/rt.mk
|
|
@ -119,6 +119,9 @@ ifeq ($$(CFG_WINDOWSY), 1)
|
|||
else ifeq ($(CFG_OSTYPE), apple-darwin)
|
||||
LIBUV_OSTYPE_$(1) := mac
|
||||
LIBUV_LIB_$(1) := rt/$(1)/libuv/Default/libuv.a
|
||||
else ifeq ($(CFG_OSTYPE), unknown-freebsd)
|
||||
LIBUV_OSTYPE_$(1) := freebsd
|
||||
LIBUV_LIB_$(1) := rt/$(1)/libuv/Default/obj.target/src/libuv/libuv.a
|
||||
else
|
||||
LIBUV_OSTYPE_$(1) := unix
|
||||
LIBUV_LIB_$(1) := rt/$(1)/libuv/Default/obj.target/src/libuv/libuv.a
|
||||
|
|
@ -174,6 +177,12 @@ $$(LIBUV_LIB_$(1)): $$(wildcard \
|
|||
# These could go in rt.mk or rustllvm.mk, they're needed for both.
|
||||
|
||||
# This regexp has a single $, escaped twice
|
||||
%.bsd.def: %.def.in $$(MKFILE_DEPS)
|
||||
@$$(call E, def: $$@)
|
||||
$$(Q)echo "{" > $$@
|
||||
$$(Q)sed 's/.$$$$/&;/' $$< >> $$@
|
||||
$$(Q)echo "};" >> $$@
|
||||
|
||||
%.linux.def: %.def.in $$(MKFILE_DEPS)
|
||||
@$$(call E, def: $$@)
|
||||
$$(Q)echo "{" > $$@
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ fn llvm_err(sess: session::session, msg: str) unsafe {
|
|||
let buf = llvm::LLVMRustGetLastError();
|
||||
if buf == ptr::null() {
|
||||
sess.fatal(msg);
|
||||
} else { sess.fatal(msg + ": " + str::str_from_cstr(buf)); }
|
||||
} else { sess.fatal(msg + ": " + str::from_cstr(buf)); }
|
||||
}
|
||||
|
||||
fn load_intrinsics_bc(sess: session::session) -> option::t<ModuleRef> {
|
||||
|
|
@ -566,7 +566,8 @@ fn link_binary(sess: session::session,
|
|||
let rmlib =
|
||||
bind fn (config: @session::config, filename: str) -> str {
|
||||
if config.os == session::os_macos ||
|
||||
config.os == session::os_linux &&
|
||||
(config.os == session::os_linux ||
|
||||
config.os == session::os_freebsd) &&
|
||||
str::find(filename, "lib") == 0 {
|
||||
ret str::slice(filename, 3u,
|
||||
str::byte_len(filename));
|
||||
|
|
@ -580,6 +581,7 @@ fn link_binary(sess: session::session,
|
|||
ret alt config.os {
|
||||
session::os_macos. { rmext(rmlib(filename)) }
|
||||
session::os_linux. { rmext(rmlib(filename)) }
|
||||
session::os_freebsd. { rmext(rmlib(filename)) }
|
||||
_ { rmext(filename) }
|
||||
};
|
||||
}
|
||||
|
|
@ -657,6 +659,15 @@ fn link_binary(sess: session::session,
|
|||
gcc_args += ["-lrt", "-ldl"];
|
||||
}
|
||||
|
||||
if sess.get_targ_cfg().os == session::os_freebsd {
|
||||
gcc_args += ["-lrt", "-L/usr/local/lib", "-lexecinfo",
|
||||
"-L/usr/local/lib/gcc46",
|
||||
"-L/usr/local/lib/gcc44", "-lstdc++",
|
||||
"-Wl,-z,origin",
|
||||
"-Wl,-rpath,/usr/local/lib/gcc46",
|
||||
"-Wl,-rpath,/usr/local/lib/gcc44"];
|
||||
}
|
||||
|
||||
// OS X 10.6 introduced 'compact unwind info', which is produced by the
|
||||
// linker from the dwarf unwind info. Unfortunately, it does not seem to
|
||||
// understand how to unwind our __morestack frame, so we have to turn it
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ fn get_rpath_relative_to_output(os: session::os,
|
|||
// Mac doesn't appear to support $ORIGIN
|
||||
let prefix = alt os {
|
||||
session::os_linux. { "$ORIGIN" + fs::path_sep() }
|
||||
session::os_freebsd. { "$ORIGIN" + fs::path_sep() }
|
||||
session::os_macos. { "@executable_path" + fs::path_sep() }
|
||||
};
|
||||
|
||||
|
|
@ -191,6 +192,7 @@ fn minimize_rpaths(rpaths: [str]) -> [str] {
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
|
|
@ -315,6 +317,14 @@ mod test {
|
|||
assert res == "$ORIGIN/../lib";
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn test_rpath_relative() {
|
||||
let res = get_rpath_relative_to_output(session::os_freebsd,
|
||||
"/usr", "bin/rustc", "lib/libstd.so");
|
||||
assert res == "$ORIGIN/../lib";
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "macos")]
|
||||
fn test_rpath_relative() {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ fn get_target_strs(target_os: session::os) -> target_strs::t {
|
|||
session::os_macos. { "__DATA,__note.rustc" }
|
||||
session::os_win32. { ".note.rustc" }
|
||||
session::os_linux. { ".note.rustc" }
|
||||
session::os_freebsd. { ".note.rustc" }
|
||||
},
|
||||
|
||||
data_layout: alt target_os {
|
||||
|
|
@ -24,12 +25,17 @@ fn get_target_strs(target_os: session::os) -> target_strs::t {
|
|||
session::os_linux. {
|
||||
"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
|
||||
}
|
||||
|
||||
session::os_freebsd. {
|
||||
"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
|
||||
}
|
||||
},
|
||||
|
||||
target_triple: alt target_os {
|
||||
session::os_macos. { "i686-apple-darwin" }
|
||||
session::os_win32. { "i686-pc-mingw32" }
|
||||
session::os_linux. { "i686-unknown-linux-gnu" }
|
||||
session::os_freebsd. { "i686-unknown-freebsd" }
|
||||
},
|
||||
|
||||
gcc_args: ["-m32"]
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ fn get_target_strs(target_os: session::os) -> target_strs::t {
|
|||
session::os_macos. { "__DATA,__note.rustc" }
|
||||
session::os_win32. { ".note.rustc" }
|
||||
session::os_linux. { ".note.rustc" }
|
||||
session::os_freebsd. { ".note.rustc" }
|
||||
},
|
||||
|
||||
data_layout: alt target_os {
|
||||
|
|
@ -29,12 +30,19 @@ fn get_target_strs(target_os: session::os) -> target_strs::t {
|
|||
"f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
|
||||
"s0:64:64-f80:128:128-n8:16:32:64-S128"
|
||||
}
|
||||
|
||||
session::os_freebsd. {
|
||||
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
|
||||
"f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
|
||||
"s0:64:64-f80:128:128-n8:16:32:64-S128"
|
||||
}
|
||||
},
|
||||
|
||||
target_triple: alt target_os {
|
||||
session::os_macos. { "x86_64-apple-darwin" }
|
||||
session::os_win32. { "x86_64-pc-mingw32" }
|
||||
session::os_linux. { "x86_64-unknown-linux-gnu" }
|
||||
session::os_freebsd. { "x86_64-unknown-freebsd" }
|
||||
},
|
||||
|
||||
gcc_args: ["-m64"]
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ fn default_configuration(sess: session::session, argv0: str, input: str) ->
|
|||
session::os_win32. { "msvcrt.dll" }
|
||||
session::os_macos. { "libc.dylib" }
|
||||
session::os_linux. { "libc.so.6" }
|
||||
session::os_freebsd. { "libc.so.7" }
|
||||
_ { "libc.so" }
|
||||
};
|
||||
|
||||
|
|
@ -172,8 +173,9 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
|
|||
time(time_passes, "const checking",
|
||||
bind middle::check_const::check_crate(sess, crate));
|
||||
let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars);
|
||||
let method_map = time(time_passes, "typechecking",
|
||||
bind typeck::check_crate(ty_cx, impl_map, crate));
|
||||
let (method_map, dict_map) =
|
||||
time(time_passes, "typechecking",
|
||||
bind typeck::check_crate(ty_cx, impl_map, crate));
|
||||
time(time_passes, "block-use checking",
|
||||
bind middle::block_use::check_crate(ty_cx, crate));
|
||||
time(time_passes, "function usage",
|
||||
|
|
@ -201,7 +203,7 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
|
|||
bind trans::trans_crate(sess, crate, ty_cx,
|
||||
outputs.obj_filename, exp_map, ast_map,
|
||||
mut_map, copy_map, last_uses,
|
||||
method_map));
|
||||
method_map, dict_map));
|
||||
time(time_passes, "LLVM passes",
|
||||
bind link::write::run_passes(sess, llmod, outputs.obj_filename));
|
||||
|
||||
|
|
@ -294,6 +296,8 @@ fn get_os(triple: str) -> session::os {
|
|||
session::os_macos
|
||||
} else if str::find(triple, "linux") >= 0 {
|
||||
session::os_linux
|
||||
} else if str::find(triple, "freebsd") >= 0 {
|
||||
session::os_freebsd
|
||||
} else { early_error("Unknown operating system!") };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import syntax::parse::parser::parse_sess;
|
|||
import util::filesearch;
|
||||
import back::target_strs;
|
||||
|
||||
tag os { os_win32; os_macos; os_linux; }
|
||||
tag os { os_win32; os_macos; os_linux; os_freebsd; }
|
||||
|
||||
tag arch { arch_x86; arch_x86_64; arch_arm; }
|
||||
|
||||
|
|
|
|||
|
|
@ -993,7 +993,8 @@ fn type_to_str_inner(names: type_names, outer0: [TypeRef], ty: TypeRef) ->
|
|||
}
|
||||
10 {
|
||||
let el_ty = llvm::LLVMGetElementType(ty);
|
||||
ret "[" + type_to_str_inner(names, outer, el_ty) + "]";
|
||||
ret "[" + type_to_str_inner(names, outer, el_ty) + " x " +
|
||||
uint::str(llvm::LLVMGetArrayLength(ty)) + "]";
|
||||
}
|
||||
11 {
|
||||
let i: uint = 0u;
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ fn default_native_lib_naming(sess: session::session, static: bool) ->
|
|||
session::os_win32. { ret {prefix: "", suffix: ".dll"}; }
|
||||
session::os_macos. { ret {prefix: "lib", suffix: ".dylib"}; }
|
||||
session::os_linux. { ret {prefix: "lib", suffix: ".so"}; }
|
||||
session::os_freebsd. { ret {prefix: "lib", suffix: ".so"}; }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -215,7 +216,7 @@ fn get_metadata_section(sess: session::session,
|
|||
let si = mk_section_iter(of.llof);
|
||||
while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False {
|
||||
let name_buf = llvm::LLVMGetSectionName(si.llsi);
|
||||
let name = unsafe { str::str_from_cstr(name_buf) };
|
||||
let name = unsafe { str::from_cstr(name_buf) };
|
||||
if str::eq(name, sess.get_targ_cfg().target_strs.meta_sect_name) {
|
||||
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
|
||||
let csz = llvm::LLVMGetSectionSize(si.llsi);
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ fn get_impls_for_mod(cstore: cstore::cstore, def: ast::def_id,
|
|||
let nm = decoder::lookup_item_name(cdata, did.node);
|
||||
if alt name { some(n) { n == nm } none. { true } } {
|
||||
result += [@{did: did,
|
||||
iface_did: none::<ast::def_id>, // FIXME[impl]
|
||||
ident: nm,
|
||||
methods: decoder::lookup_impl_methods(
|
||||
cdata, did.node, did.crate)}];
|
||||
|
|
|
|||
|
|
@ -117,23 +117,20 @@ fn item_type(item: ebml::doc, this_cnum: ast::crate_num, tcx: ty::ctxt,
|
|||
|
||||
fn item_ty_param_bounds(item: ebml::doc, this_cnum: ast::crate_num,
|
||||
tcx: ty::ctxt, extres: external_resolver)
|
||||
-> [@[ty::param_bound]] {
|
||||
-> @[ty::param_bounds] {
|
||||
let bounds = [];
|
||||
let def_parser = bind parse_external_def_id(this_cnum, extres, _);
|
||||
ebml::tagged_docs(item, tag_items_data_item_ty_param_bounds) {|p|
|
||||
bounds += [tydecode::parse_bounds_data(@ebml::doc_data(p), this_cnum,
|
||||
def_parser, tcx)];
|
||||
}
|
||||
bounds
|
||||
@bounds
|
||||
}
|
||||
|
||||
fn item_ty_param_count(item: ebml::doc) -> uint {
|
||||
let n = 0u;
|
||||
ebml::tagged_docs(item, tag_items_data_item_ty_param_bounds) {|p|
|
||||
for byte in ebml::doc_data(p) {
|
||||
if byte as char == '.' { n += 1u; }
|
||||
}
|
||||
}
|
||||
ebml::tagged_docs(item, tag_items_data_item_ty_param_bounds,
|
||||
{|_p| n += 1u; });
|
||||
n
|
||||
}
|
||||
|
||||
|
|
@ -212,8 +209,8 @@ fn get_type(data: @[u8], def: ast::def_id, tcx: ty::ctxt,
|
|||
let t = item_type(item, this_cnum, tcx, extres);
|
||||
let tp_bounds = if family_has_type_params(item_family(item)) {
|
||||
item_ty_param_bounds(item, this_cnum, tcx, extres)
|
||||
} else { [] };
|
||||
ret @{bounds: tp_bounds, ty: t};
|
||||
} else { @[] };
|
||||
ret {bounds: tp_bounds, ty: t};
|
||||
}
|
||||
|
||||
fn get_type_param_count(data: @[u8], id: ast::node_id) -> uint {
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ fn encode_type_param_bounds(ebml_w: ebml::writer, ecx: @encode_ctxt,
|
|||
abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)};
|
||||
for param in params {
|
||||
ebml::start_tag(ebml_w, tag_items_data_item_ty_param_bounds);
|
||||
let bs = ecx.ccx.tcx.ty_param_bounds.get(local_def(param.id));
|
||||
let bs = ecx.ccx.tcx.ty_param_bounds.get(param.id);
|
||||
tyencode::enc_bounds(io::new_writer(ebml_w.writer), ty_str_ctxt, bs);
|
||||
ebml::end_tag(ebml_w);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,9 +202,17 @@ fn parse_ty(st: @pstate, sd: str_def) -> ty::t {
|
|||
st.pos = st.pos + 1u;
|
||||
ret ty::mk_tag(st.tcx, def, params);
|
||||
}
|
||||
'x' {
|
||||
assert (next(st) as char == '[');
|
||||
let def = parse_def(st, sd);
|
||||
let params: [ty::t] = [];
|
||||
while peek(st) as char != ']' { params += [parse_ty(st, sd)]; }
|
||||
st.pos = st.pos + 1u;
|
||||
ret ty::mk_iface(st.tcx, def, params);
|
||||
}
|
||||
'p' {
|
||||
let bounds = parse_bounds(st, sd);
|
||||
ret ty::mk_param(st.tcx, parse_int(st) as uint, bounds);
|
||||
let did = parse_def(st, sd);
|
||||
ret ty::mk_param(st.tcx, parse_int(st) as uint, did);
|
||||
}
|
||||
'@' { ret ty::mk_box(st.tcx, parse_mt(st, sd)); }
|
||||
'~' { ret ty::mk_uniq(st.tcx, parse_mt(st, sd)); }
|
||||
|
|
@ -259,7 +267,7 @@ fn parse_ty(st: @pstate, sd: str_def) -> ty::t {
|
|||
while peek(st) as char != '[' {
|
||||
name += str::unsafe_from_byte(next(st));
|
||||
}
|
||||
methods += [{ident: name, tps: [],
|
||||
methods += [{ident: name, tps: @[],
|
||||
fty: {proto: proto with parse_ty_fn(st, sd)}}];
|
||||
}
|
||||
st.pos += 1u;
|
||||
|
|
@ -401,8 +409,7 @@ fn parse_bounds_data(data: @[u8], crate_num: int, sd: str_def, tcx: ty::ctxt)
|
|||
|
||||
fn parse_bounds(st: @pstate, sd: str_def) -> @[ty::param_bound] {
|
||||
let bounds = [];
|
||||
while peek(st) as char == '.' {
|
||||
next(st);
|
||||
while peek(st) != 0u8 {
|
||||
bounds += [alt next(st) as char {
|
||||
'S' { ty::bound_send }
|
||||
'C' { ty::bound_copy }
|
||||
|
|
|
|||
|
|
@ -126,6 +126,13 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
|
|||
for t: ty::t in tys { enc_ty(w, cx, t); }
|
||||
w.write_char(']');
|
||||
}
|
||||
ty::ty_iface(def, tys) {
|
||||
w.write_str("x[");
|
||||
w.write_str(cx.ds(def));
|
||||
w.write_char('|');
|
||||
for t: ty::t in tys { enc_ty(w, cx, t); }
|
||||
w.write_char(']');
|
||||
}
|
||||
ty::ty_tup(ts) {
|
||||
w.write_str("T[");
|
||||
for t in ts { enc_ty(w, cx, t); }
|
||||
|
|
@ -176,9 +183,10 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
|
|||
w.write_str(cx.ds(def));
|
||||
w.write_char('|');
|
||||
}
|
||||
ty::ty_param(id, bounds) {
|
||||
ty::ty_param(id, did) {
|
||||
w.write_char('p');
|
||||
enc_bounds(w, cx, bounds);
|
||||
w.write_str(cx.ds(did));
|
||||
w.write_char('|');
|
||||
w.write_str(uint::str(id));
|
||||
}
|
||||
ty::ty_type. { w.write_char('Y'); }
|
||||
|
|
@ -265,7 +273,6 @@ fn enc_ty_constr(w: io::writer, cx: @ctxt, c: @ty::type_constr) {
|
|||
|
||||
fn enc_bounds(w: io::writer, cx: @ctxt, bs: @[ty::param_bound]) {
|
||||
for bound in *bs {
|
||||
w.write_char('.');
|
||||
alt bound {
|
||||
ty::bound_send. { w.write_char('S'); }
|
||||
ty::bound_copy. { w.write_char('C'); }
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map,
|
|||
let visit = visit::mk_vt(@{
|
||||
visit_expr: check_expr,
|
||||
visit_stmt: check_stmt,
|
||||
visit_block: check_block,
|
||||
visit_fn: check_fn
|
||||
with *visit::default_visitor()
|
||||
});
|
||||
|
|
@ -117,12 +118,18 @@ fn check_fn_cap_clause(cx: ctx,
|
|||
}
|
||||
}
|
||||
|
||||
fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
||||
fn check_block(b: blk, cx: ctx, v: visit::vt<ctx>) {
|
||||
alt b.node.expr {
|
||||
some(ex) { maybe_copy(cx, ex); }
|
||||
_ {}
|
||||
}
|
||||
visit::visit_block(b, cx, v);
|
||||
}
|
||||
|
||||
fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
||||
alt e.node {
|
||||
expr_assign(_, ex) | expr_assign_op(_, _, ex) |
|
||||
expr_block({node: {expr: some(ex), _}, _}) |
|
||||
expr_unary(box(_), ex) | expr_unary(uniq(_), ex) { maybe_copy(cx, ex); }
|
||||
expr_unary(box(_), ex) | expr_unary(uniq(_), ex) |
|
||||
expr_ret(some(ex)) { maybe_copy(cx, ex); }
|
||||
expr_copy(expr) { check_copy_ex(cx, expr, false); }
|
||||
// Vector add copies.
|
||||
|
|
@ -163,14 +170,14 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
|||
alt substs.substs {
|
||||
some(ts) {
|
||||
let did = ast_util::def_id_of_def(cx.tcx.def_map.get(e.id));
|
||||
let kinds = vec::map(ty::lookup_item_type(cx.tcx, did).bounds,
|
||||
{|bs| ty::param_bounds_to_kind(bs)});
|
||||
let bounds = ty::lookup_item_type(cx.tcx, did).bounds;
|
||||
let i = 0u;
|
||||
for ty in ts {
|
||||
let kind = ty::type_kind(cx.tcx, ty);
|
||||
if !ty::kind_lteq(kinds[i], kind) {
|
||||
let p_kind = ty::param_bounds_to_kind(bounds[i]);
|
||||
if !ty::kind_lteq(p_kind, kind) {
|
||||
cx.tcx.sess.span_err(e.span, "instantiating a " +
|
||||
kind_to_str(kinds[i]) +
|
||||
kind_to_str(p_kind) +
|
||||
" type parameter with a "
|
||||
+ kind_to_str(kind) + " type");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import syntax::{visit, ast_util};
|
||||
import syntax::ast::*;
|
||||
import syntax::codemap::span;
|
||||
import std::list::{list, nil, cons, tail};
|
||||
import std::list::{is_not_empty, list, nil, cons, tail};
|
||||
import core::{vec, option};
|
||||
import std::list;
|
||||
|
||||
|
|
@ -63,6 +63,13 @@ fn find_last_uses(c: @crate, def_map: resolve::def_map,
|
|||
ret mini_table;
|
||||
}
|
||||
|
||||
fn is_block(cx: ctx, id: node_id) -> bool {
|
||||
alt ty::struct(cx.tcx, ty::node_id_to_monotype(cx.tcx, id)) {
|
||||
ty::ty_fn({proto: proto_block., _}) { true }
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
|
||||
alt ex.node {
|
||||
expr_ret(oexpr) {
|
||||
|
|
@ -135,9 +142,8 @@ fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
|
|||
let arg_ts = ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f));
|
||||
for arg in args {
|
||||
alt arg.node {
|
||||
//NDM--register captured as uses
|
||||
expr_fn(_, _, _, captured) { fns += [arg]; }
|
||||
expr_fn_block(_, _) { fns += [arg]; }
|
||||
expr_fn(proto_block., _, _, _) { fns += [arg]; }
|
||||
expr_fn_block(_, _) when is_block(cx, arg.id) { fns += [arg]; }
|
||||
_ {
|
||||
alt arg_ts[i].mode {
|
||||
by_mut_ref. { clear_if_path(cx, arg, v, false); }
|
||||
|
|
@ -163,6 +169,15 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
|
|||
visit::visit_fn(fk, decl, body, sp, id, cx, v);
|
||||
});
|
||||
} else {
|
||||
alt cx.tcx.freevars.find(id) {
|
||||
some(vars) {
|
||||
for v in *vars {
|
||||
clear_in_current(cx, ast_util::def_id_of_def(v.def).node,
|
||||
false);
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
let old = nil;
|
||||
cx.blocks <-> old;
|
||||
visit::visit_fn(fk, decl, body, sp, id, cx, v);
|
||||
|
|
@ -177,7 +192,9 @@ fn visit_block(tp: block_type, cx: ctx, visit: block()) {
|
|||
visit();
|
||||
local.second = true;
|
||||
visit();
|
||||
cx.blocks = tail(cx.blocks);
|
||||
let cx_blocks = cx.blocks;
|
||||
check is_not_empty(cx_blocks);
|
||||
cx.blocks = tail(cx_blocks);
|
||||
cx.current = join_branches(local.exits);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ tag scope {
|
|||
scope_loop(@ast::local); // there's only 1 decl per loop.
|
||||
scope_block(ast::blk, @mutable uint, @mutable uint);
|
||||
scope_arm(ast::arm);
|
||||
scope_self(ast::node_id);
|
||||
scope_method(ast::node_id, [ast::ty_param]);
|
||||
}
|
||||
|
||||
type scopes = list<scope>;
|
||||
|
|
@ -142,6 +142,7 @@ type env =
|
|||
mutable data: [ast::node_id]},
|
||||
mutable reported: [{ident: str, sc: scope}],
|
||||
mutable ignored_imports: [node_id],
|
||||
mutable current_tp: option::t<uint>,
|
||||
sess: session};
|
||||
|
||||
|
||||
|
|
@ -168,6 +169,7 @@ fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
|
|||
used_imports: {mutable track: false, mutable data: []},
|
||||
mutable reported: [],
|
||||
mutable ignored_imports: [],
|
||||
mutable current_tp: none,
|
||||
sess: sess};
|
||||
map_crate(e, crate);
|
||||
resolve_imports(*e);
|
||||
|
|
@ -266,6 +268,7 @@ fn map_crate(e: @env, c: @ast::crate) {
|
|||
let imp = follow_import(*e, sc, *path, vi.span);
|
||||
if option::is_some(imp) {
|
||||
let glob = {def: option::get(imp), item: vi};
|
||||
check list::is_not_empty(sc);
|
||||
alt list::head(sc) {
|
||||
scope_item(i) {
|
||||
e.mod_map.get(i.id).glob_imports += [glob];
|
||||
|
|
@ -335,6 +338,7 @@ fn resolve_names(e: @env, c: @ast::crate) {
|
|||
visit_pat: bind walk_pat(e, _, _, _),
|
||||
visit_expr: bind walk_expr(e, _, _, _),
|
||||
visit_ty: bind walk_ty(e, _, _, _),
|
||||
visit_ty_params: bind walk_tps(e, _, _, _),
|
||||
visit_constr: bind walk_constr(e, _, _, _, _, _),
|
||||
visit_fn: bind visit_fn_with_scope(e, _, _, _, _, _, _, _)
|
||||
with *visit::default_visitor()};
|
||||
|
|
@ -368,6 +372,20 @@ fn resolve_names(e: @env, c: @ast::crate) {
|
|||
_ { }
|
||||
}
|
||||
}
|
||||
fn walk_tps(e: @env, tps: [ast::ty_param], sc: scopes, v: vt<scopes>) {
|
||||
let outer_current_tp = e.current_tp, current = 0u;
|
||||
for tp in tps {
|
||||
e.current_tp = some(current);
|
||||
for bound in *tp.bounds {
|
||||
alt bound {
|
||||
bound_iface(t) { v.visit_ty(t, sc, v); }
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
current += 1u;
|
||||
}
|
||||
e.current_tp = outer_current_tp;
|
||||
}
|
||||
fn walk_constr(e: @env, p: @ast::path, sp: span, id: node_id, sc: scopes,
|
||||
_v: vt<scopes>) {
|
||||
maybe_insert(e, id, lookup_path_strict(*e, sc, sp, p.node, ns_value));
|
||||
|
|
@ -403,9 +421,17 @@ fn visit_item_with_scope(i: @ast::item, sc: scopes, v: vt<scopes>) {
|
|||
alt ifce { some(ty) { v.visit_ty(ty, sc, v); } _ {} }
|
||||
v.visit_ty(sty, sc, v);
|
||||
for m in methods {
|
||||
v.visit_fn(visit::fk_method(m.ident, tps + m.tps),
|
||||
m.decl, m.body, m.span,
|
||||
m.id, sc, v);
|
||||
let msc = cons(scope_method(i.id, tps + m.tps), @sc);
|
||||
v.visit_fn(visit::fk_method(m.ident, []),
|
||||
m.decl, m.body, m.span, m.id, msc, v);
|
||||
}
|
||||
}
|
||||
ast::item_iface(tps, methods) {
|
||||
visit::visit_ty_params(tps, sc, v);
|
||||
for m in methods {
|
||||
let msc = cons(scope_method(i.id, tps + m.tps), @sc);
|
||||
for a in m.decl.inputs { v.visit_ty(a.ty, msc, v); }
|
||||
v.visit_ty(m.decl.output, msc, v);
|
||||
}
|
||||
}
|
||||
_ { visit::visit_item(i, sc, v); }
|
||||
|
|
@ -436,8 +462,8 @@ fn visit_fn_with_scope(e: @env, fk: visit::fn_kind, decl: ast::fn_decl,
|
|||
// for f's constrs in the table.
|
||||
for c: @ast::constr in decl.constraints { resolve_constr(e, c, sc, v); }
|
||||
let scope = alt fk {
|
||||
visit::fk_item_fn(_, tps) | visit::fk_method(_, tps) |
|
||||
visit::fk_res(_, tps) {
|
||||
visit::fk_item_fn(_, tps) | visit::fk_res(_, tps) |
|
||||
visit::fk_method(_, tps) {
|
||||
scope_bare_fn(decl, id, tps)
|
||||
}
|
||||
visit::fk_anon(_) | visit::fk_fn_block. {
|
||||
|
|
@ -461,6 +487,7 @@ fn visit_block_with_scope(b: ast::blk, sc: scopes, v: vt<scopes>) {
|
|||
}
|
||||
|
||||
fn visit_decl_with_scope(d: @decl, sc: scopes, v: vt<scopes>) {
|
||||
check list::is_not_empty(sc);
|
||||
let loc_pos = alt list::head(sc) {
|
||||
scope_block(_, _, pos) { pos }
|
||||
_ { @mutable 0u }
|
||||
|
|
@ -489,7 +516,7 @@ fn visit_expr_with_scope(x: @ast::expr, sc: scopes, v: vt<scopes>) {
|
|||
v.visit_block(blk, new_sc, v);
|
||||
}
|
||||
ast::expr_anon_obj(_) {
|
||||
visit::visit_expr(x, cons(scope_self(x.id), @sc), v);
|
||||
visit::visit_expr(x, cons(scope_method(x.id, []), @sc), v);
|
||||
}
|
||||
_ { visit::visit_expr(x, sc, v); }
|
||||
}
|
||||
|
|
@ -796,17 +823,14 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
|
|||
scope_item(it) {
|
||||
alt it.node {
|
||||
ast::item_obj(ob, ty_params, _) {
|
||||
ret lookup_in_obj(name, ob, ty_params, ns, it.id);
|
||||
ret lookup_in_obj(e, name, ob, ty_params, ns, it.id);
|
||||
}
|
||||
ast::item_impl(ty_params, _, _, _) {
|
||||
if (name == "self" && ns == ns_value) {
|
||||
ret some(ast::def_self(local_def(it.id)));
|
||||
}
|
||||
if ns == ns_type { ret lookup_in_ty_params(name, ty_params); }
|
||||
ast::item_impl(tps, _, _, _) {
|
||||
if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
|
||||
}
|
||||
ast::item_iface(tps, _) | ast::item_tag(_, tps) |
|
||||
ast::item_ty(_, tps) {
|
||||
if ns == ns_type { ret lookup_in_ty_params(name, tps); }
|
||||
if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
|
||||
}
|
||||
ast::item_mod(_) {
|
||||
ret lookup_in_local_mod(e, it.id, sp, name, ns, inside);
|
||||
|
|
@ -817,21 +841,23 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
|
|||
_ { }
|
||||
}
|
||||
}
|
||||
scope_self(id) {
|
||||
scope_method(id, tps) {
|
||||
if (name == "self" && ns == ns_value) {
|
||||
ret some(ast::def_self(local_def(id)));
|
||||
} else if ns == ns_type {
|
||||
ret lookup_in_ty_params(e, name, tps);
|
||||
}
|
||||
}
|
||||
scope_native_item(it) {
|
||||
alt it.node {
|
||||
ast::native_item_fn(decl, ty_params) {
|
||||
ret lookup_in_fn(name, decl, ty_params, ns);
|
||||
ret lookup_in_fn(e, name, decl, ty_params, ns);
|
||||
}
|
||||
}
|
||||
}
|
||||
scope_bare_fn(decl, _, ty_params) |
|
||||
scope_fn_expr(decl, _, ty_params) {
|
||||
ret lookup_in_fn(name, decl, ty_params, ns);
|
||||
ret lookup_in_fn(e, name, decl, ty_params, ns);
|
||||
}
|
||||
scope_loop(local) {
|
||||
if ns == ns_value {
|
||||
|
|
@ -906,13 +932,13 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
|
|||
e.sess.bug("reached unreachable code in lookup_in_scope"); // sigh
|
||||
}
|
||||
|
||||
fn lookup_in_ty_params(name: ident, ty_params: [ast::ty_param]) ->
|
||||
option::t<def> {
|
||||
fn lookup_in_ty_params(e: env, name: ident, ty_params: [ast::ty_param])
|
||||
-> option::t<def> {
|
||||
let n = 0u;
|
||||
for tp: ast::ty_param in ty_params {
|
||||
if str::eq(tp.ident, name) {
|
||||
ret some(ast::def_ty_param(local_def(tp.id), n));
|
||||
}
|
||||
if str::eq(tp.ident, name) && alt e.current_tp {
|
||||
some(cur) { n < cur } none. { true }
|
||||
} { ret some(ast::def_ty_param(local_def(tp.id), n)); }
|
||||
n += 1u;
|
||||
}
|
||||
ret none::<def>;
|
||||
|
|
@ -927,7 +953,8 @@ fn lookup_in_pat(name: ident, pat: @ast::pat) -> option::t<def_id> {
|
|||
ret found;
|
||||
}
|
||||
|
||||
fn lookup_in_fn(name: ident, decl: ast::fn_decl, ty_params: [ast::ty_param],
|
||||
fn lookup_in_fn(e: env, name: ident, decl: ast::fn_decl,
|
||||
ty_params: [ast::ty_param],
|
||||
ns: namespace) -> option::t<def> {
|
||||
alt ns {
|
||||
ns_value. {
|
||||
|
|
@ -938,12 +965,13 @@ fn lookup_in_fn(name: ident, decl: ast::fn_decl, ty_params: [ast::ty_param],
|
|||
}
|
||||
ret none::<def>;
|
||||
}
|
||||
ns_type. { ret lookup_in_ty_params(name, ty_params); }
|
||||
ns_type. { ret lookup_in_ty_params(e, name, ty_params); }
|
||||
_ { ret none::<def>; }
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_in_obj(name: ident, ob: ast::_obj, ty_params: [ast::ty_param],
|
||||
fn lookup_in_obj(e: env, name: ident, ob: ast::_obj,
|
||||
ty_params: [ast::ty_param],
|
||||
ns: namespace, id: node_id) -> option::t<def> {
|
||||
alt ns {
|
||||
ns_value. {
|
||||
|
|
@ -955,7 +983,7 @@ fn lookup_in_obj(name: ident, ob: ast::_obj, ty_params: [ast::ty_param],
|
|||
}
|
||||
ret none::<def>;
|
||||
}
|
||||
ns_type. { ret lookup_in_ty_params(name, ty_params); }
|
||||
ns_type. { ret lookup_in_ty_params(e, name, ty_params); }
|
||||
_ { ret none::<def>; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1701,7 +1729,8 @@ fn check_exports(e: @env) {
|
|||
// Impl resolution
|
||||
|
||||
type method_info = {did: def_id, n_tps: uint, ident: ast::ident};
|
||||
type _impl = {did: def_id, ident: ast::ident, methods: [@method_info]};
|
||||
type _impl = {did: def_id, iface_did: option::t<def_id>,
|
||||
ident: ast::ident, methods: [@method_info]};
|
||||
type iscopes = list<@[@_impl]>;
|
||||
|
||||
fn resolve_impls(e: @env, c: @ast::crate) {
|
||||
|
|
@ -1757,14 +1786,20 @@ fn find_impls_in_view_item(e: env, vi: @ast::view_item,
|
|||
}
|
||||
}
|
||||
|
||||
fn find_impls_in_item(i: @ast::item, &impls: [@_impl],
|
||||
fn find_impls_in_item(e: env, i: @ast::item, &impls: [@_impl],
|
||||
name: option::t<ident>,
|
||||
ck_exports: option::t<ast::_mod>) {
|
||||
alt i.node {
|
||||
ast::item_impl(_, _, _, mthds) {
|
||||
ast::item_impl(_, ifce, _, mthds) {
|
||||
if alt name { some(n) { n == i.ident } _ { true } } &&
|
||||
alt ck_exports { some(m) { is_exported(i.ident, m) } _ { true } } {
|
||||
impls += [@{did: local_def(i.id),
|
||||
iface_did: alt ifce {
|
||||
some(@{node: ast::ty_path(_, id), _}) {
|
||||
some(def_id_of_def(e.def_map.get(id)))
|
||||
}
|
||||
_ { none }
|
||||
},
|
||||
ident: i.ident,
|
||||
methods: vec::map(mthds, {|m|
|
||||
@{did: local_def(m.id),
|
||||
|
|
@ -1788,7 +1823,7 @@ fn find_impls_in_mod(e: env, m: def, &impls: [@_impl],
|
|||
cached = if defid.crate == ast::local_crate {
|
||||
let tmp = [];
|
||||
for i in option::get(e.mod_map.get(defid.node).m).items {
|
||||
find_impls_in_item(i, tmp, name, none);
|
||||
find_impls_in_item(e, i, tmp, name, none);
|
||||
}
|
||||
@tmp
|
||||
} else {
|
||||
|
|
@ -1816,7 +1851,7 @@ fn visit_block_with_impl_scope(e: @env, b: ast::blk, sc: iscopes,
|
|||
for st in b.node.stmts {
|
||||
alt st.node {
|
||||
ast::stmt_decl(@{node: ast::decl_item(i), _}, _) {
|
||||
find_impls_in_item(i, impls, none, none);
|
||||
find_impls_in_item(*e, i, impls, none, none);
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
|
|
@ -1829,13 +1864,15 @@ fn visit_mod_with_impl_scope(e: @env, m: ast::_mod, s: span, sc: iscopes,
|
|||
v: vt<iscopes>) {
|
||||
let impls = [];
|
||||
for vi in m.view_items { find_impls_in_view_item(*e, vi, impls, sc); }
|
||||
for i in m.items { find_impls_in_item(i, impls, none, none); }
|
||||
for i in m.items { find_impls_in_item(*e, i, impls, none, none); }
|
||||
visit::visit_mod(m, s, vec::len(impls) > 0u ? cons(@impls, @sc) : sc, v);
|
||||
}
|
||||
|
||||
fn resolve_impl_in_expr(e: @env, x: @ast::expr, sc: iscopes, v: vt<iscopes>) {
|
||||
alt x.node {
|
||||
ast::expr_field(_, _, _) { e.impl_map.insert(x.id, sc); }
|
||||
ast::expr_field(_, _, _) | ast::expr_path(_) {
|
||||
e.impl_map.insert(x.id, sc);
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
visit::visit_expr(x, sc, v);
|
||||
|
|
|
|||
|
|
@ -450,7 +450,7 @@ fn gen_tag_shapes(ccx: @crate_ctxt) -> ValueRef {
|
|||
let did = ccx.shape_cx.tag_order[i];
|
||||
let variants = ty::tag_variants(ccx.tcx, did);
|
||||
let item_tyt = ty::lookup_item_type(ccx.tcx, did);
|
||||
let ty_param_count = vec::len(item_tyt.bounds);
|
||||
let ty_param_count = vec::len(*item_tyt.bounds);
|
||||
|
||||
for v: ty::variant_info in *variants {
|
||||
offsets += [vec::len(data) as u16];
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
// but many TypeRefs correspond to one ty::t; for instance, tup(int, int,
|
||||
// int) and rec(x=int, y=int, z=int) will have the same TypeRef.
|
||||
|
||||
import core::{either, str, int, uint, option, vec};
|
||||
import std::{map, time};
|
||||
import std::map::hashmap;
|
||||
import std::map::{new_int_hash, new_str_hash};
|
||||
|
|
@ -81,13 +80,12 @@ fn type_of_explicit_args(cx: @crate_ctxt, sp: span, inputs: [ty::arg]) ->
|
|||
// - create_llargs_for_fn_args.
|
||||
// - new_fn_ctxt
|
||||
// - trans_args
|
||||
fn type_of_fn(cx: @crate_ctxt, sp: span,
|
||||
is_method: bool, inputs: [ty::arg],
|
||||
output: ty::t, ty_param_count: uint)
|
||||
: non_ty_var(cx, output) -> TypeRef {
|
||||
fn type_of_fn(cx: @crate_ctxt, sp: span, is_method: bool, inputs: [ty::arg],
|
||||
output: ty::t, params: [ty::param_bounds]) -> TypeRef {
|
||||
let atys: [TypeRef] = [];
|
||||
|
||||
// Arg 0: Output pointer.
|
||||
check non_ty_var(cx, output);
|
||||
let out_ty = T_ptr(type_of_inner(cx, sp, output));
|
||||
atys += [out_ty];
|
||||
|
||||
|
|
@ -100,8 +98,15 @@ fn type_of_fn(cx: @crate_ctxt, sp: span,
|
|||
|
||||
// Args >2: ty params, if not acquired via capture...
|
||||
if !is_method {
|
||||
let i = 0u;
|
||||
while i < ty_param_count { atys += [T_ptr(cx.tydesc_type)]; i += 1u; }
|
||||
for bounds in params {
|
||||
atys += [T_ptr(cx.tydesc_type)];
|
||||
for bound in *bounds {
|
||||
alt bound {
|
||||
ty::bound_iface(_) { atys += [T_ptr(T_dict())]; }
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ... then explicit args.
|
||||
atys += type_of_explicit_args(cx, sp, inputs);
|
||||
|
|
@ -110,15 +115,13 @@ fn type_of_fn(cx: @crate_ctxt, sp: span,
|
|||
|
||||
// Given a function type and a count of ty params, construct an llvm type
|
||||
fn type_of_fn_from_ty(cx: @crate_ctxt, sp: span, fty: ty::t,
|
||||
ty_param_count: uint)
|
||||
: returns_non_ty_var(cx, fty) -> TypeRef {
|
||||
param_bounds: [ty::param_bounds]) -> TypeRef {
|
||||
// FIXME: Check should be unnecessary, b/c it's implied
|
||||
// by returns_non_ty_var(t). Make that a postcondition
|
||||
// (see Issue #586)
|
||||
let ret_ty = ty::ty_fn_ret(cx.tcx, fty);
|
||||
check non_ty_var(cx, ret_ty);
|
||||
ret type_of_fn(cx, sp, false, ty::ty_fn_args(cx.tcx, fty),
|
||||
ret_ty, ty_param_count);
|
||||
ret_ty, param_bounds);
|
||||
}
|
||||
|
||||
fn type_of_inner(cx: @crate_ctxt, sp: span, t: ty::t)
|
||||
|
|
@ -169,12 +172,10 @@ fn type_of_inner(cx: @crate_ctxt, sp: span, t: ty::t)
|
|||
T_struct(tys)
|
||||
}
|
||||
ty::ty_fn(_) {
|
||||
// FIXME: could be a constraint on ty_fn
|
||||
check returns_non_ty_var(cx, t);
|
||||
T_fn_pair(cx, type_of_fn_from_ty(cx, sp, t, 0u))
|
||||
T_fn_pair(cx, type_of_fn_from_ty(cx, sp, t, []))
|
||||
}
|
||||
ty::ty_native_fn(args, out) {
|
||||
let nft = native_fn_wrapper_type(cx, sp, 0u, t);
|
||||
let nft = native_fn_wrapper_type(cx, sp, [], t);
|
||||
T_fn_pair(cx, nft)
|
||||
}
|
||||
ty::ty_obj(meths) { cx.rust_object_type }
|
||||
|
|
@ -204,6 +205,11 @@ fn type_of_inner(cx: @crate_ctxt, sp: span, t: ty::t)
|
|||
ty::ty_opaque_closure. {
|
||||
T_opaque_closure(cx)
|
||||
}
|
||||
ty::ty_constr(subt,_) {
|
||||
// FIXME: could be a constraint on ty_fn
|
||||
check non_ty_var(cx, subt);
|
||||
type_of_inner(cx, sp, subt)
|
||||
}
|
||||
_ {
|
||||
fail "type_of_inner not implemented for this kind of type";
|
||||
}
|
||||
|
|
@ -233,8 +239,7 @@ fn type_of_ty_param_bounds_and_ty(lcx: @local_ctxt, sp: span,
|
|||
let t = tpt.ty;
|
||||
alt ty::struct(cx.tcx, t) {
|
||||
ty::ty_fn(_) | ty::ty_native_fn(_, _) {
|
||||
check returns_non_ty_var(cx, t);
|
||||
ret type_of_fn_from_ty(cx, sp, t, vec::len(tpt.bounds));
|
||||
ret type_of_fn_from_ty(cx, sp, t, *tpt.bounds);
|
||||
}
|
||||
_ {
|
||||
// fall through
|
||||
|
|
@ -906,7 +911,10 @@ fn linearize_ty_params(cx: @block_ctxt, t: ty::t) ->
|
|||
ty::ty_param(pid, _) {
|
||||
let seen: bool = false;
|
||||
for d: uint in r.defs { if d == pid { seen = true; } }
|
||||
if !seen { r.vals += [r.cx.fcx.lltydescs[pid]]; r.defs += [pid]; }
|
||||
if !seen {
|
||||
r.vals += [r.cx.fcx.lltyparams[pid].desc];
|
||||
r.defs += [pid];
|
||||
}
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
|
|
@ -1042,8 +1050,9 @@ fn get_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
|
|||
// Is the supplied type a type param? If so, return the passed-in tydesc.
|
||||
alt ty::type_param(bcx_tcx(cx), t) {
|
||||
some(id) {
|
||||
if id < vec::len(cx.fcx.lltydescs) {
|
||||
ret {kind: tk_param, result: rslt(cx, cx.fcx.lltydescs[id])};
|
||||
if id < vec::len(cx.fcx.lltyparams) {
|
||||
ret {kind: tk_param,
|
||||
result: rslt(cx, cx.fcx.lltyparams[id].desc)};
|
||||
} else {
|
||||
bcx_tcx(cx).sess.span_bug(cx.sp,
|
||||
"Unbound typaram in get_tydesc: " +
|
||||
|
|
@ -1206,10 +1215,7 @@ fn make_generic_glue_inner(cx: @local_ctxt, sp: span, t: ty::t,
|
|||
p += 1u;
|
||||
}
|
||||
|
||||
// FIXME: Implement some kind of freeze operation in the standard library.
|
||||
let lltydescs_frozen = [];
|
||||
for lltydesc: ValueRef in lltydescs { lltydescs_frozen += [lltydesc]; }
|
||||
fcx.lltydescs = lltydescs_frozen;
|
||||
fcx.lltyparams = vec::map_mut(lltydescs, {|d| {desc: d, dicts: none}});
|
||||
|
||||
let bcx = new_top_block_ctxt(fcx);
|
||||
let lltop = bcx.llbb;
|
||||
|
|
@ -2559,10 +2565,13 @@ fn trans_do_while(cx: @block_ctxt, body: ast::blk, cond: @ast::expr) ->
|
|||
ret next_cx;
|
||||
}
|
||||
|
||||
type generic_info =
|
||||
{item_type: ty::t,
|
||||
static_tis: [option::t<@tydesc_info>],
|
||||
tydescs: [ValueRef]};
|
||||
type generic_info = {
|
||||
item_type: ty::t,
|
||||
static_tis: [option::t<@tydesc_info>],
|
||||
tydescs: [ValueRef],
|
||||
param_bounds: @[ty::param_bounds],
|
||||
origins: option::t<typeck::dict_res>
|
||||
};
|
||||
|
||||
tag lval_kind {
|
||||
temporary; //< Temporary value passed by value if of immediate type
|
||||
|
|
@ -2571,7 +2580,12 @@ tag lval_kind {
|
|||
}
|
||||
type local_var_result = {val: ValueRef, kind: lval_kind};
|
||||
type lval_result = {bcx: @block_ctxt, val: ValueRef, kind: lval_kind};
|
||||
tag callee_env { obj_env(ValueRef); null_env; is_closure; }
|
||||
tag callee_env {
|
||||
null_env;
|
||||
is_closure;
|
||||
obj_env(ValueRef);
|
||||
dict_env(ValueRef, ValueRef);
|
||||
}
|
||||
type lval_maybe_callee = {bcx: @block_ctxt,
|
||||
val: ValueRef,
|
||||
kind: lval_kind,
|
||||
|
|
@ -2608,18 +2622,19 @@ fn trans_external_path(cx: @block_ctxt, did: ast::def_id,
|
|||
|
||||
fn lval_static_fn(bcx: @block_ctxt, fn_id: ast::def_id, id: ast::node_id)
|
||||
-> lval_maybe_callee {
|
||||
let tpt = ty::lookup_item_type(bcx_tcx(bcx), fn_id);
|
||||
let ccx = bcx_ccx(bcx);
|
||||
let tpt = ty::lookup_item_type(ccx.tcx, fn_id);
|
||||
let val = if fn_id.crate == ast::local_crate {
|
||||
// Internal reference.
|
||||
assert (bcx_ccx(bcx).item_ids.contains_key(fn_id.node));
|
||||
bcx_ccx(bcx).item_ids.get(fn_id.node)
|
||||
assert (ccx.item_ids.contains_key(fn_id.node));
|
||||
ccx.item_ids.get(fn_id.node)
|
||||
} else {
|
||||
// External reference.
|
||||
trans_external_path(bcx, fn_id, tpt)
|
||||
};
|
||||
let tys = ty::node_id_to_type_params(bcx_tcx(bcx), id);
|
||||
let tys = ty::node_id_to_type_params(ccx.tcx, id);
|
||||
let gen = none, bcx = bcx;
|
||||
if vec::len::<ty::t>(tys) != 0u {
|
||||
if vec::len(tys) != 0u {
|
||||
let tydescs = [], tis = [];
|
||||
for t in tys {
|
||||
// TODO: Doesn't always escape.
|
||||
|
|
@ -2629,7 +2644,11 @@ fn lval_static_fn(bcx: @block_ctxt, fn_id: ast::def_id, id: ast::node_id)
|
|||
bcx = td.bcx;
|
||||
tydescs += [td.val];
|
||||
}
|
||||
gen = some({item_type: tpt.ty, static_tis: tis, tydescs: tydescs});
|
||||
gen = some({item_type: tpt.ty,
|
||||
static_tis: tis,
|
||||
tydescs: tydescs,
|
||||
param_bounds: tpt.bounds,
|
||||
origins: ccx.dict_map.find(id)});
|
||||
}
|
||||
ret {bcx: bcx, val: val, kind: owned, env: null_env, generic: gen};
|
||||
}
|
||||
|
|
@ -2731,7 +2750,7 @@ fn trans_var(cx: @block_ctxt, sp: span, def: ast::def, id: ast::node_id)
|
|||
ret lval_no_env(cx, ccx.consts.get(did.node), owned);
|
||||
} else {
|
||||
let tp = ty::node_id_to_monotype(ccx.tcx, id);
|
||||
let val = trans_external_path(cx, did, @{bounds: [], ty: tp});
|
||||
let val = trans_external_path(cx, did, {bounds: @[], ty: tp});
|
||||
ret lval_no_env(cx, load_if_immediate(cx, val, tp), owned_imm);
|
||||
}
|
||||
}
|
||||
|
|
@ -2764,10 +2783,8 @@ fn trans_object_field_inner(bcx: @block_ctxt, o: ValueRef,
|
|||
let fn_ty: ty::t = ty::mk_fn(tcx, mths[ix].fty);
|
||||
let ret_ty = ty::ty_fn_ret(tcx, fn_ty);
|
||||
// FIXME: constrain ty_obj?
|
||||
check non_ty_var(ccx, ret_ty);
|
||||
|
||||
let ll_fn_ty = type_of_fn(ccx, bcx.sp, true,
|
||||
ty::ty_fn_args(tcx, fn_ty), ret_ty, 0u);
|
||||
ty::ty_fn_args(tcx, fn_ty), ret_ty, []);
|
||||
v = Load(bcx, PointerCast(bcx, v, T_ptr(T_ptr(ll_fn_ty))));
|
||||
ret {bcx: bcx, mthptr: v, objptr: o};
|
||||
}
|
||||
|
|
@ -2840,17 +2857,6 @@ fn expr_is_lval(bcx: @block_ctxt, e: @ast::expr) -> bool {
|
|||
ty::expr_is_lval(ccx.method_map, ccx.tcx, e)
|
||||
}
|
||||
|
||||
// This is for impl methods, not obj methods.
|
||||
fn trans_method_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
|
||||
did: ast::def_id) -> lval_maybe_callee {
|
||||
let tz = [], tr = [];
|
||||
let basety = ty::expr_ty(bcx_tcx(bcx), base);
|
||||
let {bcx, val} = trans_arg_expr(bcx, {mode: ast::by_ref, ty: basety},
|
||||
type_of_or_i8(bcx, basety), tz, tr, base);
|
||||
let val = PointerCast(bcx, val, T_opaque_boxed_closure_ptr(bcx_ccx(bcx)));
|
||||
{env: obj_env(val) with lval_static_fn(bcx, did, e.id)}
|
||||
}
|
||||
|
||||
fn trans_callee(bcx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
|
||||
alt e.node {
|
||||
ast::expr_path(p) { ret trans_path(bcx, p, e.id); }
|
||||
|
|
@ -2858,8 +2864,12 @@ fn trans_callee(bcx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
|
|||
// Lval means this is a record field, so not a method
|
||||
if !expr_is_lval(bcx, e) {
|
||||
alt bcx_ccx(bcx).method_map.find(e.id) {
|
||||
some(did) { // An impl method
|
||||
ret trans_method_callee(bcx, e, base, did);
|
||||
some(typeck::method_static(did)) { // An impl method
|
||||
ret trans_impl::trans_static_callee(bcx, e, base, did);
|
||||
}
|
||||
some(typeck::method_param(iid, off, p, b)) {
|
||||
ret trans_impl::trans_dict_callee(
|
||||
bcx, e, base, iid, off, p, b);
|
||||
}
|
||||
none. { // An object method
|
||||
let of = trans_object_field(bcx, base, ident);
|
||||
|
|
@ -2930,7 +2940,7 @@ fn maybe_add_env(bcx: @block_ctxt, c: lval_maybe_callee)
|
|||
-> (lval_kind, ValueRef) {
|
||||
alt c.env {
|
||||
is_closure. { (c.kind, c.val) }
|
||||
obj_env(_) {
|
||||
obj_env(_) | dict_env(_, _) {
|
||||
fail "Taking the value of a method does not work yet (issue #435)";
|
||||
}
|
||||
null_env. {
|
||||
|
|
@ -3143,7 +3153,23 @@ fn trans_args(cx: @block_ctxt, llenv: ValueRef,
|
|||
alt gen {
|
||||
some(g) {
|
||||
lazily_emit_all_generic_info_tydesc_glues(cx, g);
|
||||
lltydescs = g.tydescs;
|
||||
let i = 0u, n_orig = 0u;
|
||||
for param in *g.param_bounds {
|
||||
lltydescs += [g.tydescs[i]];
|
||||
for bound in *param {
|
||||
alt bound {
|
||||
ty::bound_iface(_) {
|
||||
let res = trans_impl::get_dict(
|
||||
bcx, option::get(g.origins)[n_orig]);
|
||||
lltydescs += [res.val];
|
||||
bcx = res.bcx;
|
||||
n_orig += 1u;
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
args = ty::ty_fn_args(tcx, g.item_type);
|
||||
retty = ty::ty_fn_ret(tcx, g.item_type);
|
||||
}
|
||||
|
|
@ -3214,12 +3240,13 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
|||
let bcx = f_res.bcx;
|
||||
|
||||
let faddr = f_res.val;
|
||||
let llenv;
|
||||
let llenv, dict_param = none;
|
||||
alt f_res.env {
|
||||
null_env. {
|
||||
llenv = llvm::LLVMGetUndef(T_opaque_boxed_closure_ptr(bcx_ccx(cx)));
|
||||
}
|
||||
obj_env(e) { llenv = e; }
|
||||
dict_env(dict, e) { llenv = e; dict_param = some(dict); }
|
||||
is_closure. {
|
||||
// It's a closure. Have to fetch the elements
|
||||
if f_res.kind == owned {
|
||||
|
|
@ -3238,6 +3265,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
|||
trans_args(bcx, llenv, f_res.generic, args, fn_expr_ty, dest);
|
||||
bcx = args_res.bcx;
|
||||
let llargs = args_res.args;
|
||||
option::may(dict_param) {|dict| llargs = [dict] + llargs}
|
||||
let llretslot = args_res.retslot;
|
||||
|
||||
/* If the block is terminated,
|
||||
|
|
@ -3300,8 +3328,7 @@ fn invoke_(bcx: @block_ctxt, llfn: ValueRef, llargs: [ValueRef],
|
|||
// cleanups to run
|
||||
if bcx.unreachable { ret bcx; }
|
||||
let normal_bcx = new_sub_block_ctxt(bcx, "normal return");
|
||||
invoker(bcx, llfn, llargs,
|
||||
normal_bcx.llbb,
|
||||
invoker(bcx, llfn, llargs, normal_bcx.llbb,
|
||||
get_landing_pad(bcx, to_zero, to_revoke));
|
||||
ret normal_bcx;
|
||||
}
|
||||
|
|
@ -4345,7 +4372,7 @@ fn new_fn_ctxt_w_id(cx: @local_ctxt, sp: span, llfndecl: ValueRef,
|
|||
llobjfields: new_int_hash::<ValueRef>(),
|
||||
lllocals: new_int_hash::<local_val>(),
|
||||
llupvars: new_int_hash::<ValueRef>(),
|
||||
mutable lltydescs: [],
|
||||
mutable lltyparams: [],
|
||||
derived_tydescs: ty::new_ty_hash(),
|
||||
id: id,
|
||||
ret_style: rstyle,
|
||||
|
|
@ -4387,10 +4414,22 @@ fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: self_arg,
|
|||
obj_self(_) {}
|
||||
_ {
|
||||
for tp in ty_params {
|
||||
let llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
|
||||
assert (llarg as int != 0);
|
||||
cx.lltydescs += [llarg];
|
||||
let lltydesc = llvm::LLVMGetParam(cx.llfn, arg_n), dicts = none;
|
||||
arg_n += 1u;
|
||||
for bound in *fcx_tcx(cx).ty_param_bounds.get(tp.id) {
|
||||
alt bound {
|
||||
ty::bound_iface(_) {
|
||||
let dict = llvm::LLVMGetParam(cx.llfn, arg_n);
|
||||
arg_n += 1u;
|
||||
dicts = some(alt dicts {
|
||||
none. { [dict] }
|
||||
some(ds) { ds + [dict] }
|
||||
});
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
cx.lltyparams += [{desc: lltydesc, dicts: dicts}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4479,7 +4518,7 @@ fn populate_fn_ctxt_from_llself(fcx: @fn_ctxt, llself: val_self_pair) {
|
|||
let lltyparam: ValueRef =
|
||||
GEPi(bcx, obj_typarams, [0, i]);
|
||||
lltyparam = Load(bcx, lltyparam);
|
||||
fcx.lltydescs += [lltyparam];
|
||||
fcx.lltyparams += [{desc: lltyparam, dicts: none}];
|
||||
i += 1;
|
||||
}
|
||||
i = 0;
|
||||
|
|
@ -4658,7 +4697,8 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
|
|||
let ty_param_substs: [ty::t] = [];
|
||||
i = 0u;
|
||||
for tp: ast::ty_param in ty_params {
|
||||
ty_param_substs += [ty::mk_param(ccx.tcx, i, @[])];
|
||||
ty_param_substs += [ty::mk_param(ccx.tcx, i,
|
||||
ast_util::local_def(tp.id))];
|
||||
i += 1u;
|
||||
}
|
||||
let arg_tys = arg_tys_of_fn(ccx, variant.node.id);
|
||||
|
|
@ -4700,20 +4740,6 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
|
|||
finish_fn(fcx, lltop);
|
||||
}
|
||||
|
||||
fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
|
||||
id: ast::node_id, tps: [ast::ty_param]) {
|
||||
let sub_cx = extend_path(cx, name);
|
||||
for m in methods {
|
||||
alt cx.ccx.item_ids.find(m.id) {
|
||||
some(llfn) {
|
||||
trans_fn(extend_path(sub_cx, m.ident), m.span, m.decl, m.body,
|
||||
llfn, impl_self(ty::node_id_to_monotype(cx.ccx.tcx, id)),
|
||||
tps + m.tps, m.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FIXME: this should do some structural hash-consing to avoid
|
||||
// duplicate constants. I think. Maybe LLVM has a magical mode
|
||||
|
|
@ -5013,8 +5039,8 @@ fn trans_item(cx: @local_ctxt, item: ast::item) {
|
|||
with *extend_path(cx, item.ident)};
|
||||
trans_obj(sub_cx, item.span, ob, ctor_id, tps);
|
||||
}
|
||||
ast::item_impl(tps, _, _, ms) {
|
||||
trans_impl(cx, item.ident, ms, item.id, tps);
|
||||
ast::item_impl(tps, ifce, _, ms) {
|
||||
trans_impl::trans_impl(cx, item.ident, ms, item.id, tps, ifce);
|
||||
}
|
||||
ast::item_res(decl, tps, body, dtor_id, ctor_id) {
|
||||
trans_res_ctor(cx, item.span, decl, ctor_id, tps);
|
||||
|
|
@ -5080,13 +5106,17 @@ fn register_fn(ccx: @crate_ctxt, sp: span, path: [str], flav: str,
|
|||
register_fn_full(ccx, sp, path, flav, ty_params, node_id, t);
|
||||
}
|
||||
|
||||
fn param_bounds(ccx: @crate_ctxt, tp: ast::ty_param) -> ty::param_bounds {
|
||||
ccx.tcx.ty_param_bounds.get(tp.id)
|
||||
}
|
||||
|
||||
fn register_fn_full(ccx: @crate_ctxt, sp: span, path: [str], _flav: str,
|
||||
ty_params: [ast::ty_param], node_id: ast::node_id,
|
||||
tps: [ast::ty_param], node_id: ast::node_id,
|
||||
node_type: ty::t)
|
||||
: returns_non_ty_var(ccx, node_type) {
|
||||
let path = path;
|
||||
let llfty =
|
||||
type_of_fn_from_ty(ccx, sp, node_type, vec::len(ty_params));
|
||||
let llfty = type_of_fn_from_ty(ccx, sp, node_type,
|
||||
vec::map(tps, {|p| param_bounds(ccx, p)}));
|
||||
let ps: str = mangle_exported_name(ccx, path, node_type);
|
||||
let llfn: ValueRef = decl_cdecl_fn(ccx.llmod, ps, llfty);
|
||||
ccx.item_ids.insert(node_id, llfn);
|
||||
|
|
@ -5122,9 +5152,7 @@ fn create_main_wrapper(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef,
|
|||
ty: ty::mk_vec(ccx.tcx, {ty: unit_ty, mut: ast::imm})};
|
||||
// FIXME: mk_nil should have a postcondition
|
||||
let nt = ty::mk_nil(ccx.tcx);
|
||||
check non_ty_var(ccx, nt);
|
||||
|
||||
let llfty = type_of_fn(ccx, sp, false, [vecarg_ty], nt, 0u);
|
||||
let llfty = type_of_fn(ccx, sp, false, [vecarg_ty], nt, []);
|
||||
let llfdecl = decl_fn(ccx.llmod, "_rust_main",
|
||||
lib::llvm::LLVMCCallConv, llfty);
|
||||
|
||||
|
|
@ -5152,6 +5180,8 @@ fn create_main_wrapper(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef,
|
|||
fn main_name() -> str { ret "main"; }
|
||||
#[cfg(target_os = "linux")]
|
||||
fn main_name() -> str { ret "main"; }
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn main_name() -> str { ret "main"; }
|
||||
let llfty = T_fn([ccx.int_type, ccx.int_type], ccx.int_type);
|
||||
let llfn = decl_cdecl_fn(ccx.llmod, main_name(), llfty);
|
||||
let llbb = str::as_buf("top", {|buf|
|
||||
|
|
@ -5215,12 +5245,12 @@ fn native_fn_ty_param_count(cx: @crate_ctxt, id: ast::node_id) -> uint {
|
|||
ret count;
|
||||
}
|
||||
|
||||
fn native_fn_wrapper_type(cx: @crate_ctxt, sp: span, ty_param_count: uint,
|
||||
fn native_fn_wrapper_type(cx: @crate_ctxt, sp: span,
|
||||
param_bounds: [ty::param_bounds],
|
||||
x: ty::t) -> TypeRef {
|
||||
alt ty::struct(cx.tcx, x) {
|
||||
ty::ty_native_fn(args, out) {
|
||||
check non_ty_var(cx, out);
|
||||
ret type_of_fn(cx, sp, false, args, out, ty_param_count);
|
||||
ret type_of_fn(cx, sp, false, args, out, param_bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5245,56 +5275,54 @@ fn collect_native_item(ccx: @crate_ctxt,
|
|||
_v: vt<[str]>) {
|
||||
alt i.node {
|
||||
ast::native_item_fn(_, tps) {
|
||||
if !ccx.obj_methods.contains_key(i.id) {
|
||||
let sp = i.span;
|
||||
let id = i.id;
|
||||
let node_type = node_id_type(ccx, id);
|
||||
let fn_abi =
|
||||
alt attr::get_meta_item_value_str_by_name(i.attrs, "abi") {
|
||||
option::none. {
|
||||
let sp = i.span;
|
||||
let id = i.id;
|
||||
let node_type = node_id_type(ccx, id);
|
||||
let fn_abi =
|
||||
alt attr::get_meta_item_value_str_by_name(i.attrs, "abi") {
|
||||
option::none. {
|
||||
// if abi isn't specified for this function, inherit from
|
||||
// its enclosing native module
|
||||
option::get(*abi)
|
||||
// its enclosing native module
|
||||
option::get(*abi)
|
||||
}
|
||||
_ {
|
||||
alt attr::native_abi(i.attrs) {
|
||||
either::right(abi_) { abi_ }
|
||||
either::left(msg) { ccx.sess.span_fatal(i.span, msg) }
|
||||
_ {
|
||||
alt attr::native_abi(i.attrs) {
|
||||
either::right(abi_) { abi_ }
|
||||
either::left(msg) { ccx.sess.span_fatal(i.span, msg) }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
alt fn_abi {
|
||||
ast::native_abi_rust_intrinsic. {
|
||||
// For intrinsics: link the function directly to the intrinsic
|
||||
// function itself.
|
||||
let num_ty_param = vec::len(tps);
|
||||
check returns_non_ty_var(ccx, node_type);
|
||||
let fn_type = type_of_fn_from_ty(ccx, sp, node_type,
|
||||
num_ty_param);
|
||||
let ri_name = "rust_intrinsic_" + link_name(i);
|
||||
let llnativefn = get_extern_fn(
|
||||
ccx.externs, ccx.llmod, ri_name,
|
||||
lib::llvm::LLVMCCallConv, fn_type);
|
||||
ccx.item_ids.insert(id, llnativefn);
|
||||
ccx.item_symbols.insert(id, ri_name);
|
||||
}
|
||||
alt fn_abi {
|
||||
ast::native_abi_rust_intrinsic. {
|
||||
// For intrinsics: link the function directly to the intrinsic
|
||||
// function itself.
|
||||
let fn_type = type_of_fn_from_ty(
|
||||
ccx, sp, node_type,
|
||||
vec::map(tps, {|p| param_bounds(ccx, p)}));
|
||||
let ri_name = "rust_intrinsic_" + link_name(i);
|
||||
let llnativefn = get_extern_fn(
|
||||
ccx.externs, ccx.llmod, ri_name,
|
||||
lib::llvm::LLVMCCallConv, fn_type);
|
||||
ccx.item_ids.insert(id, llnativefn);
|
||||
ccx.item_symbols.insert(id, ri_name);
|
||||
}
|
||||
|
||||
ast::native_abi_cdecl. | ast::native_abi_stdcall. {
|
||||
// For true external functions: create a rust wrapper
|
||||
// and link to that. The rust wrapper will handle
|
||||
// switching to the C stack.
|
||||
let new_pt = pt + [i.ident];
|
||||
register_fn(ccx, i.span, new_pt, "native fn", tps, i.id);
|
||||
}
|
||||
}
|
||||
ast::native_abi_cdecl. | ast::native_abi_stdcall. {
|
||||
// For true external functions: create a rust wrapper
|
||||
// and link to that. The rust wrapper will handle
|
||||
// switching to the C stack.
|
||||
let new_pt = pt + [i.ident];
|
||||
register_fn(ccx, i.span, new_pt, "native fn", tps, i.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_item_1(ccx: @crate_ctxt, abi: @mutable option::t<ast::native_abi>,
|
||||
i: @ast::item, &&pt: [str], v: vt<[str]>) {
|
||||
fn collect_item(ccx: @crate_ctxt, abi: @mutable option::t<ast::native_abi>,
|
||||
i: @ast::item, &&pt: [str], v: vt<[str]>) {
|
||||
let new_pt = pt + [i.ident];
|
||||
alt i.node {
|
||||
ast::item_const(_, _) {
|
||||
let typ = node_id_type(ccx, i.id);
|
||||
|
|
@ -5319,26 +5347,11 @@ fn collect_item_1(ccx: @crate_ctxt, abi: @mutable option::t<ast::native_abi>,
|
|||
}
|
||||
}
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
visit::visit_item(i, pt + [i.ident], v);
|
||||
}
|
||||
|
||||
fn collect_item_2(ccx: @crate_ctxt, i: @ast::item, &&pt: [str],
|
||||
v: vt<[str]>) {
|
||||
let new_pt = pt + [i.ident];
|
||||
visit::visit_item(i, new_pt, v);
|
||||
alt i.node {
|
||||
ast::item_fn(_, tps, _) {
|
||||
if !ccx.obj_methods.contains_key(i.id) {
|
||||
register_fn(ccx, i.span, new_pt, "fn", tps, i.id);
|
||||
}
|
||||
register_fn(ccx, i.span, new_pt, "fn", tps, i.id);
|
||||
}
|
||||
ast::item_obj(ob, tps, ctor_id) {
|
||||
register_fn(ccx, i.span, new_pt, "obj_ctor", tps, ctor_id);
|
||||
for m: @ast::method in ob.methods {
|
||||
ccx.obj_methods.insert(m.id, ());
|
||||
}
|
||||
}
|
||||
ast::item_impl(tps, _, _, methods) {
|
||||
let name = ccx.names.next(i.ident);
|
||||
|
|
@ -5358,47 +5371,28 @@ fn collect_item_2(ccx: @crate_ctxt, i: @ast::item, &&pt: [str],
|
|||
check returns_non_ty_var(ccx, t);
|
||||
register_fn_full(ccx, i.span, new_pt, "res_dtor", tps, i.id, t);
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_items(ccx: @crate_ctxt, crate: @ast::crate) {
|
||||
let abi = @mutable none::<ast::native_abi>;
|
||||
let visitor0 = visit::default_visitor();
|
||||
let visitor1 =
|
||||
@{visit_native_item: bind collect_native_item(ccx, abi, _, _, _),
|
||||
visit_item: bind collect_item_1(ccx, abi, _, _, _) with *visitor0};
|
||||
let visitor2 =
|
||||
@{visit_item: bind collect_item_2(ccx, _, _, _) with *visitor0};
|
||||
visit::visit_crate(*crate, [], visit::mk_vt(visitor1));
|
||||
visit::visit_crate(*crate, [], visit::mk_vt(visitor2));
|
||||
}
|
||||
|
||||
fn collect_tag_ctor(ccx: @crate_ctxt, i: @ast::item, &&pt: [str],
|
||||
v: vt<[str]>) {
|
||||
let new_pt = pt + [i.ident];
|
||||
visit::visit_item(i, new_pt, v);
|
||||
alt i.node {
|
||||
ast::item_tag(variants, tps) {
|
||||
for variant: ast::variant in variants {
|
||||
for variant in variants {
|
||||
if vec::len(variant.node.args) != 0u {
|
||||
register_fn(ccx, i.span, new_pt + [variant.node.name],
|
||||
"tag", tps, variant.node.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ {/* fall through */ }
|
||||
_ { }
|
||||
}
|
||||
visit::visit_item(i, new_pt, v);
|
||||
}
|
||||
|
||||
fn collect_tag_ctors(ccx: @crate_ctxt, crate: @ast::crate) {
|
||||
let visitor =
|
||||
@{visit_item: bind collect_tag_ctor(ccx, _, _, _)
|
||||
with *visit::default_visitor()};
|
||||
visit::visit_crate(*crate, [], visit::mk_vt(visitor));
|
||||
fn collect_items(ccx: @crate_ctxt, crate: @ast::crate) {
|
||||
let abi = @mutable none::<ast::native_abi>;
|
||||
visit::visit_crate(*crate, [], visit::mk_vt(@{
|
||||
visit_native_item: bind collect_native_item(ccx, abi, _, _, _),
|
||||
visit_item: bind collect_item(ccx, abi, _, _, _)
|
||||
with *visit::default_visitor()
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
// The constant translation pass.
|
||||
fn trans_constant(ccx: @crate_ctxt, it: @ast::item, &&pt: [str],
|
||||
v: vt<[str]>) {
|
||||
|
|
@ -5407,15 +5401,12 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item, &&pt: [str],
|
|||
alt it.node {
|
||||
ast::item_tag(variants, _) {
|
||||
let i = 0u;
|
||||
let n_variants = vec::len::<ast::variant>(variants);
|
||||
while i < n_variants {
|
||||
let variant = variants[i];
|
||||
let p = new_pt + [it.ident, variant.node.name, "discrim"];
|
||||
for variant in variants {
|
||||
let p = new_pt + [variant.node.name, "discrim"];
|
||||
let s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
|
||||
let discrim_gvar =
|
||||
str::as_buf(s, {|buf|
|
||||
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
|
||||
});
|
||||
let discrim_gvar = str::as_buf(s, {|buf|
|
||||
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
|
||||
});
|
||||
llvm::LLVMSetInitializer(discrim_gvar, C_int(ccx, i as int));
|
||||
llvm::LLVMSetGlobalConstant(discrim_gvar, True);
|
||||
ccx.discrims.insert(
|
||||
|
|
@ -5424,6 +5415,28 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item, &&pt: [str],
|
|||
i += 1u;
|
||||
}
|
||||
}
|
||||
ast::item_impl(tps, some(@{node: ast::ty_path(_, id), _}), _, ms) {
|
||||
let i_did = ast_util::def_id_of_def(ccx.tcx.def_map.get(id));
|
||||
let ty = ty::lookup_item_type(ccx.tcx, i_did).ty;
|
||||
// FIXME[impl] use the same name as used in collect_items, for
|
||||
// slightly more consistent symbol names?
|
||||
let new_pt = pt + [ccx.names.next(it.ident)];
|
||||
let extra_tps = vec::map(tps, {|p| param_bounds(ccx, p)});
|
||||
let tbl = C_struct(vec::map(*ty::iface_methods(ccx.tcx, i_did), {|im|
|
||||
alt vec::find(ms, {|m| m.ident == im.ident}) {
|
||||
some(m) {
|
||||
trans_impl::trans_wrapper(ccx, new_pt, extra_tps, m)
|
||||
}
|
||||
}
|
||||
}));
|
||||
let s = mangle_exported_name(ccx, new_pt + ["!vtable"], ty);
|
||||
let vt_gvar = str::as_buf(s, {|buf|
|
||||
llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl), buf)
|
||||
});
|
||||
llvm::LLVMSetInitializer(vt_gvar, tbl);
|
||||
llvm::LLVMSetGlobalConstant(vt_gvar, True);
|
||||
ccx.item_ids.insert(it.id, vt_gvar);
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
}
|
||||
|
|
@ -5601,7 +5614,8 @@ fn write_abi_version(ccx: @crate_ctxt) {
|
|||
fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
|
||||
output: str, emap: resolve::exp_map, amap: ast_map::map,
|
||||
mut_map: mut::mut_map, copy_map: alias::copy_map,
|
||||
last_uses: last_use::last_uses, method_map: typeck::method_map)
|
||||
last_uses: last_use::last_uses, method_map: typeck::method_map,
|
||||
dict_map: typeck::dict_map)
|
||||
-> (ModuleRef, link::link_meta) {
|
||||
let sha = std::sha1::mk_sha1();
|
||||
let link_meta = link::build_link_meta(sess, *crate, output, sha);
|
||||
|
|
@ -5666,7 +5680,6 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
|
|||
discrims: ast_util::new_def_id_hash::<ValueRef>(),
|
||||
discrim_symbols: new_int_hash::<str>(),
|
||||
consts: new_int_hash::<ValueRef>(),
|
||||
obj_methods: new_int_hash::<()>(),
|
||||
tydescs: ty::new_ty_hash(),
|
||||
module_data: new_str_hash::<ValueRef>(),
|
||||
lltypes: ty::new_ty_hash(),
|
||||
|
|
@ -5679,6 +5692,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
|
|||
copy_map: copy_map,
|
||||
last_uses: last_uses,
|
||||
method_map: method_map,
|
||||
dict_map: dict_map,
|
||||
stats:
|
||||
{mutable n_static_tydescs: 0u,
|
||||
mutable n_derived_tydescs: 0u,
|
||||
|
|
@ -5702,7 +5716,6 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
|
|||
dbg_cx: dbg_cx};
|
||||
let cx = new_local_ctxt(ccx);
|
||||
collect_items(ccx, crate);
|
||||
collect_tag_ctors(ccx, crate);
|
||||
trans_constants(ccx, crate);
|
||||
trans_mod(cx, crate.node.module);
|
||||
fill_crate_map(ccx, crate_map);
|
||||
|
|
@ -5720,7 +5733,6 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
|
|||
#error("n_null_glues: %u", ccx.stats.n_null_glues);
|
||||
#error("n_real_glues: %u", ccx.stats.n_real_glues);
|
||||
|
||||
|
||||
for timing: {ident: str, time: int} in *ccx.stats.fn_times {
|
||||
#error("time: %s took %d ms", timing.ident, timing.time);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,17 +82,21 @@ tag environment_value {
|
|||
// Given a closure ty, emits a corresponding tuple ty
|
||||
fn mk_closure_ty(tcx: ty::ctxt,
|
||||
ck: ty::closure_kind,
|
||||
n_bound_tds: uint,
|
||||
ty_params: [fn_ty_param],
|
||||
bound_data_ty: ty::t)
|
||||
-> ty::t {
|
||||
let tydesc_ty = alt ck {
|
||||
ty::closure_block. | ty::closure_shared. { ty::mk_type(tcx) }
|
||||
ty::closure_send. { ty::mk_send_type(tcx) }
|
||||
};
|
||||
ret ty::mk_tup(tcx, [
|
||||
tydesc_ty,
|
||||
ty::mk_tup(tcx, vec::init_elt(tydesc_ty, n_bound_tds)),
|
||||
bound_data_ty]);
|
||||
let param_ptrs = [];
|
||||
for tp in ty_params {
|
||||
param_ptrs += [tydesc_ty];
|
||||
option::may(tp.dicts) {|dicts|
|
||||
for dict in dicts { param_ptrs += [tydesc_ty]; }
|
||||
}
|
||||
}
|
||||
ty::mk_tup(tcx, [tydesc_ty, ty::mk_tup(tcx, param_ptrs), bound_data_ty])
|
||||
}
|
||||
|
||||
fn shared_opaque_closure_box_ty(tcx: ty::ctxt) -> ty::t {
|
||||
|
|
@ -117,7 +121,7 @@ type closure_result = {
|
|||
// heap allocated closure that copies the upvars into environment.
|
||||
// Otherwise, it is stack allocated and copies pointers to the upvars.
|
||||
fn store_environment(
|
||||
bcx: @block_ctxt, lltydescs: [ValueRef],
|
||||
bcx: @block_ctxt, lltyparams: [fn_ty_param],
|
||||
bound_values: [environment_value],
|
||||
ck: ty::closure_kind)
|
||||
-> closure_result {
|
||||
|
|
@ -162,7 +166,7 @@ fn store_environment(
|
|||
}
|
||||
let bound_data_ty = ty::mk_tup(tcx, bound_tys);
|
||||
let closure_ty =
|
||||
mk_closure_ty(tcx, ck, vec::len(lltydescs), bound_data_ty);
|
||||
mk_closure_ty(tcx, ck, lltyparams, bound_data_ty);
|
||||
|
||||
let temp_cleanups = [];
|
||||
|
||||
|
|
@ -210,7 +214,7 @@ fn store_environment(
|
|||
// in the shape code. Therefore, I am using
|
||||
// tps_normal, which is what we used before.
|
||||
//
|
||||
// let tps = tps_fn(vec::len(lltydescs));
|
||||
// let tps = tps_fn(vec::len(lltyparams));
|
||||
|
||||
let tps = tps_normal;
|
||||
let {result:closure_td, _} =
|
||||
|
|
@ -232,10 +236,19 @@ fn store_environment(
|
|||
let {bcx:bcx, val:ty_params_slot} =
|
||||
GEP_tup_like_1(bcx, closure_ty, closure,
|
||||
[0, abi::closure_elt_ty_params]);
|
||||
vec::iteri(lltydescs) { |i, td|
|
||||
let ty_param_slot = GEPi(bcx, ty_params_slot, [0, i as int]);
|
||||
let cloned_td = maybe_clone_tydesc(bcx, ck, td);
|
||||
Store(bcx, cloned_td, ty_param_slot);
|
||||
let off = 0;
|
||||
|
||||
for tp in lltyparams {
|
||||
let cloned_td = maybe_clone_tydesc(bcx, ck, tp.desc);
|
||||
Store(bcx, cloned_td, GEPi(bcx, ty_params_slot, [0, off]));
|
||||
off += 1;
|
||||
option::may(tp.dicts, {|dicts|
|
||||
for dict in dicts {
|
||||
let cast = PointerCast(bcx, dict, val_ty(cloned_td));
|
||||
Store(bcx, cast, GEPi(bcx, ty_params_slot, [0, off]));
|
||||
off += 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Copy expr values into boxed bindings.
|
||||
|
|
@ -316,7 +329,7 @@ fn build_closure(bcx0: @block_ctxt,
|
|||
}
|
||||
}
|
||||
}
|
||||
ret store_environment(bcx, copy bcx.fcx.lltydescs, env_vals, ck);
|
||||
ret store_environment(bcx, copy bcx.fcx.lltyparams, env_vals, ck);
|
||||
}
|
||||
|
||||
// Given an enclosing block context, a new function context, a closure type,
|
||||
|
|
@ -338,13 +351,23 @@ fn load_environment(enclosing_cx: @block_ctxt,
|
|||
// Populate the type parameters from the environment. We need to
|
||||
// do this first because the tydescs are needed to index into
|
||||
// the bindings if they are dynamically sized.
|
||||
let tydesc_count = vec::len(enclosing_cx.fcx.lltydescs);
|
||||
let lltydescs = GEPi(bcx, llclosure,
|
||||
[0, abi::box_rc_field_body,
|
||||
abi::closure_elt_ty_params]);
|
||||
uint::range(0u, tydesc_count) { |i|
|
||||
let lltydescptr = GEPi(bcx, lltydescs, [0, i as int]);
|
||||
fcx.lltydescs += [Load(bcx, lltydescptr)];
|
||||
let off = 0;
|
||||
for tp in copy enclosing_cx.fcx.lltyparams {
|
||||
let tydesc = Load(bcx, GEPi(bcx, lltydescs, [0, off]));
|
||||
off += 1;
|
||||
let dicts = option::map(tp.dicts, {|dicts|
|
||||
let rslt = [];
|
||||
for dict in dicts {
|
||||
let dict = Load(bcx, GEPi(bcx, lltydescs, [0, off]));
|
||||
rslt += [PointerCast(bcx, dict, T_ptr(T_dict()))];
|
||||
off += 1;
|
||||
}
|
||||
rslt
|
||||
});
|
||||
fcx.lltyparams += [{desc: tydesc, dicts: dicts}];
|
||||
}
|
||||
|
||||
// Populate the upvars from the environment.
|
||||
|
|
@ -382,8 +405,7 @@ fn trans_expr_fn(bcx: @block_ctxt,
|
|||
if dest == ignore { ret bcx; }
|
||||
let ccx = bcx_ccx(bcx), bcx = bcx;
|
||||
let fty = node_id_type(ccx, id);
|
||||
check returns_non_ty_var(ccx, fty);
|
||||
let llfnty = type_of_fn_from_ty(ccx, sp, fty, 0u);
|
||||
let llfnty = type_of_fn_from_ty(ccx, sp, fty, []);
|
||||
let sub_cx = extend_path(bcx.fcx.lcx, ccx.names.next("anon"));
|
||||
let s = mangle_internal_name_by_path(ccx, sub_cx.path);
|
||||
let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
|
||||
|
|
@ -436,19 +458,25 @@ fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
|
|||
}
|
||||
|
||||
// Figure out which tydescs we need to pass, if any.
|
||||
let outgoing_fty_real; // the type with typarams still in it
|
||||
let lltydescs: [ValueRef];
|
||||
alt f_res.generic {
|
||||
none. { outgoing_fty_real = outgoing_fty; lltydescs = []; }
|
||||
let (outgoing_fty_real, lltydescs, param_bounds) = alt f_res.generic {
|
||||
none. { (outgoing_fty, [], @[]) }
|
||||
some(ginfo) {
|
||||
for bounds in *ginfo.param_bounds {
|
||||
for bound in *bounds {
|
||||
alt bound {
|
||||
ty::bound_iface(_) {
|
||||
fail "FIXME[impl] binding bounded types not implemented";
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
}
|
||||
lazily_emit_all_generic_info_tydesc_glues(cx, ginfo);
|
||||
outgoing_fty_real = ginfo.item_type;
|
||||
lltydescs = ginfo.tydescs;
|
||||
(ginfo.item_type, ginfo.tydescs, ginfo.param_bounds)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let ty_param_count = vec::len(lltydescs);
|
||||
if vec::len(bound) == 0u && ty_param_count == 0u {
|
||||
if vec::len(bound) == 0u && vec::len(lltydescs) == 0u {
|
||||
// Trivial 'binding': just return the closure
|
||||
let lv = lval_maybe_callee_to_lval(f_res, pair_ty);
|
||||
bcx = lv.bcx;
|
||||
|
|
@ -480,14 +508,14 @@ fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
|
|||
|
||||
// Actually construct the closure
|
||||
let {llbox, box_ty, bcx} = store_environment(
|
||||
bcx, lltydescs,
|
||||
bcx, vec::map(lltydescs, {|d| {desc: d, dicts: none}}),
|
||||
env_vals + vec::map(bound, {|x| env_expr(x)}),
|
||||
ty::closure_shared);
|
||||
|
||||
// Make thunk
|
||||
let llthunk =
|
||||
trans_bind_thunk(cx.fcx.lcx, cx.sp, pair_ty, outgoing_fty_real, args,
|
||||
box_ty, ty_param_count, target_res);
|
||||
box_ty, *param_bounds, target_res);
|
||||
|
||||
// Fill the function pair
|
||||
fill_fn_pair(bcx, get_dest_addr(dest), llthunk.val, llbox);
|
||||
|
|
@ -558,7 +586,7 @@ fn trans_bind_thunk(cx: @local_ctxt,
|
|||
outgoing_fty: ty::t,
|
||||
args: [option::t<@ast::expr>],
|
||||
boxed_closure_ty: ty::t,
|
||||
ty_param_count: uint,
|
||||
param_bounds: [ty::param_bounds],
|
||||
target_fn: option::t<ValueRef>)
|
||||
-> {val: ValueRef, ty: TypeRef} {
|
||||
// If we supported constraints on record fields, we could make the
|
||||
|
|
@ -606,7 +634,7 @@ fn trans_bind_thunk(cx: @local_ctxt,
|
|||
// our bound tydescs, we need to load tydescs out of the environment
|
||||
// before derived tydescs are constructed. To do this, we load them
|
||||
// in the load_env block.
|
||||
let load_env_bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
|
||||
let l_bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
|
||||
|
||||
// The 'llenv' that will arrive in the thunk we're creating is an
|
||||
// environment that will contain the values of its arguments and a pointer
|
||||
|
|
@ -616,7 +644,7 @@ fn trans_bind_thunk(cx: @local_ctxt,
|
|||
// 'boxed_closure_ty', which was determined by trans_bind.
|
||||
check (type_has_static_size(ccx, boxed_closure_ty));
|
||||
let llclosure_ptr_ty = type_of(ccx, sp, boxed_closure_ty);
|
||||
let llclosure = PointerCast(load_env_bcx, fcx.llenv, llclosure_ptr_ty);
|
||||
let llclosure = PointerCast(l_bcx, fcx.llenv, llclosure_ptr_ty);
|
||||
|
||||
// "target", in this context, means the function that's having some of its
|
||||
// arguments bound and that will be called inside the thunk we're
|
||||
|
|
@ -667,19 +695,32 @@ fn trans_bind_thunk(cx: @local_ctxt,
|
|||
let llargs: [ValueRef] = [llretptr, lltargetenv];
|
||||
|
||||
// Copy in the type parameters.
|
||||
let i: uint = 0u;
|
||||
while i < ty_param_count {
|
||||
// Silly check
|
||||
check type_is_tup_like(load_env_bcx, boxed_closure_ty);
|
||||
let lltyparam_ptr =
|
||||
GEP_tup_like(load_env_bcx, boxed_closure_ty, llclosure,
|
||||
[0, abi::box_rc_field_body,
|
||||
abi::closure_elt_ty_params, i as int]);
|
||||
load_env_bcx = lltyparam_ptr.bcx;
|
||||
let td = Load(load_env_bcx, lltyparam_ptr.val);
|
||||
llargs += [td];
|
||||
fcx.lltydescs += [td];
|
||||
i += 1u;
|
||||
check type_is_tup_like(l_bcx, boxed_closure_ty);
|
||||
let {bcx: l_bcx, val: param_record} =
|
||||
GEP_tup_like(l_bcx, boxed_closure_ty, llclosure,
|
||||
[0, abi::box_rc_field_body, abi::closure_elt_ty_params]);
|
||||
let off = 0;
|
||||
for param in param_bounds {
|
||||
let dsc = Load(l_bcx, GEPi(l_bcx, param_record, [0, off])),
|
||||
dicts = none;
|
||||
llargs += [dsc];
|
||||
off += 1;
|
||||
for bound in *param {
|
||||
alt bound {
|
||||
ty::bound_iface(_) {
|
||||
let dict = Load(l_bcx, GEPi(l_bcx, param_record, [0, off]));
|
||||
dict = PointerCast(l_bcx, dict, T_ptr(T_dict()));
|
||||
llargs += [dict];
|
||||
off += 1;
|
||||
dicts = some(alt dicts {
|
||||
none. { [dict] }
|
||||
some(ds) { ds + [dict] }
|
||||
});
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
fcx.lltyparams += [{desc: dsc, dicts: dicts}];
|
||||
}
|
||||
|
||||
let a: uint = 2u; // retptr, env come first
|
||||
|
|
@ -737,13 +778,11 @@ fn trans_bind_thunk(cx: @local_ctxt,
|
|||
// needs to take.
|
||||
let ccx = bcx_ccx(bcx);
|
||||
|
||||
check returns_non_ty_var(ccx, outgoing_fty);
|
||||
let lltargetty =
|
||||
type_of_fn_from_ty(ccx, sp, outgoing_fty, ty_param_count);
|
||||
type_of_fn_from_ty(ccx, sp, outgoing_fty, param_bounds);
|
||||
lltargetfn = PointerCast(bcx, lltargetfn, T_ptr(lltargetty));
|
||||
Call(bcx, lltargetfn, llargs);
|
||||
build_return(bcx);
|
||||
finish_fn(fcx, lltop);
|
||||
ret {val: llthunk, ty: llthunk_ty};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,6 @@ type crate_ctxt =
|
|||
discrims: hashmap<ast::def_id, ValueRef>,
|
||||
discrim_symbols: hashmap<ast::node_id, str>,
|
||||
consts: hashmap<ast::node_id, ValueRef>,
|
||||
obj_methods: hashmap<ast::node_id, ()>,
|
||||
tydescs: hashmap<ty::t, @tydesc_info>,
|
||||
module_data: hashmap<str, ValueRef>,
|
||||
lltypes: hashmap<ty::t, TypeRef>,
|
||||
|
|
@ -105,6 +104,7 @@ type crate_ctxt =
|
|||
copy_map: alias::copy_map,
|
||||
last_uses: last_use::last_uses,
|
||||
method_map: typeck::method_map,
|
||||
dict_map: typeck::dict_map,
|
||||
stats: stats,
|
||||
upcalls: @upcall::upcalls,
|
||||
rust_object_type: TypeRef,
|
||||
|
|
@ -131,6 +131,8 @@ type val_self_pair = {v: ValueRef, t: ty::t};
|
|||
|
||||
tag local_val { local_mem(ValueRef); local_imm(ValueRef); }
|
||||
|
||||
type fn_ty_param = {desc: ValueRef, dicts: option::t<[ValueRef]>};
|
||||
|
||||
// Function context. Every LLVM function we create will have one of
|
||||
// these.
|
||||
type fn_ctxt =
|
||||
|
|
@ -236,7 +238,7 @@ type fn_ctxt =
|
|||
llobjfields: hashmap<ast::node_id, ValueRef>,
|
||||
lllocals: hashmap<ast::node_id, local_val>,
|
||||
llupvars: hashmap<ast::node_id, ValueRef>,
|
||||
mutable lltydescs: [ValueRef],
|
||||
mutable lltyparams: [fn_ty_param],
|
||||
derived_tydescs: hashmap<ty::t, derived_tydesc_info>,
|
||||
id: ast::node_id,
|
||||
ret_style: ast::ret_style,
|
||||
|
|
@ -320,13 +322,13 @@ fn get_res_dtor(ccx: @crate_ctxt, sp: span, did: ast::def_id, inner_t: ty::t)
|
|||
}
|
||||
}
|
||||
|
||||
let params = csearch::get_type_param_count(ccx.sess.get_cstore(), did);
|
||||
let param_bounds = ty::lookup_item_type(ccx.tcx, did).bounds;
|
||||
let nil_res = ty::mk_nil(ccx.tcx);
|
||||
// FIXME: Silly check -- mk_nil should have a postcondition
|
||||
check non_ty_var(ccx, nil_res);
|
||||
let f_t = type_of_fn(ccx, sp, false,
|
||||
[{mode: ast::by_ref, ty: inner_t}],
|
||||
nil_res, params);
|
||||
nil_res, *param_bounds);
|
||||
ret trans::get_extern_const(ccx.externs, ccx.llmod,
|
||||
csearch::get_symbol(ccx.sess.get_cstore(),
|
||||
did), f_t);
|
||||
|
|
@ -406,7 +408,7 @@ fn ty_str(tn: type_names, t: TypeRef) -> str {
|
|||
ret lib::llvm::type_to_str(tn, t);
|
||||
}
|
||||
|
||||
fn val_ty(v: ValueRef) -> TypeRef { ret llvm::LLVMTypeOf(v); }
|
||||
fn val_ty(&&v: ValueRef) -> TypeRef { ret llvm::LLVMTypeOf(v); }
|
||||
|
||||
fn val_str(tn: type_names, v: ValueRef) -> str { ret ty_str(tn, val_ty(v)); }
|
||||
|
||||
|
|
@ -533,11 +535,9 @@ fn T_size_t(targ_cfg: @session::config) -> TypeRef {
|
|||
ret T_int(targ_cfg);
|
||||
}
|
||||
|
||||
fn T_fn(inputs: [TypeRef], output: TypeRef) -> TypeRef {
|
||||
unsafe {
|
||||
ret llvm::LLVMFunctionType(output, to_ptr(inputs),
|
||||
vec::len::<TypeRef>(inputs), False);
|
||||
}
|
||||
fn T_fn(inputs: [TypeRef], output: TypeRef) -> TypeRef unsafe {
|
||||
ret llvm::LLVMFunctionType(output, to_ptr(inputs),
|
||||
vec::len::<TypeRef>(inputs), False);
|
||||
}
|
||||
|
||||
fn T_fn_pair(cx: @crate_ctxt, tfn: TypeRef) -> TypeRef {
|
||||
|
|
@ -546,10 +546,8 @@ fn T_fn_pair(cx: @crate_ctxt, tfn: TypeRef) -> TypeRef {
|
|||
|
||||
fn T_ptr(t: TypeRef) -> TypeRef { ret llvm::LLVMPointerType(t, 0u); }
|
||||
|
||||
fn T_struct(elts: [TypeRef]) -> TypeRef {
|
||||
unsafe {
|
||||
ret llvm::LLVMStructType(to_ptr(elts), vec::len(elts), False);
|
||||
}
|
||||
fn T_struct(elts: [TypeRef]) -> TypeRef unsafe {
|
||||
ret llvm::LLVMStructType(to_ptr(elts), vec::len(elts), False);
|
||||
}
|
||||
|
||||
fn T_named_struct(name: str) -> TypeRef {
|
||||
|
|
@ -574,6 +572,12 @@ fn T_rust_object() -> TypeRef {
|
|||
ret t;
|
||||
}
|
||||
|
||||
// A dict is, in reality, a vtable pointer followed by zero or more pointers
|
||||
// to tydescs and other dicts that it closes over. But the types and number of
|
||||
// those are rarely known to the code that needs to manipulate them, so they
|
||||
// are described by this opaque type.
|
||||
fn T_dict() -> TypeRef { T_array(T_ptr(T_i8()), 1u) }
|
||||
|
||||
fn T_task(targ_cfg: @session::config) -> TypeRef {
|
||||
let t = T_named_struct("task");
|
||||
|
||||
|
|
|
|||
172
src/comp/middle/trans_impl.rs
Normal file
172
src/comp/middle/trans_impl.rs
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
import trans::*;
|
||||
import trans_common::*;
|
||||
import trans_build::*;
|
||||
import option::{some, none};
|
||||
import syntax::{ast, ast_util};
|
||||
import back::link;
|
||||
import lib::llvm;
|
||||
import llvm::llvm::{ValueRef, TypeRef, LLVMGetParam};
|
||||
|
||||
fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
|
||||
id: ast::node_id, tps: [ast::ty_param],
|
||||
_ifce: option::t<@ast::ty>) {
|
||||
let sub_cx = extend_path(cx, name);
|
||||
for m in methods {
|
||||
alt cx.ccx.item_ids.find(m.id) {
|
||||
some(llfn) {
|
||||
trans_fn(extend_path(sub_cx, m.ident), m.span, m.decl, m.body,
|
||||
llfn, impl_self(ty::node_id_to_monotype(cx.ccx.tcx, id)),
|
||||
tps + m.tps, m.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_self_arg(bcx: @block_ctxt, base: @ast::expr) -> result {
|
||||
let tz = [], tr = [];
|
||||
let basety = ty::expr_ty(bcx_tcx(bcx), base);
|
||||
let {bcx, val} = trans_arg_expr(bcx, {mode: ast::by_ref, ty: basety},
|
||||
T_ptr(type_of_or_i8(bcx, basety)), tz,
|
||||
tr, base);
|
||||
rslt(bcx, PointerCast(bcx, val, T_opaque_boxed_closure_ptr(bcx_ccx(bcx))))
|
||||
}
|
||||
|
||||
fn trans_static_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
|
||||
did: ast::def_id) -> lval_maybe_callee {
|
||||
let {bcx, val} = trans_self_arg(bcx, base);
|
||||
{env: obj_env(val) with lval_static_fn(bcx, did, e.id)}
|
||||
}
|
||||
|
||||
fn trans_dict_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
|
||||
iface_id: ast::def_id, n_method: uint,
|
||||
n_param: uint, n_bound: uint) -> lval_maybe_callee {
|
||||
let tcx = bcx_tcx(bcx);
|
||||
let {bcx, val} = trans_self_arg(bcx, base);
|
||||
let dict = option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound];
|
||||
let method = ty::iface_methods(tcx, iface_id)[n_method];
|
||||
let fty = ty::expr_ty(tcx, e);
|
||||
let bare_fn_ty = type_of_fn_from_ty(bcx_ccx(bcx), ast_util::dummy_sp(),
|
||||
fty, *method.tps);
|
||||
let {inputs: bare_inputs, output} = llfn_arg_tys(bare_fn_ty);
|
||||
let fn_ty = T_fn([val_ty(dict)] + bare_inputs, output);
|
||||
let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
|
||||
T_ptr(T_array(T_ptr(fn_ty), n_method + 1u)));
|
||||
let mptr = Load(bcx, GEPi(bcx, vtable, [0, n_method as int]));
|
||||
let generic = none;
|
||||
if vec::len(*method.tps) > 0u {
|
||||
let tydescs = [], tis = [];
|
||||
for t in ty::node_id_to_type_params(tcx, e.id) {
|
||||
// TODO: Doesn't always escape.
|
||||
let ti = none;
|
||||
let td = get_tydesc(bcx, t, true, tps_normal, ti).result;
|
||||
tis += [ti];
|
||||
tydescs += [td.val];
|
||||
bcx = td.bcx;
|
||||
}
|
||||
generic = some({item_type: fty,
|
||||
static_tis: tis,
|
||||
tydescs: tydescs,
|
||||
param_bounds: method.tps,
|
||||
origins: bcx_ccx(bcx).dict_map.find(e.id)});
|
||||
}
|
||||
{bcx: bcx, val: mptr, kind: owned,
|
||||
env: dict_env(dict, val),
|
||||
generic: generic}
|
||||
}
|
||||
|
||||
fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
|
||||
let out_ty = llvm::llvm::LLVMGetReturnType(ft);
|
||||
let n_args = llvm::llvm::LLVMCountParamTypes(ft);
|
||||
let args = vec::init_elt(0 as TypeRef, n_args);
|
||||
unsafe { llvm::llvm::LLVMGetParamTypes(ft, vec::to_ptr(args)); }
|
||||
{inputs: args, output: out_ty}
|
||||
}
|
||||
|
||||
fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
|
||||
extra_tps: [ty::param_bounds], m: @ast::method) -> ValueRef {
|
||||
let real_fn = ccx.item_ids.get(m.id);
|
||||
let {inputs: real_args, output: real_ret} =
|
||||
llfn_arg_tys(llvm::llvm::LLVMGetElementType(val_ty(real_fn)));
|
||||
let extra_ptrs = [];
|
||||
for tp in extra_tps {
|
||||
extra_ptrs += [T_ptr(ccx.tydesc_type)];
|
||||
for bound in *tp {
|
||||
alt bound {
|
||||
ty::bound_iface(_) { extra_ptrs += [T_ptr(T_dict())]; }
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
}
|
||||
let env_ty = T_ptr(T_struct([T_ptr(T_i8())] + extra_ptrs));
|
||||
let n_extra_ptrs = vec::len(extra_ptrs);
|
||||
|
||||
let wrap_args = [T_ptr(T_dict())] + vec::slice(real_args, 0u, 2u) +
|
||||
vec::slice(real_args, 2u + vec::len(extra_ptrs), vec::len(real_args));
|
||||
let llfn_ty = T_fn(wrap_args, real_ret);
|
||||
|
||||
let lcx = @{path: pt + ["wrapper", m.ident], module_path: [],
|
||||
obj_typarams: [], obj_fields: [], ccx: ccx};
|
||||
let name = link::mangle_internal_name_by_path_and_seq(ccx, pt, m.ident);
|
||||
let llfn = decl_internal_cdecl_fn(ccx.llmod, name, llfn_ty);
|
||||
let fcx = new_fn_ctxt(lcx, ast_util::dummy_sp(), llfn);
|
||||
let bcx = new_top_block_ctxt(fcx), lltop = bcx.llbb;
|
||||
|
||||
let dict = PointerCast(bcx, LLVMGetParam(llfn, 0u), env_ty);
|
||||
// retptr, self
|
||||
let args = [LLVMGetParam(llfn, 1u), LLVMGetParam(llfn, 2u)], i = 0u;
|
||||
// saved tydescs/dicts
|
||||
while i < n_extra_ptrs {
|
||||
i += 1u;
|
||||
args += [load_inbounds(bcx, dict, [0, i as int])];
|
||||
}
|
||||
// the rest of the parameters
|
||||
let i = 3u, params_total = llvm::llvm::LLVMCountParamTypes(llfn_ty);
|
||||
while i < params_total {
|
||||
args += [LLVMGetParam(llfn, i)];
|
||||
i += 1u;
|
||||
}
|
||||
Call(bcx, ccx.item_ids.get(m.id), args);
|
||||
build_return(bcx);
|
||||
finish_fn(fcx, lltop);
|
||||
ret llfn;
|
||||
}
|
||||
|
||||
// FIXME[impl] cache these on the function level somehow
|
||||
fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
|
||||
let bcx = bcx, ccx = bcx_ccx(bcx);
|
||||
alt origin {
|
||||
typeck::dict_static(impl_did, tys, sub_origins) {
|
||||
assert impl_did.crate == ast::local_crate; // FIXME[impl]
|
||||
let vtable = ccx.item_ids.get(impl_did.node);
|
||||
let impl_params = ty::lookup_item_type(ccx.tcx, impl_did).bounds;
|
||||
let ptrs = [vtable], i = 0u, origin = 0u, ti = none;
|
||||
for param in *impl_params {
|
||||
let rslt = get_tydesc(bcx, tys[i], false, tps_normal, ti).result;
|
||||
ptrs += [rslt.val];
|
||||
bcx = rslt.bcx;
|
||||
for bound in *param {
|
||||
alt bound {
|
||||
ty::bound_iface(_) {
|
||||
let res = get_dict(bcx, sub_origins[origin]);
|
||||
ptrs += [res.val];
|
||||
bcx = res.bcx;
|
||||
origin += 1u;
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
let pty = T_ptr(T_i8()), dict_ty = T_array(pty, vec::len(ptrs));
|
||||
let dict = alloca(bcx, dict_ty), i = 0;
|
||||
for ptr in ptrs {
|
||||
Store(bcx, PointerCast(bcx, ptr, pty), GEPi(bcx, dict, [0, i]));
|
||||
i += 1;
|
||||
}
|
||||
rslt(bcx, PointerCast(bcx, dict, T_ptr(T_dict())))
|
||||
}
|
||||
typeck::dict_param(n_param, n_bound) {
|
||||
rslt(bcx, option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -158,7 +158,7 @@ fn trans_obj(cx: @local_ctxt, sp: span, ob: ast::_obj, ctor_id: ast::node_id,
|
|||
let typarams_ty: ty::t = ty::mk_tup(ccx.tcx, tps);
|
||||
let i: int = 0;
|
||||
for tp: ast::ty_param in ty_params {
|
||||
let typaram = bcx.fcx.lltydescs[i];
|
||||
let typaram = bcx.fcx.lltyparams[i].desc;
|
||||
// Silly check
|
||||
check type_is_tup_like(bcx, typarams_ty);
|
||||
let capture =
|
||||
|
|
@ -880,8 +880,9 @@ fn process_normal_mthd(cx: @local_ctxt, m: @ast::method, self_ty: ty::t,
|
|||
ty::ty_fn(f) {
|
||||
let out = f.output;
|
||||
check non_ty_var(ccx, out);
|
||||
llfnty = type_of_fn(ccx, m.span, true, f.inputs, out,
|
||||
vec::len(ty_params));
|
||||
llfnty = type_of_fn(
|
||||
ccx, m.span, true, f.inputs, out,
|
||||
vec::map(ty_params, {|p| param_bounds(ccx, p)}));
|
||||
}
|
||||
}
|
||||
let mcx: @local_ctxt =
|
||||
|
|
@ -933,7 +934,8 @@ fn type_of_meth(ccx: @crate_ctxt, sp: span, m: @ty::method,
|
|||
tps: [ast::ty_param]) -> TypeRef {
|
||||
let out_ty = m.fty.output;
|
||||
check non_ty_var(ccx, out_ty);
|
||||
type_of_fn(ccx, sp, true, m.fty.inputs, out_ty, vec::len(tps))
|
||||
type_of_fn(ccx, sp, true, m.fty.inputs, out_ty,
|
||||
vec::map(tps, {|p| param_bounds(ccx, p)}))
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -50,12 +50,14 @@ fn comma_str(args: [@constr_arg_use]) -> str {
|
|||
fn constraint_to_str(tcx: ty::ctxt, c: sp_constr) -> str {
|
||||
alt c.node {
|
||||
ninit(id, i) {
|
||||
ret #fmt("init(%s id=%d [%s])",
|
||||
ret #fmt("init(%s id=%d - arising from %s)",
|
||||
i, id, tcx.sess.span_str(c.span));
|
||||
}
|
||||
npred(p, _, args) {
|
||||
ret path_to_str(p) + "(" + comma_str(args) + ")" + "[" +
|
||||
tcx.sess.span_str(c.span) + "]";
|
||||
ret #fmt("%s(%s) - arising from %s",
|
||||
path_to_str(p),
|
||||
comma_str(args),
|
||||
tcx.sess.span_str(c.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import util::common::*;
|
|||
import syntax::util::interner;
|
||||
import util::ppaux::ty_to_str;
|
||||
import util::ppaux::ty_constr_to_str;
|
||||
import util::ppaux::mode_str_1;
|
||||
import util::ppaux::mode_str;
|
||||
import syntax::print::pprust::*;
|
||||
|
||||
export node_id_to_monotype;
|
||||
|
|
@ -185,7 +185,7 @@ export closure_kind;
|
|||
export closure_block;
|
||||
export closure_shared;
|
||||
export closure_send;
|
||||
export param_bound, bound_copy, bound_send, bound_iface;
|
||||
export param_bound, param_bounds, bound_copy, bound_send, bound_iface;
|
||||
export param_bounds_to_kind;
|
||||
|
||||
// Data types
|
||||
|
|
@ -194,7 +194,9 @@ type arg = {mode: mode, ty: t};
|
|||
|
||||
type field = {ident: ast::ident, mt: mt};
|
||||
|
||||
type method = {ident: ast::ident, tps: [@[param_bound]], fty: fn_ty};
|
||||
type param_bounds = @[param_bound];
|
||||
|
||||
type method = {ident: ast::ident, tps: @[param_bounds], fty: fn_ty};
|
||||
|
||||
type constr_table = hashmap<ast::node_id, [constr]>;
|
||||
|
||||
|
|
@ -218,9 +220,9 @@ type ctxt =
|
|||
needs_drop_cache: hashmap<t, bool>,
|
||||
kind_cache: hashmap<t, kind>,
|
||||
ast_ty_to_ty_cache: hashmap<@ast::ty, option::t<t>>,
|
||||
tag_var_cache: hashmap<ast::def_id, @[variant_info]>,
|
||||
tag_var_cache: hashmap<def_id, @[variant_info]>,
|
||||
iface_method_cache: hashmap<def_id, @[method]>,
|
||||
ty_param_bounds: hashmap<def_id, @[param_bound]>};
|
||||
ty_param_bounds: hashmap<ast::node_id, param_bounds>};
|
||||
|
||||
type ty_ctxt = ctxt;
|
||||
|
||||
|
|
@ -268,7 +270,7 @@ tag sty {
|
|||
ty_tup([t]);
|
||||
ty_var(int); // type variable
|
||||
|
||||
ty_param(uint, @[param_bound]); // fn/tag type param
|
||||
ty_param(uint, def_id); // fn/tag type param
|
||||
|
||||
ty_type; // type_desc*
|
||||
ty_send_type; // type_desc* that has been cloned into exchange heap
|
||||
|
|
@ -308,7 +310,7 @@ tag param_bound {
|
|||
bound_iface(t);
|
||||
}
|
||||
|
||||
fn param_bounds_to_kind(bounds: @[param_bound]) -> kind {
|
||||
fn param_bounds_to_kind(bounds: param_bounds) -> kind {
|
||||
let kind = kind_noncopyable;
|
||||
for bound in *bounds {
|
||||
alt bound {
|
||||
|
|
@ -322,7 +324,7 @@ fn param_bounds_to_kind(bounds: @[param_bound]) -> kind {
|
|||
kind
|
||||
}
|
||||
|
||||
type ty_param_bounds_and_ty = @{bounds: [@[param_bound]], ty: t};
|
||||
type ty_param_bounds_and_ty = {bounds: @[param_bounds], ty: t};
|
||||
|
||||
type type_cache = hashmap<ast::def_id, ty_param_bounds_and_ty>;
|
||||
|
||||
|
|
@ -439,7 +441,7 @@ fn mk_ctxt(s: session::session, dm: resolve::def_map, amap: ast_map::map,
|
|||
map::mk_hashmap(ast_util::hash_ty, ast_util::eq_ty),
|
||||
tag_var_cache: new_def_hash(),
|
||||
iface_method_cache: new_def_hash(),
|
||||
ty_param_bounds: new_def_hash()};
|
||||
ty_param_bounds: map::new_int_hash()};
|
||||
populate_type_store(cx);
|
||||
ret cx;
|
||||
}
|
||||
|
|
@ -624,7 +626,7 @@ fn mk_res(cx: ctxt, did: ast::def_id, inner: t, tps: [t]) -> t {
|
|||
|
||||
fn mk_var(cx: ctxt, v: int) -> t { ret gen_ty(cx, ty_var(v)); }
|
||||
|
||||
fn mk_param(cx: ctxt, n: uint, k: @[param_bound]) -> t {
|
||||
fn mk_param(cx: ctxt, n: uint, k: def_id) -> t {
|
||||
ret gen_ty(cx, ty_param(n, k));
|
||||
}
|
||||
|
||||
|
|
@ -722,7 +724,7 @@ fn walk_ty(cx: ctxt, walker: ty_walk, ty: t) {
|
|||
|
||||
tag fold_mode {
|
||||
fm_var(fn@(int) -> t);
|
||||
fm_param(fn@(uint, @[param_bound]) -> t);
|
||||
fm_param(fn@(uint, def_id) -> t);
|
||||
fm_general(fn@(t) -> t);
|
||||
}
|
||||
|
||||
|
|
@ -813,8 +815,14 @@ fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
|
|||
ty_var(id) {
|
||||
alt fld { fm_var(folder) { ty = folder(id); } _ {/* no-op */ } }
|
||||
}
|
||||
ty_param(id, k) {
|
||||
alt fld { fm_param(folder) { ty = folder(id, k); } _ {/* no-op */ } }
|
||||
ty_param(id, did) {
|
||||
alt fld { fm_param(folder) { ty = folder(id, did); } _ {} }
|
||||
}
|
||||
ty_constr(subty, cs) {
|
||||
ty = mk_constr(cx, fold_ty(cx, fld, subty), cs);
|
||||
}
|
||||
_ {
|
||||
cx.sess.fatal("Unsupported sort of type in fold_ty");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1083,7 +1091,9 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
|
|||
}
|
||||
// Resources are always noncopyable.
|
||||
ty_res(did, inner, tps) { kind_noncopyable }
|
||||
ty_param(_, bounds) { param_bounds_to_kind(bounds) }
|
||||
ty_param(_, did) {
|
||||
param_bounds_to_kind(cx.ty_param_bounds.get(did.node))
|
||||
}
|
||||
ty_constr(t, _) { type_kind(cx, t) }
|
||||
};
|
||||
|
||||
|
|
@ -1131,7 +1141,7 @@ fn type_structurally_contains(cx: ctxt, ty: t, test: fn(sty) -> bool) ->
|
|||
}
|
||||
}
|
||||
|
||||
pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool {
|
||||
pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool unchecked {
|
||||
|
||||
/* type_structurally_contains can't be declared pure
|
||||
because it takes a function argument. But it should be
|
||||
|
|
@ -1141,15 +1151,9 @@ pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool {
|
|||
actually checkable. It seems to me like a lot of properties
|
||||
that the type context tracks about types should be immutable.)
|
||||
*/
|
||||
unchecked{
|
||||
type_structurally_contains(cx, ty,
|
||||
fn (sty: sty) -> bool {
|
||||
ret alt sty {
|
||||
ty_param(_, _) { true }
|
||||
_ { false }
|
||||
};
|
||||
})
|
||||
}
|
||||
type_structurally_contains(cx, ty, fn (sty: sty) -> bool {
|
||||
alt sty { ty_param(_, _) { true } _ { false }}
|
||||
})
|
||||
}
|
||||
|
||||
// Returns true for noncopyable types and types where a copy of a value can be
|
||||
|
|
@ -1464,8 +1468,6 @@ fn constrs_eq(cs: [@constr], ds: [@constr]) -> bool {
|
|||
// Type lookups
|
||||
fn node_id_to_ty_param_substs_opt_and_ty(cx: ctxt, id: ast::node_id) ->
|
||||
ty_param_substs_opt_and_ty {
|
||||
|
||||
|
||||
// Pull out the node type table.
|
||||
alt smallintmap::find(*cx.node_types, id as uint) {
|
||||
none. {
|
||||
|
|
@ -1737,6 +1739,7 @@ mod unify {
|
|||
export ures_ok;
|
||||
export ures_err;
|
||||
export var_bindings;
|
||||
export precise, in_bindings;
|
||||
|
||||
tag result { ures_ok(t); ures_err(type_err); }
|
||||
tag union_result { unres_ok; unres_err(type_err); }
|
||||
|
|
@ -1747,7 +1750,11 @@ mod unify {
|
|||
type var_bindings =
|
||||
{sets: ufind::ufind, types: smallintmap::smallintmap<t>};
|
||||
|
||||
type ctxt = {vb: option::t<@var_bindings>, tcx: ty_ctxt};
|
||||
tag unify_style {
|
||||
precise;
|
||||
in_bindings(@var_bindings);
|
||||
}
|
||||
type ctxt = {st: unify_style, tcx: ty_ctxt};
|
||||
|
||||
fn mk_var_bindings() -> @var_bindings {
|
||||
ret @{sets: ufind::make(), types: smallintmap::mk::<t>()};
|
||||
|
|
@ -1756,7 +1763,9 @@ mod unify {
|
|||
// Unifies two sets.
|
||||
fn union(cx: @ctxt, set_a: uint, set_b: uint,
|
||||
variance: variance) -> union_result {
|
||||
let vb = option::get(cx.vb);
|
||||
let vb = alt cx.st {
|
||||
in_bindings(vb) { vb }
|
||||
};
|
||||
ufind::grow(vb.sets, float::max(set_a, set_b) + 1u);
|
||||
let root_a = ufind::find(vb.sets, set_a);
|
||||
let root_b = ufind::find(vb.sets, set_b);
|
||||
|
|
@ -1806,7 +1815,7 @@ mod unify {
|
|||
fn record_var_binding(
|
||||
cx: @ctxt, key: int, typ: t, variance: variance) -> result {
|
||||
|
||||
let vb = option::get(cx.vb);
|
||||
let vb = alt cx.st { in_bindings(vb) { vb } };
|
||||
ufind::grow(vb.sets, (key as uint) + 1u);
|
||||
let root = ufind::find(vb.sets, key as uint);
|
||||
let result_type = typ;
|
||||
|
|
@ -2142,7 +2151,6 @@ mod unify {
|
|||
// If the RHS is a variable type, then just do the
|
||||
// appropriate binding.
|
||||
ty::ty_var(actual_id) {
|
||||
assert option::is_some(cx.vb);
|
||||
let actual_n = actual_id as uint;
|
||||
alt struct(cx.tcx, expected) {
|
||||
ty::ty_var(expected_id) {
|
||||
|
|
@ -2167,7 +2175,6 @@ mod unify {
|
|||
}
|
||||
alt struct(cx.tcx, expected) {
|
||||
ty::ty_var(expected_id) {
|
||||
assert option::is_some(cx.vb);
|
||||
// Add a binding. (`actual` can't actually be a var here.)
|
||||
alt record_var_binding_for_expected(
|
||||
cx, expected_id, actual,
|
||||
|
|
@ -2205,7 +2212,14 @@ mod unify {
|
|||
_ { ret ures_err(terr_mismatch); }
|
||||
}
|
||||
}
|
||||
ty::ty_param(_, _) { ret struct_cmp(cx, expected, actual); }
|
||||
ty::ty_param(expected_n, _) {
|
||||
alt struct(cx.tcx, actual) {
|
||||
ty::ty_param(actual_n, _) when expected_n == actual_n {
|
||||
ret ures_ok(expected);
|
||||
}
|
||||
_ { ret ures_err(terr_mismatch); }
|
||||
}
|
||||
}
|
||||
ty::ty_tag(expected_id, expected_tps) {
|
||||
alt struct(cx.tcx, actual) {
|
||||
ty::ty_tag(actual_id, actual_tps) {
|
||||
|
|
@ -2477,9 +2491,9 @@ mod unify {
|
|||
}
|
||||
}
|
||||
}
|
||||
fn unify(expected: t, actual: t, vb: option::t<@var_bindings>,
|
||||
fn unify(expected: t, actual: t, st: unify_style,
|
||||
tcx: ty_ctxt) -> result {
|
||||
let cx = @{vb: vb, tcx: tcx};
|
||||
let cx = @{st: st, tcx: tcx};
|
||||
ret unify_step(cx, expected, actual, covariant);
|
||||
}
|
||||
fn dump_var_bindings(tcx: ty_ctxt, vb: @var_bindings) {
|
||||
|
|
@ -2552,7 +2566,7 @@ mod unify {
|
|||
}
|
||||
|
||||
fn same_type(cx: ctxt, a: t, b: t) -> bool {
|
||||
alt unify::unify(a, b, none, cx) {
|
||||
alt unify::unify(a, b, unify::precise, cx) {
|
||||
unify::ures_ok(_) { true }
|
||||
_ { false }
|
||||
}
|
||||
|
|
@ -2602,8 +2616,8 @@ fn type_err_to_str(err: ty::type_err) -> str {
|
|||
"' but found one with method '" + a_meth + "'";
|
||||
}
|
||||
terr_mode_mismatch(e_mode, a_mode) {
|
||||
ret "expected argument mode " + mode_str_1(e_mode) + " but found " +
|
||||
mode_str_1(a_mode);
|
||||
ret "expected argument mode " + mode_str(e_mode) + " but found " +
|
||||
mode_str(a_mode);
|
||||
}
|
||||
terr_constr_len(e_len, a_len) {
|
||||
ret "Expected a type with " + uint::str(e_len) +
|
||||
|
|
@ -2621,25 +2635,17 @@ fn type_err_to_str(err: ty::type_err) -> str {
|
|||
|
||||
// Converts type parameters in a type to type variables and returns the
|
||||
// resulting type along with a list of type variable IDs.
|
||||
fn bind_params_in_type(sp: span, cx: ctxt, next_ty_var: fn@() -> int, typ: t,
|
||||
fn bind_params_in_type(cx: ctxt, next_ty_var: block() -> int, typ: t,
|
||||
ty_param_count: uint) -> {ids: [int], ty: t} {
|
||||
let param_var_ids: @mutable [int] = @mutable [];
|
||||
let i = 0u;
|
||||
while i < ty_param_count { *param_var_ids += [next_ty_var()]; i += 1u; }
|
||||
fn binder(sp: span, cx: ctxt, param_var_ids: @mutable [int],
|
||||
_next_ty_var: fn@() -> int, index: uint,
|
||||
_bounds: @[param_bound]) -> t {
|
||||
if index < vec::len(*param_var_ids) {
|
||||
ret mk_var(cx, param_var_ids[index]);
|
||||
} else {
|
||||
cx.sess.span_fatal(sp, "Unbound type parameter in callee's type");
|
||||
}
|
||||
let param_var_ids = [], i = 0u;
|
||||
while i < ty_param_count { param_var_ids += [next_ty_var()]; i += 1u; }
|
||||
let param_var_ids = @param_var_ids;
|
||||
fn binder(cx: ctxt, param_var_ids: @[int], index: uint,
|
||||
_did: def_id) -> t {
|
||||
ret mk_var(cx, param_var_ids[index]);
|
||||
}
|
||||
let new_typ =
|
||||
fold_ty(cx,
|
||||
fm_param(bind binder(sp, cx, param_var_ids, next_ty_var, _,
|
||||
_)), typ);
|
||||
ret {ids: *param_var_ids, ty: new_typ};
|
||||
{ids: *param_var_ids,
|
||||
ty: fold_ty(cx, fm_param(bind binder(cx, param_var_ids, _, _)), typ)}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2647,9 +2653,8 @@ fn bind_params_in_type(sp: span, cx: ctxt, next_ty_var: fn@() -> int, typ: t,
|
|||
// substitions.
|
||||
fn substitute_type_params(cx: ctxt, substs: [ty::t], typ: t) -> t {
|
||||
if !type_contains_params(cx, typ) { ret typ; }
|
||||
fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint,
|
||||
_bounds: @[param_bound])
|
||||
-> t {
|
||||
fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint, _did: def_id)
|
||||
-> t {
|
||||
// FIXME: bounds check can fail
|
||||
ret substs[idx];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import driver::session;
|
|||
import util::common::*;
|
||||
import syntax::codemap::span;
|
||||
import middle::ty;
|
||||
import middle::ty::{node_id_to_type, arg, bind_params_in_type, block_ty,
|
||||
import middle::ty::{node_id_to_type, arg, block_ty,
|
||||
expr_ty, field, node_type_table, mk_nil,
|
||||
ty_param_substs_opt_and_ty, ty_param_bounds_and_ty};
|
||||
import util::ppaux::ty_to_str;
|
||||
|
|
@ -18,9 +18,24 @@ import std::map::{hashmap, new_int_hash};
|
|||
import option::{none, some};
|
||||
import syntax::print::pprust::*;
|
||||
|
||||
export check_crate, method_map;
|
||||
export check_crate, method_map, method_origin, method_static, method_param;
|
||||
export dict_map, dict_res, dict_origin, dict_static, dict_param;
|
||||
|
||||
type method_map = hashmap<ast::node_id, ast::def_id>;
|
||||
tag method_origin {
|
||||
method_static(ast::def_id);
|
||||
// iface id, method num, param num, bound num
|
||||
method_param(ast::def_id, uint, uint, uint);
|
||||
}
|
||||
type method_map = hashmap<ast::node_id, method_origin>;
|
||||
|
||||
// Resolutions for bounds of all parameters, left to right, for a given path.
|
||||
type dict_res = @[dict_origin];
|
||||
tag dict_origin {
|
||||
dict_static(ast::def_id, [ty::t], dict_res);
|
||||
// Param number, bound number
|
||||
dict_param(uint, uint);
|
||||
}
|
||||
type dict_map = hashmap<ast::node_id, dict_res>;
|
||||
|
||||
type ty_table = hashmap<ast::def_id, ty::t>;
|
||||
|
||||
|
|
@ -33,6 +48,7 @@ tag self_info {
|
|||
type crate_ctxt = {mutable self_infos: [self_info],
|
||||
impl_map: resolve::impl_map,
|
||||
method_map: method_map,
|
||||
dict_map: dict_map,
|
||||
tcx: ty::ctxt};
|
||||
|
||||
type fn_ctxt =
|
||||
|
|
@ -76,22 +92,22 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
|
|||
ast::def_arg(id, _) {
|
||||
assert (fcx.locals.contains_key(id.node));
|
||||
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
|
||||
ret @{bounds: [], ty: typ};
|
||||
ret {bounds: @[], ty: typ};
|
||||
}
|
||||
ast::def_local(id, _) {
|
||||
assert (fcx.locals.contains_key(id.node));
|
||||
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
|
||||
ret @{bounds: [], ty: typ};
|
||||
ret {bounds: @[], ty: typ};
|
||||
}
|
||||
ast::def_obj_field(id, _) {
|
||||
assert (fcx.locals.contains_key(id.node));
|
||||
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
|
||||
ret @{bounds: [], ty: typ};
|
||||
ret {bounds: @[], ty: typ};
|
||||
}
|
||||
ast::def_self(id) {
|
||||
alt get_self_info(fcx.ccx) {
|
||||
some(self_obj(_, obj_t)) | some(self_impl(obj_t)) {
|
||||
ret @{bounds: [], ty: obj_t};
|
||||
ret {bounds: @[], ty: obj_t};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -102,12 +118,12 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
|
|||
ast::def_binding(id) {
|
||||
assert (fcx.locals.contains_key(id.node));
|
||||
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
|
||||
ret @{bounds: [], ty: typ};
|
||||
ret {bounds: @[], ty: typ};
|
||||
}
|
||||
ast::def_mod(_) {
|
||||
// Hopefully part of a path.
|
||||
// TODO: return a type that's more poisonous, perhaps?
|
||||
ret @{bounds: [], ty: ty::mk_nil(fcx.ccx.tcx)};
|
||||
ret {bounds: @[], ty: ty::mk_nil(fcx.ccx.tcx)};
|
||||
}
|
||||
ast::def_ty(_) {
|
||||
fcx.ccx.tcx.sess.span_fatal(sp, "expected value but found type");
|
||||
|
|
@ -122,16 +138,18 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
|
|||
}
|
||||
}
|
||||
|
||||
fn bind_params(fcx: @fn_ctxt, tp: ty::t, count: uint)
|
||||
-> {ids: [int], ty: ty::t} {
|
||||
ty::bind_params_in_type(fcx.ccx.tcx, {|| next_ty_var_id(fcx)}, tp, count)
|
||||
}
|
||||
|
||||
// Instantiates the given path, which must refer to an item with the given
|
||||
// number of type parameters and type.
|
||||
fn instantiate_path(fcx: @fn_ctxt, pth: @ast::path,
|
||||
tpt: ty_param_bounds_and_ty, sp: span)
|
||||
-> ty_param_substs_opt_and_ty {
|
||||
let ty_param_count = vec::len(tpt.bounds);
|
||||
let bind_result =
|
||||
bind_params_in_type(sp, fcx.ccx.tcx, bind next_ty_var_id(fcx), tpt.ty,
|
||||
ty_param_count);
|
||||
let ty_param_count = vec::len(*tpt.bounds);
|
||||
let bind_result = bind_params(fcx, tpt.ty, ty_param_count);
|
||||
let ty_param_vars = bind_result.ids;
|
||||
let ty_substs_opt;
|
||||
let ty_substs_len = vec::len::<@ast::ty>(pth.node.types);
|
||||
|
|
@ -282,13 +300,13 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
|
|||
// "foo = int" like OCaml?
|
||||
|
||||
let ty_param_bounds_and_ty = getter(tcx, mode, id);
|
||||
if vec::len(ty_param_bounds_and_ty.bounds) == 0u {
|
||||
if vec::len(*ty_param_bounds_and_ty.bounds) == 0u {
|
||||
ret ty_param_bounds_and_ty.ty;
|
||||
}
|
||||
|
||||
// The typedef is type-parametric. Do the type substitution.
|
||||
let param_bindings: [ty::t] = [];
|
||||
if vec::len(args) != vec::len(ty_param_bounds_and_ty.bounds) {
|
||||
if vec::len(args) != vec::len(*ty_param_bounds_and_ty.bounds) {
|
||||
tcx.sess.span_fatal(sp, "Wrong number of type arguments for a \
|
||||
polymorphic type");
|
||||
}
|
||||
|
|
@ -343,7 +361,7 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
|
|||
}
|
||||
some(ast::def_native_ty(id)) { typ = getter(tcx, mode, id).ty; }
|
||||
some(ast::def_ty_param(id, n)) {
|
||||
typ = ty::mk_param(tcx, n, tcx.ty_param_bounds.get(id));
|
||||
typ = ty::mk_param(tcx, n, id);
|
||||
}
|
||||
some(_) {
|
||||
tcx.sess.span_fatal(ast_ty.span,
|
||||
|
|
@ -382,7 +400,7 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
|
|||
alt it.node {
|
||||
ast::item_const(t, _) {
|
||||
let typ = ast_ty_to_ty(tcx, mode, t);
|
||||
let tpt = @{bounds: [], ty: typ};
|
||||
let tpt = {bounds: @[], ty: typ};
|
||||
tcx.tcache.insert(local_def(it.id), tpt);
|
||||
ret tpt;
|
||||
}
|
||||
|
|
@ -401,7 +419,7 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
|
|||
}
|
||||
// Tell ast_ty_to_ty() that we want to perform a recursive
|
||||
// call to resolve any named types.
|
||||
let tpt = @{bounds: ty_param_bounds(tcx, mode, tps),
|
||||
let tpt = {bounds: ty_param_bounds(tcx, mode, tps),
|
||||
ty: ty::mk_named(tcx, ast_ty_to_ty(tcx, mode, t),
|
||||
@it.ident)};
|
||||
tcx.tcache.insert(local_def(it.id), tpt);
|
||||
|
|
@ -413,7 +431,7 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
|
|||
let t = ty::mk_named(tcx, ty::mk_res(tcx, local_def(it.id), t_arg.ty,
|
||||
params),
|
||||
@it.ident);
|
||||
let t_res = @{bounds: bounds, ty: t};
|
||||
let t_res = {bounds: bounds, ty: t};
|
||||
tcx.tcache.insert(local_def(it.id), t_res);
|
||||
ret t_res;
|
||||
}
|
||||
|
|
@ -422,7 +440,7 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
|
|||
let {bounds, params} = mk_ty_params(tcx, tps);
|
||||
let t = ty::mk_named(tcx, ty::mk_tag(tcx, local_def(it.id), params),
|
||||
@it.ident);
|
||||
let tpt = @{bounds: bounds, ty: t};
|
||||
let tpt = {bounds: bounds, ty: t};
|
||||
tcx.tcache.insert(local_def(it.id), tpt);
|
||||
ret tpt;
|
||||
}
|
||||
|
|
@ -431,7 +449,7 @@ fn ty_of_item(tcx: ty::ctxt, mode: mode, it: @ast::item)
|
|||
let t = ty::mk_named(tcx, ty::mk_iface(tcx, local_def(it.id),
|
||||
params),
|
||||
@it.ident);
|
||||
let tpt = @{bounds: bounds, ty: t};
|
||||
let tpt = {bounds: bounds, ty: t};
|
||||
tcx.tcache.insert(local_def(it.id), tpt);
|
||||
ty::store_iface_methods(tcx, it.id, @vec::map(ms, {|m|
|
||||
ty_of_ty_method(tcx, m_collect, m)
|
||||
|
|
@ -455,7 +473,7 @@ fn ty_of_native_item(tcx: ty::ctxt, mode: mode, it: @ast::native_item)
|
|||
none. { }
|
||||
}
|
||||
let t = ty::mk_native(tcx, ast_util::local_def(it.id));
|
||||
let tpt = @{bounds: [], ty: t};
|
||||
let tpt = {bounds: @[], ty: t};
|
||||
tcx.tcache.insert(local_def(it.id), tpt);
|
||||
ret tpt;
|
||||
}
|
||||
|
|
@ -483,7 +501,7 @@ fn ty_of_fn(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl,
|
|||
-> ty::ty_param_bounds_and_ty {
|
||||
let bounds = ty_param_bounds(tcx, mode, ty_params);
|
||||
let tofd = ty_of_fn_decl(tcx, mode, ast::proto_bare, decl);
|
||||
let tpt = @{bounds: bounds, ty: ty::mk_fn(tcx, tofd)};
|
||||
let tpt = {bounds: bounds, ty: ty::mk_fn(tcx, tofd)};
|
||||
tcx.tcache.insert(def_id, tpt);
|
||||
ret tpt;
|
||||
}
|
||||
|
|
@ -495,15 +513,15 @@ fn ty_of_native_fn_decl(tcx: ty::ctxt, mode: mode, decl: ast::fn_decl,
|
|||
let output_ty = ast_ty_to_ty(tcx, mode, decl.output);
|
||||
|
||||
let t_fn = ty::mk_native_fn(tcx, input_tys, output_ty);
|
||||
let tpt = @{bounds: bounds, ty: t_fn};
|
||||
let tpt = {bounds: bounds, ty: t_fn};
|
||||
tcx.tcache.insert(def_id, tpt);
|
||||
ret tpt;
|
||||
}
|
||||
fn ty_param_bounds(tcx: ty::ctxt, mode: mode, params: [ast::ty_param])
|
||||
-> [@[ty::param_bound]] {
|
||||
-> @[ty::param_bounds] {
|
||||
let result = [];
|
||||
for param in params {
|
||||
result += [alt tcx.ty_param_bounds.find(local_def(param.id)) {
|
||||
result += [alt tcx.ty_param_bounds.find(param.id) {
|
||||
some(bs) { bs }
|
||||
none. {
|
||||
let bounds = [];
|
||||
|
|
@ -517,12 +535,12 @@ fn ty_param_bounds(tcx: ty::ctxt, mode: mode, params: [ast::ty_param])
|
|||
}];
|
||||
}
|
||||
let boxed = @bounds;
|
||||
tcx.ty_param_bounds.insert(local_def(param.id), boxed);
|
||||
tcx.ty_param_bounds.insert(param.id, boxed);
|
||||
boxed
|
||||
}
|
||||
}];
|
||||
}
|
||||
result
|
||||
@result
|
||||
}
|
||||
fn ty_of_method(tcx: ty::ctxt, mode: mode, m: @ast::method) -> ty::method {
|
||||
{ident: m.ident, tps: ty_param_bounds(tcx, mode, m.tps),
|
||||
|
|
@ -539,7 +557,7 @@ fn ty_of_obj(tcx: ty::ctxt, mode: mode, id: ast::ident, ob: ast::_obj,
|
|||
let methods = vec::map(ob.methods, {|m| ty_of_method(tcx, mode, m)});
|
||||
let t_obj = ty::mk_named(tcx, ty::mk_obj(tcx, ty::sort_methods(methods)),
|
||||
@id);
|
||||
ret @{bounds: bounds, ty: t_obj};
|
||||
ret {bounds: bounds, ty: t_obj};
|
||||
}
|
||||
fn ty_of_obj_ctor(tcx: ty::ctxt, mode: mode, id: ast::ident, ob: ast::_obj,
|
||||
ctor_id: ast::node_id, ty_params: [ast::ty_param])
|
||||
|
|
@ -553,7 +571,7 @@ fn ty_of_obj_ctor(tcx: ty::ctxt, mode: mode, id: ast::ident, ob: ast::_obj,
|
|||
let t_fn = ty::mk_fn(tcx, {proto: ast::proto_shared(ast::sugar_normal),
|
||||
inputs: t_inputs, output: t_obj.ty,
|
||||
ret_style: ast::return_val, constraints: []});
|
||||
let tpt = @{bounds: ty_param_bounds(tcx, mode, ty_params), ty: t_fn};
|
||||
let tpt = {bounds: ty_param_bounds(tcx, mode, ty_params), ty: t_fn};
|
||||
tcx.tcache.insert(local_def(ctor_id), tpt);
|
||||
ret tpt;
|
||||
}
|
||||
|
|
@ -622,11 +640,11 @@ mod write {
|
|||
}
|
||||
|
||||
fn mk_ty_params(tcx: ty::ctxt, atps: [ast::ty_param])
|
||||
-> {bounds: [@[ty::param_bound]], params: [ty::t]} {
|
||||
-> {bounds: @[ty::param_bounds], params: [ty::t]} {
|
||||
let i = 0u, bounds = ty_param_bounds(tcx, m_collect, atps);
|
||||
{bounds: bounds,
|
||||
params: vec::map(atps, {|_atp|
|
||||
let t = ty::mk_param(tcx, i, bounds[i]);
|
||||
params: vec::map(atps, {|atp|
|
||||
let t = ty::mk_param(tcx, i, local_def(atp.id));
|
||||
i += 1u;
|
||||
t
|
||||
})}
|
||||
|
|
@ -674,7 +692,7 @@ mod collect {
|
|||
inputs: args, output: tag_ty,
|
||||
ret_style: ast::return_val, constraints: []})
|
||||
};
|
||||
let tpt = @{bounds: ty_param_bounds(cx.tcx, m_collect, ty_params),
|
||||
let tpt = {bounds: ty_param_bounds(cx.tcx, m_collect, ty_params),
|
||||
ty: result_ty};
|
||||
cx.tcx.tcache.insert(local_def(variant.node.id), tpt);
|
||||
write::ty_only(cx.tcx, variant.node.id, result_ty);
|
||||
|
|
@ -690,14 +708,15 @@ mod collect {
|
|||
get_tag_variant_types(cx, tpt.ty, variants, ty_params);
|
||||
}
|
||||
ast::item_impl(tps, _, selfty, ms) {
|
||||
ty_param_bounds(cx.tcx, m_collect, tps);
|
||||
let i_bounds = ty_param_bounds(cx.tcx, m_collect, tps);
|
||||
for m in ms {
|
||||
let bounds = ty_param_bounds(cx.tcx, m_collect, m.tps);
|
||||
let ty = ty::mk_fn(cx.tcx,
|
||||
ty_of_fn_decl(cx.tcx, m_collect,
|
||||
ast::proto_bare, m.decl));
|
||||
cx.tcx.tcache.insert(local_def(m.id), @{bounds: bounds,
|
||||
ty: ty});
|
||||
cx.tcx.tcache.insert(local_def(m.id),
|
||||
{bounds: @(*i_bounds + *bounds),
|
||||
ty: ty});
|
||||
write::ty_only(cx.tcx, m.id, ty);
|
||||
}
|
||||
write::ty_only(cx.tcx, it.id, ast_ty_to_ty(cx.tcx, m_collect,
|
||||
|
|
@ -754,8 +773,7 @@ mod collect {
|
|||
write::ty_only(cx.tcx, it.id, t_res);
|
||||
write::ty_only(cx.tcx, ctor_id, t_ctor);
|
||||
cx.tcx.tcache.insert(local_def(ctor_id),
|
||||
@{bounds: bounds,
|
||||
ty: t_ctor});
|
||||
{bounds: bounds, ty: t_ctor});
|
||||
write::ty_only(cx.tcx, dtor_id, t_dtor);
|
||||
}
|
||||
_ {
|
||||
|
|
@ -798,7 +816,8 @@ mod collect {
|
|||
mod unify {
|
||||
fn unify(fcx: @fn_ctxt, expected: ty::t, actual: ty::t) ->
|
||||
ty::unify::result {
|
||||
ret ty::unify::unify(expected, actual, some(fcx.var_bindings),
|
||||
ret ty::unify::unify(expected, actual,
|
||||
ty::unify::in_bindings(fcx.var_bindings),
|
||||
fcx.ccx.tcx);
|
||||
}
|
||||
}
|
||||
|
|
@ -1115,7 +1134,8 @@ fn gather_locals(ccx: @crate_ctxt,
|
|||
alt ty_opt {
|
||||
none. {/* nothing to do */ }
|
||||
some(typ) {
|
||||
ty::unify::unify(ty::mk_var(tcx, var_id), typ, some(vb), tcx);
|
||||
ty::unify::unify(ty::mk_var(tcx, var_id), typ,
|
||||
ty::unify::in_bindings(vb), tcx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1465,39 +1485,92 @@ fn check_expr_with(fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool {
|
|||
ret check_expr_with_unifier(fcx, expr, demand::simple, expected);
|
||||
}
|
||||
|
||||
fn impl_self_ty(tcx: ty::ctxt, did: ast::def_id) -> {n_tps: uint, ty: ty::t} {
|
||||
if did.crate == ast::local_crate {
|
||||
alt tcx.items.get(did.node) {
|
||||
ast_map::node_item(@{node: ast::item_impl(ts, _, st, _),
|
||||
_}) {
|
||||
{n_tps: vec::len(ts), ty: ast_ty_to_ty(tcx, m_check, st)}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let tpt = csearch::get_type(tcx, did);
|
||||
{n_tps: vec::len(*tpt.bounds), ty: tpt.ty}
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
|
||||
name: ast::ident, ty: ty::t, sp: span)
|
||||
-> option::t<{method: @resolve::method_info, ids: [int]}> {
|
||||
-> option::t<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
|
||||
origin: method_origin}> {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
|
||||
// First, see whether this is an interface-bounded parameter
|
||||
alt ty::struct(tcx, ty) {
|
||||
ty::ty_param(n, did) {
|
||||
let bound_n = 0u;
|
||||
for bound in *tcx.ty_param_bounds.get(did.node) {
|
||||
alt bound {
|
||||
ty::bound_iface(t) {
|
||||
let (iid, tps) = alt ty::struct(tcx, t) {
|
||||
ty::ty_iface(i, tps) { (i, tps) }
|
||||
_ { cont; }
|
||||
};
|
||||
let ifce_methods = ty::iface_methods(tcx, iid);
|
||||
alt vec::position_pred(*ifce_methods, {|m| m.ident == name}) {
|
||||
some(pos) {
|
||||
let m = ifce_methods[pos];
|
||||
ret some({method_ty: ty::mk_fn(tcx, m.fty),
|
||||
n_tps: vec::len(*m.tps),
|
||||
substs: tps,
|
||||
origin: method_param(iid, pos, n, bound_n)});
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
bound_n += 1u;
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
ret none;
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
|
||||
fn ty_from_did(tcx: ty::ctxt, did: ast::def_id) -> ty::t {
|
||||
if did.crate == ast::local_crate {
|
||||
alt tcx.items.get(did.node) {
|
||||
ast_map::node_method(m) {
|
||||
let mt = ty_of_method(tcx, m_check, m);
|
||||
ty::mk_fn(tcx, mt.fty)
|
||||
}
|
||||
}
|
||||
} else { csearch::get_type(tcx, did).ty }
|
||||
}
|
||||
|
||||
let result = none;
|
||||
std::list::iter(isc) {|impls|
|
||||
if option::is_some(result) { ret; }
|
||||
for @{did, methods, _} in *impls {
|
||||
alt vec::find(methods, {|m| m.ident == name}) {
|
||||
some(m) {
|
||||
let (n_tps, self_ty) = if did.crate == ast::local_crate {
|
||||
alt fcx.ccx.tcx.items.get(did.node) {
|
||||
ast_map::node_item(@{node: ast::item_impl(ts, _, st, _),
|
||||
_}) {
|
||||
(vec::len(ts), ast_ty_to_ty_crate(fcx.ccx, st))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let tpt = csearch::get_type(fcx.ccx.tcx, did);
|
||||
(vec::len(tpt.bounds), tpt.ty)
|
||||
};
|
||||
let {n_tps, ty: self_ty} = impl_self_ty(tcx, did);
|
||||
let {ids, ty: self_ty} = if n_tps > 0u {
|
||||
bind_params_in_type(ast_util::dummy_sp(), fcx.ccx.tcx,
|
||||
bind next_ty_var_id(fcx), self_ty,
|
||||
n_tps)
|
||||
bind_params(fcx, self_ty, n_tps)
|
||||
} else { {ids: [], ty: self_ty} };
|
||||
alt unify::unify(fcx, ty, self_ty) {
|
||||
ures_ok(_) {
|
||||
if option::is_some(result) {
|
||||
// FIXME[impl] score specificity to resolve ambiguity?
|
||||
fcx.ccx.tcx.sess.span_err(
|
||||
tcx.sess.span_err(
|
||||
sp, "multiple applicable methods in scope");
|
||||
} else {
|
||||
result = some({method: m, ids: ids});
|
||||
result = some({
|
||||
method_ty: ty_from_did(tcx, m.did),
|
||||
n_tps: m.n_tps,
|
||||
substs: vec::map(ids, {|id| ty::mk_var(tcx, id)}),
|
||||
origin: method_static(m.did)
|
||||
});
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
|
|
@ -1680,7 +1753,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||
let element_ty = demand::simple(fcx, local.span, element_ty,
|
||||
ty::mk_var(fcx.ccx.tcx, locid));
|
||||
let bot = check_decl_local(fcx, local);
|
||||
check_block(fcx, body);
|
||||
check_block_no_value(fcx, body);
|
||||
// Unify type of decl with element type of the seq
|
||||
demand::simple(fcx, local.span,
|
||||
ty::node_id_to_type(fcx.ccx.tcx, local.node.id),
|
||||
|
|
@ -1695,22 +1768,27 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||
fn check_then_else(fcx: @fn_ctxt, thn: ast::blk,
|
||||
elsopt: option::t<@ast::expr>, id: ast::node_id,
|
||||
_sp: span) -> bool {
|
||||
let then_bot = check_block(fcx, thn);
|
||||
let els_bot = false;
|
||||
let if_t =
|
||||
let (if_t, if_bot) =
|
||||
alt elsopt {
|
||||
some(els) {
|
||||
let thn_bot = check_block(fcx, thn);
|
||||
let thn_t = block_ty(fcx.ccx.tcx, thn);
|
||||
els_bot = check_expr_with(fcx, els, thn_t);
|
||||
let elsopt_t = expr_ty(fcx.ccx.tcx, els);
|
||||
if !ty::type_is_bot(fcx.ccx.tcx, elsopt_t) {
|
||||
elsopt_t
|
||||
} else { thn_t }
|
||||
let els_bot = check_expr_with(fcx, els, thn_t);
|
||||
let els_t = expr_ty(fcx.ccx.tcx, els);
|
||||
let if_t = if !ty::type_is_bot(fcx.ccx.tcx, els_t) {
|
||||
els_t
|
||||
} else {
|
||||
thn_t
|
||||
};
|
||||
(if_t, thn_bot & els_bot)
|
||||
}
|
||||
none. {
|
||||
check_block_no_value(fcx, thn);
|
||||
(ty::mk_nil(fcx.ccx.tcx), false)
|
||||
}
|
||||
none. { ty::mk_nil(fcx.ccx.tcx) }
|
||||
};
|
||||
write::ty_only_fixup(fcx, id, if_t);
|
||||
ret then_bot & els_bot;
|
||||
ret if_bot;
|
||||
}
|
||||
|
||||
// Checks the compatibility
|
||||
|
|
@ -1932,12 +2010,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||
}
|
||||
ast::expr_while(cond, body) {
|
||||
bot = check_expr_with(fcx, cond, ty::mk_bool(tcx));
|
||||
check_block(fcx, body);
|
||||
check_block_no_value(fcx, body);
|
||||
write::ty_only_fixup(fcx, id, ty::mk_nil(tcx));
|
||||
}
|
||||
ast::expr_do_while(body, cond) {
|
||||
bot = check_expr_with(fcx, cond, ty::mk_bool(tcx)) |
|
||||
check_block(fcx, body);
|
||||
check_block_no_value(fcx, body);
|
||||
write::ty_only_fixup(fcx, id, block_ty(tcx, body));
|
||||
}
|
||||
ast::expr_alt(expr, arms) {
|
||||
|
|
@ -2153,7 +2231,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||
}
|
||||
ast::expr_field(base, field, tys) {
|
||||
bot |= check_expr(fcx, base);
|
||||
let expr_t = expr_ty(tcx, base);
|
||||
let expr_t = structurally_resolved_type(fcx, expr.span,
|
||||
expr_ty(tcx, base));
|
||||
let base_t = do_autoderef(fcx, expr.span, expr_t);
|
||||
let handled = false, n_tys = vec::len(tys);
|
||||
alt structure_of(fcx, expr.span, base_t) {
|
||||
|
|
@ -2191,51 +2270,35 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
|||
if !handled {
|
||||
let iscope = fcx.ccx.impl_map.get(expr.id);
|
||||
alt lookup_method(fcx, iscope, field, expr_t, expr.span) {
|
||||
some({method, ids}) {
|
||||
let fty = if method.did.crate == ast::local_crate {
|
||||
alt tcx.items.get(method.did.node) {
|
||||
ast_map::node_method(m) {
|
||||
let mt = ty_of_method(tcx, m_check, m);
|
||||
ty::mk_fn(tcx, mt.fty)
|
||||
}
|
||||
}
|
||||
} else { csearch::get_type(tcx, method.did).ty };
|
||||
let tvars = vec::map(ids, {|id| ty::mk_var(tcx, id)});
|
||||
let n_tps = vec::len(ids);
|
||||
if method.n_tps + n_tps > 0u {
|
||||
let b = bind_params_in_type(expr.span, tcx,
|
||||
bind next_ty_var_id(fcx), fty,
|
||||
n_tps + method.n_tps);
|
||||
let _tvars = vec::map(b.ids, {|id| ty::mk_var(tcx, id)});
|
||||
let i = 0;
|
||||
for v in tvars {
|
||||
demand::simple(fcx, expr.span, v, _tvars[i]);
|
||||
i += 1;
|
||||
}
|
||||
tvars = _tvars;
|
||||
fty = b.ty;
|
||||
some({method_ty: fty, n_tps: method_n_tps, substs, origin}) {
|
||||
let substs = substs, n_tps = vec::len(substs);
|
||||
if method_n_tps + n_tps > 0u {
|
||||
if n_tys > 0u {
|
||||
if n_tys != method.n_tps {
|
||||
if n_tys != method_n_tps {
|
||||
tcx.sess.span_fatal
|
||||
(expr.span, "incorrect number of type \
|
||||
parameters given for this method");
|
||||
|
||||
}
|
||||
let i = 0u;
|
||||
for ty in tys {
|
||||
let tvar = tvars[i + n_tps];
|
||||
let t_subst = ast_ty_to_ty_crate(fcx.ccx, ty);
|
||||
demand::simple(fcx, expr.span, tvar, t_subst);
|
||||
substs += [ast_ty_to_ty_crate(fcx.ccx, ty)];
|
||||
}
|
||||
} else {
|
||||
let i = 0u;
|
||||
while i < method_n_tps {
|
||||
substs += [ty::mk_var(tcx, next_ty_var_id(fcx))];
|
||||
i += 1u;
|
||||
}
|
||||
}
|
||||
write::ty_fixup(fcx, id, {substs: some(substs), ty: fty});
|
||||
} else if n_tys > 0u {
|
||||
tcx.sess.span_fatal(expr.span,
|
||||
"this method does not take type \
|
||||
parameters");
|
||||
} else {
|
||||
write::ty_only_fixup(fcx, id, fty);
|
||||
}
|
||||
write::ty_fixup(fcx, id, {substs: some(tvars), ty: fty});
|
||||
fcx.ccx.method_map.insert(id, method.did);
|
||||
fcx.ccx.method_map.insert(id, origin);
|
||||
}
|
||||
none. {
|
||||
let t_err = resolve_type_vars_if_possible(fcx, expr_t);
|
||||
|
|
@ -2437,6 +2500,16 @@ fn check_stmt(fcx: @fn_ctxt, stmt: @ast::stmt) -> bool {
|
|||
ret bot;
|
||||
}
|
||||
|
||||
fn check_block_no_value(fcx: @fn_ctxt, blk: ast::blk) -> bool {
|
||||
let bot = check_block(fcx, blk);
|
||||
if !bot {
|
||||
let blkty = ty::node_id_to_monotype(fcx.ccx.tcx, blk.node.id);
|
||||
let nilty = ty::mk_nil(fcx.ccx.tcx);
|
||||
demand::simple(fcx, blk.span, nilty, blkty);
|
||||
}
|
||||
ret bot;
|
||||
}
|
||||
|
||||
fn check_block(fcx0: @fn_ctxt, blk: ast::blk) -> bool {
|
||||
let fcx = alt blk.node.rules {
|
||||
ast::unchecked_blk. { @{purity: ast::impure_fn with *fcx0} }
|
||||
|
|
@ -2655,6 +2728,7 @@ fn check_fn(ccx: @crate_ctxt,
|
|||
// If we have an enclosing function scope, our type variables will be
|
||||
// resolved when the enclosing scope finishes up.
|
||||
if option::is_none(old_fcx) {
|
||||
dict::resolve_in_block(fcx, body);
|
||||
writeback::resolve_type_vars_in_block(fcx, body);
|
||||
}
|
||||
}
|
||||
|
|
@ -2663,16 +2737,40 @@ fn check_method(ccx: @crate_ctxt, method: @ast::method) {
|
|||
check_fn(ccx, ast::proto_bare, method.decl, method.body, method.id, none);
|
||||
}
|
||||
|
||||
fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
|
||||
impl_tps: uint, if_m: ty::method, substs: [ty::t]) {
|
||||
if impl_m.tps != if_m.tps {
|
||||
tcx.sess.span_err(sp, "method `" + if_m.ident +
|
||||
"` has an incompatible set of type parameters");
|
||||
} else {
|
||||
let impl_fty = ty::mk_fn(tcx, impl_m.fty);
|
||||
// Add dummy substs for the parameters of the impl method
|
||||
let substs = substs + vec::init_fn({|i|
|
||||
ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0})
|
||||
}, vec::len(*if_m.tps));
|
||||
let if_fty = ty::substitute_type_params(tcx, substs,
|
||||
ty::mk_fn(tcx, if_m.fty));
|
||||
alt ty::unify::unify(impl_fty, if_fty, ty::unify::precise, tcx) {
|
||||
ty::unify::ures_err(err) {
|
||||
tcx.sess.span_err(sp, "method `" + if_m.ident +
|
||||
"` has an incompatible type: " +
|
||||
ty::type_err_to_str(err));
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_item(ccx: @crate_ctxt, it: @ast::item) {
|
||||
alt it.node {
|
||||
ast::item_const(_, e) { check_const(ccx, it.span, e, it.id); }
|
||||
ast::item_fn(decl, _, body) {
|
||||
ast::item_fn(decl, tps, body) {
|
||||
check_fn(ccx, ast::proto_bare, decl, body, it.id, none);
|
||||
}
|
||||
ast::item_res(decl, _, body, dtor_id, _) {
|
||||
ast::item_res(decl, tps, body, dtor_id, _) {
|
||||
check_fn(ccx, ast::proto_bare, decl, body, dtor_id, none);
|
||||
}
|
||||
ast::item_obj(ob, _, _) {
|
||||
ast::item_obj(ob, tps, _) {
|
||||
// We're entering an object, so gather up the info we need.
|
||||
ccx.self_infos += [self_obj(ob.fields,
|
||||
ccx.tcx.tcache.get(local_def(it.id)).ty)];
|
||||
|
|
@ -2681,7 +2779,7 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
|
|||
// Now remove the info from the stack.
|
||||
vec::pop(ccx.self_infos);
|
||||
}
|
||||
ast::item_impl(_, ifce, ty, ms) {
|
||||
ast::item_impl(tps, ifce, ty, ms) {
|
||||
ccx.self_infos += [self_impl(ast_ty_to_ty(ccx.tcx, m_check, ty))];
|
||||
let my_methods = vec::map(ms, {|m|
|
||||
check_method(ccx, m);
|
||||
|
|
@ -2690,16 +2788,14 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
|
|||
vec::pop(ccx.self_infos);
|
||||
alt ifce {
|
||||
some(ty) {
|
||||
alt ty::struct(ccx.tcx, ast_ty_to_ty(ccx.tcx, m_check, ty)) {
|
||||
let iface_ty = ast_ty_to_ty(ccx.tcx, m_check, ty);
|
||||
alt ty::struct(ccx.tcx, iface_ty) {
|
||||
ty::ty_iface(did, tys) {
|
||||
for if_m in *ty::iface_methods(ccx.tcx, did) {
|
||||
alt vec::find(my_methods, {|m| if_m.ident == m.ident}) {
|
||||
some(m) {
|
||||
if !ty::same_method(ccx.tcx, m, if_m) {
|
||||
ccx.tcx.sess.span_err(
|
||||
ty.span, "method `" + if_m.ident +
|
||||
"` has the wrong type");
|
||||
}
|
||||
compare_impl_method(ccx.tcx, ty.span, m,
|
||||
vec::len(tps), if_m, tys);
|
||||
}
|
||||
none. {
|
||||
ccx.tcx.sess.span_err(ty.span, "missing method `" +
|
||||
|
|
@ -2707,6 +2803,9 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
|
|||
}
|
||||
}
|
||||
}
|
||||
let tpt = {bounds: ty_param_bounds(ccx.tcx, m_check, tps),
|
||||
ty: iface_ty};
|
||||
ccx.tcx.tcache.insert(local_def(it.id), tpt);
|
||||
}
|
||||
_ {
|
||||
ccx.tcx.sess.span_err(ty.span, "can only implement interface \
|
||||
|
|
@ -2721,6 +2820,29 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_ty_params(ccx: @crate_ctxt, tps: [ast::ty_param]) {
|
||||
for tp in tps {
|
||||
let i = 0u;
|
||||
for bound in *tp.bounds {
|
||||
alt bound {
|
||||
ast::bound_iface(at) {
|
||||
let tbound = ccx.tcx.ty_param_bounds.get(tp.id)[i];
|
||||
let bound_ty = alt tbound { ty::bound_iface(t) { t } };
|
||||
alt ty::struct(ccx.tcx, bound_ty) {
|
||||
ty::ty_iface(_, _) {}
|
||||
_ {
|
||||
ccx.tcx.sess.span_err(at.span, "type parameter bounds \
|
||||
must be interface types");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn arg_is_argv_ty(tcx: ty::ctxt, a: ty::arg) -> bool {
|
||||
alt ty::struct(tcx, a.ty) {
|
||||
ty::ty_vec(mt) {
|
||||
|
|
@ -2769,21 +2891,209 @@ fn check_for_main_fn(tcx: ty::ctxt, crate: @ast::crate) {
|
|||
}
|
||||
}
|
||||
|
||||
mod dict {
|
||||
fn has_iface_bounds(tps: [ty::param_bounds]) -> bool {
|
||||
vec::any(tps, {|bs|
|
||||
vec::any(*bs, {|b|
|
||||
alt b { ty::bound_iface(_) { true } _ { false } }
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn lookup_dicts(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
|
||||
bounds: @[ty::param_bounds], tys: [ty::t])
|
||||
-> dict_res {
|
||||
let tcx = fcx.ccx.tcx, result = [], i = 0u;
|
||||
for ty in tys {
|
||||
for bound in *bounds[i] {
|
||||
alt bound {
|
||||
ty::bound_iface(i_ty) {
|
||||
let i_ty = ty::substitute_type_params(tcx, tys, i_ty);
|
||||
result += [lookup_dict(fcx, isc, sp, ty, i_ty)];
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
@result
|
||||
}
|
||||
|
||||
fn lookup_dict(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
|
||||
ty: ty::t, iface_ty: ty::t) -> dict_origin {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
let (iface_id, iface_tps) = alt ty::struct(tcx, iface_ty) {
|
||||
ty::ty_iface(did, tps) { (did, tps) }
|
||||
_ { tcx.sess.abort_if_errors(); fail; }
|
||||
};
|
||||
let ty = fixup_ty(fcx, sp, ty);
|
||||
alt ty::struct(tcx, ty) {
|
||||
ty::ty_param(n, did) {
|
||||
let n_bound = 0u;
|
||||
for bound in *tcx.ty_param_bounds.get(did.node) {
|
||||
alt bound {
|
||||
ty::bound_iface(ity) {
|
||||
alt ty::struct(tcx, ity) {
|
||||
ty::ty_iface(idid, _) {
|
||||
if iface_id == idid { ret dict_param(n, n_bound); }
|
||||
}
|
||||
}
|
||||
n_bound += 1u;
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ {
|
||||
let found = none;
|
||||
std::list::iter(isc) {|impls|
|
||||
if option::is_some(found) { ret; }
|
||||
for im in *impls {
|
||||
if im.iface_did == some(iface_id) {
|
||||
let {n_tps, ty: self_ty} = impl_self_ty(tcx, im.did);
|
||||
let {ids, ty: self_ty} = if n_tps > 0u {
|
||||
bind_params(fcx, self_ty, n_tps)
|
||||
} else { {ids: [], ty: self_ty} };
|
||||
let vars = vec::map(ids, {|id| ty::mk_var(tcx, id)});
|
||||
let im_bs = ty::lookup_item_type(tcx, im.did).bounds;
|
||||
// FIXME[impl] don't do this in fcx (or make
|
||||
// unify transactional by scrubbing bindings on fail)
|
||||
alt unify::unify(fcx, ty, self_ty) {
|
||||
ures_ok(_) {
|
||||
if option::is_some(found) {
|
||||
tcx.sess.span_err(
|
||||
sp, "multiple applicable implementations \
|
||||
in scope");
|
||||
} else {
|
||||
connect_iface_tps(fcx, sp, vars, iface_tps,
|
||||
im.did);
|
||||
let params = vec::map(vars, {|t|
|
||||
fixup_ty(fcx, sp, t)});
|
||||
let subres = lookup_dicts(fcx, isc, sp, im_bs,
|
||||
params);
|
||||
found = some(dict_static(im.did, params,
|
||||
subres));
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
alt found {
|
||||
some(rslt) { ret rslt; }
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tcx.sess.span_fatal(
|
||||
sp, "failed to find an implementation of interface " +
|
||||
ty_to_str(tcx, iface_ty) + " for " +
|
||||
ty_to_str(tcx, ty));
|
||||
}
|
||||
|
||||
fn fixup_ty(fcx: @fn_ctxt, sp: span, ty: ty::t) -> ty::t {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
alt ty::unify::fixup_vars(tcx, some(sp), fcx.var_bindings, ty) {
|
||||
fix_ok(new_type) { new_type }
|
||||
fix_err(vid) {
|
||||
tcx.sess.span_fatal(sp, "could not determine a type for a \
|
||||
bounded type parameter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn connect_iface_tps(fcx: @fn_ctxt, sp: span, impl_tys: [ty::t],
|
||||
iface_tys: [ty::t], impl_did: ast::def_id) {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
// FIXME[impl]
|
||||
assert impl_did.crate == ast::local_crate;
|
||||
let ity = alt tcx.items.get(impl_did.node) {
|
||||
ast_map::node_item(@{node: ast::item_impl(_, some(ity), _, _), _}) {
|
||||
ast_ty_to_ty(tcx, m_check, ity)
|
||||
}
|
||||
};
|
||||
let iface_ty = ty::substitute_type_params(tcx, impl_tys, ity);
|
||||
alt ty::struct(tcx, iface_ty) {
|
||||
ty::ty_iface(_, tps) {
|
||||
vec::iter2(tps, iface_tys,
|
||||
{|a, b| demand::simple(fcx, sp, a, b);});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
|
||||
let cx = fcx.ccx;
|
||||
alt ex.node {
|
||||
ast::expr_path(_) {
|
||||
let substs = ty::node_id_to_ty_param_substs_opt_and_ty(
|
||||
cx.tcx, ex.id);
|
||||
alt substs.substs {
|
||||
some(ts) {
|
||||
let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id));
|
||||
let item_ty = ty::lookup_item_type(cx.tcx, did);
|
||||
if has_iface_bounds(*item_ty.bounds) {
|
||||
let impls = cx.impl_map.get(ex.id);
|
||||
cx.dict_map.insert(ex.id, lookup_dicts(
|
||||
fcx, impls, ex.span, item_ty.bounds, ts));
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
// Must resolve bounds on methods with bounded params
|
||||
ast::expr_field(_, _, _) {
|
||||
alt cx.method_map.find(ex.id) {
|
||||
some(method_static(did)) {
|
||||
let bounds = ty::lookup_item_type(cx.tcx, did).bounds;
|
||||
if has_iface_bounds(*bounds) {
|
||||
let ts = ty::node_id_to_type_params(cx.tcx, ex.id);
|
||||
let iscs = cx.impl_map.get(ex.id);
|
||||
cx.dict_map.insert(ex.id, lookup_dicts(
|
||||
fcx, iscs, ex.span, bounds, ts));
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
ast::expr_fn(ast::proto_block., _, _, _) {}
|
||||
ast::expr_fn(_, _, _, _) { ret; }
|
||||
_ {}
|
||||
}
|
||||
visit::visit_expr(ex, fcx, v);
|
||||
}
|
||||
|
||||
// Detect points where an interface-bounded type parameter is
|
||||
// instantiated, resolve the impls for the parameters.
|
||||
fn resolve_in_block(fcx: @fn_ctxt, bl: ast::blk) {
|
||||
visit::visit_block(bl, fcx, visit::mk_vt(@{
|
||||
visit_expr: resolve_expr,
|
||||
visit_item: fn(_i: @ast::item, &&_e: @fn_ctxt,
|
||||
_v: visit::vt<@fn_ctxt>) {}
|
||||
with *visit::default_visitor()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map,
|
||||
crate: @ast::crate) -> method_map {
|
||||
crate: @ast::crate) -> (method_map, dict_map) {
|
||||
collect::collect_item_types(tcx, crate);
|
||||
|
||||
let ccx = @{mutable self_infos: [],
|
||||
impl_map: impl_map,
|
||||
method_map: std::map::new_int_hash(),
|
||||
dict_map: std::map::new_int_hash(),
|
||||
tcx: tcx};
|
||||
let visit =
|
||||
visit::mk_simple_visitor(@{visit_item: bind check_item(ccx, _)
|
||||
with *visit::default_simple_visitor()});
|
||||
let visit = visit::mk_simple_visitor(@{
|
||||
visit_item: bind check_item(ccx, _),
|
||||
visit_ty_params: bind check_ty_params(ccx, _)
|
||||
with *visit::default_simple_visitor()
|
||||
});
|
||||
visit::visit_crate(*crate, (), visit);
|
||||
check_for_main_fn(tcx, crate);
|
||||
tcx.sess.abort_if_errors();
|
||||
ccx.method_map
|
||||
(ccx.method_map, ccx.dict_map)
|
||||
}
|
||||
//
|
||||
// Local Variables:
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ mod middle {
|
|||
mod trans_uniq;
|
||||
mod trans_closure;
|
||||
mod trans_vec;
|
||||
mod trans_impl;
|
||||
mod ty;
|
||||
mod ast_map;
|
||||
mod resolve;
|
||||
|
|
|
|||
|
|
@ -56,10 +56,10 @@ fn parse_companion_mod(cx: ctx, prefix: str, suffix: option::t<str>)
|
|||
-> ([@ast::view_item], [@ast::item], [ast::attribute]) {
|
||||
|
||||
fn companion_file(prefix: str, suffix: option::t<str>) -> str {
|
||||
alt suffix {
|
||||
ret alt suffix {
|
||||
option::some(s) { fs::connect(prefix, s) }
|
||||
option::none. { prefix }
|
||||
} + ".rs"
|
||||
} + ".rs";
|
||||
}
|
||||
|
||||
fn file_exists(path: str) -> bool {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,12 @@ import util::interner;
|
|||
import ast::{node_id, spanned};
|
||||
import front::attr;
|
||||
|
||||
tag restriction { UNRESTRICTED; RESTRICT_NO_CALL_EXPRS; RESTRICT_NO_BAR_OP; }
|
||||
tag restriction {
|
||||
UNRESTRICTED;
|
||||
RESTRICT_STMT_EXPR;
|
||||
RESTRICT_NO_CALL_EXPRS;
|
||||
RESTRICT_NO_BAR_OP;
|
||||
}
|
||||
|
||||
tag file_type { CRATE_FILE; SOURCE_FILE; }
|
||||
|
||||
|
|
@ -977,28 +982,45 @@ fn parse_syntax_ext_naked(p: parser, lo: uint) -> @ast::expr {
|
|||
|
||||
fn parse_dot_or_call_expr(p: parser) -> @ast::expr {
|
||||
let b = parse_bottom_expr(p);
|
||||
if expr_has_value(b) { parse_dot_or_call_expr_with(p, b) }
|
||||
else { b }
|
||||
parse_dot_or_call_expr_with(p, b)
|
||||
}
|
||||
|
||||
fn permits_call(p: parser) -> bool {
|
||||
ret p.get_restriction() != RESTRICT_NO_CALL_EXPRS;
|
||||
}
|
||||
|
||||
fn parse_dot_or_call_expr_with(p: parser, e: @ast::expr) -> @ast::expr {
|
||||
let lo = e.span.lo;
|
||||
let hi = e.span.hi;
|
||||
let e = e;
|
||||
while true {
|
||||
while !expr_is_complete(p, e) {
|
||||
alt p.peek() {
|
||||
token::LPAREN. {
|
||||
if p.get_restriction() == RESTRICT_NO_CALL_EXPRS {
|
||||
ret e;
|
||||
} else {
|
||||
// Call expr.
|
||||
let es = parse_seq(token::LPAREN, token::RPAREN,
|
||||
seq_sep(token::COMMA), parse_expr, p);
|
||||
hi = es.span.hi;
|
||||
let nd = ast::expr_call(e, es.node, false);
|
||||
e = mk_expr(p, lo, hi, nd);
|
||||
// expr(...)
|
||||
token::LPAREN. when permits_call(p) {
|
||||
let es = parse_seq(token::LPAREN, token::RPAREN,
|
||||
seq_sep(token::COMMA), parse_expr, p);
|
||||
hi = es.span.hi;
|
||||
let nd = ast::expr_call(e, es.node, false);
|
||||
e = mk_expr(p, lo, hi, nd);
|
||||
}
|
||||
|
||||
// expr { || ... }
|
||||
token::LBRACE. when is_bar(p.look_ahead(1u)) && permits_call(p) {
|
||||
p.bump();
|
||||
let blk = parse_fn_block_expr(p);
|
||||
alt e.node {
|
||||
ast::expr_call(f, args, false) {
|
||||
e = @{node: ast::expr_call(f, args + [blk], true)
|
||||
with *e};
|
||||
}
|
||||
_ {
|
||||
e = mk_expr(p, lo, p.get_last_hi_pos(),
|
||||
ast::expr_call(e, [blk], true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// expr[...]
|
||||
token::LBRACKET. {
|
||||
p.bump();
|
||||
let ix = parse_expr(p);
|
||||
|
|
@ -1006,6 +1028,8 @@ fn parse_dot_or_call_expr_with(p: parser, e: @ast::expr) -> @ast::expr {
|
|||
expect(p, token::RBRACKET);
|
||||
e = mk_expr(p, lo, hi, ast::expr_index(e, ix));
|
||||
}
|
||||
|
||||
// expr.f
|
||||
token::DOT. {
|
||||
p.bump();
|
||||
alt p.peek() {
|
||||
|
|
@ -1022,6 +1046,7 @@ fn parse_dot_or_call_expr_with(p: parser, e: @ast::expr) -> @ast::expr {
|
|||
t { unexpected(p, t); }
|
||||
}
|
||||
}
|
||||
|
||||
_ { ret e; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1126,7 +1151,7 @@ const ternary_prec: int = 0;
|
|||
|
||||
fn parse_more_binops(p: parser, lhs: @ast::expr, min_prec: int) ->
|
||||
@ast::expr {
|
||||
if !expr_has_value(lhs) { ret lhs; }
|
||||
if expr_is_complete(p, lhs) { ret lhs; }
|
||||
let peeked = p.peek();
|
||||
if peeked == token::BINOP(token::OR) &&
|
||||
p.get_restriction() == RESTRICT_NO_BAR_OP { ret lhs; }
|
||||
|
|
@ -1207,11 +1232,6 @@ fn parse_if_expr_1(p: parser) ->
|
|||
let elexpr = parse_else_expr(p);
|
||||
els = some(elexpr);
|
||||
hi = elexpr.span.hi;
|
||||
} else if !option::is_none(thn.node.expr) {
|
||||
let sp = option::get(thn.node.expr).span;
|
||||
p.span_fatal(sp, "`if` without `else` can not produce a result");
|
||||
//TODO: If a suggestion mechanism appears, suggest that the
|
||||
//user may have forgotten a ';'
|
||||
}
|
||||
ret {cond: cond, then: thn, els: els, lo: lo, hi: hi};
|
||||
}
|
||||
|
|
@ -1550,84 +1570,52 @@ fn parse_stmt(p: parser) -> @ast::stmt {
|
|||
}
|
||||
}
|
||||
|
||||
let maybe_item = parse_item(p, item_attrs);
|
||||
|
||||
// If we have attributes then we should have an item
|
||||
if vec::len(item_attrs) > 0u {
|
||||
alt maybe_item {
|
||||
some(_) {/* fallthrough */ }
|
||||
_ { ret p.fatal("expected item"); }
|
||||
}
|
||||
}
|
||||
|
||||
alt maybe_item {
|
||||
alt parse_item(p, item_attrs) {
|
||||
some(i) {
|
||||
let hi = i.span.hi;
|
||||
let decl = @spanned(lo, hi, ast::decl_item(i));
|
||||
ret @spanned(lo, hi, ast::stmt_decl(decl, p.get_id()));
|
||||
}
|
||||
none. {
|
||||
// Remainder are line-expr stmts.
|
||||
let e = parse_expr(p);
|
||||
// See if it is a block call
|
||||
if expr_has_value(e) && p.peek() == token::LBRACE &&
|
||||
is_bar(p.look_ahead(1u)) {
|
||||
p.bump();
|
||||
let blk = parse_fn_block_expr(p);
|
||||
alt e.node {
|
||||
ast::expr_call(f, args, false) {
|
||||
e = @{node: ast::expr_call(f, args + [blk], true)
|
||||
with *e};
|
||||
}
|
||||
_ {
|
||||
e = mk_expr(p, lo, p.get_last_hi_pos(),
|
||||
ast::expr_call(e, [blk], true));
|
||||
}
|
||||
}
|
||||
}
|
||||
ret @spanned(lo, e.span.hi, ast::stmt_expr(e, p.get_id()));
|
||||
}
|
||||
_ { p.fatal("expected statement"); }
|
||||
none() { /* fallthrough */ }
|
||||
}
|
||||
|
||||
// If we have attributes then we should have an item
|
||||
if vec::len(item_attrs) > 0u {
|
||||
ret p.fatal("expected item");
|
||||
}
|
||||
|
||||
// Remainder are line-expr stmts.
|
||||
let e = parse_expr_res(p, RESTRICT_STMT_EXPR);
|
||||
ret @spanned(lo, e.span.hi, ast::stmt_expr(e, p.get_id()));
|
||||
}
|
||||
}
|
||||
|
||||
fn expr_has_value(e: @ast::expr) -> bool {
|
||||
fn expr_is_complete(p: parser, e: @ast::expr) -> bool {
|
||||
log(debug, ("expr_is_complete", p.get_restriction(),
|
||||
print::pprust::expr_to_str(e),
|
||||
expr_requires_semi_to_be_stmt(e)));
|
||||
ret p.get_restriction() == RESTRICT_STMT_EXPR &&
|
||||
!expr_requires_semi_to_be_stmt(e);
|
||||
}
|
||||
|
||||
fn expr_requires_semi_to_be_stmt(e: @ast::expr) -> bool {
|
||||
alt e.node {
|
||||
ast::expr_if(_, th, els) | ast::expr_if_check(_, th, els) {
|
||||
if option::is_none(els) { false }
|
||||
else { !option::is_none(th.node.expr) ||
|
||||
expr_has_value(option::get(els)) }
|
||||
ast::expr_if(_, _, _) | ast::expr_if_check(_, _, _)
|
||||
| ast::expr_alt(_, _) | ast::expr_block(_)
|
||||
| ast::expr_do_while(_, _) | ast::expr_while(_, _)
|
||||
| ast::expr_for(_, _, _)
|
||||
| ast::expr_call(_, _, true) {
|
||||
false
|
||||
}
|
||||
ast::expr_alt(_, arms) {
|
||||
let found_expr = false;
|
||||
for arm in arms {
|
||||
if !option::is_none(arm.body.node.expr) { found_expr = true; }
|
||||
}
|
||||
found_expr
|
||||
}
|
||||
ast::expr_block(blk) | ast::expr_while(_, blk) |
|
||||
ast::expr_for(_, _, blk) | ast::expr_do_while(blk, _) {
|
||||
!option::is_none(blk.node.expr)
|
||||
}
|
||||
ast::expr_call(_, _, true) { false }
|
||||
_ { true }
|
||||
}
|
||||
}
|
||||
|
||||
fn stmt_is_expr(stmt: @ast::stmt) -> bool {
|
||||
ret alt stmt.node {
|
||||
ast::stmt_expr(e, _) { expr_has_value(e) }
|
||||
_ { false }
|
||||
};
|
||||
}
|
||||
|
||||
fn stmt_to_expr(stmt: @ast::stmt) -> option::t<@ast::expr> {
|
||||
ret if stmt_is_expr(stmt) {
|
||||
alt stmt.node {
|
||||
ast::stmt_expr(e, _) { some(e) }
|
||||
}
|
||||
} else { none };
|
||||
alt stmt.node {
|
||||
ast::stmt_expr(e, _) { some(e) }
|
||||
_ { none }
|
||||
}
|
||||
}
|
||||
|
||||
fn stmt_ends_with_semi(stmt: ast::stmt) -> bool {
|
||||
|
|
@ -1639,7 +1627,7 @@ fn stmt_ends_with_semi(stmt: ast::stmt) -> bool {
|
|||
}
|
||||
}
|
||||
ast::stmt_expr(e, _) {
|
||||
ret expr_has_value(e);
|
||||
ret expr_requires_semi_to_be_stmt(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1659,14 +1647,10 @@ fn parse_block(p: parser) -> ast::blk {
|
|||
}
|
||||
|
||||
fn parse_block_no_value(p: parser) -> ast::blk {
|
||||
let blk = parse_block(p);
|
||||
if !option::is_none(blk.node.expr) {
|
||||
let sp = option::get(blk.node.expr).span;
|
||||
p.span_fatal(sp, "this block must not have a result");
|
||||
//TODO: If a suggestion mechanism appears, suggest that the
|
||||
//user may have forgotten a ';'
|
||||
}
|
||||
ret blk;
|
||||
// We parse blocks that cannot have a value the same as any other block;
|
||||
// the type checker will make sure that the tail expression (if any) has
|
||||
// unit type.
|
||||
ret parse_block(p);
|
||||
}
|
||||
|
||||
// Precondition: already parsed the '{' or '#{'
|
||||
|
|
@ -1850,34 +1834,29 @@ fn parse_item_iface(p: parser, attrs: [ast::attribute]) -> @ast::item {
|
|||
ast::item_iface(tps, meths), attrs);
|
||||
}
|
||||
|
||||
// Parses three variants (with the initial params always optional):
|
||||
// impl <T: copy> of to_str for [T] { ... }
|
||||
// impl name<T> of to_str for [T] { ... }
|
||||
// impl name<T> for [T] { ... }
|
||||
fn parse_item_impl(p: parser, attrs: [ast::attribute]) -> @ast::item {
|
||||
let lo = p.get_last_lo_pos(), ident, tps, ifce;
|
||||
let lo = p.get_last_lo_pos();
|
||||
fn wrap_path(p: parser, pt: @ast::path) -> @ast::ty {
|
||||
@{node: ast::ty_path(pt, p.get_id()), span: pt.span}
|
||||
}
|
||||
if eat_word(p, "of") {
|
||||
let (ident, tps) = if !is_word(p, "of") {
|
||||
if p.peek() == token::LT { (none, parse_ty_params(p)) }
|
||||
else { (some(parse_ident(p)), parse_ty_params(p)) }
|
||||
} else { (none, []) };
|
||||
let ifce = if eat_word(p, "of") {
|
||||
let path = parse_path_and_ty_param_substs(p, false);
|
||||
tps = vec::map(path.node.types, {|tp|
|
||||
alt tp.node {
|
||||
ast::ty_path(pt, _) {
|
||||
if vec::len(pt.node.idents) == 1u &&
|
||||
vec::len(pt.node.types) == 0u {
|
||||
ret {ident: pt.node.idents[0], id: p.get_id(),
|
||||
bounds: @[]};
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
p.fatal("only single-word, parameter-less types allowed here");
|
||||
});
|
||||
ident = path.node.idents[vec::len(path.node.idents)-1u];
|
||||
ifce = some(wrap_path(p, path));
|
||||
} else {
|
||||
ident = parse_ident(p);
|
||||
tps = parse_ty_params(p);
|
||||
ifce = if eat_word(p, "of") {
|
||||
some(wrap_path(p, parse_path_and_ty_param_substs(p, false)))
|
||||
} else { none };
|
||||
if option::is_none(ident) {
|
||||
ident = some(path.node.idents[vec::len(path.node.idents) - 1u]);
|
||||
}
|
||||
some(wrap_path(p, path))
|
||||
} else { none };
|
||||
let ident = alt ident {
|
||||
some(name) { name }
|
||||
none. { expect_word(p, "of"); fail; }
|
||||
};
|
||||
expect_word(p, "for");
|
||||
let ty = parse_ty(p, false), meths = [];
|
||||
|
|
|
|||
|
|
@ -558,11 +558,39 @@ fn print_attribute(s: ps, attr: ast::attribute) {
|
|||
word(s.s, "]");
|
||||
}
|
||||
|
||||
// An expression that begins with a dual-form statement/expression like `{
|
||||
// ... }-10` would be parsed as `{ ... };-10` unless parentheses are used (ie,
|
||||
// `({...}-10)`). These parentheses are not, however, preserved by the
|
||||
// parser. This function specifies whether parentheses must be inserted.
|
||||
fn stmt_expr_requires_parens(ex: @ast::expr) -> bool {
|
||||
fn helper(ex: @ast::expr, inner: bool) -> bool {
|
||||
alt ex.node {
|
||||
ast::expr_call(subex, _, _) | ast::expr_binary(_, subex, _) {
|
||||
be helper(subex, true);
|
||||
}
|
||||
_ when !inner { ret false; }
|
||||
_ { ret !parse::parser::expr_requires_semi_to_be_stmt(ex); }
|
||||
}
|
||||
}
|
||||
ret helper(ex, false);
|
||||
}
|
||||
|
||||
fn print_stmt(s: ps, st: ast::stmt) {
|
||||
maybe_print_comment(s, st.span.lo);
|
||||
alt st.node {
|
||||
ast::stmt_decl(decl, _) { print_decl(s, decl); }
|
||||
ast::stmt_expr(expr, _) { space_if_not_bol(s); print_expr(s, expr); }
|
||||
ast::stmt_decl(decl, _) {
|
||||
print_decl(s, decl);
|
||||
}
|
||||
ast::stmt_expr(expr, _) {
|
||||
space_if_not_bol(s);
|
||||
if stmt_expr_requires_parens(expr) {
|
||||
popen(s);
|
||||
print_expr(s, expr);
|
||||
pclose(s);
|
||||
} else {
|
||||
print_expr(s, expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
if parse::parser::stmt_ends_with_semi(st) { word(s.s, ";"); }
|
||||
maybe_print_trailing_comment(s, st.span, none::<uint>);
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ type visitor<E> =
|
|||
visit_decl: fn@(@decl, E, vt<E>),
|
||||
visit_expr: fn@(@expr, E, vt<E>),
|
||||
visit_ty: fn@(@ty, E, vt<E>),
|
||||
visit_ty_params: fn@([ty_param], E, vt<E>),
|
||||
visit_constr: fn@(@path, span, node_id, E, vt<E>),
|
||||
visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id, E, vt<E>)};
|
||||
|
||||
|
|
@ -68,6 +69,7 @@ fn default_visitor<E>() -> visitor<E> {
|
|||
visit_decl: bind visit_decl::<E>(_, _, _),
|
||||
visit_expr: bind visit_expr::<E>(_, _, _),
|
||||
visit_ty: bind skip_ty::<E>(_, _, _),
|
||||
visit_ty_params: bind visit_ty_params::<E>(_, _, _),
|
||||
visit_constr: bind visit_constr::<E>(_, _, _, _, _),
|
||||
visit_fn: bind visit_fn::<E>(_, _, _, _, _, _, _)};
|
||||
}
|
||||
|
|
@ -113,19 +115,19 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
|
|||
for vi: @view_item in nm.view_items { v.visit_view_item(vi, e, v); }
|
||||
for ni: @native_item in nm.items { v.visit_native_item(ni, e, v); }
|
||||
}
|
||||
item_ty(t, tps) { v.visit_ty(t, e, v); visit_ty_params(tps, e, v); }
|
||||
item_ty(t, tps) { v.visit_ty(t, e, v); v.visit_ty_params(tps, e, v); }
|
||||
item_res(decl, tps, body, dtor_id, _) {
|
||||
v.visit_fn(fk_res(i.ident, tps), decl, body, i.span,
|
||||
dtor_id, e, v);
|
||||
}
|
||||
item_tag(variants, tps) {
|
||||
visit_ty_params(tps, e, v);
|
||||
v.visit_ty_params(tps, e, v);
|
||||
for vr: variant in variants {
|
||||
for va: variant_arg in vr.node.args { v.visit_ty(va.ty, e, v); }
|
||||
}
|
||||
}
|
||||
item_obj(ob, tps, _) {
|
||||
visit_ty_params(tps, e, v);
|
||||
v.visit_ty_params(tps, e, v);
|
||||
for f: obj_field in ob.fields { v.visit_ty(f.ty, e, v); }
|
||||
for m: @method in ob.methods {
|
||||
v.visit_fn(fk_method(m.ident, m.tps), m.decl, m.body, m.span,
|
||||
|
|
@ -133,7 +135,7 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
|
|||
}
|
||||
}
|
||||
item_impl(tps, ifce, ty, methods) {
|
||||
visit_ty_params(tps, e, v);
|
||||
v.visit_ty_params(tps, e, v);
|
||||
alt ifce { some(ty) { v.visit_ty(ty, e, v); } _ {} }
|
||||
v.visit_ty(ty, e, v);
|
||||
for m in methods {
|
||||
|
|
@ -142,7 +144,7 @@ fn visit_item<E>(i: @item, e: E, v: vt<E>) {
|
|||
}
|
||||
}
|
||||
item_iface(tps, methods) {
|
||||
visit_ty_params(tps, e, v);
|
||||
v.visit_ty_params(tps, e, v);
|
||||
for m in methods {
|
||||
for a in m.decl.inputs { v.visit_ty(a.ty, e, v); }
|
||||
v.visit_ty(m.decl.output, e, v);
|
||||
|
|
@ -217,7 +219,7 @@ fn visit_pat<E>(p: @pat, e: E, v: vt<E>) {
|
|||
fn visit_native_item<E>(ni: @native_item, e: E, v: vt<E>) {
|
||||
alt ni.node {
|
||||
native_item_fn(fd, tps) {
|
||||
visit_ty_params(tps, e, v);
|
||||
v.visit_ty_params(tps, e, v);
|
||||
visit_fn_decl(fd, e, v);
|
||||
}
|
||||
native_item_ty. { }
|
||||
|
|
@ -246,7 +248,7 @@ fn visit_fn_decl<E>(fd: fn_decl, e: E, v: vt<E>) {
|
|||
fn visit_fn<E>(fk: fn_kind, decl: fn_decl, body: blk, _sp: span,
|
||||
_id: node_id, e: E, v: vt<E>) {
|
||||
visit_fn_decl(decl, e, v);
|
||||
visit_ty_params(tps_of_fn(fk), e, v);
|
||||
v.visit_ty_params(tps_of_fn(fk), e, v);
|
||||
v.visit_block(body, e, v);
|
||||
}
|
||||
|
||||
|
|
@ -414,6 +416,7 @@ type simple_visitor =
|
|||
visit_decl: fn@(@decl),
|
||||
visit_expr: fn@(@expr),
|
||||
visit_ty: fn@(@ty),
|
||||
visit_ty_params: fn@([ty_param]),
|
||||
visit_constr: fn@(@path, span, node_id),
|
||||
visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id)};
|
||||
|
||||
|
|
@ -432,6 +435,7 @@ fn default_simple_visitor() -> simple_visitor {
|
|||
visit_decl: fn(_d: @decl) { },
|
||||
visit_expr: fn(_e: @expr) { },
|
||||
visit_ty: simple_ignore_ty,
|
||||
visit_ty_params: fn(_ps: [ty_param]) {},
|
||||
visit_constr: fn(_p: @path, _sp: span, _id: node_id) { },
|
||||
visit_fn: fn(_fk: fn_kind, _d: fn_decl, _b: blk, _sp: span,
|
||||
_id: node_id) { }
|
||||
|
|
@ -488,6 +492,10 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
|
|||
f(ty);
|
||||
visit_ty(ty, e, v);
|
||||
}
|
||||
fn v_ty_params(f: fn@([ty_param]), ps: [ty_param], &&e: (), v: vt<()>) {
|
||||
f(ps);
|
||||
visit_ty_params(ps, e, v);
|
||||
}
|
||||
fn v_constr(f: fn@(@path, span, node_id), pt: @path, sp: span,
|
||||
id: node_id, &&e: (), v: vt<()>) {
|
||||
f(pt, sp, id);
|
||||
|
|
@ -517,6 +525,7 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
|
|||
visit_decl: bind v_decl(v.visit_decl, _, _, _),
|
||||
visit_expr: bind v_expr(v.visit_expr, _, _, _),
|
||||
visit_ty: visit_ty,
|
||||
visit_ty_params: bind v_ty_params(v.visit_ty_params, _, _, _),
|
||||
visit_constr: bind v_constr(v.visit_constr, _, _, _, _, _),
|
||||
visit_fn: bind v_fn(v.visit_fn, _, _, _, _, _, _, _)
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,10 +19,6 @@ fn mode_str(m: ty::mode) -> str {
|
|||
}
|
||||
}
|
||||
|
||||
fn mode_str_1(m: ty::mode) -> str {
|
||||
alt m { ast::by_ref. { "ref" } _ { mode_str(m) } }
|
||||
}
|
||||
|
||||
fn ty_to_str(cx: ctxt, typ: t) -> str {
|
||||
fn fn_input_to_str(cx: ctxt, input: {mode: middle::ty::mode, ty: t}) ->
|
||||
str {
|
||||
|
|
@ -95,6 +91,7 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
|
|||
ty_str. { "str" }
|
||||
ty_box(tm) { "@" + mt_to_str(cx, tm) }
|
||||
ty_uniq(tm) { "~" + mt_to_str(cx, tm) }
|
||||
ty_ptr(tm) { "*" + mt_to_str(cx, tm) }
|
||||
ty_vec(tm) { "[" + mt_to_str(cx, tm) + "]" }
|
||||
ty_type. { "type" }
|
||||
ty_rec(elems) {
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ fn maybe_with_lib_path<T>(path: str, f: fn@() -> T) -> T {
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn maybe_with_lib_path<T>(_path: str, f: fn@() -> T) -> T {
|
||||
f()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@ fn program_output(cx: cx, testfile: str, lib_path: str, prog: str,
|
|||
// Linux and mac don't require adjusting the library search path
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn make_cmdline(_libpath: str, prog: str, args: [str]) -> str {
|
||||
#fmt["%s %s", prog, str::connect(args, " ")]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ fn make_new_path(path: str) -> str {
|
|||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn lib_path_env_var() -> str { "LD_LIBRARY_PATH" }
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
|
|
@ -27,6 +28,7 @@ fn lib_path_env_var() -> str { "PATH" }
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn path_div() -> str { ":" }
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
|
|
|
|||
|
|
@ -33,7 +33,13 @@ snapshot_files = {
|
|||
"lib/std-*.dll",
|
||||
"lib/rustc-*.dll",
|
||||
"lib/rustrt.dll",
|
||||
"lib/rustllvm.dll"]
|
||||
"lib/rustllvm.dll"],
|
||||
"freebsd": ["bin/rustc",
|
||||
"lib/libcore-*.so",
|
||||
"lib/libstd-*.so",
|
||||
"lib/librustc-*.so",
|
||||
"lib/librustrt.so",
|
||||
"lib/librustllvm.so"]
|
||||
}
|
||||
|
||||
def parse_line(n, line):
|
||||
|
|
@ -73,6 +79,8 @@ def get_kernel(triple):
|
|||
return "winnt"
|
||||
if os_name == "darwin":
|
||||
return "macos"
|
||||
if os_name == "freebsd":
|
||||
return "freebsd"
|
||||
return "linux"
|
||||
|
||||
def get_cpu(triple):
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export is_alphabetic,
|
|||
is_XID_start, is_XID_continue,
|
||||
is_lowercase, is_uppercase,
|
||||
is_whitespace, is_alphanumeric,
|
||||
to_digit, maybe_digit, cmp;
|
||||
to_digit, to_lower, to_upper, maybe_digit, cmp;
|
||||
|
||||
import is_alphabetic = unicode::derived_property::Alphabetic;
|
||||
import is_XID_start = unicode::derived_property::XID_Start;
|
||||
|
|
@ -122,7 +122,7 @@ pure fn to_digit(c: char) -> u8 unsafe {
|
|||
}
|
||||
|
||||
/*
|
||||
Function: to_digit
|
||||
Function: maybe_digit
|
||||
|
||||
Convert a char to the corresponding digit. Returns none when the
|
||||
character is not a valid hexadecimal digit.
|
||||
|
|
@ -136,6 +136,34 @@ pure fn maybe_digit(c: char) -> option::t<u8> {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Function: to_lower
|
||||
|
||||
Convert a char to the corresponding lower case.
|
||||
|
||||
FIXME: works only on ASCII
|
||||
*/
|
||||
pure fn to_lower(c: char) -> char {
|
||||
alt c {
|
||||
'A' to 'Z' { ((c as u8) + 32u8) as char }
|
||||
_ { c }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Function: to_upper
|
||||
|
||||
Convert a char to the corresponding upper case.
|
||||
|
||||
FIXME: works only on ASCII
|
||||
*/
|
||||
pure fn to_upper(c: char) -> char {
|
||||
alt c {
|
||||
'a' to 'z' { ((c as u8) - 32u8) as char }
|
||||
_ { c }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Function: cmp
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import ctypes::c_int;
|
|||
import ctypes::c_float;
|
||||
import ctypes::c_double;
|
||||
|
||||
// function names are almost identical to C's libmath, a few have been
|
||||
// renamed, grep for "rename:"
|
||||
|
||||
#[link_name = "m"]
|
||||
#[abi = "cdecl"]
|
||||
native mod c_double {
|
||||
|
|
@ -26,8 +29,10 @@ native mod c_double {
|
|||
pure fn expm1(n: c_double) -> c_double;
|
||||
pure fn exp2(n: c_double) -> c_double;
|
||||
#[link_name="fabs"] pure fn abs(n: c_double) -> c_double;
|
||||
#[link_name="fdim"] pure fn sub_pos(a: c_double, b: c_double) -> c_double;
|
||||
// rename: for clarity and consistency with add/sub/mul/div
|
||||
#[link_name="fdim"] pure fn abs_sub(a: c_double, b: c_double) -> c_double;
|
||||
pure fn floor(n: c_double) -> c_double;
|
||||
// rename: for clarity and consistency with add/sub/mul/div
|
||||
#[link_name="fma"] pure fn mul_add(a: c_double, b: c_double,
|
||||
c: c_double) -> c_double;
|
||||
#[link_name="fmax"] pure fn fmax(a: c_double, b: c_double) -> c_double;
|
||||
|
|
@ -38,17 +43,26 @@ native mod c_double {
|
|||
pure fn ldexp(x: c_double, n: c_int) -> c_double;
|
||||
#[link_name="lgamma_r"] pure fn lgamma(n: c_double,
|
||||
&sign: c_int) -> c_double;
|
||||
// renamed: log is a reserved keyword; ln seems more natural, too
|
||||
#[link_name="log"] pure fn ln(n: c_double) -> c_double;
|
||||
pure fn logb(n: c_double) -> c_double;
|
||||
// renamed: "logb" /often/ is confused for log2 by beginners
|
||||
#[link_name="logb"] pure fn log_radix(n: c_double) -> c_double;
|
||||
// renamed: to be consitent with log as ln
|
||||
#[link_name="log1p"] pure fn ln1p(n: c_double) -> c_double;
|
||||
pure fn log10(n: c_double) -> c_double;
|
||||
#[cfg(target_os="linux")]
|
||||
#[cfg(target_os="macos")]
|
||||
#[cfg(target_os="win32")]
|
||||
pure fn log2(n: c_double) -> c_double;
|
||||
pure fn ilogb(n: c_double) -> c_int;
|
||||
#[link_name="ilogb"] pure fn ilogradix(n: c_double) -> c_int;
|
||||
pure fn modf(n: c_double, &iptr: c_double) -> c_double;
|
||||
pure fn pow(n: c_double, e: c_double) -> c_double;
|
||||
pure fn rint(n: c_double) -> c_double;
|
||||
// FIXME enable when rounding modes become available
|
||||
// pure fn rint(n: c_double) -> c_double;
|
||||
pure fn round(n: c_double) -> c_double;
|
||||
pure fn scalbn(n: c_double, i: c_int) -> c_double;
|
||||
// rename: for consistency with logradix
|
||||
#[link_name="scalbn"] pure fn ldexp_radix(n: c_double, i: c_int) ->
|
||||
c_double;
|
||||
pure fn sin(n: c_double) -> c_double;
|
||||
pure fn sinh(n: c_double) -> c_double;
|
||||
pure fn sqrt(n: c_double) -> c_double;
|
||||
|
|
@ -90,7 +104,7 @@ native mod c_float {
|
|||
#[link_name="expm1f"]pure fn expm1(n: c_float) -> c_float;
|
||||
#[link_name="exp2f"] pure fn exp2(n: c_float) -> c_float;
|
||||
#[link_name="fabsf"] pure fn abs(n: c_float) -> c_float;
|
||||
#[link_name="fdimf"] pure fn sub_pos(a: c_float, b: c_float) -> c_float;
|
||||
#[link_name="fdimf"] pure fn abs_sub(a: c_float, b: c_float) -> c_float;
|
||||
#[link_name="floorf"] pure fn floor(n: c_float) -> c_float;
|
||||
#[link_name="frexpf"] pure fn frexp(n: c_float,
|
||||
&value: c_int) -> c_float;
|
||||
|
|
@ -105,17 +119,21 @@ native mod c_float {
|
|||
#[link_name="lgammaf_r"] pure fn lgamma(n: c_float,
|
||||
&sign: c_int) -> c_float;
|
||||
#[link_name="logf"] pure fn ln(n: c_float) -> c_float;
|
||||
#[link_name="logbf"] pure fn logb(n: c_float) -> c_float;
|
||||
#[link_name="logbf"] pure fn log_radix(n: c_float) -> c_float;
|
||||
#[link_name="log1pf"] pure fn ln1p(n: c_float) -> c_float;
|
||||
#[cfg(target_os="linux")]
|
||||
#[cfg(target_os="macos")]
|
||||
#[cfg(target_os="win32")]
|
||||
#[link_name="log2f"] pure fn log2(n: c_float) -> c_float;
|
||||
#[link_name="log10f"] pure fn log10(n: c_float) -> c_float;
|
||||
#[link_name="ilogbf"] pure fn ilogb(n: c_float) -> c_int;
|
||||
#[link_name="ilogbf"] pure fn ilog_radix(n: c_float) -> c_int;
|
||||
#[link_name="modff"] pure fn modf(n: c_float,
|
||||
&iptr: c_float) -> c_float;
|
||||
#[link_name="powf"] pure fn pow(n: c_float, e: c_float) -> c_float;
|
||||
#[link_name="rintf"] pure fn rint(n: c_float) -> c_float;
|
||||
// FIXME enable when rounding modes become available
|
||||
// #[link_name="rintf"] pure fn rint(n: c_float) -> c_float;
|
||||
#[link_name="roundf"] pure fn round(n: c_float) -> c_float;
|
||||
#[link_name="scalbnf"] pure fn scalbn(n: c_float, i: c_int) -> c_float;
|
||||
#[link_name="scalbnf"] pure fn ldexp_radix(n: c_float, i: c_int) -> c_float;
|
||||
#[link_name="sinf"] pure fn sin(n: c_float) -> c_float;
|
||||
#[link_name="sinhf"] pure fn sinh(n: c_float) -> c_float;
|
||||
#[link_name="sqrtf"] pure fn sqrt(n: c_float) -> c_float;
|
||||
|
|
|
|||
|
|
@ -103,6 +103,24 @@ pure fn to_result<copy T, copy U>(eith: t<T, U>) -> result::t<U, T> {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Function: is_left
|
||||
|
||||
Checks whether the given value is a left
|
||||
*/
|
||||
pure fn is_left<T, U>(eith: t<T, U>) -> bool {
|
||||
alt eith { left(_) { true } _ { false } }
|
||||
}
|
||||
|
||||
/*
|
||||
Function: is_left
|
||||
|
||||
Checks whether the given value is a right
|
||||
*/
|
||||
pure fn is_right<T, U>(eith: t<T, U>) -> bool {
|
||||
alt eith { right(_) { true } _ { false } }
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ type t = f32;
|
|||
|
||||
// PORT check per architecture
|
||||
|
||||
// FIXME obtain these in a different way
|
||||
|
||||
const radix: uint = 2u;
|
||||
|
||||
const mantissa_digits: uint = 24u;
|
||||
|
|
@ -42,7 +44,7 @@ const infinity: f32 = 1.0_f32/0.0_f32;
|
|||
const neg_infinity: f32 = -1.0_f32/0.0_f32;
|
||||
|
||||
/* Predicate: isNaN */
|
||||
pure fn isNaN(f: f32) -> bool { f != f }
|
||||
pure fn is_NaN(f: f32) -> bool { f != f }
|
||||
|
||||
/* Function: add */
|
||||
pure fn add(x: f32, y: f32) -> f32 { ret x + y; }
|
||||
|
|
@ -77,29 +79,32 @@ pure fn ge(x: f32, y: f32) -> bool { ret x >= y; }
|
|||
/* Predicate: gt */
|
||||
pure fn gt(x: f32, y: f32) -> bool { ret x > y; }
|
||||
|
||||
// FIXME replace the predicates below with llvm intrinsics or calls
|
||||
// to the libmath macros in the rust runtime for performance
|
||||
|
||||
/*
|
||||
Predicate: positive
|
||||
Predicate: is_positive
|
||||
|
||||
Returns true if `x` is a positive number, including +0.0f320 and +Infinity.
|
||||
*/
|
||||
pure fn positive(x: f32) -> bool
|
||||
pure fn is_positive(x: f32) -> bool
|
||||
{ ret x > 0.0f32 || (1.0f32/x) == infinity; }
|
||||
|
||||
/*
|
||||
Predicate: negative
|
||||
Predicate: is_negative
|
||||
|
||||
Returns true if `x` is a negative number, including -0.0f320 and -Infinity.
|
||||
*/
|
||||
pure fn negative(x: f32) -> bool
|
||||
pure fn is_negative(x: f32) -> bool
|
||||
{ ret x < 0.0f32 || (1.0f32/x) == neg_infinity; }
|
||||
|
||||
/*
|
||||
Predicate: nonpositive
|
||||
Predicate: is_nonpositive
|
||||
|
||||
Returns true if `x` is a negative number, including -0.0f320 and -Infinity.
|
||||
(This is the same as `f32::negative`.)
|
||||
*/
|
||||
pure fn nonpositive(x: f32) -> bool {
|
||||
pure fn is_nonpositive(x: f32) -> bool {
|
||||
ret x < 0.0f32 || (1.0f32/x) == neg_infinity;
|
||||
}
|
||||
|
||||
|
|
@ -109,10 +114,39 @@ Predicate: nonnegative
|
|||
Returns true if `x` is a positive number, including +0.0f320 and +Infinity.
|
||||
(This is the same as `f32::positive`.)
|
||||
*/
|
||||
pure fn nonnegative(x: f32) -> bool {
|
||||
pure fn is_nonnegative(x: f32) -> bool {
|
||||
ret x > 0.0f32 || (1.0f32/x) == infinity;
|
||||
}
|
||||
|
||||
/*
|
||||
Predicate: is_zero
|
||||
|
||||
Returns true if `x` is a zero number (positive or negative zero)
|
||||
*/
|
||||
pure fn is_zero(x: f32) -> bool {
|
||||
ret x == 0.0f32 || x == -0.0f32;
|
||||
}
|
||||
|
||||
/*
|
||||
Predicate: is_infinite
|
||||
|
||||
Returns true if `x`is an infinite numer
|
||||
*/
|
||||
pure fn is_infinite(x: f32) -> bool {
|
||||
ret x == infinity || x == neg_infinity;
|
||||
}
|
||||
|
||||
/*
|
||||
Predicate: is_finite
|
||||
|
||||
Returns true if `x`is a finite numer
|
||||
*/
|
||||
pure fn is_finite(x: f32) -> bool {
|
||||
ret !(is_nan(x) || is_infinite(x));
|
||||
}
|
||||
|
||||
// FIXME add is_normal, is_subnormal, and fpclassify
|
||||
|
||||
/* Module: consts */
|
||||
mod consts {
|
||||
|
||||
|
|
@ -208,6 +242,15 @@ mod consts {
|
|||
const ln_10: f32 = 2.30258509299404568401799145468436421_f32;
|
||||
}
|
||||
|
||||
pure fn logarithm(n: f32, b: f32) -> f32 {
|
||||
ret ln(n) / ln(b);
|
||||
}
|
||||
|
||||
#[cfg(target_os="freebsd")]
|
||||
pure fn log2(n: f32) -> f32 {
|
||||
ret ln(n) / consts::ln_2;
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ type t = f64;
|
|||
|
||||
// PORT check per architecture
|
||||
|
||||
// FIXME obtain these in a different way
|
||||
|
||||
const radix: uint = 2u;
|
||||
|
||||
const mantissa_digits: uint = 53u;
|
||||
|
|
@ -42,7 +44,7 @@ const infinity: f64 = 1.0_f64/0.0_f64;
|
|||
const neg_infinity: f64 = -1.0_f64/0.0_f64;
|
||||
|
||||
/* Predicate: isNaN */
|
||||
pure fn isNaN(f: f64) -> bool { f != f }
|
||||
pure fn is_NaN(f: f64) -> bool { f != f }
|
||||
|
||||
/* Function: add */
|
||||
pure fn add(x: f64, y: f64) -> f64 { ret x + y; }
|
||||
|
|
@ -78,41 +80,70 @@ pure fn ge(x: f64, y: f64) -> bool { ret x >= y; }
|
|||
pure fn gt(x: f64, y: f64) -> bool { ret x > y; }
|
||||
|
||||
/*
|
||||
Predicate: positive
|
||||
Predicate: is_positive
|
||||
|
||||
Returns true if `x` is a positive number, including +0.0f640 and +Infinity.
|
||||
*/
|
||||
pure fn positive(x: f64) -> bool
|
||||
pure fn is_positive(x: f64) -> bool
|
||||
{ ret x > 0.0f64 || (1.0f64/x) == infinity; }
|
||||
|
||||
/*
|
||||
Predicate: negative
|
||||
Predicate: is_negative
|
||||
|
||||
Returns true if `x` is a negative number, including -0.0f640 and -Infinity.
|
||||
*/
|
||||
pure fn negative(x: f64) -> bool
|
||||
pure fn is_negative(x: f64) -> bool
|
||||
{ ret x < 0.0f64 || (1.0f64/x) == neg_infinity; }
|
||||
|
||||
/*
|
||||
Predicate: nonpositive
|
||||
Predicate: is_nonpositive
|
||||
|
||||
Returns true if `x` is a negative number, including -0.0f640 and -Infinity.
|
||||
(This is the same as `f64::negative`.)
|
||||
*/
|
||||
pure fn nonpositive(x: f64) -> bool {
|
||||
pure fn is_nonpositive(x: f64) -> bool {
|
||||
ret x < 0.0f64 || (1.0f64/x) == neg_infinity;
|
||||
}
|
||||
|
||||
/*
|
||||
Predicate: nonnegative
|
||||
Predicate: is_nonnegative
|
||||
|
||||
Returns true if `x` is a positive number, including +0.0f640 and +Infinity.
|
||||
(This is the same as `f64::positive`.)
|
||||
*/
|
||||
pure fn nonnegative(x: f64) -> bool {
|
||||
pure fn is_nonnegative(x: f64) -> bool {
|
||||
ret x > 0.0f64 || (1.0f64/x) == infinity;
|
||||
}
|
||||
|
||||
/*
|
||||
Predicate: is_zero
|
||||
|
||||
Returns true if `x` is a zero number (positive or negative zero)
|
||||
*/
|
||||
pure fn is_zero(x: f64) -> bool {
|
||||
ret x == 0.0f64 || x == -0.0f64;
|
||||
}
|
||||
|
||||
/*
|
||||
Predicate: is_infinite
|
||||
|
||||
Returns true if `x`is an infinite numer
|
||||
*/
|
||||
pure fn is_infinite(x: f64) -> bool {
|
||||
ret x == infinity || x == neg_infinity;
|
||||
}
|
||||
|
||||
/*
|
||||
Predicate: is_finite
|
||||
|
||||
Returns true if `x`is a finite numer
|
||||
*/
|
||||
pure fn is_finite(x: f64) -> bool {
|
||||
ret !(is_nan(x) || is_infinite(x));
|
||||
}
|
||||
|
||||
// FIXME add is_normal, is_subnormal, and fpclassify
|
||||
|
||||
/* Module: consts */
|
||||
mod consts {
|
||||
|
||||
|
|
@ -208,6 +239,15 @@ mod consts {
|
|||
const ln_10: f64 = 2.30258509299404568401799145468436421_f64;
|
||||
}
|
||||
|
||||
pure fn logarithm(n: f64, b: f64) -> f64 {
|
||||
ret ln(n) / ln(b);
|
||||
}
|
||||
|
||||
#[cfg(target_os="freebsd")]
|
||||
pure fn log2(n: f64) -> f64 {
|
||||
ret ln(n) / consts::ln_2;
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ pure fn get<copy T>(opt: t<T>) -> T {
|
|||
|
||||
/*
|
||||
*/
|
||||
fn map<T, U>(opt: t<T>, f: block(T) -> U) -> t<U> {
|
||||
fn map<T, copy U>(opt: t<T>, f: block(T) -> U) -> t<U> {
|
||||
alt opt { some(x) { some(f(x)) } none. { none } }
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ Function: from_maybe
|
|||
|
||||
Returns the contained value or a default
|
||||
*/
|
||||
pure fn from_maybe<T>(def: T, opt: t<T>) -> T {
|
||||
pure fn from_maybe<copy T>(def: T, opt: t<T>) -> T {
|
||||
alt opt { some(x) { x } none. { def } }
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ Function: maybe
|
|||
|
||||
Applies a function to the contained value or returns a default
|
||||
*/
|
||||
fn maybe<T, U>(def: U, opt: t<T>, f: block(T) -> U) -> U {
|
||||
fn maybe<T, copy U>(def: U, opt: t<T>, f: block(T) -> U) -> U {
|
||||
alt opt { none. { def } some(t) { f(t) } }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ Failure:
|
|||
|
||||
If the result is an error
|
||||
*/
|
||||
fn get<T, U>(res: t<T, U>) -> T {
|
||||
fn get<copy T, U>(res: t<T, U>) -> T {
|
||||
alt res {
|
||||
ok(t) { t }
|
||||
err(_) {
|
||||
|
|
@ -57,7 +57,7 @@ Failure:
|
|||
|
||||
If the result is not an error
|
||||
*/
|
||||
fn get_err<T, U>(res: t<T, U>) -> U {
|
||||
fn get_err<T, copy U>(res: t<T, U>) -> U {
|
||||
alt res {
|
||||
err(u) { u }
|
||||
ok(_) {
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ String manipulation.
|
|||
export eq, lteq, hash, is_empty, is_not_empty, is_whitespace, byte_len,
|
||||
byte_len_range, index,
|
||||
rindex, find, starts_with, ends_with, substr, slice, split, splitn,
|
||||
split_str, concat, connect, to_upper, replace, char_slice, trim_left,
|
||||
trim_right, trim, unshift_char, shift_char, pop_char, push_char,
|
||||
is_utf8, from_chars, to_chars, char_len, char_len_range, char_at,
|
||||
bytes, is_ascii, shift_byte, pop_byte,
|
||||
split_str, concat, connect, to_lower, to_upper, replace, char_slice,
|
||||
trim_left, trim_right, trim, unshift_char, shift_char, pop_char,
|
||||
push_char, is_utf8, from_chars, to_chars, char_len, char_len_range,
|
||||
char_at, bytes, is_ascii, shift_byte, pop_byte,
|
||||
unsafe_from_byte, unsafe_from_bytes, from_char, char_range_at,
|
||||
str_from_cstr, sbuf, as_buf, push_byte, utf8_char_width, safe_slice,
|
||||
from_cstr, sbuf, as_buf, push_byte, utf8_char_width, safe_slice,
|
||||
contains, iter_chars, loop_chars, loop_chars_sub,
|
||||
escape;
|
||||
|
||||
|
|
@ -116,14 +116,7 @@ Function: is_whitespace
|
|||
Returns true if the string contains only whitespace
|
||||
*/
|
||||
fn is_whitespace(s: str) -> bool {
|
||||
let i = 0u;
|
||||
let len = char_len(s);
|
||||
while i < len {
|
||||
// FIXME: This is not how char_at works
|
||||
if !char::is_whitespace(char_at(s, i)) { ret false; }
|
||||
i += 1u;
|
||||
}
|
||||
ret true;
|
||||
ret loop_chars(s, char::is_whitespace);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -832,7 +825,18 @@ fn connect(v: [str], sep: str) -> str {
|
|||
ret s;
|
||||
}
|
||||
|
||||
// FIXME: This only handles ASCII
|
||||
/*
|
||||
Function: to_lower
|
||||
|
||||
Convert a string to lowercase
|
||||
*/
|
||||
fn to_lower(s: str) -> str {
|
||||
let outstr = "";
|
||||
iter_chars(s) { |c|
|
||||
push_char(outstr, char::to_lower(c));
|
||||
}
|
||||
ret outstr;
|
||||
}
|
||||
/*
|
||||
Function: to_upper
|
||||
|
||||
|
|
@ -840,15 +844,8 @@ Convert a string to uppercase
|
|||
*/
|
||||
fn to_upper(s: str) -> str {
|
||||
let outstr = "";
|
||||
let ascii_a = 'a' as u8;
|
||||
let ascii_z = 'z' as u8;
|
||||
let diff = 32u8;
|
||||
for byte: u8 in s {
|
||||
let next;
|
||||
if ascii_a <= byte && byte <= ascii_z {
|
||||
next = byte - diff;
|
||||
} else { next = byte; }
|
||||
push_byte(outstr, next);
|
||||
iter_chars(s) { |c|
|
||||
push_char(outstr, char::to_upper(c));
|
||||
}
|
||||
ret outstr;
|
||||
}
|
||||
|
|
@ -976,11 +973,11 @@ fn as_buf<T>(s: str, f: block(sbuf) -> T) -> T unsafe {
|
|||
}
|
||||
|
||||
/*
|
||||
Function: str_from_cstr
|
||||
Function: from_cstr
|
||||
|
||||
Create a Rust string from a null-terminated C string
|
||||
*/
|
||||
unsafe fn str_from_cstr(cstr: sbuf) -> str {
|
||||
unsafe fn from_cstr(cstr: sbuf) -> str {
|
||||
let res = "";
|
||||
let start = cstr;
|
||||
let curr = start;
|
||||
|
|
|
|||
|
|
@ -742,6 +742,17 @@ fn iter<T>(v: [const T], f: block(T)) {
|
|||
iteri(v) { |_i, v| f(v) }
|
||||
}
|
||||
|
||||
/*
|
||||
Function: iter2
|
||||
|
||||
Iterates over two vectors in parallel
|
||||
|
||||
*/
|
||||
fn iter2<U, T>(v: [U], v2: [T], f: block(U, T)) {
|
||||
let i = 0;
|
||||
for elt in v { f(elt, v2[i]); i += 1; }
|
||||
}
|
||||
|
||||
/*
|
||||
Function: iteri
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ fn create<copy T>() -> t<T> {
|
|||
|
||||
ret rv;
|
||||
}
|
||||
fn get<T>(elts: [mutable cell<T>], i: uint) -> T {
|
||||
fn get<copy T>(elts: [mutable cell<T>], i: uint) -> T {
|
||||
ret alt elts[i] { option::some(t) { t } _ { fail } };
|
||||
}
|
||||
obj deque<copy T>(mutable nelts: uint,
|
||||
|
|
|
|||
155
src/libstd/freebsd_os.rs
Normal file
155
src/libstd/freebsd_os.rs
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
Module: os
|
||||
|
||||
TODO: Restructure and document
|
||||
*/
|
||||
|
||||
import core::option;
|
||||
import core::ctypes::*;
|
||||
|
||||
export libc;
|
||||
export libc_constants;
|
||||
export pipe;
|
||||
export fd_FILE;
|
||||
export close;
|
||||
export fclose;
|
||||
export waitpid;
|
||||
export getcwd;
|
||||
export exec_suffix;
|
||||
export target_os;
|
||||
export dylib_filename;
|
||||
export get_exe_path;
|
||||
export fsync_fd;
|
||||
|
||||
// FIXME Somehow merge stuff duplicated here and macosx_os.rs. Made difficult
|
||||
// by https://github.com/graydon/rust/issues#issue/268
|
||||
|
||||
#[link_name = ""] // FIXME remove after #[nolink] is snapshotted
|
||||
#[nolink]
|
||||
#[abi = "cdecl"]
|
||||
native mod libc {
|
||||
fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
|
||||
fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
|
||||
fn fread(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
|
||||
fn fwrite(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
|
||||
fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> fd_t;
|
||||
fn close(fd: fd_t) -> c_int;
|
||||
type FILE;
|
||||
fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
|
||||
fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
|
||||
fn fclose(f: FILE);
|
||||
fn fflush(f: FILE) -> c_int;
|
||||
fn fsync(fd: fd_t) -> c_int;
|
||||
fn fileno(f: FILE) -> fd_t;
|
||||
fn fgetc(f: FILE) -> c_int;
|
||||
fn ungetc(c: c_int, f: FILE);
|
||||
fn feof(f: FILE) -> c_int;
|
||||
fn fseek(f: FILE, offset: long, whence: c_int) -> c_int;
|
||||
fn ftell(f: FILE) -> long;
|
||||
type dir;
|
||||
fn opendir(d: str::sbuf) -> dir;
|
||||
fn closedir(d: dir) -> c_int;
|
||||
type dirent;
|
||||
fn readdir(d: dir) -> dirent;
|
||||
fn getenv(n: str::sbuf) -> str::sbuf;
|
||||
fn setenv(n: str::sbuf, v: str::sbuf, overwrite: c_int) -> c_int;
|
||||
fn unsetenv(n: str::sbuf) -> c_int;
|
||||
fn pipe(buf: *mutable fd_t) -> c_int;
|
||||
fn waitpid(pid: pid_t, &status: c_int, options: c_int) -> pid_t;
|
||||
fn readlink(path: str::sbuf, buf: str::sbuf, bufsize: size_t) -> ssize_t;
|
||||
fn mkdir(path: str::sbuf, mode: c_int) -> c_int;
|
||||
fn rmdir(path: str::sbuf) -> c_int;
|
||||
fn chdir(path: str::sbuf) -> c_int;
|
||||
|
||||
fn sysctl(name: *c_int, namelen: c_uint,
|
||||
oldp: *u8, &oldlenp: size_t,
|
||||
newp: *u8, newlen: size_t) -> c_int;
|
||||
}
|
||||
|
||||
mod libc_constants {
|
||||
const O_RDONLY: c_int = 0i32;
|
||||
const O_WRONLY: c_int = 1i32;
|
||||
const O_RDWR: c_int = 2i32;
|
||||
const O_APPEND: c_int = 8i32;
|
||||
const O_CREAT: c_int = 512i32;
|
||||
const O_EXCL: c_int = 2048i32;
|
||||
const O_TRUNC: c_int = 1024i32;
|
||||
const O_TEXT: c_int = 0i32; // nonexistent in FreeBSD libc
|
||||
const O_BINARY: c_int = 0i32; // nonexistent in FreeBSD libc
|
||||
|
||||
const S_IRUSR: unsigned = 256u32;
|
||||
const S_IWUSR: unsigned = 128u32;
|
||||
|
||||
const CTL_KERN: c_int = 1i32;
|
||||
const KERN_PROC: c_int = 14i32;
|
||||
const KERN_PROC_PATHNAME: c_int = 12i32;
|
||||
}
|
||||
|
||||
fn pipe() -> {in: fd_t, out: fd_t} {
|
||||
let fds = {mutable in: 0i32, mutable out: 0i32};
|
||||
assert (os::libc::pipe(ptr::mut_addr_of(fds.in)) == 0i32);
|
||||
ret {in: fds.in, out: fds.out};
|
||||
}
|
||||
|
||||
fn fd_FILE(fd: fd_t) -> libc::FILE {
|
||||
ret str::as_buf("r", {|modebuf| libc::fdopen(fd, modebuf) });
|
||||
}
|
||||
|
||||
fn close(fd: fd_t) -> c_int {
|
||||
libc::close(fd)
|
||||
}
|
||||
|
||||
fn fclose(file: libc::FILE) {
|
||||
libc::fclose(file)
|
||||
}
|
||||
|
||||
fn fsync_fd(fd: fd_t, _l: io::fsync::level) -> c_int {
|
||||
ret libc::fsync(fd);
|
||||
}
|
||||
|
||||
fn waitpid(pid: pid_t) -> i32 {
|
||||
let status = 0i32;
|
||||
assert (os::libc::waitpid(pid, status, 0i32) != -1i32);
|
||||
ret status;
|
||||
}
|
||||
|
||||
#[abi = "cdecl"]
|
||||
native mod rustrt {
|
||||
fn rust_getcwd() -> str;
|
||||
}
|
||||
|
||||
fn getcwd() -> str { ret rustrt::rust_getcwd(); }
|
||||
|
||||
fn exec_suffix() -> str { ret ""; }
|
||||
|
||||
fn target_os() -> str { ret "freebsd"; }
|
||||
|
||||
fn dylib_filename(base: str) -> str { ret "lib" + base + ".so"; }
|
||||
|
||||
/// Returns the directory containing the running program
|
||||
/// followed by a path separator
|
||||
fn get_exe_path() -> option::t<fs::path> unsafe {
|
||||
let bufsize = 1023u;
|
||||
let path = str::unsafe_from_bytes(vec::init_elt(0u8, bufsize));
|
||||
let mib = [libc_constants::CTL_KERN,
|
||||
libc_constants::KERN_PROC,
|
||||
libc_constants::KERN_PROC_PATHNAME, -1i32];
|
||||
ret str::as_buf(path, { |path_buf|
|
||||
if libc::sysctl(vec::unsafe::to_ptr(mib),
|
||||
vec::len(mib) as c_uint,
|
||||
path_buf, bufsize,
|
||||
ptr::null(), 0u) == 0i32 {
|
||||
option::some(fs::dirname(path) + fs::path_sep())
|
||||
} else {
|
||||
option::none
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
||||
|
|
@ -148,6 +148,7 @@ fn make_dir(p: path, mode: ctypes::c_int) -> bool {
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn mkdir(_p: path, _mode: ctypes::c_int) -> bool {
|
||||
ret str::as_buf(_p, {|buf| os::libc::mkdir(buf, _mode) == 0i32 });
|
||||
}
|
||||
|
|
@ -186,6 +187,7 @@ fn remove_dir(p: path) -> bool {
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn rmdir(_p: path) -> bool {
|
||||
ret str::as_buf(_p, {|buf| os::libc::rmdir(buf) == 0i32 });
|
||||
}
|
||||
|
|
@ -201,6 +203,7 @@ fn change_dir(p: path) -> bool {
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn chdir(_p: path) -> bool {
|
||||
ret str::as_buf(_p, {|buf| os::libc::chdir(buf) == 0i32 });
|
||||
}
|
||||
|
|
@ -367,6 +370,7 @@ fn normalize(p: path) -> path {
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn reabsolute(orig: path, new: path) -> path {
|
||||
if path_is_absolute(orig) {
|
||||
path_sep() + new
|
||||
|
|
|
|||
|
|
@ -28,18 +28,20 @@ fn setenv(n: str, v: str) { }
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn getenv(n: str) -> option::t<str> unsafe {
|
||||
let s = str::as_buf(n, {|buf| os::libc::getenv(buf) });
|
||||
ret if unsafe::reinterpret_cast(s) == 0 {
|
||||
option::none::<str>
|
||||
} else {
|
||||
let s = unsafe::reinterpret_cast(s);
|
||||
option::some::<str>(str::str_from_cstr(s))
|
||||
option::some::<str>(str::from_cstr(s))
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn setenv(n: str, v: str) {
|
||||
// FIXME (868)
|
||||
str::as_buf(
|
||||
|
|
|
|||
|
|
@ -97,6 +97,27 @@ fn has<copy T>(ls: list<T>, elt: T) -> bool {
|
|||
ret false;
|
||||
}
|
||||
|
||||
/*
|
||||
Function: is_empty
|
||||
|
||||
Returns true if the list is empty.
|
||||
*/
|
||||
pure fn is_empty<copy T>(ls: list<T>) -> bool {
|
||||
alt ls {
|
||||
nil. { true }
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Function: is_not_empty
|
||||
|
||||
Returns true if the list is not empty.
|
||||
*/
|
||||
pure fn is_not_empty<copy T>(ls: list<T>) -> bool {
|
||||
ret !is_empty(ls);
|
||||
}
|
||||
|
||||
/*
|
||||
Function: len
|
||||
|
||||
|
|
@ -112,8 +133,11 @@ Function: tail
|
|||
|
||||
Returns all but the first element of a list
|
||||
*/
|
||||
pure fn tail<copy T>(ls: list<T>) -> list<T> {
|
||||
alt ls { cons(_, tl) { ret *tl; } nil. { fail "list empty" } }
|
||||
pure fn tail<copy T>(ls: list<T>) : is_not_empty(ls) -> list<T> {
|
||||
alt ls {
|
||||
cons(_, tl) { ret *tl; }
|
||||
nil. { fail "list empty" }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -121,8 +145,11 @@ Function: head
|
|||
|
||||
Returns the first element of a list
|
||||
*/
|
||||
pure fn head<copy T>(ls: list<T>) -> T {
|
||||
alt ls { cons(hd, _) { ret hd; } nil. { fail "list empty" } }
|
||||
pure fn head<copy T>(ls: list<T>) : is_not_empty(ls) -> T {
|
||||
alt ls {
|
||||
cons(hd, _) { ret hd; }
|
||||
nil. { fail "list empty" }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -443,7 +443,7 @@ fn iter_chars(rope: rope, it: block(char)) {
|
|||
loop_chars(rope) {|x|
|
||||
it(x);
|
||||
ret true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -266,6 +266,7 @@ fn waitpid(pid: pid_t) -> int {
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn waitpid_os(pid: pid_t) -> int {
|
||||
#[cfg(target_os = "linux")]
|
||||
fn WIFEXITED(status: i32) -> bool {
|
||||
|
|
@ -273,6 +274,7 @@ fn waitpid(pid: pid_t) -> int {
|
|||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn WIFEXITED(status: i32) -> bool {
|
||||
(status & 0x7fi32) == 0i32
|
||||
}
|
||||
|
|
@ -283,6 +285,7 @@ fn waitpid(pid: pid_t) -> int {
|
|||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn WEXITSTATUS(status: i32) -> i32 {
|
||||
status >> 8i32
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,13 @@ mod os;
|
|||
#[path = "posix_fs.rs"]
|
||||
mod os_fs;
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[path = "freebsd_os.rs"]
|
||||
mod os;
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[path = "posix_fs.rs"]
|
||||
mod os_fs;
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ Function: id
|
|||
|
||||
The identity function
|
||||
*/
|
||||
pure fn id<T>(x: T) -> T { x }
|
||||
pure fn id<copy T>(x: T) -> T { x }
|
||||
|
||||
/*
|
||||
Function: unreachable
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ the C libuv API. Does very little right now pending scheduler improvements.
|
|||
|
||||
#[cfg(target_os = "linux")];
|
||||
#[cfg(target_os = "macos")];
|
||||
#[cfg(target_os = "freebsd")];
|
||||
|
||||
export sanity_check;
|
||||
export loop_t, idle_t;
|
||||
|
|
@ -39,6 +40,7 @@ type idle_cb = opaque_cb;
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
type handle_private_fields = {
|
||||
a00: ctypes::c_int,
|
||||
a01: ctypes::c_int,
|
||||
|
|
@ -121,6 +123,7 @@ fn sanity_check() {
|
|||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn handle_fields_new() -> handle_fields {
|
||||
{
|
||||
loop: ptr::null(),
|
||||
|
|
@ -149,4 +152,4 @@ fn idle_new() -> idle_t {
|
|||
{
|
||||
fields: handle_fields_new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
src/llvm
2
src/llvm
|
|
@ -1 +1 @@
|
|||
Subproject commit a320b2aa41fbe3f944bad33780626d65d1b11e6f
|
||||
Subproject commit 4fb132c803512f06f7cbc38baa6e86280912f800
|
||||
|
|
@ -16,20 +16,20 @@ ___morestack:
|
|||
__morestack:
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
.cfi_startproc
|
||||
#endif
|
||||
|
||||
pushl %ebp
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_offset %ebp, -8
|
||||
#endif
|
||||
|
||||
movl %esp,%ebp // save esp
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
.cfi_def_cfa_register %ebp
|
||||
#endif
|
||||
|
||||
|
|
@ -42,6 +42,6 @@ __morestack:
|
|||
|
||||
ret
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
.cfi_endproc
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
#define UPCALL_DEL_STACK L_upcall_del_stack$stub
|
||||
#define MORESTACK ___morestack
|
||||
#else
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
#define UPCALL_NEW_STACK upcall_new_stack
|
||||
#define UPCALL_DEL_STACK upcall_del_stack
|
||||
#define RUST_GET_TASK rust_get_task
|
||||
|
|
@ -93,7 +93,7 @@
|
|||
.globl MORESTACK
|
||||
|
||||
// FIXME: What about _WIN32?
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
.hidden MORESTACK
|
||||
#else
|
||||
#if defined(__APPLE__)
|
||||
|
|
@ -106,7 +106,7 @@
|
|||
#endif
|
||||
|
||||
MORESTACK:
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
.cfi_startproc
|
||||
#endif
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ MORESTACK:
|
|||
// __morestack, and an extra return address.
|
||||
|
||||
pushl %ebp
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
// The CFA is 20 bytes above the register that it is
|
||||
// associated with for this frame (which will be %ebp)
|
||||
.cfi_def_cfa_offset 20
|
||||
|
|
@ -133,7 +133,7 @@ MORESTACK:
|
|||
.cfi_offset %ebp, -20
|
||||
#endif
|
||||
movl %esp, %ebp
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
// Calculate the CFA as an offset from %ebp
|
||||
.cfi_def_cfa_register %ebp
|
||||
#endif
|
||||
|
|
@ -216,7 +216,7 @@ MORESTACK:
|
|||
// FIXME: I don't think these rules are necessary
|
||||
// since the unwinder should never encounter an instruction
|
||||
// pointer pointing here.
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
// Restore the rule for how to find %ebp
|
||||
.cfi_restore %ebp
|
||||
// Tell the unwinder how to find the CFA in terms of %esp
|
||||
|
|
@ -234,7 +234,7 @@ MORESTACK:
|
|||
|
||||
jmpl *%eax
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
.cfi_endproc
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
.globl GET_SP
|
||||
.globl CHECK_STACK
|
||||
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
RECORD_SP:
|
||||
movl 4(%esp), %eax
|
||||
movl %eax, %gs:48
|
||||
|
|
|
|||
|
|
@ -23,19 +23,19 @@ ___morestack:
|
|||
__morestack:
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
.cfi_startproc
|
||||
#endif
|
||||
|
||||
push %rbp
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
.cfi_def_cfa_offset 16
|
||||
.cfi_offset %rbp, -16
|
||||
#endif
|
||||
|
||||
mov %rsp,%rbp // save rsp
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
.cfi_def_cfa_register %rbp
|
||||
#endif
|
||||
|
||||
|
|
@ -46,6 +46,6 @@ __morestack:
|
|||
|
||||
ret
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
.cfi_endproc
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,7 +31,11 @@ extern "C" void __morestack(void *args, void *fn_ptr, uintptr_t stack_ptr);
|
|||
|
||||
class context {
|
||||
public:
|
||||
#ifdef __FreeBSD__
|
||||
registers_t regs __attribute__((aligned(16)));
|
||||
#else
|
||||
registers_t regs;
|
||||
#endif
|
||||
|
||||
context();
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
.globl UPCALL_DEL_STACK
|
||||
.globl MORESTACK
|
||||
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
.hidden MORESTACK
|
||||
#else
|
||||
#if defined(__APPLE__)
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
#endif
|
||||
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
MORESTACK:
|
||||
.cfi_startproc
|
||||
|
||||
|
|
@ -92,6 +92,9 @@ MORESTACK:
|
|||
#ifdef __linux__
|
||||
call UPCALL_NEW_STACK@PLT
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
call UPCALL_NEW_STACK@PLT
|
||||
#endif
|
||||
|
||||
// Pop the saved arguments
|
||||
movdqa (%rsp), %xmm0
|
||||
|
|
@ -135,6 +138,9 @@ MORESTACK:
|
|||
#ifdef __linux__
|
||||
call UPCALL_DEL_STACK@PLT
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
call UPCALL_DEL_STACK@PLT
|
||||
#endif
|
||||
|
||||
popq %rax // Restore the return value
|
||||
popq %rbp
|
||||
|
|
|
|||
|
|
@ -18,17 +18,19 @@
|
|||
RECORD_SP:
|
||||
movq %rdi, %fs:112
|
||||
ret
|
||||
#else
|
||||
#if defined(__APPLE__)
|
||||
#elif defined(__APPLE__)
|
||||
RECORD_SP:
|
||||
movq $0x60+90*8, %rsi
|
||||
movq %rdi, %gs:(%rsi)
|
||||
ret
|
||||
#elif defined(__FreeBSD__)
|
||||
RECORD_SP:
|
||||
movq %rdi, %fs:24
|
||||
ret
|
||||
#else
|
||||
RECORD_SP:
|
||||
ret
|
||||
#endif
|
||||
#endif
|
||||
|
||||
GET_SP:
|
||||
movq %rsp, %rax
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include <stdint.h>
|
||||
#include "rust_abi.h"
|
||||
|
||||
#if defined(__APPLE__) || defined(__linux__)
|
||||
#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__)
|
||||
#define HAVE_DLFCN_H
|
||||
#include <dlfcn.h>
|
||||
#elif defined(_WIN32)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#define RZ_MAC_32 (1024*20)
|
||||
#define RZ_MAC_64 (1024*20)
|
||||
#define RZ_WIN_32 (1024*20)
|
||||
#define RZ_BSD_32 (1024*20)
|
||||
#define RZ_BSD_64 (1024*20)
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef __i386__
|
||||
|
|
@ -48,6 +50,14 @@
|
|||
#define RED_ZONE_SIZE RZ_WIN_64
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
#ifdef __i386__
|
||||
#define RED_ZONE_SIZE RZ_BSD_32
|
||||
#endif
|
||||
#ifdef __x86_64__
|
||||
#define RED_ZONE_SIZE RZ_BSD_64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// A value that goes at the end of the stack and must not be touched
|
||||
const uint8_t stack_canary[] = {0xAB, 0xCD, 0xAB, 0xCD,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
// the rust stack and happen frequently enough to catch most stack changes,
|
||||
// including at the beginning of all landing pads.
|
||||
// FIXME: Enable this for windows
|
||||
#if defined __linux__ || defined __APPLE__
|
||||
#if defined __linux__ || defined __APPLE__ || defined __FreeBSD__
|
||||
extern "C" void
|
||||
check_stack_alignment() __attribute__ ((aligned (16)));
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// error-pattern:binary operation + cannot be applied to type `*i`
|
||||
// error-pattern:binary operation + cannot be applied to type `*int`
|
||||
|
||||
fn die() -> *int { (0 as *int) + (0 as *int) }
|
||||
fn main() { }
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// error-pattern:this block must not have a result
|
||||
// error-pattern:mismatched types: expected `()` but found `bool`
|
||||
|
||||
fn main() {
|
||||
do {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// error-pattern:this block must not have a result
|
||||
// error-pattern:mismatched types: expected `()` but found `bool`
|
||||
|
||||
fn main() {
|
||||
for i in [0] {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// error-pattern:this block must not have a result
|
||||
// error-pattern:mismatched types: expected `()` but found `bool`
|
||||
|
||||
resource r(i: int) {
|
||||
true
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// error-pattern:this block must not have a result
|
||||
// error-pattern:mismatched types: expected `()` but found `bool`
|
||||
|
||||
fn main() {
|
||||
while true {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@
|
|||
|
||||
fn god_exists(a: int) -> bool { be god_exists(a); }
|
||||
|
||||
fn f(a: int) -> int { if god_exists(a) { ret 5; } }
|
||||
fn f(a: int) -> int { if god_exists(a) { ret 5; }; }
|
||||
|
||||
fn main() { f(12); }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// error-pattern:`if` without `else` can not produce a result
|
||||
// error-pattern:mismatched types: expected `()` but found `bool`
|
||||
|
||||
fn main() {
|
||||
let a = if true { true };
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
fn f() -> int {
|
||||
// Make sure typestate doesn't interpret this alt expression
|
||||
// as the function result
|
||||
alt true { true { } }
|
||||
alt true { true { } };
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// error-pattern:expected `*Mb` but found `native`
|
||||
// error-pattern:expected `*u8` but found `native`
|
||||
use std;
|
||||
|
||||
fn main() unsafe {
|
||||
|
|
|
|||
8
src/test/pretty/disamb-stmt-expr.rs
Normal file
8
src/test/pretty/disamb-stmt-expr.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// pp-exact
|
||||
|
||||
// Here we check that the parentheses around the body of `wsucc()` are
|
||||
// preserved. They are needed to disambiguate `{ret n+1}; - 0` from
|
||||
// `({ret n+1}-0)`.
|
||||
|
||||
fn wsucc(n: int) -> int { ({ ret n + 1 } - 0); }
|
||||
fn main() { }
|
||||
25
src/test/run-pass/block-arg-as-stmt.rs
Normal file
25
src/test/run-pass/block-arg-as-stmt.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
fn compute1() -> float {
|
||||
let v = [0f, 1f, 2f, 3f];
|
||||
|
||||
// Here the "-10f" parses as a second
|
||||
// statement in tail position:
|
||||
vec::foldl(0f, v) { |x, y| x + y } - 10f
|
||||
}
|
||||
|
||||
fn compute2() -> float {
|
||||
let v = [0f, 1f, 2f, 3f];
|
||||
|
||||
// Here the ret makes this explicit:
|
||||
ret vec::foldl(0f, v) { |x, y| x + y } - 10f;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = compute1();
|
||||
log(debug, x);
|
||||
assert(x == -10f);
|
||||
|
||||
let y = compute2();
|
||||
log(debug, y);
|
||||
assert(y == -4f);
|
||||
}
|
||||
8
src/test/run-pass/block-arg-can-be-followed-by-binop.rs
Normal file
8
src/test/run-pass/block-arg-can-be-followed-by-binop.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fn main() {
|
||||
let v = [-1f, 0f, 1f, 2f, 3f];
|
||||
|
||||
// Trailing expressions require parentheses:
|
||||
let y = vec::foldl(0f, v) { |x, y| x + y } + 10f;
|
||||
|
||||
assert y == 15f;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
fn main() {
|
||||
fn f(i: block() -> uint) -> uint { i() }
|
||||
let v = [-1f, 0f, 1f, 2f, 3f];
|
||||
let z = vec::foldl(f, v) { |x, _y| x } { || 22u };
|
||||
assert z == 22u;
|
||||
}
|
||||
6
src/test/run-pass/block-arg-can-be-followed-by-call.rs
Normal file
6
src/test/run-pass/block-arg-can-be-followed-by-call.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
fn main() {
|
||||
fn f(i: uint) -> uint { i }
|
||||
let v = [-1f, 0f, 1f, 2f, 3f];
|
||||
let z = vec::foldl(f, v) { |x, _y| x } (22u);
|
||||
assert z == 22u;
|
||||
}
|
||||
23
src/test/run-pass/block-arg-in-parentheses.rs
Normal file
23
src/test/run-pass/block-arg-in-parentheses.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// xfail-test
|
||||
|
||||
// FIXME: Parser doesn't distinguish expression in parentheses (as in
|
||||
// this example) from one that is not! It is somewhat of a pain to
|
||||
// fix this though there are no theoretical difficulties. We could
|
||||
// either add paren to the AST (better for pretty-print, I suppose) or
|
||||
// modify the parser to track whether the expression in question is
|
||||
// parenthesized. I did the latter once and it was a bit of pain but
|
||||
// not terribly difficult. We could also the decision as to whether
|
||||
// something is an "expression with a value" down into the
|
||||
// parse_expr() codepath, where we *know* if there are parentheses or
|
||||
// not, but we'd probably have to be a bit more careful then with
|
||||
// clearing the top-level restrction flag (which we ought to do
|
||||
// anyhow!)
|
||||
|
||||
fn main() {
|
||||
let v = [1f, 2f, 3f];
|
||||
let w =
|
||||
if true { (vec::any(v) { |e| float::nonnegative(e) }) }
|
||||
else { false };
|
||||
assert w;
|
||||
}
|
||||
|
||||
6
src/test/run-pass/block-arg-in-ternary.rs
Normal file
6
src/test/run-pass/block-arg-in-ternary.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// Allow block arguments with ternary... why not, no chance of ambig.
|
||||
fn main() {
|
||||
let v = [-1f, 1f];
|
||||
let foo = vec::any(v) { |e| float::negative(e) } ? true : false;
|
||||
assert foo;
|
||||
}
|
||||
52
src/test/run-pass/block-arg.rs
Normal file
52
src/test/run-pass/block-arg.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// Check usage and precedence of block arguments in expressions:
|
||||
fn main() {
|
||||
let v = [-1f, 0f, 1f, 2f, 3f];
|
||||
|
||||
// Statement form does not require parentheses:
|
||||
vec::iter(v) { |i|
|
||||
log(info, i);
|
||||
}
|
||||
|
||||
// Usable at all:
|
||||
let any_negative = vec::any(v) { |e| float::negative(e) };
|
||||
assert any_negative;
|
||||
|
||||
// Higher precedence than assignments:
|
||||
any_negative = vec::any(v) { |e| float::negative(e) };
|
||||
assert any_negative;
|
||||
|
||||
// Higher precedence than unary operations:
|
||||
let abs_v = vec::map(v) { |e| float::abs(e) };
|
||||
assert vec::all(abs_v) { |e| float::nonnegative(e) };
|
||||
assert !vec::any(abs_v) { |e| float::negative(e) };
|
||||
|
||||
// Usable in funny statement-like forms:
|
||||
if !vec::any(v) { |e| float::positive(e) } {
|
||||
assert false;
|
||||
}
|
||||
alt vec::all(v) { |e| float::negative(e) } {
|
||||
true { fail "incorrect answer."; }
|
||||
false { }
|
||||
}
|
||||
alt 3 {
|
||||
_ when vec::any(v) { |e| float::negative(e) } {
|
||||
}
|
||||
_ {
|
||||
fail "wrong answer.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Lower precedence than binary operations:
|
||||
let w = vec::foldl(0f, v, { |x, y| x + y }) + 10f;
|
||||
let y = vec::foldl(0f, v) { |x, y| x + y } + 10f;
|
||||
let z = 10f + vec::foldl(0f, v) { |x, y| x + y };
|
||||
assert w == y;
|
||||
assert y == z;
|
||||
|
||||
// They are not allowed as the tail of a block without parentheses:
|
||||
let w =
|
||||
if true { vec::any(abs_v, { |e| float::nonnegative(e) }) }
|
||||
else { false };
|
||||
assert w;
|
||||
}
|
||||
|
|
@ -8,4 +8,7 @@ mod hello;
|
|||
mod hello;
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
mod hello;
|
||||
mod hello;
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
mod hello;
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
fn wsucc(n: int) -> int { { ret n + 1 } + 0; }
|
||||
fn wsucc(n: int) -> int { ({ ret n + 1 } + 0); }
|
||||
fn main() { }
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
fn wsucc(n: int) -> int { { ret n + 1 } == 0; }
|
||||
fn wsucc(n: int) -> int { ({ ret n + 1 } == 0); }
|
||||
fn main() { }
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
// -*- rust -*-
|
||||
type compare<T> = fn@(T, T) -> bool;
|
||||
|
||||
fn test_generic<T>(expected: T, eq: compare<T>) {
|
||||
fn test_generic<copy T>(expected: T, eq: compare<T>) {
|
||||
let actual: T = alt true { true { expected } };
|
||||
assert (eq(expected, actual));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// -*- rust -*-
|
||||
type compare<T> = fn@(~T, ~T) -> bool;
|
||||
|
||||
fn test_generic<T>(expected: ~T, eq: compare<T>) {
|
||||
fn test_generic<copy T>(expected: ~T, eq: compare<T>) {
|
||||
let actual: ~T = alt true { true { expected } };
|
||||
assert (eq(expected, actual));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
// -*- rust -*-
|
||||
type compare<T> = fn@(T, T) -> bool;
|
||||
|
||||
fn test_generic<T>(expected: T, eq: compare<T>) {
|
||||
fn test_generic<copy T>(expected: T, eq: compare<T>) {
|
||||
let actual: T = alt true { true { expected } };
|
||||
assert (eq(expected, actual));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
// -*- rust -*-
|
||||
type compare<T> = fn@(T, T) -> bool;
|
||||
|
||||
fn test_generic<T>(expected: T, eq: compare<T>) {
|
||||
fn test_generic<copy T>(expected: T, eq: compare<T>) {
|
||||
let actual: T = alt true { true { expected } };
|
||||
assert (eq(expected, actual));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ fn test_vec() {
|
|||
}
|
||||
|
||||
fn test_generic() {
|
||||
fn f<T>(t: T) -> T { t }
|
||||
fn f<copy T>(t: T) -> T { t }
|
||||
assert (f(10) == 10);
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue