From 08a77e06a8b7e76466a5c177159a5ecdf3cad31b Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 25 Jul 2012 14:05:06 -0700 Subject: [PATCH 01/24] Rewrite task-comm-NN to use pipes --- src/libcore/pipes.rs | 59 +++-------------------- src/test/run-pass/task-comm-0.rs | 22 ++++----- src/test/run-pass/task-comm-10.rs | 21 ++++----- src/test/run-pass/task-comm-11.rs | 13 +++--- src/test/run-pass/task-comm-13.rs | 11 ++--- src/test/run-pass/task-comm-14.rs | 14 +++--- src/test/run-pass/task-comm-15.rs | 12 ++--- src/test/run-pass/task-comm-16.rs | 70 ++++++++++++++-------------- src/test/run-pass/task-comm-3.rs | 16 +++---- src/test/run-pass/task-comm-4.rs | 39 ++++++++-------- src/test/run-pass/task-comm-5.rs | 9 ++-- src/test/run-pass/task-comm-6.rs | 34 +++++++------- src/test/run-pass/task-comm-7.rs | 20 ++++---- src/test/run-pass/task-comm-9.rs | 11 ++--- src/test/run-pass/trivial-message.rs | 10 ++-- 15 files changed, 151 insertions(+), 210 deletions(-) diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 27cd8ef7cafa..a999d615e31b 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -30,59 +30,6 @@ macro_rules! move { // places. Once there is unary move, it can be removed. fn move(-x: T) -> T { x } -/** - -Some thoughts about fixed buffers. - -The idea is if a protocol is bounded, we will synthesize a record that -has a field for each state. Each of these states contains a packet for -the messages that are legal to be sent in that state. Then, instead of -allocating, the send code just finds a pointer to the right field and -uses that instead. - -Unforunately, this makes things kind of tricky. We need to be able to -find the buffer, which means we need to pass it around. This could -either be associated with the (send|recv)_packet classes, or with the -packet itself. We will also need some form of reference counting so we -can track who has the responsibility of freeing the buffer. - -We want to preserve the ability to do things like optimistic buffer -re-use, and skipping over to a new buffer when necessary. What I mean -is, suppose we had the typical stream protocol. It'd make sense to -amortize allocation costs by allocating a buffer with say 16 -messages. When the sender gets to the end of the buffer, it could -check if the receiver is done with the packet in slot 0. If so, it can -just reuse that one, checking if the receiver is done with the next -one in each case. If it is ever not done, it just allocates a new -buffer and skips over to that. - -Also, since protocols are in libcore, we have to do this in a way that -maintains backwards compatibility. - -buffer header and buffer. Cast as c_void when necessary. - -=== - -Okay, here are some new ideas. - -It'd be nice to keep the bounded/unbounded case as uniform as -possible. It leads to less code duplication, and less things that can -go sublty wrong. For the bounded case, we could either have a struct -with a bunch of unique pointers to pre-allocated packets, or we could -lay them out inline. Inline layout is better, if for no other reason -than that we don't have to allocate each packet -individually. Currently we pass unique packets around as unsafe -pointers, but they are actually unique pointers. We should instead use -real unsafe pointers. This makes freeing data and running destructors -trickier though. Thus, we should allocate all packets in parter of a -higher level buffer structure. Packets can maintain a pointer to their -buffer, and this is the part that gets freed. - -It might be helpful to have some idea of a semi-unique pointer (like -being partially pregnant, also like an ARC). - -*/ - enum state { empty, full, @@ -805,6 +752,12 @@ class port_set : recv { vec::push(self.ports, port) } + fn chan() -> chan { + let (ch, po) = stream(); + self.add(po); + ch + } + fn try_recv() -> option { let mut result = none; while result == none && self.ports.len() > 0 { diff --git a/src/test/run-pass/task-comm-0.rs b/src/test/run-pass/task-comm-0.rs index 532daf3651c8..eb866ee7b3e7 100644 --- a/src/test/run-pass/task-comm-0.rs +++ b/src/test/run-pass/task-comm-0.rs @@ -1,31 +1,29 @@ use std; -import comm; -import comm::chan; -import comm::send; +import pipes; +import pipes::chan; +import pipes::port; import task; fn main() { test05(); } fn test05_start(ch : chan) { - log(error, ch); - send(ch, 10); + ch.send(10); #error("sent 10"); - send(ch, 20); + ch.send(20); #error("sent 20"); - send(ch, 30); + ch.send(30); #error("sent 30"); } fn test05() { - let po = comm::port(); - let ch = comm::chan(po); + let (ch, po) = pipes::stream(); task::spawn(|| test05_start(ch) ); - let mut value = comm::recv(po); + let mut value = po.recv(); log(error, value); - value = comm::recv(po); + value = po.recv(); log(error, value); - value = comm::recv(po); + value = po.recv(); log(error, value); assert (value == 30); } diff --git a/src/test/run-pass/task-comm-10.rs b/src/test/run-pass/task-comm-10.rs index 1d0963a29dca..ef94a13c0726 100644 --- a/src/test/run-pass/task-comm-10.rs +++ b/src/test/run-pass/task-comm-10.rs @@ -1,28 +1,27 @@ use std; import task; -import comm; +import pipes; -fn start(c: comm::chan>) { - let p = comm::port(); - comm::send(c, comm::chan(p)); +fn start(c: pipes::chan>) { + let (ch, p) = pipes::stream(); + c.send(ch); let mut a; let mut b; - a = comm::recv(p); + a = p.recv(); assert a == ~"A"; log(error, a); - b = comm::recv(p); + b = p.recv(); assert b == ~"B"; log(error, b); } fn main() { - let p = comm::port(); - let ch = comm::chan(p); + let (ch, p) = pipes::stream(); let child = task::spawn(|| start(ch) ); - let c = comm::recv(p); - comm::send(c, ~"A"); - comm::send(c, ~"B"); + let c = p.recv(); + c.send(~"A"); + c.send(~"B"); task::yield(); } diff --git a/src/test/run-pass/task-comm-11.rs b/src/test/run-pass/task-comm-11.rs index f96f9d148d00..5e1e5c5facd2 100644 --- a/src/test/run-pass/task-comm-11.rs +++ b/src/test/run-pass/task-comm-11.rs @@ -1,15 +1,14 @@ use std; -import comm; +import pipes; import task; -fn start(c: comm::chan>) { - let p: comm::port = comm::port(); - comm::send(c, comm::chan(p)); +fn start(c: pipes::chan>) { + let (ch, p) = pipes::stream(); + c.send(ch); } fn main() { - let p = comm::port(); - let ch = comm::chan(p); + let (ch, p) = pipes::stream(); let child = task::spawn(|| start(ch) ); - let c = comm::recv(p); + let c = p.recv(); } diff --git a/src/test/run-pass/task-comm-13.rs b/src/test/run-pass/task-comm-13.rs index 3ded4aac5ae9..88220437c431 100644 --- a/src/test/run-pass/task-comm-13.rs +++ b/src/test/run-pass/task-comm-13.rs @@ -1,17 +1,16 @@ use std; import task; -import comm; -import comm::send; +import pipes; +import pipes::send; -fn start(c: comm::chan, start: int, number_of_messages: int) { +fn start(c: pipes::chan, start: int, number_of_messages: int) { let mut i: int = 0; - while i < number_of_messages { send(c, start + i); i += 1; } + while i < number_of_messages { c.send(start + i); i += 1; } } fn main() { #debug("Check that we don't deadlock."); - let p = comm::port::(); - let ch = comm::chan(p); + let (ch, p) = pipes::stream(); task::try(|| start(ch, 0, 10) ); #debug("Joined task"); } diff --git a/src/test/run-pass/task-comm-14.rs b/src/test/run-pass/task-comm-14.rs index ef9c4ae5010d..268b6d06dfde 100644 --- a/src/test/run-pass/task-comm-14.rs +++ b/src/test/run-pass/task-comm-14.rs @@ -1,15 +1,14 @@ -use std; -import comm; import task; fn main() { - let po = comm::port::(); - let ch = comm::chan(po); + let po = pipes::port_set(); // Spawn 10 tasks each sending us back one int. let mut i = 10; while (i > 0) { log(debug, i); + let (ch, p) = pipes::stream(); + po.add(p); task::spawn(|copy i| child(i, ch) ); i = i - 1; } @@ -18,17 +17,16 @@ fn main() { // anything back, so we deadlock here. i = 10; - let mut value = 0; while (i > 0) { log(debug, i); - value = comm::recv(po); + po.recv(); i = i - 1; } #debug("main thread exiting"); } -fn child(x: int, ch: comm::chan) { +fn child(x: int, ch: pipes::chan) { log(debug, x); - comm::send(ch, copy x); + ch.send(x); } diff --git a/src/test/run-pass/task-comm-15.rs b/src/test/run-pass/task-comm-15.rs index d9291fd68986..71a732490ce0 100644 --- a/src/test/run-pass/task-comm-15.rs +++ b/src/test/run-pass/task-comm-15.rs @@ -1,23 +1,21 @@ // xfail-win32 use std; -import comm; import task; -fn start(c: comm::chan, i0: int) { +fn start(c: pipes::chan, i0: int) { let mut i = i0; while i > 0 { - comm::send(c, 0); + c.send(0); i = i - 1; } } fn main() { - let p = comm::port(); // Spawn a task that sends us back messages. The parent task // is likely to terminate before the child completes, so from // the child's point of view the receiver may die. We should // drop messages on the floor in this case, and not crash! - let ch = comm::chan(p); - let child = task::spawn(|| start(ch, 10) ); - let c = comm::recv(p); + let (ch, p) = pipes::stream(); + task::spawn(|| start(ch, 10)); + p.recv(); } diff --git a/src/test/run-pass/task-comm-16.rs b/src/test/run-pass/task-comm-16.rs index bc46de64cd72..2d1c72df713c 100644 --- a/src/test/run-pass/task-comm-16.rs +++ b/src/test/run-pass/task-comm-16.rs @@ -1,44 +1,41 @@ // -*- rust -*- use std; -import comm; -import comm::send; -import comm::port; -import comm::recv; -import comm::chan; +import pipes; +import pipes::send; +import pipes::port; +import pipes::recv; +import pipes::chan; // Tests of ports and channels on various types fn test_rec() { type r = {val0: int, val1: u8, val2: char}; - let po = comm::port(); - let ch = chan(po); + let (ch, po) = pipes::stream(); let r0: r = {val0: 0, val1: 1u8, val2: '2'}; - send(ch, r0); + ch.send(r0); let mut r1: r; - r1 = recv(po); + r1 = po.recv(); assert (r1.val0 == 0); assert (r1.val1 == 1u8); assert (r1.val2 == '2'); } fn test_vec() { - let po = port(); - let ch = chan(po); + let (ch, po) = pipes::stream(); let v0: ~[int] = ~[0, 1, 2]; - send(ch, v0); - let v1 = recv(po); + ch.send(v0); + let v1 = po.recv(); assert (v1[0] == 0); assert (v1[1] == 1); assert (v1[2] == 2); } fn test_str() { - let po = port(); - let ch = chan(po); - let s0 = ~"test"; - send(ch, s0); - let s1 = recv(po); + let (ch, po) = pipes::stream(); + let s0 = "test"; + ch.send(s0); + let s1 = po.recv(); assert (s1[0] == 't' as u8); assert (s1[1] == 'e' as u8); assert (s1[2] == 's' as u8); @@ -47,33 +44,36 @@ fn test_str() { fn test_tag() { enum t { tag1, tag2(int), tag3(int, u8, char), } - let po = port(); - let ch = chan(po); - send(ch, tag1); - send(ch, tag2(10)); - send(ch, tag3(10, 11u8, 'A')); + let (ch, po) = pipes::stream(); + ch.send(tag1); + ch.send(tag2(10)); + ch.send(tag3(10, 11u8, 'A')); let mut t1: t; - t1 = recv(po); + t1 = po.recv(); assert (t1 == tag1); - t1 = recv(po); + t1 = po.recv(); assert (t1 == tag2(10)); - t1 = recv(po); + t1 = po.recv(); assert (t1 == tag3(10, 11u8, 'A')); } fn test_chan() { - let po = port(); - let ch = chan(po); - let po0 = port(); - let ch0 = chan(po0); - send(ch, ch0); - let ch1 = recv(po); + let (ch, po) = pipes::stream(); + let (ch0, po0) = pipes::stream(); + ch.send(ch0); + let ch1 = po.recv(); // Does the transmitted channel still work? - send(ch1, 10); + ch1.send(10); let mut i: int; - i = recv(po0); + i = po0.recv(); assert (i == 10); } -fn main() { test_rec(); test_vec(); test_str(); test_tag(); test_chan(); } +fn main() { + test_rec(); + test_vec(); + test_str(); + test_tag(); + test_chan(); +} diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs index c03db4420226..05c057d85fd8 100644 --- a/src/test/run-pass/task-comm-3.rs +++ b/src/test/run-pass/task-comm-3.rs @@ -1,9 +1,9 @@ use std; import task; -import comm; -import comm::chan; -import comm::send; -import comm::recv; +import pipes; +import pipes::chan; +import pipes::send; +import pipes::recv; fn main() { #debug("===== WITHOUT THREADS ====="); test00(); } @@ -12,7 +12,7 @@ fn test00_start(ch: chan, message: int, count: int) { let mut i: int = 0; while i < count { #debug("Sending Message"); - send(ch, message + 0); + ch.send(message + 0); i = i + 1; } #debug("Ending test00_start"); @@ -24,14 +24,14 @@ fn test00() { #debug("Creating tasks"); - let po = comm::port(); - let ch = chan(po); + let po = pipes::port_set(); let mut i: int = 0; // Create and spawn tasks... let mut results = ~[]; while i < number_of_tasks { + let ch = po.chan(); do task::task().future_result(|-r| { results += ~[r]; }).spawn |copy i| { @@ -45,7 +45,7 @@ fn test00() { for results.each |r| { i = 0; while i < number_of_messages { - let value = recv(po); + let value = po.recv(); sum += value; i = i + 1; } diff --git a/src/test/run-pass/task-comm-4.rs b/src/test/run-pass/task-comm-4.rs index f7de33c63d62..9b99c1cb799b 100644 --- a/src/test/run-pass/task-comm-4.rs +++ b/src/test/run-pass/task-comm-4.rs @@ -1,44 +1,43 @@ use std; -import comm; -import comm::send; +import pipes; +import pipes::send; fn main() { test00(); } fn test00() { let mut r: int = 0; let mut sum: int = 0; - let p = comm::port(); - let c = comm::chan(p); - send(c, 1); - send(c, 2); - send(c, 3); - send(c, 4); - r = comm::recv(p); + let (c, p) = pipes::stream(); + c.send(1); + c.send(2); + c.send(3); + c.send(4); + r = p.recv(); sum += r; log(debug, r); - r = comm::recv(p); + r = p.recv(); sum += r; log(debug, r); - r = comm::recv(p); + r = p.recv(); sum += r; log(debug, r); - r = comm::recv(p); + r = p.recv(); sum += r; log(debug, r); - send(c, 5); - send(c, 6); - send(c, 7); - send(c, 8); - r = comm::recv(p); + c.send(5); + c.send(6); + c.send(7); + c.send(8); + r = p.recv(); sum += r; log(debug, r); - r = comm::recv(p); + r = p.recv(); sum += r; log(debug, r); - r = comm::recv(p); + r = p.recv(); sum += r; log(debug, r); - r = comm::recv(p); + r = p.recv(); sum += r; log(debug, r); assert (sum == 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8); diff --git a/src/test/run-pass/task-comm-5.rs b/src/test/run-pass/task-comm-5.rs index a0d4f4595bec..249bdaf1c9a5 100644 --- a/src/test/run-pass/task-comm-5.rs +++ b/src/test/run-pass/task-comm-5.rs @@ -1,17 +1,16 @@ use std; -import comm; +import pipes; fn main() { test00(); } fn test00() { let r: int = 0; let mut sum: int = 0; - let p = comm::port(); - let c = comm::chan(p); + let (c, p) = pipes::stream(); let number_of_messages: int = 1000; let mut i: int = 0; - while i < number_of_messages { comm::send(c, i + 0); i += 1; } + while i < number_of_messages { c.send(i + 0); i += 1; } i = 0; - while i < number_of_messages { sum += comm::recv(p); i += 1; } + while i < number_of_messages { sum += p.recv(); i += 1; } assert (sum == number_of_messages * (number_of_messages - 1) / 2); } diff --git a/src/test/run-pass/task-comm-6.rs b/src/test/run-pass/task-comm-6.rs index b363b25e864a..8bc93a78913d 100644 --- a/src/test/run-pass/task-comm-6.rs +++ b/src/test/run-pass/task-comm-6.rs @@ -1,37 +1,37 @@ use std; -import comm; -import comm::send; -import comm::chan; -import comm::recv; +import pipes; +import pipes::send; +import pipes::chan; +import pipes::recv; fn main() { test00(); } fn test00() { let mut r: int = 0; let mut sum: int = 0; - let p = comm::port(); - let c0 = chan(p); - let c1 = chan(p); - let c2 = chan(p); - let c3 = chan(p); + let p = pipes::port_set(); + let c0 = p.chan(); + let c1 = p.chan(); + let c2 = p.chan(); + let c3 = p.chan(); let number_of_messages: int = 1000; let mut i: int = 0; while i < number_of_messages { - send(c0, i + 0); - send(c1, i + 0); - send(c2, i + 0); - send(c3, i + 0); + c0.send(i + 0); + c1.send(i + 0); + c2.send(i + 0); + c3.send(i + 0); i += 1; } i = 0; while i < number_of_messages { - r = recv(p); + r = p.recv(); sum += r; - r = recv(p); + r = p.recv(); sum += r; - r = recv(p); + r = p.recv(); sum += r; - r = recv(p); + r = p.recv(); sum += r; i += 1; } diff --git a/src/test/run-pass/task-comm-7.rs b/src/test/run-pass/task-comm-7.rs index b8922400777c..1df3de6ba1eb 100644 --- a/src/test/run-pass/task-comm-7.rs +++ b/src/test/run-pass/task-comm-7.rs @@ -1,43 +1,45 @@ use std; import task; -import comm; fn main() { test00(); } -fn test00_start(c: comm::chan, start: int, number_of_messages: int) { +fn test00_start(c: pipes::chan, start: int, number_of_messages: int) { let mut i: int = 0; - while i < number_of_messages { comm::send(c, start + i); i += 1; } + while i < number_of_messages { c.send(start + i); i += 1; } } fn test00() { let mut r: int = 0; let mut sum: int = 0; - let p = comm::port(); + let p = pipes::port_set(); let number_of_messages: int = 10; - let c = comm::chan(p); + let c = p.chan(); do task::spawn { test00_start(c, number_of_messages * 0, number_of_messages); } + let c = p.chan(); do task::spawn { test00_start(c, number_of_messages * 1, number_of_messages); } + let c = p.chan(); do task::spawn { test00_start(c, number_of_messages * 2, number_of_messages); } + let c = p.chan(); do task::spawn { test00_start(c, number_of_messages * 3, number_of_messages); } let mut i: int = 0; while i < number_of_messages { - r = comm::recv(p); + r = p.recv(); sum += r; - r = comm::recv(p); + r = p.recv(); sum += r; - r = comm::recv(p); + r = p.recv(); sum += r; - r = comm::recv(p); + r = p.recv(); sum += r; i += 1; } diff --git a/src/test/run-pass/task-comm-9.rs b/src/test/run-pass/task-comm-9.rs index 964029dee207..939cfd15797f 100644 --- a/src/test/run-pass/task-comm-9.rs +++ b/src/test/run-pass/task-comm-9.rs @@ -1,20 +1,19 @@ use std; import task; -import comm; fn main() { test00(); } -fn test00_start(c: comm::chan, number_of_messages: int) { +fn test00_start(c: pipes::chan, number_of_messages: int) { let mut i: int = 0; - while i < number_of_messages { comm::send(c, i + 0); i += 1; } + while i < number_of_messages { c.send(i + 0); i += 1; } } fn test00() { let r: int = 0; let mut sum: int = 0; - let p = comm::port(); + let p = pipes::port_set(); let number_of_messages: int = 10; - let ch = comm::chan(p); + let ch = p.chan(); let mut result = none; do task::task().future_result(|-r| { result = some(r); }).spawn { @@ -23,7 +22,7 @@ fn test00() { let mut i: int = 0; while i < number_of_messages { - sum += comm::recv(p); + sum += p.recv(); log(debug, r); i += 1; } diff --git a/src/test/run-pass/trivial-message.rs b/src/test/run-pass/trivial-message.rs index 487b440ee420..8e92e8f2020f 100644 --- a/src/test/run-pass/trivial-message.rs +++ b/src/test/run-pass/trivial-message.rs @@ -1,14 +1,12 @@ -use std; -import comm::*; +import pipes::{port, chan} /* This is about the simplest program that can successfully send a message. */ fn main() { - let po = port(); - let ch = chan(po); - send(ch, 42); - let r = recv(po); + let (ch, po) = pipes::stream(); + ch.send(42); + let r = po.recv(); log(error, r); } From 2d15b6ef424016765c659305a4265813d2b498d0 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 25 Jul 2012 14:10:12 -0700 Subject: [PATCH 02/24] Use pipes in compiletest --- src/compiletest/compiletest.rs | 5 ----- src/compiletest/procsrv.rs | 27 +++++++++++++++------------ 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 3ba358bfb934..1ee7edb4dc70 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -8,11 +8,6 @@ import task; import core::result; import result::{ok, err}; -import comm::port; -import comm::chan; -import comm::send; -import comm::recv; - import common::config; import common::mode_run_pass; import common::mode_run_fail; diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index 35da5d2bc6d8..d93ae3f80177 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -2,6 +2,8 @@ import run::spawn_process; import io::{writer_util, reader_util}; import libc::{c_int, pid_t}; +import pipes::chan; + export run; #[cfg(target_os = "win32")] @@ -58,29 +60,30 @@ fn run(lib_path: ~str, writeclose(pipe_in.out, input); - let p = comm::port(); - let ch = comm::chan(p); + let p = pipes::port_set(); + let ch = p.chan(); do task::spawn_sched(task::single_threaded) { let errput = readclose(pipe_err.in); - comm::send(ch, (2, errput)); + ch.send((2, errput)); } + let ch = p.chan(); do task::spawn_sched(task::single_threaded) { let output = readclose(pipe_out.in); - comm::send(ch, (1, output)); + ch.send((1, output)); } let status = run::waitpid(pid); let mut errs = ~""; let mut outs = ~""; let mut count = 2; while count > 0 { - let stream = comm::recv(p); - alt check stream { - (1, s) { - outs = s; - } - (2, s) { - errs = s; - } + alt p.recv() { + (1, s) { + outs = s; + } + (2, s) { + errs = s; + } + _ { fail } }; count -= 1; }; From 531ea695f64e8d7105f904c515a6ff84fa32dc77 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 25 Jul 2012 14:33:18 -0700 Subject: [PATCH 03/24] Remove shared_arc (unused) and fix trivial-message --- src/libcore/arc.rs | 65 +--------------------------- src/test/run-pass/trivial-message.rs | 2 +- 2 files changed, 2 insertions(+), 65 deletions(-) diff --git a/src/libcore/arc.rs b/src/libcore/arc.rs index 28f072644105..9c46df9731b9 100644 --- a/src/libcore/arc.rs +++ b/src/libcore/arc.rs @@ -3,10 +3,9 @@ * share immutable data between tasks. */ -import comm::{port, chan, methods}; import sys::methods; -export arc, get, clone, shared_arc, get_arc; +export arc, get, clone; export exclusive, methods; @@ -122,49 +121,6 @@ impl methods for exclusive { } } -// Convenience code for sharing arcs between tasks - -type get_chan = chan>>; - -// (terminate, get) -type shared_arc = (shared_arc_res, get_chan); - -class shared_arc_res { - let c: comm::chan<()>; - new(c: comm::chan<()>) { self.c = c; } - drop { self.c.send(()); } -} - -fn shared_arc(-data: T) -> shared_arc { - let a = arc::arc(data); - let p = port(); - let c = chan(p); - do task::spawn() |move a| { - let mut live = true; - let terminate = port(); - let get = port(); - - c.send((chan(terminate), chan(get))); - - while live { - alt comm::select2(terminate, get) { - either::left(()) { live = false; } - either::right(cc) { - comm::send(cc, arc::clone(&a)); - } - } - } - }; - let (terminate, get) = p.recv(); - (shared_arc_res(terminate), get) -} - -fn get_arc(c: get_chan) -> arc::arc { - let p = port(); - c.send(chan(p)); - p.recv() -} - #[cfg(test)] mod tests { import comm::*; @@ -196,25 +152,6 @@ mod tests { log(info, arc_v); } - #[test] - fn auto_share_arc() { - let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - let (_res, arc_c) = shared_arc(v); - - let p = port(); - let c = chan(p); - - do task::spawn() { - let arc_v = get_arc(arc_c); - let v = *get(&arc_v); - assert v[2] == 3; - - c.send(()); - }; - - assert p.recv() == (); - } - #[test] #[ignore] // this can probably infinite loop too. fn exclusive_arc() { diff --git a/src/test/run-pass/trivial-message.rs b/src/test/run-pass/trivial-message.rs index 8e92e8f2020f..ab3efd6b22ea 100644 --- a/src/test/run-pass/trivial-message.rs +++ b/src/test/run-pass/trivial-message.rs @@ -1,4 +1,4 @@ -import pipes::{port, chan} +import pipes::{port, chan}; /* This is about the simplest program that can successfully send a From 62d4f8fe825c907bd03c275f85aeeaf7b25c4336 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 25 Jul 2012 14:46:15 -0700 Subject: [PATCH 04/24] Added a select2 trait. Fixes #2898 --- src/libcore/pipes.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index a999d615e31b..4ffa040250f6 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -822,3 +822,52 @@ impl chan of channel for shared_chan { fn shared_chan(+c: chan) -> shared_chan { arc::exclusive(c) } + +trait select2 { + fn try_select() -> either, option>; + fn select() -> either; +} + +impl, Right: selectable recv> + of select2 for (Left, Right) { + + fn select() -> either { + alt self { + (lp, rp) { + alt select2i(lp, rp) { + left(()) { left (lp.recv()) } + right(()) { right(rp.recv()) } + } + } + } + } + + fn try_select() -> either, option> { + alt self { + (lp, rp) { + alt select2i(lp, rp) { + left(()) { left (lp.try_recv()) } + right(()) { right(rp.try_recv()) } + } + } + } + } +} + +#[cfg(test)] +mod test { + #[test] + fn test_select2() { + let (c1, p1) = pipes::stream(); + let (c2, p2) = pipes::stream(); + + c1.send("abc"); + + alt (p1, p2).select() { + right(_) { fail } + _ { } + } + + c2.send(123); + } +} From f8dc9283ad13f990d1ee5ac814eac49189edcd59 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 25 Jul 2012 14:58:48 -0700 Subject: [PATCH 05/24] Reject non-UTF-8 files when reading as str. Close #2918. --- src/libcore/io.rs | 6 +++++- src/test/compile-fail/not-utf8.bin | Bin 0 -> 3036 bytes src/test/compile-fail/not-utf8.rs | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/not-utf8.bin create mode 100644 src/test/compile-fail/not-utf8.rs diff --git a/src/libcore/io.rs b/src/libcore/io.rs index 25d1b5e66805..3704f2b70da4 100644 --- a/src/libcore/io.rs +++ b/src/libcore/io.rs @@ -687,7 +687,11 @@ fn seek_in_buf(offset: int, pos: uint, len: uint, whence: seek_style) -> fn read_whole_file_str(file: ~str) -> result<~str, ~str> { result::chain(read_whole_file(file), |bytes| { - result::ok(str::from_bytes(bytes)) + if str::is_utf8(bytes) { + result::ok(str::from_bytes(bytes)) + } else { + result::err(file + ~" is not UTF-8") + } }) } diff --git a/src/test/compile-fail/not-utf8.bin b/src/test/compile-fail/not-utf8.bin new file mode 100644 index 0000000000000000000000000000000000000000..4148e5b88fe6369c7056f9659bb48902fefa19c6 GIT binary patch literal 3036 zcmX?DbCpTabWw7$C{xenU75R@!o#yRoLG8I{ao!qp&qa4Cpz!_4c{W?zrkVV{4WP( z%GZZodH&7E|J(iplSQHxnB(`UFW%V{9C)$r#)ds>j&4@_+NR6-{dSID-QKH;4m=9+ z%9~$rzMmb~eInysd+Vw9{f)90t+vas-{mqETVycD<%iqE8*yPXP9=JH+_?SZO6I=j zFX~_Z`6sp|`YK<4ho8R8S0mf}}PzCK!Aa#rG+Oqjx! zvfPR{^(z)%EH=`}>3;Nq;o*`wE(d=<6=%8k=kKJFODl}mJ$k?vIL$}@d+|0uPtm(k zQzfd|UR7$}^zGbiRqe|g|MTfJ7ORTmVfJoQxely)U3Q|cwBq%G)k`P*w`@9p^tnz4 zH_MlsAr>p;>K^7#@U!u(eehk-|77|f2LIH5Q>q_l7wIo&Nwr&>n`9C9%EZhngOi8BhK?)LhWbkg#>iZk4-=vuqyDV9XMpzasNe*QQnL->!LhULxYg zOq>2??sE3075{5iZ_?)~IjyaJRd}aDP_19?ZJ{ZXRAN(NuKF2XG`X{9{)MfqYbS`g zt=+M!Vt#((Aql${`C|`QmS_U-fv$F_D{AnJ7O;*CmWZc9Qd=L{fdOy zq)z2y=XmF^2Y<8+94N8zdbH5VH;?ocGTLd}Mz0J>AUOm`x_Wq;QI#0vh4!rR-+c$mg z<;15aXRFT>61;MEd*i(~m)$K&rcW2iWmqwDzGl^4JsTZ%h8y1`)+a@;XVK%Fd&qyH za`h$gJv^JwGP%`MT{&t#5o~>s%u*YZ4LXD+cwy3=;o&4Ew`gx9!vPYLyN_)&w zl6s@O9;i=IP~lr9;>xmGei^1d}cw#xM^Igr~eN= zf9pX@ZC}d*#o3K^mH{`@svn%uc3ax@&c<||)v>2S7ZP92PMlVfD-oP{sa$)hsDc0H zgANBio^Mr5e*EMZTb0_~#X^mFTn>-7#ot+I`|8)G+2OCH!aVvW->sHpdh$o&b=Jh$ zk1tNYdHXAy_GA9b`EzD&*M596*>tv8!K`ZE?8Jk-$G=?dnDdAwxX7jF$G&#PX;L?w zJ|u04IB`Z~4*%+Xkstqh$flO3otgS7v*mDdR5Od&bLP{rHX7y%4?i{d_M75cI)mS-Z5rTcEtuYKWm{H$R+AH>+KKNeQRe|zPE8Oai6ucYqZU6K%1Tt4NO z*h85)FV*g-cg$eE-=-MgasR{$-tg<+5AoIQW!Lz?IX&{6pvN5lOH&@+?eEsTebexz zL#ysl6+5PRYcv~g72c{Zx+ZsH-{t96Pk!C^+Wg}p|80e{&%ao7{gl((_OSLAuhl_~ zYxZ9!_?zgTdK|7Vu-|K%oup7@V~v>HulKL^GO@kV)8%-yA=NbEL50l`vk%qBLss>i zTI_NwasBi&j@y~v#BMgvnmD7rF9j59y`&o4Z1rz2?t*N=6x7v7CnXDIt5V3ylL5!Sa^t2Im| zl&^eU9U>?8YLbG$w7=)_f-V&1rG0kzZ{zt(j^#-8tSVE!KOrYKh<670_Es4>Zk7W((@2!!0#N9;Zh-!<) zq@_i3vKD^+xgo|TE<(U*+pFIftq%3^l`NPkC)US4W%lb|=fCgS67l%QHqDIQmsSg& zoSAV={H|w^Rr+-0{t}1ht(PxVa)`ht?h=6WBFaR-)fR^dy5@JlQj(zdfzg?n4`Zf>DPfLt8Rzx zS*`H+h|Ae$6QzUM?>#Y{bEEgmt=R7B#YeA4eR7|0X~%)jY%9H9O}bU5Z`Z5Rk!QEL z;Zv^PzdtiMt17O1IMK2?-Tu1On}=yJPxNHw7YcrQ=wMoXHtep~s?%XbX(5t*Gh|;@ zFV~y1d*6jWCWr4oZVxUk{vL0+Gx+A&bD^28i%q^d`EI;dT_hQ;>$B`<`~6c1+ZQ*K zi$&gFEx%XtiKjeg!upuIe`2GzFv_rtS$XEO7FmaUf1PVkXY%F30nRP=uazYyitw^; z->!1&J*#%Y$JGxv9d({KZ`E9uS?v>qA1B>@!~Eg($v**N{;Wq!mM%=ml~Y+R8MOCn zDC4Omw+>6x>PTkZU7&X7=B7vQ*z}LD-LxzH_ynaxQmXOsGevF`pGmwRc0I^UqIA-n ze@%Opt3A?WioBYlayWOJ-hQw1`|+}J$BG}F`(M=VeJ^Dsb?%4Ih85BL zo`%2d*!HHu*Aa4f^?N_r?2Fr|V7DZT z<@a^(t|tw`IuQ)_BKrzufBGybE4+99PvWuGez(Ksc2Yqva@8$;To=tqdbuieTEEBi zB|f`1ZlCh>G4H+IRl;qy2QTq%UTUHpa!9{$#?d9rTFcHqV-{RmwChufWV3K!&(?a<>vg;!as2K*q`2a^sa2q_m?%+xeo$wZA#mr zd_Ch=Sc}o=<=cKA5>&ij=d&$o*0c%ecdx8Iv@7&A>%QIzyRJRY`2D}^Hh|F^5*m+VG zofmjMxhAt`?e_Y(h#S+&t>-?vn|~zT@5lB1E{kPi6)vmk9MGHY?QGV}r+sy+sG6_R z{nwJGd|cUfIDbvKba6xAm3J-=|8LwboAPPViucL;S1 Date: Wed, 25 Jul 2012 15:39:46 -0700 Subject: [PATCH 06/24] Add check-notidy target. Close #2943. --- mk/tests.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mk/tests.mk b/mk/tests.mk index 89646a90a4c7..cf33cff82ea5 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -95,6 +95,9 @@ cleantestlibs: check: cleantestlibs cleantmptestlogs tidy all check-stage2 $(Q)$(S)src/etc/check-summary.py tmp/*.log +check-notidy: cleantestlibs cleantmptestlogs all check-stage2 + $(Q)$(S)src/etc/check-summary.py tmp/*.log + check-full: cleantestlibs cleantmptestlogs tidy \ all check-stage1 check-stage2 check-stage3 $(Q)$(S)src/etc/check-summary.py tmp/*.log From 0b3dba42cf62419518137ec17ce7630f0174f26c Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 25 Jul 2012 15:59:24 -0700 Subject: [PATCH 07/24] Change iface and interface to trait. Close #2967. --- doc/tutorial.md | 75 +++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/doc/tutorial.md b/doc/tutorial.md index fbb1ca416e4c..59e1a9d7d9d2 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -34,8 +34,9 @@ high-level features include: * ***Higher-order functions.*** Rust functions may take closures as arguments or return closures as return values. Closures in Rust are very powerful and used pervasively. -* ***Interface polymorphism.*** Rust's type system features a unique - combination of Java-style interfaces and Haskell-style typeclasses. +* ***Trait polymorphism.*** Rust's type system features a unique + combination of Java-style interfaces and Haskell-style typeclasses + called _traits_. * ***Parametric polymorphism (generics).*** Functions and types can be parameterized over type variables with optional type constraints. * ***Type inference.*** Type annotations on local variable @@ -2089,9 +2090,9 @@ resource type. Rust has several kinds that can be used as type bounds: mutable fields nor shared boxes. > ***Note:*** Rust type kinds are syntactically very similar to -> [interfaces](#interfaces) when used as type bounds, and can be -> conveniently thought of as built-in interfaces. In the future type -> kinds will actually be interfaces that the compiler has special +> [traits](#traits) when used as type bounds, and can be +> conveniently thought of as built-in traits. In the future type +> kinds will actually be traits that the compiler has special > knowledge about. ## Generic functions and argument-passing @@ -2388,9 +2389,9 @@ This makes it possible to rebind a variable without actually mutating it, which is mostly useful for destructuring (which can rebind, but not assign). -# Interfaces +# Traits -Interfaces are Rust's take on value polymorphism—the thing that +Traits are Rust's take on value polymorphism—the thing that object-oriented languages tend to solve with methods and inheritance. For example, writing a function that can operate on multiple types of collections. @@ -2400,27 +2401,27 @@ collections. ## Declaration -An interface consists of a set of methods. A method is a function that +A trait consists of a set of methods. A method is a function that can be applied to a `self` value and a number of arguments, using the dot notation: `self.foo(arg1, arg2)`. -For example, we could declare the interface `to_str` for things that +For example, we could declare the trait `to_str` for things that can be converted to a string, with a single method of the same name: ~~~~ -iface to_str { +trait to_str { fn to_str() -> ~str; } ~~~~ ## Implementation -To actually implement an interface for a given type, the `impl` form +To actually implement an trait for a given type, the `impl` form is used. This defines implementations of `to_str` for the `int` and `~str` types. ~~~~ -# iface to_str { fn to_str() -> ~str; } +# trait to_str { fn to_str() -> ~str; } impl of to_str for int { fn to_str() -> ~str { int::to_str(self, 10u) } } @@ -2439,13 +2440,13 @@ method that matches the name, and simply calls that. Implementations are not globally visible. Resolving a method to an implementation requires that implementation to be in scope. You can -import and export implementations using the name of the interface they +import and export implementations using the name of the trait they implement (multiple implementations with the same name can be in scope without problems). Or you can give them an explicit name if you prefer, using this syntax: ~~~~ -# iface to_str { fn to_str() -> ~str; } +# trait to_str { fn to_str() -> ~str; } impl nil_to_str of to_str for () { fn to_str() -> ~str { ~"()" } } @@ -2461,7 +2462,7 @@ known at compile time, it is possible to specify 'bounds' for type parameters. ~~~~ -# iface to_str { fn to_str() -> ~str; } +# trait to_str { fn to_str() -> ~str; } fn comma_sep(elts: ~[T]) -> ~str { let mut result = ~"", first = true; for elts.each |elt| { @@ -2476,18 +2477,18 @@ fn comma_sep(elts: ~[T]) -> ~str { The syntax for this is similar to the syntax for specifying that a parameter type has to be copyable (which is, in principle, another kind of bound). By declaring `T` as conforming to the `to_str` -interface, it becomes possible to call methods from that interface on +trait, it becomes possible to call methods from that trait on values of that type inside the function. It will also cause a compile-time error when anyone tries to call `comma_sep` on an array whose element type does not have a `to_str` implementation in scope. -## Polymorphic interfaces +## Polymorphic traits -Interfaces may contain type parameters. This defines an interface for +Traits may contain type parameters. This defines a trait for generalized sequence types: ~~~~ -iface seq { +trait seq { fn len() -> uint; fn iter(fn(T)); } @@ -2500,25 +2501,25 @@ impl of seq for ~[T] { ~~~~ Note that the implementation has to explicitly declare the its -parameter `T` before using it to specify its interface type. This is +parameter `T` before using it to specify its trait type. This is needed because it could also, for example, specify an implementation of `seq`—the `of` clause *refers* to a type, rather than defining one. -The type parameters bound by an iface are in scope in each of the +The type parameters bound by a trait are in scope in each of the method declarations. So, re-declaring the type parameter -`T` as an explicit type parameter for `len` -- in either the iface or +`T` as an explicit type parameter for `len` -- in either the trait or the impl -- would be a compile-time error. -## The `self` type in interfaces +## The `self` type in traits -In an interface, `self` is a special type that you can think of as a -type parameter. An implementation of the interface for any given type +In a trait, `self` is a special type that you can think of as a +type parameter. An implementation of the trait for any given type `T` replaces the `self` type parameter with `T`. The following -interface describes types that support an equality operation: +trait describes types that support an equality operation: ~~~~ -iface eq { +trait eq { fn equals(&&other: self) -> bool; } @@ -2530,15 +2531,15 @@ impl of eq for int { Notice that `equals` takes an `int` argument, rather than a `self` argument, in an implementation for type `int`. -## Casting to an interface type +## Casting to an trait type The above allows us to define functions that polymorphically act on -values of *an* unknown type that conforms to a given interface. +values of *an* unknown type that conforms to a given trait. However, consider this function: ~~~~ # type circle = int; type rectangle = int; -# iface drawable { fn draw(); } +# trait drawable { fn draw(); } # impl of drawable for int { fn draw() {} } # fn new_circle() -> int { 1 } fn draw_all(shapes: ~[T]) { @@ -2549,14 +2550,14 @@ fn draw_all(shapes: ~[T]) { ~~~~ You can call that on an array of circles, or an array of squares -(assuming those have suitable `drawable` interfaces defined), but not +(assuming those have suitable `drawable` traits defined), but not on an array containing both circles and squares. -When this is needed, an interface name can be used as a type, causing +When this is needed, a trait name can be used as a type, causing the function to be written simply like this: ~~~~ -# iface drawable { fn draw(); } +# trait drawable { fn draw(); } fn draw_all(shapes: ~[drawable]) { for shapes.each |shape| { shape.draw(); } } @@ -2571,11 +2572,11 @@ is very similar to the 'vtables' used in most object-oriented languages. To construct such a value, you use the `as` operator to cast a value -to an interface type: +to a trait type: ~~~~ # type circle = int; type rectangle = int; -# iface drawable { fn draw(); } +# trait drawable { fn draw(); } # impl of drawable for int { fn draw() {} } # fn new_circle() -> int { 1 } # fn new_rectangle() -> int { 2 } @@ -2594,10 +2595,10 @@ Note that the allocation of a box is somewhat more expensive than simply using a type parameter and passing in the value as-is, and much more expensive than statically resolved method calls. -## Interface-less implementations +## Trait-less implementations If you only intend to use an implementation for static overloading, -and there is no interface available that it conforms to, you are free +and there is no trait available that it conforms to, you are free to leave off the `of` clause. However, this is only possible when you are defining an implementation in the same module as the receiver type, and the receiver type is a named type (i.e., an enum or a From 987814f11e4614b8aa712eb19cff78fbbe0d34fa Mon Sep 17 00:00:00 2001 From: Elliott Slaughter Date: Wed, 25 Jul 2012 12:06:03 -0700 Subject: [PATCH 08/24] Added debug flag to enable LLVM debug output. --- src/rustc/driver/driver.rs | 4 ++++ src/rustc/driver/session.rs | 4 +++- src/rustc/lib/llvm.rs | 3 +++ src/rustllvm/RustWrapper.cpp | 5 +++++ src/rustllvm/rustllvm.def.in | 1 + 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 52aa88e6cb63..369eccc6bed1 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -14,6 +14,7 @@ import io::{reader_util, writer_util}; import getopts::{optopt, optmulti, optflag, optflagopt, opt_present}; import back::{x86, x86_64}; import std::map::hashmap; +import lib::llvm::llvm; enum pp_mode {ppm_normal, ppm_expanded, ppm_typed, ppm_identified, ppm_expanded_identified } @@ -440,6 +441,9 @@ fn build_session_options(match: getopts::match, } debugging_opts |= this_bit; } + if debugging_opts & session::debug_llvm != 0 { + llvm::LLVMSetDebug(1); + } let output_type = if parse_only || no_trans { diff --git a/src/rustc/driver/session.rs b/src/rustc/driver/session.rs index 64ae30895c41..61ef9f73c3f3 100644 --- a/src/rustc/driver/session.rs +++ b/src/rustc/driver/session.rs @@ -40,6 +40,7 @@ const borrowck_stats: uint = 1024u; const borrowck_note_pure: uint = 2048; const borrowck_note_loan: uint = 4096; const no_landing_pads: uint = 8192; +const debug_llvm: uint = 16384; fn debugging_opts_map() -> ~[(~str, ~str, uint)] { ~[(~"ppregions", ~"prettyprint regions with \ @@ -61,7 +62,8 @@ fn debugging_opts_map() -> ~[(~str, ~str, uint)] { (~"borrowck-note-loan", ~"note where loans are req'd", borrowck_note_loan), (~"no-landing-pads", ~"omit landing pads for unwinding", - no_landing_pads) + no_landing_pads), + (~"debug-llvm", ~"enable debug output from LLVM", debug_llvm) ] } diff --git a/src/rustc/lib/llvm.rs b/src/rustc/lib/llvm.rs index 376012dcf4e5..7dbefa8e4980 100644 --- a/src/rustc/lib/llvm.rs +++ b/src/rustc/lib/llvm.rs @@ -969,6 +969,9 @@ extern mod llvm { fn LLVMConstNamedStruct(S: TypeRef, ConstantVals: *ValueRef, Count: c_uint) -> ValueRef; + + /** Enables LLVM debug output. */ + fn LLVMSetDebug(Enabled: c_int); } fn SetInstructionCallConv(Instr: ValueRef, CC: CallConv) { diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index a9f759b26aac..4a927744f07a 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Support/Host.h" +#include "llvm/Support/Debug.h" #include "llvm-c/Core.h" #include "llvm-c/BitReader.h" #include "llvm-c/Object.h" @@ -185,3 +186,7 @@ extern "C" LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef B, unwrap(target), unwrap(source), order)); } + +extern "C" void LLVMSetDebug(int Enabled) { + DebugFlag = Enabled; +} diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index f3a3d7f4f23b..64b560999bec 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -528,6 +528,7 @@ LLVMSetAlignment LLVMSetCleanup LLVMSetCurrentDebugLocation LLVMSetDataLayout +LLVMSetDebug LLVMSetFunctionCallConv LLVMSetGC LLVMSetGlobalConstant From 3aee39a6ec910bde6ae9a5423b11aaaad4a1b089 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 25 Jul 2012 17:29:34 -0700 Subject: [PATCH 09/24] Add #[inline(never)], and also fixed inlining on vec::push --- src/libcore/dvec.rs | 5 +++++ src/libcore/vec.rs | 20 ++++++++++++++------ src/libstd/smallintmap.rs | 4 +++- src/libsyntax/attr.rs | 6 +++++- src/rustc/metadata/encoder.rs | 4 ++-- src/rustc/middle/trans/base.rs | 1 + 6 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/libcore/dvec.rs b/src/libcore/dvec.rs index bdbdb6cef16b..60cb1b51be68 100644 --- a/src/libcore/dvec.rs +++ b/src/libcore/dvec.rs @@ -108,6 +108,11 @@ impl private_methods for dvec { // almost nothing works without the copy bound due to limitations // around closures. impl extensions for dvec { + /// Reserves space for N elements + fn reserve(count: uint) { + vec::reserve(self.data, count) + } + /** * Swaps out the current vector and hands it off to a user-provided * function `f`. The function should transform it however is desired diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 5aa2f35029ab..c07dd9b8224c 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -509,10 +509,7 @@ fn push(&v: ~[const T], +initval: T) { let repr: **unsafe::vec_repr = ::unsafe::reinterpret_cast(addr_of(v)); let fill = (**repr).fill; if (**repr).alloc > fill { - (**repr).fill += sys::size_of::(); - let p = ptr::addr_of((**repr).data); - let p = ptr::offset(p, fill) as *mut T; - rusti::move_val_init(*p, initval); + push_fast(v, initval); } else { push_slow(v, initval); @@ -520,9 +517,21 @@ fn push(&v: ~[const T], +initval: T) { } } +// This doesn't bother to make sure we have space. +#[inline(always)] // really pretty please +unsafe fn push_fast(&v: ~[const T], +initval: T) { + let repr: **unsafe::vec_repr = ::unsafe::reinterpret_cast(addr_of(v)); + let fill = (**repr).fill; + (**repr).fill += sys::size_of::(); + let p = ptr::addr_of((**repr).data); + let p = ptr::offset(p, fill) as *mut T; + rusti::move_val_init(*p, initval); +} + +#[inline(never)] fn push_slow(&v: ~[const T], +initval: T) { reserve_at_least(v, v.len() + 1u); - push(v, initval); + unsafe { push_fast(v, initval) } } // Unchecked vector indexing @@ -644,7 +653,6 @@ fn grow_fn(&v: ~[const T], n: uint, op: init_op) { * of the vector, expands the vector by replicating `initval` to fill the * intervening space. */ -#[inline(always)] fn grow_set(&v: ~[mut T], index: uint, initval: T, val: T) { if index >= len(v) { grow(v, index - len(v) + 1u, initval); } v[index] = val; diff --git a/src/libstd/smallintmap.rs b/src/libstd/smallintmap.rs index 112a55ab67d8..09f14f4f63e6 100644 --- a/src/libstd/smallintmap.rs +++ b/src/libstd/smallintmap.rs @@ -17,7 +17,8 @@ enum smallintmap { /// Create a smallintmap fn mk() -> smallintmap { - ret smallintmap_(@{v: dvec()}); + let v = dvec(); + ret smallintmap_(@{v: v}); } /** @@ -26,6 +27,7 @@ fn mk() -> smallintmap { */ #[inline(always)] fn insert(self: smallintmap, key: uint, val: T) { + //#error("inserting key %?", key); self.v.grow_set_elt(key, none, some(val)); } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 859bc70bfd64..4587a5b8b297 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -364,7 +364,8 @@ fn foreign_abi(attrs: ~[ast::attribute]) -> either<~str, ast::foreign_abi> { enum inline_attr { ia_none, ia_hint, - ia_always + ia_always, + ia_never, } /// True if something like #[inline] is found in the list of attrs. @@ -376,6 +377,9 @@ fn find_inline_attr(attrs: ~[ast::attribute]) -> inline_attr { ast::meta_list(@~"inline", items) { if !vec::is_empty(find_meta_items_by_name(items, ~"always")) { ia_always + } else if !vec::is_empty( + find_meta_items_by_name(items, ~"never")) { + ia_never } else { ia_hint } diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index 69e97f7e9db6..b2847b3acc53 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -545,8 +545,8 @@ fn purity_fn_family(p: purity) -> char { fn should_inline(attrs: ~[attribute]) -> bool { alt attr::find_inline_attr(attrs) { - attr::ia_none { false } - attr::ia_hint | attr::ia_always { true } + attr::ia_none | attr::ia_never { false } + attr::ia_hint | attr::ia_always { true } } } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 209bb6ee7c2c..94a4a30021db 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -456,6 +456,7 @@ fn set_inline_hint_if_appr(attrs: ~[ast::attribute], alt attr::find_inline_attr(attrs) { attr::ia_hint { set_inline_hint(llfn); } attr::ia_always { set_always_inline(llfn); } + attr::ia_never { set_no_inline(llfn); } attr::ia_none { /* fallthrough */ } } } From e1d4bd463c29e4224f0ac41652d75ffac8080683 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 25 Jul 2012 18:00:29 -0700 Subject: [PATCH 10/24] 3x faster typechecking --- src/libstd/smallintmap.rs | 2 +- src/rustc/middle/typeck/check.rs | 12 ++++++------ src/rustc/middle/typeck/check/writeback.rs | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libstd/smallintmap.rs b/src/libstd/smallintmap.rs index 09f14f4f63e6..02948f58fc4d 100644 --- a/src/libstd/smallintmap.rs +++ b/src/libstd/smallintmap.rs @@ -27,7 +27,7 @@ fn mk() -> smallintmap { */ #[inline(always)] fn insert(self: smallintmap, key: uint, val: T) { - //#error("inserting key %?", key); + //io::println(#fmt("%?", key)); self.v.grow_set_elt(key, none, some(val)); } diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 599bfc18b136..0b78fd1a5054 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -109,7 +109,7 @@ type fn_ctxt_ = in_scope_regions: isr_alist, - node_types: smallintmap::smallintmap, + node_types: hashmap, node_type_substs: hashmap, ccx: @crate_ctxt}; @@ -132,7 +132,7 @@ fn blank_fn_ctxt(ccx: @crate_ctxt, rty: ty::t, mut region_lb: region_bnd, mut region_ub: region_bnd, in_scope_regions: @nil, - node_types: smallintmap::mk(), + node_types: map::int_hash(), node_type_substs: map::int_hash(), ccx: ccx}) } @@ -218,7 +218,7 @@ fn check_fn(ccx: @crate_ctxt, {infcx: infer::new_infer_ctxt(tcx), locals: int_hash(), purity: decl.purity, - node_types: smallintmap::mk(), + node_types: map::int_hash(), node_type_substs: map::int_hash()} } some(fcx) { @@ -490,7 +490,7 @@ impl methods for @fn_ctxt { fn write_ty(node_id: ast::node_id, ty: ty::t) { #debug["write_ty(%d, %s) in fcx %s", node_id, ty_to_str(self.tcx(), ty), self.tag()]; - self.node_types.insert(node_id as uint, ty); + self.node_types.insert(node_id, ty); } fn write_substs(node_id: ast::node_id, +substs: ty::substs) { if !ty::substs_is_noop(substs) { @@ -515,7 +515,7 @@ impl methods for @fn_ctxt { } fn expr_ty(ex: @ast::expr) -> ty::t { - alt self.node_types.find(ex.id as uint) { + alt self.node_types.find(ex.id) { some(t) { t } none { self.tcx().sess.bug(#fmt["no type for expr %d (%s) in fcx %s", @@ -524,7 +524,7 @@ impl methods for @fn_ctxt { } } fn node_ty(id: ast::node_id) -> ty::t { - alt self.node_types.find(id as uint) { + alt self.node_types.find(id) { some(t) { t } none { self.tcx().sess.bug( diff --git a/src/rustc/middle/typeck/check/writeback.rs b/src/rustc/middle/typeck/check/writeback.rs index 720c85bf18e2..f97ff61dbf4d 100644 --- a/src/rustc/middle/typeck/check/writeback.rs +++ b/src/rustc/middle/typeck/check/writeback.rs @@ -59,7 +59,7 @@ fn resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id) fn maybe_resolve_type_vars_for_node(wbcx: wb_ctxt, sp: span, id: ast::node_id) -> option { - if wbcx.fcx.node_types.contains_key(id as uint) { + if wbcx.fcx.node_types.contains_key(id) { resolve_type_vars_for_node(wbcx, sp, id) } else { none From da80bd17c30db599de43355f07783ee0bf846162 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 25 Jul 2012 18:36:18 -0700 Subject: [PATCH 11/24] rustc: Introduce a lang_items pass, part of coherence and operator overloading. This will also help us remove kinds. --- src/libcore/core.rc | 1 + src/libcore/core.rs | 5 + src/rustc/driver/driver.rs | 3 + src/rustc/metadata/csearch.rs | 9 ++ src/rustc/metadata/decoder.rs | 13 ++ src/rustc/metadata/encoder.rs | 1 + src/rustc/middle/lang_items.rs | 209 +++++++++++++++++++++++++++++++++ src/rustc/rustc.rc | 1 + 8 files changed, 242 insertions(+) create mode 100644 src/rustc/middle/lang_items.rs diff --git a/src/libcore/core.rc b/src/libcore/core.rc index d298ff15a9ec..11e305e22e8b 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -161,6 +161,7 @@ mod tuple; // Ubiquitous-utility-type modules +mod ops; mod cmp; mod num; mod hash; diff --git a/src/libcore/core.rs b/src/libcore/core.rs index 4738574fdb47..fdf535241888 100644 --- a/src/libcore/core.rs +++ b/src/libcore/core.rs @@ -30,6 +30,8 @@ import float::num; import f32::num; import f64::num; import num::num; +import ops::{const, copy, send, owned}; +import ops::{add, sub, mul, div, modulo, neg, bitops, index}; export path, option, some, none, unreachable; export extensions; @@ -42,6 +44,9 @@ export immutable_copyable_vector, iter_trait_extensions, vec_concat; export base_iter, copyable_iter, extended_iter; export tuple_ops, extended_tuple_ops; export ptr; +// The following exports are the core operators and kinds +export const, copy, send, owned; +export add, sub, mul, div, modulo, neg, bitops, index; // Export the log levels as global constants. Higher levels mean // more-verbosity. Error is the bottom level, default logging level is diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 369eccc6bed1..a6734b285a19 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -170,6 +170,9 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg, session::sess_os_to_meta_os(sess.targ_cfg.os), sess.opts.static)); + time(time_passes, ~"language item collection", || + middle::lang_items::collect_language_items(crate, sess)); + let { def_map: def_map, exp_map: exp_map, impl_map: impl_map, diff --git a/src/rustc/metadata/csearch.rs b/src/rustc/metadata/csearch.rs index 7f97583fe3d2..0ba76c49246a 100644 --- a/src/rustc/metadata/csearch.rs +++ b/src/rustc/metadata/csearch.rs @@ -25,6 +25,7 @@ export get_enum_variants; export get_impls_for_mod; export get_trait_methods; export get_method_names_if_trait; +export get_item_attrs; export each_path; export get_type; export get_impl_traits; @@ -149,6 +150,14 @@ fn get_method_names_if_trait(cstore: cstore::cstore, def: ast::def_id) ret decoder::get_method_names_if_trait(cdata, def.node); } +fn get_item_attrs(cstore: cstore::cstore, + def_id: ast::def_id, + f: fn(~[@ast::meta_item])) { + + let cdata = cstore::get_crate_data(cstore, def_id.crate); + decoder::get_item_attrs(cdata, def_id.node, f) +} + fn get_class_fields(tcx: ty::ctxt, def: ast::def_id) -> ~[ty::field_ty] { let cstore = tcx.cstore; let cdata = cstore::get_crate_data(cstore, def.crate); diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index 3ff9ded3f1ef..a5261d039c19 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -39,6 +39,7 @@ export get_crate_vers; export get_impls_for_mod; export get_trait_methods; export get_method_names_if_trait; +export get_item_attrs; export get_crate_module_paths; export def_like; export dl_def; @@ -659,6 +660,18 @@ fn get_method_names_if_trait(cdata: cmd, node_id: ast::node_id) ret some(resulting_method_names); } +fn get_item_attrs(cdata: cmd, + node_id: ast::node_id, + f: fn(~[@ast::meta_item])) { + + let item = lookup_item(node_id, cdata.data); + do ebml::tagged_docs(item, tag_attributes) |attributes| { + do ebml::tagged_docs(attributes, tag_attribute) |attribute| { + f(get_meta_items(attribute)); + } + } +} + // Helper function that gets either fields or methods fn get_class_members(cdata: cmd, id: ast::node_id, p: fn(char) -> bool) -> ~[ty::field_ty] { diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index b2847b3acc53..b4818959344b 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -759,6 +759,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, encode_type_param_bounds(ebml_w, ecx, tps); encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); encode_name(ebml_w, item.ident); + encode_attributes(ebml_w, item.attrs); let mut i = 0u; for vec::each(*ty::trait_methods(tcx, local_def(item.id))) |mty| { alt ms[i] { diff --git a/src/rustc/middle/lang_items.rs b/src/rustc/middle/lang_items.rs new file mode 100644 index 000000000000..2353da51f981 --- /dev/null +++ b/src/rustc/middle/lang_items.rs @@ -0,0 +1,209 @@ +// Detecting language items. +// +// Language items are items that represent concepts intrinsic to the language +// itself. Examples are: +// +// * Traits that specify "kinds"; e.g. "const", "copy", "send". +// +// * Traits that represent operators; e.g. "add", "sub", "index". +// +// * Functions called by the compiler itself. + +import driver::session::session; +import metadata::csearch::{each_path, get_item_attrs}; +import metadata::cstore::{iter_crate_data}; +import metadata::decoder::{dl_def, dl_field, dl_impl}; +import syntax::ast::{crate, def_id, def_ty, lit_str, meta_item, meta_list}; +import syntax::ast::{meta_name_value, meta_word}; +import syntax::ast_util::{local_def}; +import syntax::visit::{default_simple_visitor, mk_simple_visitor}; +import syntax::visit::{visit_crate, visit_item}; + +import std::map::{hashmap, str_hash}; +import str_eq = str::eq; + +class LanguageItems { + let mut const_trait: option; + let mut copy_trait: option; + let mut send_trait: option; + let mut owned_trait: option; + + let mut add_trait: option; + let mut sub_trait: option; + let mut mul_trait: option; + let mut div_trait: option; + let mut modulo_trait: option; + let mut neg_trait: option; + let mut bitops_trait: option; + let mut index_trait: option; + + new() { + self.const_trait = none; + self.copy_trait = none; + self.send_trait = none; + self.owned_trait = none; + + self.add_trait = none; + self.sub_trait = none; + self.mul_trait = none; + self.div_trait = none; + self.modulo_trait = none; + self.neg_trait = none; + self.bitops_trait = none; + self.index_trait = none; + } +} + +class LanguageItemCollector { + let items: LanguageItems; + + let crate: @crate; + let session: session; + + let item_refs: hashmap<~str,&mut option>; + + new(crate: @crate, session: session) { + self.crate = crate; + self.session = session; + + self.items = LanguageItems(); + + self.item_refs = str_hash(); + } + + // XXX: Needed to work around an issue with constructors. + fn init() { + self.item_refs.insert(~"const", &mut self.items.const_trait); + self.item_refs.insert(~"copy", &mut self.items.copy_trait); + self.item_refs.insert(~"send", &mut self.items.send_trait); + self.item_refs.insert(~"owned", &mut self.items.owned_trait); + + self.item_refs.insert(~"add", &mut self.items.add_trait); + self.item_refs.insert(~"sub", &mut self.items.sub_trait); + self.item_refs.insert(~"mul", &mut self.items.mul_trait); + self.item_refs.insert(~"div", &mut self.items.div_trait); + self.item_refs.insert(~"modulo", &mut self.items.modulo_trait); + self.item_refs.insert(~"neg", &mut self.items.neg_trait); + self.item_refs.insert(~"bitops", &mut self.items.bitops_trait); + self.item_refs.insert(~"index", &mut self.items.index_trait); + } + + fn match_and_collect_meta_item(item_def_id: def_id, + meta_item: meta_item) { + + alt meta_item.node { + meta_name_value(key, literal) => { + alt literal.node { + lit_str(value) => { + self.match_and_collect_item(item_def_id, + *key, + *value); + } + _ => { + // Skip. + } + } + } + meta_word(*) | meta_list(*) { + // Skip. + } + } + } + + fn match_and_collect_item(item_def_id: def_id, key: ~str, value: ~str) { + if !str_eq(key, ~"lang") { + ret; // Didn't match. + } + + alt self.item_refs.find(value) { + none => { + // Didn't match. + } + some(item_ref) => { + // Check for duplicates. + alt copy *item_ref { + some(original_def_id) + if original_def_id != item_def_id => { + + self.session.warn(#fmt("duplicate entry for `%s`", + value)); + } + some(_) | none => { + // OK. + } + } + + // Matched. + *item_ref = some(item_def_id); + } + } + } + + fn collect_local_language_items() { + let this = unsafe { ptr::addr_of(self) }; + visit_crate(*self.crate, (), mk_simple_visitor(@{ + visit_item: |item| { + for item.attrs.each |attribute| { + unsafe { + (*this).match_and_collect_meta_item(local_def(item + .id), + attribute.node + .value); + } + } + } + with *default_simple_visitor() + })); + } + + fn collect_external_language_items() { + let crate_store = self.session.cstore; + do iter_crate_data(crate_store) |crate_number, _crate_metadata| { + for each_path(crate_store, crate_number) |path_entry| { + let def_id; + alt path_entry.def_like { + dl_def(def_ty(did)) => { + def_id = did; + } + dl_def(_) | dl_impl(_) | dl_field { + // Skip this. + again; + } + } + + do get_item_attrs(crate_store, def_id) |meta_items| { + for meta_items.each |meta_item| { + self.match_and_collect_meta_item(def_id, *meta_item); + } + } + } + } + } + + fn check_completeness() { + for self.item_refs.each |key, item_ref| { + alt copy *item_ref { + none => { + self.session.warn(#fmt("no item found for `%s`", key)); + } + some(did) => { + // OK. + } + } + } + } + + fn collect() { + self.init(); + self.collect_local_language_items(); + self.collect_external_language_items(); + self.check_completeness(); + } +} + +fn collect_language_items(crate: @crate, session: session) -> LanguageItems { + let collector = LanguageItemCollector(crate, session); + collector.collect(); + copy collector.items +} + diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc index 406c46cc6c6a..b2cce508e57f 100644 --- a/src/rustc/rustc.rc +++ b/src/rustc/rustc.rc @@ -88,6 +88,7 @@ mod middle { mod region; mod const_eval; mod astencode; + mod lang_items; } mod front { From 10d8a68791ff2103a84c02783db4e3fd28f2cd87 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 25 Jul 2012 19:03:55 -0700 Subject: [PATCH 12/24] libcore: Add missing ops.rs --- src/libcore/ops.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/libcore/ops.rs diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs new file mode 100644 index 000000000000..61efe704974a --- /dev/null +++ b/src/libcore/ops.rs @@ -0,0 +1,66 @@ +// Core operators and kinds. + +#[lang="const"] +trait const { + // Empty. +} + +#[lang="copy"] +trait copy { + // Empty. +} + +#[lang="send"] +trait send { + // Empty. +} + +#[lang="owned"] +trait owned { + // Empty. +} + +#[lang="add"] +trait add { + pure fn add(rhs: RHS) -> Result; +} + +#[lang="sub"] +trait sub { + pure fn sub(rhs: RHS) -> Result; +} + +#[lang="mul"] +trait mul { + pure fn mul(rhs: RHS) -> Result; +} + +#[lang="div"] +trait div { + pure fn div(rhs: RHS) -> Result; +} + +#[lang="modulo"] +trait modulo { + pure fn modulo(rhs: RHS) -> Result; +} + +#[lang="neg"] +trait neg { + pure fn neg(rhs: RHS) -> Result; +} + +#[lang="bitops"] +trait bitops { + pure fn and(rhs: RHS) -> Result; + pure fn or(rhs: RHS) -> Result; + pure fn xor(rhs: RHS) -> Result; + pure fn shl(n: BitCount) -> Result; + pure fn shr(n: BitCount) -> Result; +} + +#[lang="index"] +trait index { + pure fn index(index: Index) -> Result; +} + From c953dad0b915deb81cf03ce6919096e60bb1e6b8 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 25 Jul 2012 18:52:59 -0700 Subject: [PATCH 13/24] Pick up changes from eds' unique-ptrs branch. --- src/llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm b/src/llvm index cc8c2479de69..5e5c8465696c 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit cc8c2479de6987aed367ce8fb2f343713056b189 +Subproject commit 5e5c8465696cbaa8197e391230a7b33cf99afafa From ab1defb1ce8d40d03fe0074b56d3066873f62911 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 25 Jul 2012 19:13:58 -0700 Subject: [PATCH 14/24] Make parsing about 0.3 seconds faster. --- src/libsyntax/parse/common.rs | 19 ++++++++++--------- src/libsyntax/parse/lexer.rs | 6 +++--- src/libsyntax/parse/parser.rs | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs index 9126bbb3be4d..e35b762f9720 100644 --- a/src/libsyntax/parse/common.rs +++ b/src/libsyntax/parse/common.rs @@ -141,17 +141,18 @@ impl parser_common of parser_common for parser { fn eat_keyword(word: ~str) -> bool { self.require_keyword(word); - // FIXME (#13042): this gratuitous use of @ is to - // workaround LLVM bug. - alt @self.token { - @token::IDENT(sid, false) { + let mut bump = false; + let val = alt self.token { + token::IDENT(sid, false) { if str::eq(word, *self.get_str(sid)) { - self.bump(); - ret true; - } else { ret false; } + bump = true; + true + } else { false } } - _ { ret false; } - } + _ { false } + }; + if bump { self.bump() } + val } fn expect_keyword(word: ~str) { diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 7afdc301b023..94e12e161859 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -14,7 +14,7 @@ iface reader { fn next_token() -> {tok: token::token, sp: span}; fn fatal(~str) -> !; fn span_diag() -> span_handler; - fn interner() -> @interner<@~str>; + pure fn interner() -> @interner<@~str>; fn peek() -> {tok: token::token, sp: span}; fn dup() -> reader; } @@ -79,7 +79,7 @@ impl string_reader_as_reader of reader for string_reader { self.span_diagnostic.span_fatal(copy self.peek_span, m) } fn span_diag() -> span_handler { self.span_diagnostic } - fn interner() -> @interner<@~str> { self.interner } + pure fn interner() -> @interner<@~str> { self.interner } fn peek() -> {tok: token::token, sp: span} { {tok: self.peek_tok, sp: self.peek_span} } @@ -101,7 +101,7 @@ impl tt_reader_as_reader of reader for tt_reader { self.sp_diag.span_fatal(copy self.cur_span, m); } fn span_diag() -> span_handler { self.sp_diag } - fn interner() -> @interner<@~str> { self.interner } + pure fn interner() -> @interner<@~str> { self.interner } fn peek() -> {tok: token::token, sp: span} { { tok: self.cur_tok, sp: self.cur_span } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index de772b0ff1cb..21248b496a47 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -232,7 +232,7 @@ class parser { fn warn(m: ~str) { self.sess.span_diagnostic.span_warn(copy self.span, m) } - fn get_str(i: token::str_num) -> @~str { + pure fn get_str(i: token::str_num) -> @~str { interner::get(*self.reader.interner(), i) } fn get_id() -> node_id { next_node_id(self.sess) } From fec749df169945f856fcfe0c5ee265616a224d3a Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 25 Jul 2012 15:28:36 -0700 Subject: [PATCH 15/24] Comments Only: Remove outdated FIXMEs. Fixes #2886. --- src/libsyntax/ext/pipes/ast_builder.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs index c9b35e561bb4..f367fb63985a 100644 --- a/src/libsyntax/ext/pipes/ast_builder.rs +++ b/src/libsyntax/ext/pipes/ast_builder.rs @@ -183,7 +183,6 @@ impl ast_builder of ext_ctxt_ast_builder for ext_ctxt { {mode: ast::infer(self.next_id()), ty: ty, ident: name, - // FIXME #2886: should this be the same as the infer id? id: self.next_id()} } @@ -280,7 +279,6 @@ impl ast_builder of ext_ctxt_ast_builder for ext_ctxt { } fn ty_path_ast_builder(path: @ast::path) -> @ast::ty { - // FIXME #2886: make sure the node ids are legal. @{id: self.next_id(), node: ast::ty_path(path, self.next_id()), span: self.empty_span()} From 96c6f57d18a26157117911a05152e135cfcee2ff Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 26 Jul 2012 14:11:46 -0700 Subject: [PATCH 16/24] Revert "Use pipes in compiletest" This reverts commit 2d15b6ef424016765c659305a4265813d2b498d0. This seems like a likely candidate for causing the recent lock_and_signal failures. I'll revert it for now to see if it fixes it and hopefully nail down the problem better. --- src/compiletest/compiletest.rs | 5 +++++ src/compiletest/procsrv.rs | 27 ++++++++++++--------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 1ee7edb4dc70..3ba358bfb934 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -8,6 +8,11 @@ import task; import core::result; import result::{ok, err}; +import comm::port; +import comm::chan; +import comm::send; +import comm::recv; + import common::config; import common::mode_run_pass; import common::mode_run_fail; diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index d93ae3f80177..35da5d2bc6d8 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -2,8 +2,6 @@ import run::spawn_process; import io::{writer_util, reader_util}; import libc::{c_int, pid_t}; -import pipes::chan; - export run; #[cfg(target_os = "win32")] @@ -60,30 +58,29 @@ fn run(lib_path: ~str, writeclose(pipe_in.out, input); - let p = pipes::port_set(); - let ch = p.chan(); + let p = comm::port(); + let ch = comm::chan(p); do task::spawn_sched(task::single_threaded) { let errput = readclose(pipe_err.in); - ch.send((2, errput)); + comm::send(ch, (2, errput)); } - let ch = p.chan(); do task::spawn_sched(task::single_threaded) { let output = readclose(pipe_out.in); - ch.send((1, output)); + comm::send(ch, (1, output)); } let status = run::waitpid(pid); let mut errs = ~""; let mut outs = ~""; let mut count = 2; while count > 0 { - alt p.recv() { - (1, s) { - outs = s; - } - (2, s) { - errs = s; - } - _ { fail } + let stream = comm::recv(p); + alt check stream { + (1, s) { + outs = s; + } + (2, s) { + errs = s; + } }; count -= 1; }; From d19b915bc40d36cdf9866bfd3cf160ddabc7cc9d Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Thu, 26 Jul 2012 14:29:24 -0700 Subject: [PATCH 17/24] Add test for issue 868 --- src/test/run-pass/issue-868.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/test/run-pass/issue-868.rs diff --git a/src/test/run-pass/issue-868.rs b/src/test/run-pass/issue-868.rs new file mode 100644 index 000000000000..dcc8c4e08db8 --- /dev/null +++ b/src/test/run-pass/issue-868.rs @@ -0,0 +1,15 @@ +fn f(g: fn() -> T) -> T { g() } + +fn main() { + let _x = f( | | { 10 }); + // used to be: cannot determine a type for this expression + f(| | { }); + // ditto + f( | | { ()}); + // always worked + let _: () = f(| | { }); + // empty block with no type info should compile too + let _ = f(||{}); + let _ = (||{}); +} + From 1dd8acd56acc189db2c0bb3266536d35646380b4 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 26 Jul 2012 14:42:44 -0700 Subject: [PATCH 18/24] core: Mark a bunch of numeric functions as pure --- src/libcore/cmp.rs | 8 +++---- src/libcore/f32.rs | 16 ++++++------- src/libcore/f64.rs | 16 ++++++------- src/libcore/float.rs | 44 ++++++++++++++++++------------------ src/libcore/int-template.rs | 20 ++++++++-------- src/libcore/num.rs | 18 +++++++-------- src/libcore/uint-template.rs | 20 ++++++++-------- src/libstd/cmp.rs | 10 ++++---- 8 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 1bdf3b9909ac..d10b9603af0d 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -1,10 +1,10 @@ /// Interfaces used for comparison. -iface ord { - fn lt(&&other: self) -> bool; +trait ord { + pure fn lt(&&other: self) -> bool; } -iface eq { - fn eq(&&other: self) -> bool; +trait eq { + pure fn eq(&&other: self) -> bool; } diff --git a/src/libcore/f32.rs b/src/libcore/f32.rs index c72aa6e3aef0..3e7bc0097f74 100644 --- a/src/libcore/f32.rs +++ b/src/libcore/f32.rs @@ -168,15 +168,15 @@ pure fn log2(n: f32) -> f32 { } impl num of num::num for f32 { - fn add(&&other: f32) -> f32 { ret self + other; } - fn sub(&&other: f32) -> f32 { ret self - other; } - fn mul(&&other: f32) -> f32 { ret self * other; } - fn div(&&other: f32) -> f32 { ret self / other; } - fn modulo(&&other: f32) -> f32 { ret self % other; } - fn neg() -> f32 { ret -self; } + pure fn add(&&other: f32) -> f32 { ret self + other; } + pure fn sub(&&other: f32) -> f32 { ret self - other; } + pure fn mul(&&other: f32) -> f32 { ret self * other; } + pure fn div(&&other: f32) -> f32 { ret self / other; } + pure fn modulo(&&other: f32) -> f32 { ret self % other; } + pure fn neg() -> f32 { ret -self; } - fn to_int() -> int { ret self as int; } - fn from_int(n: int) -> f32 { ret n as f32; } + pure fn to_int() -> int { ret self as int; } + pure fn from_int(n: int) -> f32 { ret n as f32; } } // diff --git a/src/libcore/f64.rs b/src/libcore/f64.rs index 40488d9f8f4f..9e84c432bad2 100644 --- a/src/libcore/f64.rs +++ b/src/libcore/f64.rs @@ -195,15 +195,15 @@ pure fn log2(n: f64) -> f64 { } impl num of num::num for f64 { - fn add(&&other: f64) -> f64 { ret self + other; } - fn sub(&&other: f64) -> f64 { ret self - other; } - fn mul(&&other: f64) -> f64 { ret self * other; } - fn div(&&other: f64) -> f64 { ret self / other; } - fn modulo(&&other: f64) -> f64 { ret self % other; } - fn neg() -> f64 { ret -self; } + pure fn add(&&other: f64) -> f64 { ret self + other; } + pure fn sub(&&other: f64) -> f64 { ret self - other; } + pure fn mul(&&other: f64) -> f64 { ret self * other; } + pure fn div(&&other: f64) -> f64 { ret self / other; } + pure fn modulo(&&other: f64) -> f64 { ret self % other; } + pure fn neg() -> f64 { ret -self; } - fn to_int() -> int { ret self as int; } - fn from_int(n: int) -> f64 { ret n as f64; } + pure fn to_int() -> int { ret self as int; } + pure fn from_int(n: int) -> f64 { ret n as f64; } } // diff --git a/src/libcore/float.rs b/src/libcore/float.rs index 0139c60873b8..8b8cc4664dc8 100644 --- a/src/libcore/float.rs +++ b/src/libcore/float.rs @@ -403,32 +403,32 @@ fn pow_with_uint(base: uint, pow: uint) -> float { ret total; } -fn is_positive(x: float) -> bool { f64::is_positive(x as f64) } -fn is_negative(x: float) -> bool { f64::is_negative(x as f64) } -fn is_nonpositive(x: float) -> bool { f64::is_nonpositive(x as f64) } -fn is_nonnegative(x: float) -> bool { f64::is_nonnegative(x as f64) } -fn is_zero(x: float) -> bool { f64::is_zero(x as f64) } -fn is_infinite(x: float) -> bool { f64::is_infinite(x as f64) } -fn is_finite(x: float) -> bool { f64::is_finite(x as f64) } -fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) } +pure fn is_positive(x: float) -> bool { f64::is_positive(x as f64) } +pure fn is_negative(x: float) -> bool { f64::is_negative(x as f64) } +pure fn is_nonpositive(x: float) -> bool { f64::is_nonpositive(x as f64) } +pure fn is_nonnegative(x: float) -> bool { f64::is_nonnegative(x as f64) } +pure fn is_zero(x: float) -> bool { f64::is_zero(x as f64) } +pure fn is_infinite(x: float) -> bool { f64::is_infinite(x as f64) } +pure fn is_finite(x: float) -> bool { f64::is_finite(x as f64) } +pure fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) } -fn abs(x: float) -> float { f64::abs(x as f64) as float } -fn sqrt(x: float) -> float { f64::sqrt(x as f64) as float } -fn atan(x: float) -> float { f64::atan(x as f64) as float } -fn sin(x: float) -> float { f64::sin(x as f64) as float } -fn cos(x: float) -> float { f64::cos(x as f64) as float } -fn tan(x: float) -> float { f64::tan(x as f64) as float } +pure fn abs(x: float) -> float { f64::abs(x as f64) as float } +pure fn sqrt(x: float) -> float { f64::sqrt(x as f64) as float } +pure fn atan(x: float) -> float { f64::atan(x as f64) as float } +pure fn sin(x: float) -> float { f64::sin(x as f64) as float } +pure fn cos(x: float) -> float { f64::cos(x as f64) as float } +pure fn tan(x: float) -> float { f64::tan(x as f64) as float } impl num of num::num for float { - fn add(&&other: float) -> float { ret self + other; } - fn sub(&&other: float) -> float { ret self - other; } - fn mul(&&other: float) -> float { ret self * other; } - fn div(&&other: float) -> float { ret self / other; } - fn modulo(&&other: float) -> float { ret self % other; } - fn neg() -> float { ret -self; } + pure fn add(&&other: float) -> float { ret self + other; } + pure fn sub(&&other: float) -> float { ret self - other; } + pure fn mul(&&other: float) -> float { ret self * other; } + pure fn div(&&other: float) -> float { ret self / other; } + pure fn modulo(&&other: float) -> float { ret self % other; } + pure fn neg() -> float { ret -self; } - fn to_int() -> int { ret self as int; } - fn from_int(n: int) -> float { ret n as float; } + pure fn to_int() -> int { ret self as int; } + pure fn from_int(n: int) -> float { ret n as float; } } #[test] diff --git a/src/libcore/int-template.rs b/src/libcore/int-template.rs index 02ce125e35cf..2b950e4a7977 100644 --- a/src/libcore/int-template.rs +++ b/src/libcore/int-template.rs @@ -112,27 +112,27 @@ fn to_str_bytes(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U { fn str(i: T) -> ~str { ret to_str(i, 10u); } impl ord of ord for T { - fn lt(&&other: T) -> bool { + pure fn lt(&&other: T) -> bool { ret self < other; } } impl eq of eq for T { - fn eq(&&other: T) -> bool { + pure fn eq(&&other: T) -> bool { ret self == other; } } impl num of num::num for T { - fn add(&&other: T) -> T { ret self + other; } - fn sub(&&other: T) -> T { ret self - other; } - fn mul(&&other: T) -> T { ret self * other; } - fn div(&&other: T) -> T { ret self / other; } - fn modulo(&&other: T) -> T { ret self % other; } - fn neg() -> T { ret -self; } + pure fn add(&&other: T) -> T { ret self + other; } + pure fn sub(&&other: T) -> T { ret self - other; } + pure fn mul(&&other: T) -> T { ret self * other; } + pure fn div(&&other: T) -> T { ret self / other; } + pure fn modulo(&&other: T) -> T { ret self % other; } + pure fn neg() -> T { ret -self; } - fn to_int() -> int { ret self as int; } - fn from_int(n: int) -> T { ret n as T; } + pure fn to_int() -> int { ret self as int; } + pure fn from_int(n: int) -> T { ret n as T; } } impl times of iter::times for T { diff --git a/src/libcore/num.rs b/src/libcore/num.rs index 130b259c1dfd..038685276559 100644 --- a/src/libcore/num.rs +++ b/src/libcore/num.rs @@ -1,17 +1,17 @@ /// An interface for numbers. -iface num { +trait num { // FIXME: Cross-crate overloading doesn't work yet. (#2615) // FIXME: Interface inheritance. (#2616) - fn add(&&other: self) -> self; - fn sub(&&other: self) -> self; - fn mul(&&other: self) -> self; - fn div(&&other: self) -> self; - fn modulo(&&other: self) -> self; - fn neg() -> self; + pure fn add(&&other: self) -> self; + pure fn sub(&&other: self) -> self; + pure fn mul(&&other: self) -> self; + pure fn div(&&other: self) -> self; + pure fn modulo(&&other: self) -> self; + pure fn neg() -> self; - fn to_int() -> int; - fn from_int(n: int) -> self; // FIXME (#2376) Static functions. + pure fn to_int() -> int; + pure fn from_int(n: int) -> self; // FIXME (#2376) Static functions. // n.b. #2376 is for classes, not ifaces, but it could be generalized... } diff --git a/src/libcore/uint-template.rs b/src/libcore/uint-template.rs index 75e17cd6a9b0..9561ed4e65f8 100644 --- a/src/libcore/uint-template.rs +++ b/src/libcore/uint-template.rs @@ -53,27 +53,27 @@ pure fn compl(i: T) -> T { } impl ord of ord for T { - fn lt(&&other: T) -> bool { + pure fn lt(&&other: T) -> bool { ret self < other; } } impl eq of eq for T { - fn eq(&&other: T) -> bool { + pure fn eq(&&other: T) -> bool { ret self == other; } } impl num of num::num for T { - fn add(&&other: T) -> T { ret self + other; } - fn sub(&&other: T) -> T { ret self - other; } - fn mul(&&other: T) -> T { ret self * other; } - fn div(&&other: T) -> T { ret self / other; } - fn modulo(&&other: T) -> T { ret self % other; } - fn neg() -> T { ret -self; } + pure fn add(&&other: T) -> T { ret self + other; } + pure fn sub(&&other: T) -> T { ret self - other; } + pure fn mul(&&other: T) -> T { ret self * other; } + pure fn div(&&other: T) -> T { ret self / other; } + pure fn modulo(&&other: T) -> T { ret self % other; } + pure fn neg() -> T { ret -self; } - fn to_int() -> int { ret self as int; } - fn from_int(n: int) -> T { ret n as T; } + pure fn to_int() -> int { ret self as int; } + pure fn from_int(n: int) -> T { ret n as T; } } /** diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs index a89148ecec9d..f74cbba23ce2 100644 --- a/src/libstd/cmp.rs +++ b/src/libstd/cmp.rs @@ -2,24 +2,24 @@ const fuzzy_epsilon: float = 1.0e-6; -iface fuzzy_eq { - fn fuzzy_eq(&&other: self) -> bool; +trait fuzzy_eq { + pure fn fuzzy_eq(&&other: self) -> bool; } impl fuzzy_eq of fuzzy_eq for float { - fn fuzzy_eq(&&other: float) -> bool { + pure fn fuzzy_eq(&&other: float) -> bool { ret float::abs(self - other) < fuzzy_epsilon; } } impl fuzzy_eq of fuzzy_eq for f32 { - fn fuzzy_eq(&&other: f32) -> bool { + pure fn fuzzy_eq(&&other: f32) -> bool { ret f32::abs(self - other) < (fuzzy_epsilon as f32); } } impl fuzzy_eq of fuzzy_eq for f64 { - fn fuzzy_eq(&&other: f64) -> bool { + pure fn fuzzy_eq(&&other: f64) -> bool { ret f64::abs(self - other) < (fuzzy_epsilon as f64); } } From c8ea9fc4c343470bf381f9258dbeac9fac1ca830 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Thu, 26 Jul 2012 14:47:05 -0700 Subject: [PATCH 19/24] Re-added test for Issue 935 -- not sure what happened to it --- src/test/run-pass/unreachable-code.rs | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/test/run-pass/unreachable-code.rs diff --git a/src/test/run-pass/unreachable-code.rs b/src/test/run-pass/unreachable-code.rs new file mode 100644 index 000000000000..0d1a49917512 --- /dev/null +++ b/src/test/run-pass/unreachable-code.rs @@ -0,0 +1,31 @@ +// xfail-pretty + +fn id(x: bool) -> bool { x } + +fn call_id() { + let c <- fail; + id(c); +} + +fn call_id_2() { id(true) && id(ret); } + +fn call_id_3() { id(ret) && id(ret); } + +fn log_fail() { log(error, fail); } + +fn log_ret() { log(error, ret); } + +fn log_break() { loop { log(error, break); } } + +fn log_again() { loop { log(error, again); } } + +fn ret_ret() -> int { ret (ret 2) + 3; } + +fn ret_guard() { + alt 2 { + x if (ret) { x; } + _ {} + } +} + +fn main() {} From 20c6f3c37a7ec90ed308ae564d78a38639ac8146 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Thu, 26 Jul 2012 14:51:10 -0700 Subject: [PATCH 20/24] Add xfailed test case for #3029 --- src/test/run-pass/issue-3029.rs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/test/run-pass/issue-3029.rs diff --git a/src/test/run-pass/issue-3029.rs b/src/test/run-pass/issue-3029.rs new file mode 100644 index 000000000000..352ada202e2a --- /dev/null +++ b/src/test/run-pass/issue-3029.rs @@ -0,0 +1,8 @@ +// xfail-test +fn fail_then_concat() { + let x = ~[], y = ~[3]; + fail; + x += y; + ~"good" + ~"bye"; +} + From de48b7d4c4bba0212080c9aeb63ac8a13bb04b06 Mon Sep 17 00:00:00 2001 From: Ben Blum Date: Wed, 25 Jul 2012 19:51:12 -0400 Subject: [PATCH 21/24] dlist: cleanup a little; pretend to implement "cycle-collecting" destructor --- src/libcore/dlist.rs | 76 +++++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/src/libcore/dlist.rs b/src/libcore/dlist.rs index 087194f721df..d2215ea528ad 100644 --- a/src/libcore/dlist.rs +++ b/src/libcore/dlist.rs @@ -18,12 +18,28 @@ enum dlist_node = @{ mut next: dlist_link }; -// Needs to be an @-box so nodes can back-reference it. -enum dlist = @{ - mut size: uint, - mut hd: dlist_link, - mut tl: dlist_link -}; +class dlist_root { + let mut size: uint; + let mut hd: dlist_link; + let mut tl: dlist_link; + new() { + self.size = 0; self.hd = none; self.tl = none; + } + drop { + /* FIXME (#????) This doesn't work during task failure - the box + * annihilator might have killed some of our nodes already. This will + * be safe to uncomment when the box annihilator is safer. As is, + * this makes test_dlist_cyclic_link below crash the runtime. + // Empty the list. Not doing this explicitly would leave cyclic links + // around, not to be freed until cycle collection at task exit. + while self.hd.is_some() { + self.unlink(self.hd.get()); + } + */ + } +} + +type dlist = @dlist_root; impl private_methods for dlist_node { pure fn assert_links() { @@ -91,7 +107,7 @@ pure fn new_dlist_node(+data: T) -> dlist_node { /// Creates a new, empty dlist. pure fn new_dlist() -> dlist { - dlist(@{mut size: 0, mut hd: none, mut tl: none}) + @unchecked { dlist_root() } } /// Creates a new dlist with a single element @@ -118,7 +134,7 @@ fn concat(lists: dlist>) -> dlist { result } -impl private_methods for dlist { +impl private_methods for dlist_root { pure fn new_link(-data: T) -> dlist_link { some(dlist_node(@{data: data, mut linked: true, mut prev: none, mut next: none})) @@ -334,7 +350,7 @@ impl extensions for dlist { * to the other list's head. O(1). */ fn append(them: dlist) { - if box::ptr_eq(*self, *them) { + if box::ptr_eq(self, them) { fail ~"Cannot append a dlist to itself!" } if them.len() > 0 { @@ -351,7 +367,7 @@ impl extensions for dlist { * list's tail to this list's head. O(1). */ fn prepend(them: dlist) { - if box::ptr_eq(*self, *them) { + if box::ptr_eq(self, them) { fail ~"Cannot prepend a dlist to itself!" } if them.len() > 0 { @@ -366,15 +382,25 @@ impl extensions for dlist { /// Reverse the list's elements in place. O(n). fn reverse() { - let temp = new_dlist::(); - while !self.is_empty() { - let nobe = self.pop_n().get(); - nobe.linked = true; // meh, kind of disorganised. - temp.add_head(some(nobe)); + do option::while_some(self.hd) |nobe| { + let next_nobe = nobe.next; + self.remove(nobe); + self.make_mine(nobe); + self.add_head(some(nobe)); + next_nobe + } + } + + /** + * Remove everything from the list. This is important because the cyclic + * links won't otherwise be automatically refcounted-collected. O(n). + */ + fn clear() { + // Cute as it would be to simply detach the list and proclaim "O(1)!", + // the GC would still be a hidden O(n). Better to be honest about it. + while !self.is_empty() { + let _ = self.pop(); } - self.hd = temp.hd; - self.tl = temp.tl; - self.size = temp.size; } /// Iterate over nodes. @@ -847,7 +873,7 @@ mod tests { l.assert_consistent(); assert l.is_empty(); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_asymmetric_link() { + fn test_dlist_asymmetric_link() { let l = new_dlist::(); let _one = l.push_n(1); let two = l.push_n(2); @@ -855,7 +881,7 @@ mod tests { l.assert_consistent(); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_cyclic_list() { + fn test_dlist_cyclic_list() { let l = new_dlist::(); let one = l.push_n(1); let _two = l.push_n(2); @@ -865,32 +891,32 @@ mod tests { l.assert_consistent(); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_headless() { + fn test_dlist_headless() { new_dlist::().head(); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_insert_already_present_before() { + fn test_dlist_insert_already_present_before() { let l = new_dlist::(); let one = l.push_n(1); let two = l.push_n(2); l.insert_n_before(two, one); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_insert_already_present_after() { + fn test_dlist_insert_already_present_after() { let l = new_dlist::(); let one = l.push_n(1); let two = l.push_n(2); l.insert_n_after(one, two); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_insert_before_orphan() { + fn test_dlist_insert_before_orphan() { let l = new_dlist::(); let one = new_dlist_node(1); let two = new_dlist_node(2); l.insert_n_before(one, two); } #[test] #[should_fail] #[ignore(cfg(windows))] - fn test_insert_after_orphan() { + fn test_dlist_insert_after_orphan() { let l = new_dlist::(); let one = new_dlist_node(1); let two = new_dlist_node(2); From 5cf99c585ac16ad8c990c134333e61ea3bf591fb Mon Sep 17 00:00:00 2001 From: Ben Blum Date: Thu, 26 Jul 2012 00:23:42 -0400 Subject: [PATCH 22/24] dlist pop needs copy after all (#3024) --- src/libcore/dlist.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/libcore/dlist.rs b/src/libcore/dlist.rs index d2215ea528ad..cd36d14816cb 100644 --- a/src/libcore/dlist.rs +++ b/src/libcore/dlist.rs @@ -304,20 +304,6 @@ impl extensions for dlist { tl.map(|nobe| self.unlink(nobe)); tl } - /// Remove data from the head of the list. O(1). - fn pop() -> option { - do option::map_consume(self.pop_n()) |nobe| { - let dlist_node(@{ data: x, _ }) <- nobe; - x - } - } - /// Remove data from the tail of the list. O(1). - fn pop_tail() -> option { - do option::map_consume(self.pop_tail_n()) |nobe| { - let dlist_node(@{ data: x, _ }) <- nobe; - x - } - } /// Get the node at the list's head. O(1). pure fn peek_n() -> option> { self.hd } /// Get the node at the list's tail. O(1). @@ -399,7 +385,7 @@ impl extensions for dlist { // Cute as it would be to simply detach the list and proclaim "O(1)!", // the GC would still be a hidden O(n). Better to be honest about it. while !self.is_empty() { - let _ = self.pop(); + let _ = self.pop_n(); } } @@ -457,6 +443,10 @@ impl extensions for dlist { } impl extensions for dlist { + /// Remove data from the head of the list. O(1). + fn pop() -> option { self.pop_n().map (|nobe| nobe.data) } + /// Remove data from the tail of the list. O(1). + fn pop_tail() -> option { self.pop_tail_n().map (|nobe| nobe.data) } /// Get data at the list's head. O(1). pure fn peek() -> option { self.peek_n().map (|nobe| nobe.data) } /// Get data at the list's tail. O(1). @@ -622,6 +612,13 @@ mod tests { a.assert_consistent(); assert a.is_empty(); } #[test] + fn test_dlist_clear() { + let a = from_vec(~[5,4,3,2,1]); + a.clear(); + assert a.len() == 0; + a.assert_consistent(); + } + #[test] fn test_dlist_is_empty() { let empty = new_dlist::(); let full1 = from_vec(~[1,2,3]); From afd9a75c9ebf56b0a387928cdbef7d086200f534 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 26 Jul 2012 15:29:33 -0700 Subject: [PATCH 23/24] rustc: Fix cross-crate max/min-class-style constructors --- src/libsyntax/ast.rs | 2 +- src/libsyntax/ast_util.rs | 2 +- src/rustc/metadata/decoder.rs | 6 +++-- src/rustc/metadata/encoder.rs | 11 +++++++++- src/rustc/middle/astencode.rs | 4 ++-- src/rustc/middle/borrowck/categorization.rs | 2 +- src/rustc/middle/region.rs | 2 +- src/rustc/middle/resolve3.rs | 23 +++++++++++++------- src/rustc/middle/ty.rs | 2 +- src/rustc/middle/typeck/astconv.rs | 2 +- src/rustc/middle/typeck/check.rs | 4 ++-- src/rustc/middle/typeck/check/regionmanip.rs | 2 +- 12 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index fb27724e369d..4988adf93734 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -87,7 +87,7 @@ enum def { def_upvar(node_id /* local id of closed over var */, @def /* closed over def */, node_id /* expr node that creates the closure */), - def_class(def_id), + def_class(def_id, bool /* has constructor */), def_region(node_id) } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 37e8671facd3..0cf593efdc30 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -53,7 +53,7 @@ pure fn def_id_of_def(d: def) -> def_id { def_fn(id, _) | def_mod(id) | def_foreign_mod(id) | def_const(id) | def_variant(_, id) | def_ty(id) | def_ty_param(id, _) | - def_use(id) | def_class(id) { id } + def_use(id) | def_class(id, _) { id } def_arg(id, _) | def_local(id, _) | def_self(id) | def_upvar(id, _, _) | def_binding(id) | def_region(id) { local_def(id) diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index a5261d039c19..83684413641f 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -283,7 +283,8 @@ fn item_to_def_like(item: ebml::doc, did: ast::def_id, cnum: ast::crate_num) let fam_ch = item_family(item); alt fam_ch { 'c' { dl_def(ast::def_const(did)) } - 'C' { dl_def(ast::def_class(did)) } + 'C' { dl_def(ast::def_class(did, true)) } + 'S' { dl_def(ast::def_class(did, false)) } 'u' { dl_def(ast::def_fn(did, ast::unsafe_fn)) } 'f' { dl_def(ast::def_fn(did, ast::impure_fn)) } 'p' { dl_def(ast::def_fn(did, ast::pure_fn)) } @@ -707,7 +708,7 @@ fn family_has_type_params(fam_ch: char) -> bool { alt check fam_ch { 'c' | 'T' | 'm' | 'n' | 'g' | 'h' | 'j' { false } 'f' | 'u' | 'p' | 'F' | 'U' | 'P' | 'y' | 't' | 'v' | 'i' | 'I' | 'C' - | 'a' + | 'a' | 'S' { true } } } @@ -751,6 +752,7 @@ fn item_family_to_str(fam: char) -> ~str { 'i' { ret ~"impl"; } 'I' { ret ~"trait"; } 'C' { ret ~"class"; } + 'S' { ret ~"struct"; } 'g' { ret ~"public field"; } 'j' { ret ~"private field"; } } diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index b4818959344b..e1ed9fe396aa 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -663,7 +663,16 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, /* Now, make an item for the class itself */ ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'C'); + + alt ctor { + none { + encode_family(ebml_w, 'S'); + } + some(_) { + encode_family(ebml_w, 'C'); + } + } + encode_type_param_bounds(ebml_w, ecx, tps); encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); encode_name(ebml_w, item.ident); diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index 002b4d97e23a..1f5f7c4518d5 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -369,8 +369,8 @@ impl of tr for ast::def { ast::def_upvar(nid1, def, nid2) { ast::def_upvar(xcx.tr_id(nid1), @(*def).tr(xcx), xcx.tr_id(nid2)) } - ast::def_class(did) { - ast::def_class(did.tr(xcx)) + ast::def_class(did, has_constructor) { + ast::def_class(did.tr(xcx), has_constructor) } ast::def_region(nid) { ast::def_region(xcx.tr_id(nid)) } } diff --git a/src/rustc/middle/borrowck/categorization.rs b/src/rustc/middle/borrowck/categorization.rs index f5879145a9d4..4088945e550e 100644 --- a/src/rustc/middle/borrowck/categorization.rs +++ b/src/rustc/middle/borrowck/categorization.rs @@ -196,7 +196,7 @@ impl public_methods for borrowck_ctxt { ast::def_foreign_mod(_) | ast::def_const(_) | ast::def_use(_) | ast::def_variant(_, _) | ast::def_ty(_) | ast::def_prim_ty(_) | - ast::def_ty_param(_, _) | ast::def_class(_) | + ast::def_ty_param(_, _) | ast::def_class(_, _) | ast::def_region(_) { @{id:id, span:span, cat:cat_special(sk_static_item), lp:none, diff --git a/src/rustc/middle/region.rs b/src/rustc/middle/region.rs index ca00aeaa0f4a..cc6874bc9679 100644 --- a/src/rustc/middle/region.rs +++ b/src/rustc/middle/region.rs @@ -467,7 +467,7 @@ fn determine_rp_in_ty(ty: @ast::ty, alt ty.node { ast::ty_path(_, id) { alt cx.def_map.get(id) { - ast::def_ty(did) | ast::def_class(did) { + ast::def_ty(did) | ast::def_class(did, _) { if did.crate == ast::local_crate { cx.add_dep(did.node, cx.item_id); } else { diff --git a/src/rustc/middle/resolve3.rs b/src/rustc/middle/resolve3.rs index bddf83c429e7..e75268cde7f6 100644 --- a/src/rustc/middle/resolve3.rs +++ b/src/rustc/middle/resolve3.rs @@ -41,7 +41,7 @@ import syntax::visit::{visit_mod, visit_ty, vt}; import box::ptr_eq; import dvec::{dvec, extensions}; -import option::get; +import option::{get, is_some}; import str::{connect, split_str}; import vec::pop; @@ -604,7 +604,7 @@ class Resolver { let unused_import_lint_level: level; let trait_info: hashmap>; - let structs: hashmap; + let structs: hashmap; // The number of imports that are currently unresolved. let mut unresolved_imports: uint; @@ -926,7 +926,8 @@ class Resolver { (*name_bindings).define_impl(impl_info); // Record the def ID of this struct. - self.structs.insert(local_def(item.id), ()); + self.structs.insert(local_def(item.id), + is_some(optional_ctor)); visit_item(item, new_parent, visitor); } @@ -1378,12 +1379,16 @@ class Resolver { (*child_name_bindings).define_type(def); } - def_class(def_id) { + def_class(def_id, has_constructor) { #debug("(building reduced graph for external \ - crate) building value and type %s", - final_ident); - (*child_name_bindings).define_value(def); + crate) building type %s (value? %d)", + final_ident, + if has_constructor { 1 } else { 0 }); (*child_name_bindings).define_type(def); + + if has_constructor { + (*child_name_bindings).define_value(def); + } } def_self(*) | def_arg(*) | def_local(*) | def_prim_ty(*) | def_ty_param(*) | def_binding(*) | @@ -4201,7 +4206,9 @@ class Resolver { some(definition @ def_ty(class_id)) if self.structs.contains_key(class_id) { - self.record_def(expr.id, def_class(class_id)); + let has_constructor = self.structs.get(class_id); + let class_def = def_class(class_id, has_constructor); + self.record_def(expr.id, class_def); } _ { self.session.span_err(path.span, diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index b6b1873b1dc2..465aeebe3af2 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -2587,7 +2587,7 @@ fn type_err_to_str(cx: ctxt, err: type_err) -> ~str { fn def_has_ty_params(def: ast::def) -> bool { alt def { - ast::def_fn(_, _) | ast::def_variant(_, _) | ast::def_class(_) + ast::def_fn(_, _) | ast::def_variant(_, _) | ast::def_class(_, _) { true } _ { false } } diff --git a/src/rustc/middle/typeck/astconv.rs b/src/rustc/middle/typeck/astconv.rs index ebd189a15b71..3baea12ab484 100644 --- a/src/rustc/middle/typeck/astconv.rs +++ b/src/rustc/middle/typeck/astconv.rs @@ -270,7 +270,7 @@ fn ast_ty_to_ty( path_to_str(path))); } some(d) { d }}; alt a_def { - ast::def_ty(did) | ast::def_class(did) { + ast::def_ty(did) | ast::def_class(did, _) { ast_path_to_ty(self, rscope, did, path, id).ty } ast::def_prim_ty(nty) { diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 0b78fd1a5054..eaf0e90b26d6 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -1649,7 +1649,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, // Resolve the path. let class_id; alt tcx.def_map.find(id) { - some(ast::def_class(type_def_id)) => { + some(ast::def_class(type_def_id, _)) => { class_id = type_def_id; } _ => { @@ -2160,7 +2160,7 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> } ast::def_fn(id, _) | ast::def_const(id) | - ast::def_variant(_, id) | ast::def_class(id) { + ast::def_variant(_, id) | ast::def_class(id, _) { ret ty::lookup_item_type(fcx.ccx.tcx, id); } ast::def_binding(nid) { diff --git a/src/rustc/middle/typeck/check/regionmanip.rs b/src/rustc/middle/typeck/check/regionmanip.rs index 2231d9b320aa..d1052fd6a2ab 100644 --- a/src/rustc/middle/typeck/check/regionmanip.rs +++ b/src/rustc/middle/typeck/check/regionmanip.rs @@ -200,7 +200,7 @@ fn region_of(fcx: @fn_ctxt, expr: @ast::expr) -> ty::region { ast::def_foreign_mod(_) | ast::def_const(_) | ast::def_use(_) | ast::def_variant(_, _) | ast::def_ty(_) | ast::def_prim_ty(_) | - ast::def_ty_param(_, _) | ast::def_class(_) | + ast::def_ty_param(_, _) | ast::def_class(_, _) | ast::def_region(_) { ty::re_static } From 44631722ff234241cb7100103320a402fe4fdfa9 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Thu, 26 Jul 2012 15:46:34 -0700 Subject: [PATCH 24/24] Tutorial fixes Closes #3032 Closes #3031 Closes #3030 Closes #3028 --- doc/tutorial.md | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/doc/tutorial.md b/doc/tutorial.md index 59e1a9d7d9d2..ed32100c6fc6 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -735,9 +735,12 @@ of numeric literal patterns can be expressed with `to`. The underscore (`_`) is a wildcard pattern that matches everything. If the arm with the wildcard pattern was left off in the above -example, running it on a number greater than ten (or negative) would -cause a run-time failure. When no arm matches, `alt` constructs do not -silently fall through—they blow up instead. +example, the typechecker would reject it at compile time. `alt` +constructs must be exhaustive: they must have an arm covering every +possible case. (You may use the `alt check` construct to write a +non-exhaustive match, but it's highly undesirable to do so. You may +reason that the missing cases will never occur, but the typechecker +provides you with no assurance that your reasoning is correct.) A powerful application of pattern matching is *destructuring*, where you use the matching to get at the contents of data types. Remember @@ -2500,8 +2503,8 @@ impl of seq for ~[T] { } ~~~~ -Note that the implementation has to explicitly declare the its -parameter `T` before using it to specify its trait type. This is +Note that the implementation has to explicitly declare the type +parameter that it binds, `T`, before using it to specify its trait type. This is needed because it could also, for example, specify an implementation of `seq`—the `of` clause *refers* to a type, rather than defining one. @@ -2621,9 +2624,10 @@ OpenSSL libraries installed, it should 'just work'. ~~~~ {.xfail-test} use std; +import libc::c_uint; extern mod crypto { - fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8; + fn SHA1(src: *u8, sz: c_uint, out: *u8) -> *u8; } fn as_hex(data: ~[u8]) -> ~str { @@ -2635,7 +2639,7 @@ fn as_hex(data: ~[u8]) -> ~str { fn sha1(data: ~str) -> ~str unsafe { let bytes = str::bytes(data); let hash = crypto::SHA1(vec::unsafe::to_ptr(bytes), - vec::len(bytes), ptr::null()); + vec::len(bytes) as c_uint, ptr::null()); ret as_hex(vec::unsafe::from_buf(hash, 20u)); } @@ -2701,7 +2705,7 @@ return a pointer. ~~~~ {.xfail-test} # extern mod crypto { -fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8; +fn SHA1(src: *u8, sz: libc::c_uint, out: *u8) -> *u8; # } ~~~~ @@ -2792,7 +2796,7 @@ This pointer will become invalid as soon as the vector it points into is cleaned up, so you should be very careful how you use it. In this case, the local variable `bytes` outlives the pointer, so we're good. -Passing a null pointer as third argument to `SHA1` causes it to use a +Passing a null pointer as the third argument to `SHA1` makes it use a static buffer, and thus save us the effort of allocating memory ourselves. `ptr::null` is a generic function that will return an unsafe null pointer of the correct type (Rust generics are awesome @@ -2815,15 +2819,17 @@ microsecond-resolution timer. ~~~~ use std; -type timeval = {mut tv_sec: uint, - mut tv_usec: uint}; +import libc::c_ulonglong; + +type timeval = {mut tv_sec: c_ulonglong, + mut tv_usec: c_ulonglong}; #[nolink] -extern mod libc { +extern mod lib_c { fn gettimeofday(tv: *timeval, tz: *()) -> i32; } fn unix_time_in_microseconds() -> u64 unsafe { - let x = {mut tv_sec: 0u, mut tv_usec: 0u}; - libc::gettimeofday(ptr::addr_of(x), ptr::null()); + let x = {mut tv_sec: 0 as c_ulonglong, mut tv_usec: 0 as c_ulonglong}; + lib_c::gettimeofday(ptr::addr_of(x), ptr::null()); ret (x.tv_sec as u64) * 1000_000_u64 + (x.tv_usec as u64); } @@ -2839,8 +2845,8 @@ define a record type with the same contents, and declare The second argument to `gettimeofday` (the time zone) is not used by this program, so it simply declares it to be a pointer to the nil -type. Since null pointer look the same, no matter which type they are -supposed to point at, this is safe. +type. Since all null pointers have the same representation regardless of +their referent type, this is safe. # Tasks