But don't actually generate code that does the operation. That means
hoisting the check I added in my last commit from trans_compare
up into trans_eager_binop (don't generate any code if one operand
has type _|_ ).
Closes#777
This was at least partially responsible for Issue 777.
The only solution I can think of is for trans to just not generate
code for a comparison if one or both sides has type _|_. Since
that means evaluating that subexpression diverges, it should be ok
to never do the comparison. Actually generating code for the
comparison would trip an LLVM assertion failure.
After running source files through the pretty printer, we sanity check them by
running the results through the compiler with the --no-trans flag. Now also
use the --lib flag so that pretty-printer tests don't have to include a main
function.
Add a new src/test/pretty directory to hold just source files for testing the
pretty-printer.
Add a new pp-exact directive. When this directive is followed by a file name
it specifies a file containing the output that the pretty-printer should
generate. When pp-exact is not followed by a filename it says that the file
should pretty-print as written.
This is required so that assigning to these locals doesn't clobber
the content of the box.
(A possible optimization would be to only do this copying for
locals that actually are assigned to.)
The logic for how the "returns" constraint was handled was always
dodgy, for reasons explained in the comments I added to
auxiliary::fn_info in this commit. Fixed it by adding distinct
"returns" and "diverges" constraints for each function, which
are both handled positively (that is: for a ! function, the
"diverges" constraint must be true on every exit path; for
any other function, the "returns" constraint must be true
on every exit path).
Closes#779
Still working on getting backwarding to play nicely with self and
overriding. Currently can't fix issue #702 without breaking how self
and overriding interact.
Takes a lot of workarounds. The biggest problem is that boxes still don't seem
to be moved across channels and bad things happen when the receiver destroys
them. So there's all sorts of defensive cloning and scoping going on here to
make the box lifetimes come out right.
that absolutely will not succeed with a large default stack. This
should be removed once we have stack grown working.
Also updated word-count to succeed under the new test framework.
Tasks are spawned on a random thread. Currently they stay there, but
we should add task migration and load balancing in the future. This
should drammatically improve our task performance benchmarks.
This was previously disallowed by the typechecker and not properly handled
in trans. I removed the typechecker check (replacing it with a simpler
check that spawned functions don't have type params) and fixed trans.
Closes#756.
This commit just disables the check. All of the real work was in previous
commits that moved the target function into the bindings part of the closure
that is tracked by the tydesc.
Closes#754.
In theory. There's still something leaking but I hope it's no longer due to
the test runner doing unsafe things.
This is a pretty nasty patch, working around limitations in the type and task
systems, and it makes the std::test API a little uglier.
Putting shared boxes into a closure then running that closure in parallel
tasks seems like a recipe for refcounting disaster.
This doesn't completely fix the problems when running in parallel, but I'm
working on it.
It takes a lot of boilerplate to create a task and establish a way to talk to
it. This function simplifies that, allowing you to write something like
'worker(f).chan <| start'. Implementation is very unsafe and only works for a
few types of channels, but something like this is very useful.
This replaces the make-based test runner with a set of Rust-based test
runners. I believe that all existing functionality has been
preserved. The primary objective is to dogfood the Rust test
framework.
A few main things happen here:
1) The run-pass/lib-* tests are all moved into src/test/stdtest. This
is a standalone test crate intended for all standard library tests. It
compiles to build/test/stdtest.stageN.
2) rustc now compiles into yet another build artifact, this one a test
runner that runs any tests contained directly in the rustc crate. This
allows much more fine-grained unit testing of the compiler. It
compiles to build/test/rustctest.stageN.
3) There is a new custom test runner crate at src/test/compiletest
that reproduces all the functionality for running the compile-fail,
run-fail, run-pass and bench tests while integrating with Rust's test
framework. It compiles to build/test/compiletest.stageN.
4) The build rules have been completely changed to use the new test
runners, while also being less redundant, following the example of the
recent stageN.mk rewrite.
It adds two new features to the cfail/rfail/rpass/bench tests:
1) Tests can specify multiple 'error-pattern' directives which must be
satisfied in order.
2) Tests can specify a 'compile-flags' directive which will make the
test runner provide additional command line arguments to rustc.
There are some downsides, the primary being that Rust has to be
functioning pretty well just to run _any_ tests, which I imagine will
be the source of some frustration when the entire test suite
breaks. Will also cause some headaches during porting.
Not having individual make rules, each rpass, etc test no longer
remembers between runs whether it completed successfully. As a result,
it's not possible to incrementally fix multiple tests by just running
'make check', fixing a test, and repeating without re-running all the
tests contained in the test runner. Instead you can filter just the
tests you want to run by using the TESTNAME environment variable.
This also dispenses with the ability to run stage0 tests, but they
tended to be broken more often than not anyway.
Updated the MapReduce protocol so that it's correct more often. It's
still not perfect, but the bugs repro less often now.
Also found a race condition in channel sending. The problem is that
send and receive both need to refer to the _unread field in
circular_buffer. For now I just grabbed the port lock to send. We can
probably get around this by using atomics instead.
This meant most of the generic-ness of it had to go away, since our
type system doesn't quite support it yet. Hopefully someday...
This version has lots of memory management errors. My next commit will
hopefully fix these.
We're trying to get closer to doing correct move semantics for channel
operations. This involves a lot of cleanup (such as removing the
unused sched parameter from rust_vec constructor) and making
circular_buffer kernel_owned.
Added tagging for memory allocations. This means we give a string tag
to everything we allocate. If we leak something and TRACK_ALLOCATIONS
is enabled, then it's much easier now to tell exactly what is leaking.
I'm not sure if this is because of changes to glue generation in the
last few days while I've been working on other things, or if it's a
side effect of the improvements I made to typechecking for anonymous
objects, or something else, but I guess I'll take it!
Closes issue #543.
Programs with constrained types now parse and typecheck, but
typestate doesn't check them specially, so the one relevant test
case so far is XFAILed.
Also rewrote all of the constraint-related data structures in the
process (again), for some reason. I got rid of a superfluous
data structure in the context that was mapping front-end constraints
to resolved constraints, instead handling constraints in the same
way in which everything else gets resolved.
This reverts commit 8c94d8fd54.
There's no mechanism to actually return the value from main, so all this does
is allow main -> int to compile. Per #688, the program returns non-zero on
failure, so it's not obvious that this change is appropriate at this time.
ret is similar to fail: if not followed by an expression, it
should be parsed as a ret without an argument. The old version would
fail if ret was followed by a close paren (for example). Fixed it.
Closes#676.
Capturing a type argument in the enclosing scope should be an error --
this commit implements that check in resolve, avoiding a potential
assertion failure in trans.
Closes#648.
Typestate was failing to check some code because if it saw an item,
it would quit immediately. This was to avoid checking nested items
in the same context as the lexically enclosing item, but it was
having the wrong effect: not checking the code after the item at all.
Fixed by switching to visit and skipping over items in a proper
nested fashion. Closes#668.
A check in trans didn't have a corresponding check in typeck, causing
some programs (to wit, compile-fail/chan-parameterized-args.rs - part of this
commit) to fail with an assertion failure in trans instead of a type error.
Fixed it. In short, arguments that are future thunk arguments (any spawn
arguments, and _ arguments in bind) need to either not contain type params
or type vars, or be by-reference.
Closes#665.
Currently it's only sequential, but it can do word frequency
counting. In an ideal world it would all be polymorphic, but that
pushes the limits of our type system right now. We can generalize it
later.
You can now say
expr_move(?dst, ?src) | expr_assign(?dst, ?src) { ... }
to match both expr_move and expr_assign. The names, types, and number
of bound names have to match in all the patterns.
Closes#449.
trans::trans_lval will now autobind if the given expression was the
name of a generic functions. Those callees (trans_call and trans_bind)
that are interested in the generics information call trans_lval_gen
now.
Previously, we were creating both a normal vtable entry and a
forwarding function for overriding methods, when they should have just
gotten a vtable entry. This patch fixes that.
This adds support for dropping cleanups for temporary values when they
are moved somewhere else. It then adds wraps most copy operations
(return, put in data structure, box, etc) in a way that will fall back
to a move when it is safe.
This saves a lot of taking/dropping, shaving over a megabyte off the
stage2/rustc binary size.
In some cases, most notably function returns, we could detect that the
returned value is a local variable, and can thus be safely moved even
though it is not a temporary. This will require putting some more
information in lvals.
I did not yet handle function arguments, since the logic for passing
them looked too convoluted to touch. I'll probably try that in the
near future, since it's bound to be a big win.
This will link to std and compile with the --test flag. Eventually the
run-pass/lib* tests will move here.
We could also put the std tests directly into the library and compile both a
library version and a test version, but I think this way will make for faster
builds.
Issue #428
(The old syntax is still supported as well, for now.)
It is now possible to leave out the parens around if, while, and
do/while conditions, and around alt expressions. Cases in an alt block
can now leave off the case keyword and parens around the pattern.
After the next snapshot, we can start migrating our code to use the
new alt syntax, probably with a pretty-printer pass. The paren-free
syntax will remain optional (you may always parenthesize expressions),
but the old case syntax will no longer be supported in the future.
If a closure inside a case alternative (for example, a for each loop)
referenced a pattern-bound variable, this would cause an assertion
failure in trans. Changed trans::collect_upvars to handle pattern-bound
vars correctly.
Incidentally, eliminated all direct uses of option::get in trans.
An expression like:
foo(1, fail, 2)
was failing to parse, because the parser was interpreting the comma
as the start of an expression that was an argument to fail, rather
than recognizing that the fail here has no arguments
Fixed this by using can_begin_expr to determine whether the next
token after a fail token suggests that this is a nullary fail or a
unary fail.
In addition, when translating calls, check before translating each
argument that the block still isn't terminated. This has the effect
that if an argument list includes fail, the back-end won't keep trying
to generate code for successive arguments and trip the !*terminated
assertion.
The code for translating a fail (for example) would call
Unreachable(), which terminates the block; if a fail appeared as an
argument, this would cause an LLVM assertion failure. Changed
trans_call to handle this situation correctly.
This is important since we are going to be making functions noncopyable
soon, which means we'll be seeing a lot of boxed functions.
(*f)(...) is really just too heavyweight.
Doing the autodereferencing was a very little bit tricky since
trans_call works with an *lval* of the function whereas existing
autoderef code was not for lvals.
Implement "claim" (issue #14), which is a version of "check" that
doesn't really do the check at runtime. It's an unsafe feature.
The new flag --check-claims turns claims into checks automatically --
but it's off by default, so by default, the assertion in a claim
doesn't execute at runtime.
The meta items within a crate's link attribute are used in linkage:
#[link(name = "std",
vers = "1.0",
custom = "whatever")];
Name and vers are treated specially, and everything else is hashed together
into the crate meta hash.
Issue #487
Resources are now defined like...
resource fd(int n) { close(n); }
Calling fd with an int will then produce a non-copyable value
that, when dropped, will call close on the given int.
Wrote some small test cases that use while loops and moves, to
make sure the poststate for the loop body gets propagated into the
new prestate and deinitialization gets reflected.
Along with that, rewrite the code for intersecting states. I still
find it dodgy, but I guess I'll continue trying to add more tests.
Also, I'll probably feel better about it once I start formalizing
the algorithm.
Includes assignment operations. Add regression tests for lots of less useful,
less used or unexpected combinations, as well as a selection of compile-fail
tests. Closes#500 (again!)
Modified typestate to throw away any constraints mentioning a
variable on the LHS of an assignment, recv, assign_op, or on
either side of a swap.
Some code cleanup as well.
If you use a function expecting an alias argument in a context that
expects a function expecting a value argument, or vice versa, the
previous error message complained that the number of arguments was
wrong. Fixed the error message to be accurate.
typestate now drops constraints correctly in the post-state of
a move expression or a declaration whose op is a move. It doesn't
yet drop constraints mentioning variables that get updated.
To do this, I had to change typestate to use trit-vectors instead
of bit-vectors, because for every constraint, there are three
possible values: known-to-be-false (e.g. after x <- y, init(y) is
known-to-be-false), known-to-be-true, and unknown. Before, we
conflated known-to-be-false with unknown. But move requires them
to be treated differently. Consider:
(program a)
(a1) x = 1;
(a2) y <- x;
(a3) log x;
(program b)
(b1) x = 1;
(b2) y <- z;
(b3) log x;
With only two values, the postcondition of statement a2 for
constraint init(x) is the same as that of b2: 0. But in (a2)'s
postcondition, init(x) *must* be false, but in (b2)'s condition,
it's just whatever it was in the postcondition of the preceding statement.
This code was causing a bounds check failure:
fn hd[U](&vec[U] v) -> U {
fn hd1(&vec[U] w) -> U {
ret w.(0);
}
ret hd1(v);
}
because in hd1, U was being treated as if it referred to a type
parameter of hd1, rather than referring to the lexically enclosing binding
for U that's part of hd.
I'm actually not sure whether this is a legit program or not. But I wanted
to get rid of the bounds check error, so I assumed that program shouldn't
compile and made it a proper error message.
This involved, in part, changing the ast::def type so that a def_fn
has a "purity" field. This lets the typechecker determine whether
functions defined in other crates are pure.
It also required updating some error messages in tests. As a test
for cross-crate constrained functions, I added a safe_slice function
to std::str (slice(), with one of the asserts replaced with a
function precondition) and some test cases (various versions of
fn-constraint.rs) that call it. Also, I changed "fn" to "pred" for
some of the boolean functions in std::uint.