Merge branch 'master' into kmath

Conflicts:
	src/libcore/cmath.rs
This commit is contained in:
Stefan Plantikow 2012-01-05 00:11:25 +01:00
commit 6284190ef9
113 changed files with 2814 additions and 766 deletions

View file

@ -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
View file

@ -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
;;

View file

@ -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].

View 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

View 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

View 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

View 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

View 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

View file

@ -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))))

View file

@ -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 "{" > $$@

View file

@ -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

View file

@ -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() {

View file

@ -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"]

View file

@ -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"]

View file

@ -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!") };
}

View file

@ -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; }

View file

@ -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;

View file

@ -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);

View file

@ -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)}];

View file

@ -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 {

View file

@ -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);
}

View file

@ -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 }

View file

@ -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'); }

View file

@ -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");
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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];

View file

@ -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);
}

View file

@ -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};
}

View file

@ -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");

View 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])
}
}
}

View file

@ -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)}))
}
//

View file

@ -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));
}
}
}

View file

@ -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];
}

View file

@ -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:

View file

@ -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;

View file

@ -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 {

View file

@ -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 = [];

View file

@ -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>);

View file

@ -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, _, _, _, _, _, _, _)
});

View file

@ -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) {

View file

@ -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()
}

View file

@ -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, " ")]
}

View file

@ -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")]

View file

@ -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):

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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) } }
}

View file

@ -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(_) {

View file

@ -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;

View file

@ -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

View file

@ -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
View 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:

View file

@ -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

View file

@ -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(

View file

@ -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" }
}
}
/*

View file

@ -443,7 +443,7 @@ fn iter_chars(rope: rope, it: block(char)) {
loop_chars(rope) {|x|
it(x);
ret true
}
};
}
/*

View file

@ -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
}

View file

@ -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;

View file

@ -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

View file

@ -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()
}
}
}

@ -1 +1 @@
Subproject commit a320b2aa41fbe3f944bad33780626d65d1b11e6f
Subproject commit 4fb132c803512f06f7cbc38baa6e86280912f800

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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,

View file

@ -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

View file

@ -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() { }

View file

@ -1,4 +1,4 @@
// error-pattern:this block must not have a result
// error-pattern:mismatched types: expected `()` but found `bool`
fn main() {
do {

View file

@ -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] {

View file

@ -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

View file

@ -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 {

View file

@ -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); }

View file

@ -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 };

View file

@ -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() { }

View file

@ -1,4 +1,4 @@
// error-pattern:expected `*Mb` but found `native`
// error-pattern:expected `*u8` but found `native`
use std;
fn main() unsafe {

View 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() { }

View 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);
}

View 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;
}

View file

@ -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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View file

@ -8,4 +8,7 @@ mod hello;
mod hello;
#[cfg(target_os = "win32")]
mod hello;
mod hello;
#[cfg(target_os = "freebsd")]
mod hello;

View file

@ -1,2 +1,2 @@
fn wsucc(n: int) -> int { { ret n + 1 } + 0; }
fn wsucc(n: int) -> int { ({ ret n + 1 } + 0); }
fn main() { }

View file

@ -1,2 +1,2 @@
fn wsucc(n: int) -> int { { ret n + 1 } == 0; }
fn wsucc(n: int) -> int { ({ ret n + 1 } == 0); }
fn main() { }

View file

@ -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));
}

View file

@ -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));
}

View file

@ -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));
}

View file

@ -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));
}

View file

@ -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