From 090b247056a9dd2d4d4a32c631fe2f0ddd3e744d Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 8 Jan 2013 19:46:12 -0800 Subject: [PATCH 01/31] Spawn new tasks onto the primary scheduler by default. #3760 --- src/libcore/task/mod.rs | 100 ++++++++++++++++---------------------- src/libcore/task/spawn.rs | 23 +++++---- src/rt/rust.cpp | 4 +- src/rt/rust_builtin.cpp | 5 +- src/rt/rust_kernel.cpp | 91 +++++++++++++++++++++++++++------- src/rt/rust_kernel.h | 11 ++++- 6 files changed, 145 insertions(+), 89 deletions(-) diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index c6b0491786d7f..86d38a18c50b5 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -52,7 +52,7 @@ use prelude::*; use ptr; use result; use task::local_data_priv::{local_get, local_set}; -use task::rt::{task_id, rust_task}; +use task::rt::{task_id, sched_id, rust_task}; use task; use util; use util::replace; @@ -62,6 +62,12 @@ pub mod local_data; pub mod rt; pub mod spawn; +/// A handle to a scheduler +#[deriving_eq] +pub enum Scheduler { + SchedulerHandle(sched_id) +} + /// A handle to a task #[deriving_eq] pub enum Task { @@ -95,7 +101,21 @@ impl TaskResult : Eq { } /// Scheduler modes +#[deriving_eq] pub enum SchedMode { + /// Run task on the default scheduler + DefaultScheduler, + /// Run task on the current scheduler + CurrentScheduler, + /// Run task on a specific scheduler + ExistingScheduler(Scheduler), + /** + * Tasks are scheduled on the main OS thread + * + * The main OS thread is the thread used to launch the runtime which, + * in most cases, is the process's initial thread as created by the OS. + */ + PlatformThread, /// All tasks run in the same OS thread SingleThreaded, /// Tasks are distributed among available CPUs @@ -104,53 +124,6 @@ pub enum SchedMode { ThreadPerTask, /// Tasks are distributed among a fixed number of OS threads ManualThreads(uint), - /** - * Tasks are scheduled on the main OS thread - * - * The main OS thread is the thread used to launch the runtime which, - * in most cases, is the process's initial thread as created by the OS. - */ - PlatformThread -} - -impl SchedMode : cmp::Eq { - pure fn eq(&self, other: &SchedMode) -> bool { - match (*self) { - SingleThreaded => { - match (*other) { - SingleThreaded => true, - _ => false - } - } - ThreadPerCore => { - match (*other) { - ThreadPerCore => true, - _ => false - } - } - ThreadPerTask => { - match (*other) { - ThreadPerTask => true, - _ => false - } - } - ManualThreads(e0a) => { - match (*other) { - ManualThreads(e0b) => e0a == e0b, - _ => false - } - } - PlatformThread => { - match (*other) { - PlatformThread => true, - _ => false - } - } - } - } - pure fn ne(&self, other: &SchedMode) -> bool { - !(*self).eq(other) - } } /** @@ -204,7 +177,7 @@ pub type TaskOpts = { linked: bool, supervised: bool, mut notify_chan: Option>, - sched: Option, + sched: SchedOpts, }; /** @@ -370,7 +343,7 @@ impl TaskBuilder { linked: self.opts.linked, supervised: self.opts.supervised, mut notify_chan: move notify_chan, - sched: Some({ mode: mode, foreign_stack_size: None}) + sched: { mode: mode, foreign_stack_size: None} }, can_not_copy: None, .. self.consume() @@ -486,7 +459,10 @@ pub fn default_task_opts() -> TaskOpts { linked: true, supervised: false, mut notify_chan: None, - sched: None + sched: { + mode: DefaultScheduler, + foreign_stack_size: None + } } } @@ -539,10 +515,9 @@ pub fn spawn_with(arg: A, f: fn~(v: A)) { pub fn spawn_sched(mode: SchedMode, f: fn~()) { /*! - * Creates a new scheduler and executes a task on it - * - * Tasks subsequently spawned by that task will also execute on - * the new scheduler. When there are no more tasks to execute the + * Creates a new task on a new or existing scheduler + + * When there are no more tasks to execute the * scheduler terminates. * * # Failure @@ -590,6 +565,10 @@ pub fn get_task() -> Task { TaskHandle(rt::get_task_id()) } +pub fn get_scheduler() -> Scheduler { + SchedulerHandle(rt::rust_get_sched_id()) +} + /** * Temporarily make the task unkillable * @@ -927,16 +906,19 @@ fn test_spawn_sched() { } #[test] -fn test_spawn_sched_childs_on_same_sched() { +fn test_spawn_sched_childs_on_default_sched() { let po = oldcomm::Port(); let ch = oldcomm::Chan(&po); + // Assuming tests run on the default scheduler + let default_id = rt::rust_get_sched_id(); + do spawn_sched(SingleThreaded) { let parent_sched_id = rt::rust_get_sched_id(); do spawn { let child_sched_id = rt::rust_get_sched_id(); - // This should be on the same scheduler - assert parent_sched_id == child_sched_id; + assert parent_sched_id != child_sched_id; + assert child_sched_id == default_id; oldcomm::send(ch, ()); }; }; @@ -1206,7 +1188,7 @@ fn test_spawn_thread_on_demand() { let (port2, chan2) = pipes::stream(); - do spawn() |move chan2| { + do spawn_sched(CurrentScheduler) |move chan2| { chan2.send(()); } diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs index 1c5531303e141..e3afa7c45353e 100644 --- a/src/libcore/task/spawn.rs +++ b/src/libcore/task/spawn.rs @@ -88,6 +88,7 @@ use task::rt::rust_closure; use task::rt; use task::{Failure, ManualThreads, PlatformThread, SchedOpts, SingleThreaded}; use task::{Success, TaskOpts, TaskResult, ThreadPerCore, ThreadPerTask}; +use task::{ExistingScheduler, SchedulerHandle}; use task::{default_task_opts, unkillable}; use uint; use util; @@ -525,9 +526,9 @@ pub fn spawn_raw(opts: TaskOpts, f: fn~()) { // Agh. Get move-mode items into the closure. FIXME (#2829) let (child_tg, ancestors, f) = option::swap_unwrap(child_data); // Create child task. - let new_task = match opts.sched { - None => rt::new_task(), - Some(sched_opts) => new_task_in_new_sched(sched_opts) + let new_task = match opts.sched.mode { + DefaultScheduler => rt::new_task(), + _ => new_task_in_sched(opts.sched) }; assert !new_task.is_null(); // Getting killed after here would leak the task. @@ -631,12 +632,16 @@ pub fn spawn_raw(opts: TaskOpts, f: fn~()) { } } - fn new_task_in_new_sched(opts: SchedOpts) -> *rust_task { + fn new_task_in_sched(opts: SchedOpts) -> *rust_task { if opts.foreign_stack_size != None { fail ~"foreign_stack_size scheduler option unimplemented"; } let num_threads = match opts.mode { + DefaultScheduler + | CurrentScheduler + | ExistingScheduler(*) + | PlatformThread => 0u, /* Won't be used */ SingleThreaded => 1u, ThreadPerCore => rt::rust_num_threads(), ThreadPerTask => { @@ -648,13 +653,13 @@ pub fn spawn_raw(opts: TaskOpts, f: fn~()) { } threads } - PlatformThread => 0u /* Won't be used */ }; - let sched_id = if opts.mode != PlatformThread { - rt::rust_new_sched(num_threads) - } else { - rt::rust_osmain_sched_id() + let sched_id = match opts.mode { + CurrentScheduler => rt::rust_get_sched_id(), + ExistingScheduler(SchedulerHandle(id)) => id, + PlatformThread => rt::rust_osmain_sched_id(), + _ => rt::rust_new_sched(num_threads) }; rt::rust_new_task_in_sched(sched_id) } diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp index f21a7441640c0..803da32cbc8ac 100644 --- a/src/rt/rust.cpp +++ b/src/rt/rust.cpp @@ -43,8 +43,8 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) { rust_kernel *kernel = new rust_kernel(env); - // Create the main scheduler and the main task - rust_sched_id sched_id = kernel->create_scheduler(env->num_sched_threads); + // Create the main task + rust_sched_id sched_id = kernel->main_sched_id(); rust_scheduler *sched = kernel->get_scheduler_by_id(sched_id); assert(sched != NULL); rust_task *root_task = sched->create_task(NULL, "main"); diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index de69272aca174..cbc58e85db614 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -652,7 +652,10 @@ new_task_common(rust_scheduler *sched, rust_task *parent) { extern "C" CDECL rust_task* new_task() { rust_task *task = rust_get_current_task(); - return new_task_common(task->sched, task); + rust_sched_id sched_id = task->kernel->main_sched_id(); + rust_scheduler *sched = task->kernel->get_scheduler_by_id(sched_id); + assert(sched != NULL && "should always have a main scheduler"); + return new_task_common(sched, task); } extern "C" CDECL rust_task* diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index 8871d133ea1b2..cc98b474ee357 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -30,6 +30,7 @@ rust_kernel::rust_kernel(rust_env *env) : rval(0), max_sched_id(1), killed(false), + already_exiting(false), sched_reaper(this), osmain_driver(NULL), non_weak_tasks(0), @@ -38,13 +39,20 @@ rust_kernel::rust_kernel(rust_env *env) : env(env) { - // Create the single threaded scheduler that will run on the platform's // main thread - rust_manual_sched_launcher_factory *launchfac = + rust_manual_sched_launcher_factory *osmain_launchfac = new rust_manual_sched_launcher_factory(); - osmain_scheduler = create_scheduler(launchfac, 1, false); - osmain_driver = launchfac->get_driver(); + osmain_scheduler = create_scheduler(osmain_launchfac, 1, false); + osmain_driver = osmain_launchfac->get_driver(); + + // Create the primary scheduler + rust_thread_sched_launcher_factory *main_launchfac = + new rust_thread_sched_launcher_factory(); + main_scheduler = create_scheduler(main_launchfac, + env->num_sched_threads, + false); + sched_reaper.start(); } @@ -103,15 +111,22 @@ rust_kernel::create_scheduler(rust_sched_launcher_factory *launchfac, { scoped_lock with(sched_lock); + /*if (sched_table.size() == 2) { + // The main and OS main schedulers may not exit while there are + // other schedulers + KLOG_("Disallowing main scheduler to exit"); + rust_scheduler *main_sched = + get_scheduler_by_id_nolock(main_scheduler); + assert(main_sched != NULL); + main_sched->disallow_exit(); + } if (sched_table.size() == 1) { - // The OS main scheduler may not exit while there are other - // schedulers KLOG_("Disallowing osmain scheduler to exit"); - rust_scheduler *sched = + rust_scheduler *osmain_sched = get_scheduler_by_id_nolock(osmain_scheduler); - assert(sched != NULL); - sched->disallow_exit(); - } + assert(osmain_sched != NULL); + osmain_sched->disallow_exit(); + }*/ id = max_sched_id++; assert(id != INTPTR_MAX && "Hit the maximum scheduler id"); @@ -175,14 +190,21 @@ rust_kernel::wait_for_schedulers() sched_table.erase(iter); sched->join_task_threads(); sched->deref(); + /*if (sched_table.size() == 2) { + KLOG_("Allowing main scheduler to exit"); + // It's only the main schedulers left. Tell them to exit + rust_scheduler *main_sched = + get_scheduler_by_id_nolock(main_scheduler); + assert(main_sched != NULL); + main_sched->allow_exit(); + } if (sched_table.size() == 1) { KLOG_("Allowing osmain scheduler to exit"); - // It's only the osmain scheduler left. Tell it to exit - rust_scheduler *sched = + rust_scheduler *osmain_sched = get_scheduler_by_id_nolock(osmain_scheduler); - assert(sched != NULL); - sched->allow_exit(); - } + assert(osmain_sched != NULL); + osmain_sched->allow_exit(); + }*/ } if (!sched_table.empty()) { sched_lock.wait(); @@ -318,13 +340,31 @@ rust_kernel::register_task() { KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); } +void +rust_kernel::allow_scheduler_exit() { + scoped_lock with(sched_lock); + + KLOG_("Allowing main scheduler to exit"); + // It's only the main schedulers left. Tell them to exit + rust_scheduler *main_sched = + get_scheduler_by_id_nolock(main_scheduler); + assert(main_sched != NULL); + main_sched->allow_exit(); + + KLOG_("Allowing osmain scheduler to exit"); + rust_scheduler *osmain_sched = + get_scheduler_by_id_nolock(osmain_scheduler); + assert(osmain_sched != NULL); + osmain_sched->allow_exit(); +} + void rust_kernel::unregister_task() { KLOG_("Unregistering task"); uintptr_t new_non_weak_tasks = sync::decrement(non_weak_tasks); KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); if (new_non_weak_tasks == 0) { - end_weak_tasks(); + begin_shutdown(); } } @@ -338,7 +378,7 @@ rust_kernel::weaken_task(rust_port_id chan) { uintptr_t new_non_weak_tasks = sync::decrement(non_weak_tasks); KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); if (new_non_weak_tasks == 0) { - end_weak_tasks(); + begin_shutdown(); } } @@ -374,6 +414,23 @@ rust_kernel::end_weak_tasks() { } } +void +rust_kernel::begin_shutdown() { + { + scoped_lock with(sched_lock); + // FIXME #4410: This shouldn't be necessary, but because of + // unweaken_task this may end up getting called multiple times. + if (already_exiting) { + return; + } else { + already_exiting = true; + } + } + + allow_scheduler_exit(); + end_weak_tasks(); +} + bool rust_kernel::send_to_port(rust_port_id chan, void *sptr) { KLOG_("rust_port_id*_send port: 0x%" PRIxPTR, (uintptr_t) chan); diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index cd52bfae8d3f4..13fd893417261 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -82,7 +82,8 @@ class rust_kernel { lock_and_signal rval_lock; int rval; - // Protects max_sched_id and sched_table, join_list, killed + // Protects max_sched_id and sched_table, join_list, killed, + // already_exiting lock_and_signal sched_lock; // The next scheduler id rust_sched_id max_sched_id; @@ -95,8 +96,13 @@ class rust_kernel { // task group fails). This propagates to all new schedulers and tasks // created after it is set. bool killed; + bool already_exiting; + rust_sched_reaper sched_reaper; + + // The primary scheduler + rust_sched_id main_scheduler; // The single-threaded scheduler that uses the main thread rust_sched_id osmain_scheduler; // Runs the single-threaded scheduler that executes tasks @@ -111,7 +117,9 @@ class rust_kernel { std::vector weak_task_chans; rust_scheduler* get_scheduler_by_id_nolock(rust_sched_id id); + void allow_scheduler_exit(); void end_weak_tasks(); + void begin_shutdown(); // Used to communicate with the process-side, global libuv loop uintptr_t global_loop_chan; @@ -155,6 +163,7 @@ class rust_kernel { void set_exit_status(int code); + rust_sched_id main_sched_id() { return main_scheduler; } rust_sched_id osmain_sched_id() { return osmain_scheduler; } void register_task(); From ac435af73a0009daf22164ee2f081a7c98ca844c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 11 Jan 2013 15:55:14 -0800 Subject: [PATCH 02/31] Add at_exit function #4450 --- src/libcore/private.rs | 3 ++ src/libcore/private/at_exit.rs | 86 ++++++++++++++++++++++++++++++++++ src/rt/rust_builtin.cpp | 5 ++ src/rt/rust_kernel.cpp | 44 +++++++++++++++++ src/rt/rust_kernel.h | 18 +++++++ src/rt/rustrt.def.in | 1 + 6 files changed, 157 insertions(+) create mode 100644 src/libcore/private/at_exit.rs diff --git a/src/libcore/private.rs b/src/libcore/private.rs index d3002ba931622..48489dab4880b 100644 --- a/src/libcore/private.rs +++ b/src/libcore/private.rs @@ -28,6 +28,9 @@ use task; use task::{TaskBuilder, atomically}; use uint; +#[path = "private/at_exit.rs"] +pub mod at_exit; + extern mod rustrt { #[legacy_exports]; unsafe fn rust_task_weaken(ch: rust_port_id); diff --git a/src/libcore/private/at_exit.rs b/src/libcore/private/at_exit.rs new file mode 100644 index 0000000000000..7ac252ea10211 --- /dev/null +++ b/src/libcore/private/at_exit.rs @@ -0,0 +1,86 @@ +use sys; +use cast; +use ptr; +use task; +use uint; +use vec; +use rand; +use libc::{c_void, size_t}; + +/** +Register a function to be run during runtime shutdown. + +After all non-weak tasks have exited, registered exit functions will +execute, in random order, on the primary scheduler. Each function runs +in its own unsupervised task. +*/ +pub fn at_exit(f: ~fn()) unsafe { + let runner: &fn(*ExitFunctions) = exit_runner; + let runner_pair: sys::Closure = cast::transmute(runner); + let runner_ptr = runner_pair.code; + let runner_ptr = cast::transmute(runner_ptr); + rustrt::rust_register_exit_function(runner_ptr, ~f); +} + +// NB: The double pointer indirection here is because ~fn() is a fat +// pointer and due to FFI problems I am more comfortable making the +// interface use a normal pointer +extern mod rustrt { + fn rust_register_exit_function(runner: *c_void, f: ~~fn()); +} + +struct ExitFunctions { + // The number of exit functions + count: size_t, + // The buffer of exit functions + start: *~~fn() +} + +fn exit_runner(exit_fns: *ExitFunctions) unsafe { + let exit_fns = &*exit_fns; + let count = (*exit_fns).count; + let start = (*exit_fns).start; + + // NB: from_buf memcpys from the source, which will + // give us ownership of the array of functions + let mut exit_fns_vec = vec::from_buf(start, count as uint); + // Let's not make any promises about execution order + rand::Rng().shuffle_mut(exit_fns_vec); + + debug!("running %u exit functions", exit_fns_vec.len()); + + while exit_fns_vec.is_not_empty() { + match exit_fns_vec.pop() { + ~f => { + task::task().supervised().spawn(f); + } + } + } +} + +#[abi = "rust-intrinsic"] +pub extern mod rusti { + fn move_val_init(dst: &mut T, -src: T); + fn init() -> T; +} + +#[test] +fn test_at_exit() { + let i = 10; + do at_exit { + debug!("at_exit1"); + assert i == 10; + } +} + +#[test] +fn test_at_exit_many() { + let i = 10; + for uint::range(20, 100) |j| { + do at_exit { + debug!("at_exit2"); + assert i == 10; + assert j > i; + } + } +} \ No newline at end of file diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index cbc58e85db614..a37aea13e4061 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -1026,6 +1026,11 @@ rust_raw_thread_join_delete(raw_thread *thread) { delete thread; } +extern "C" void +rust_register_exit_function(spawn_fn runner, fn_env_pair *f) { + rust_task *task = rust_get_current_task(); + task->kernel->register_exit_function(runner, f); +} // // Local Variables: diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index cc98b474ee357..3042b006a92cf 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -36,6 +36,8 @@ rust_kernel::rust_kernel(rust_env *env) : non_weak_tasks(0), global_loop_chan(0), global_env_chan(0), + at_exit_runner(NULL), + at_exit_started(false), env(env) { @@ -427,6 +429,7 @@ rust_kernel::begin_shutdown() { } } + run_exit_functions(); allow_scheduler_exit(); end_weak_tasks(); } @@ -446,6 +449,47 @@ rust_kernel::send_to_port(rust_port_id chan, void *sptr) { } } +void +rust_kernel::register_exit_function(spawn_fn runner, fn_env_pair *f) { + scoped_lock with(at_exit_lock); + + assert(!at_exit_started && "registering at_exit function after exit"); + + if (at_exit_runner) { + assert(runner == at_exit_runner + && "there can be only one at_exit_runner"); + } + + at_exit_runner = runner; + at_exit_fns.push_back(f); +} + +void +rust_kernel::run_exit_functions() { + rust_task *task; + + { + scoped_lock with(at_exit_lock); + + assert(!at_exit_started && "running exit functions twice?"); + + at_exit_started = true; + + if (at_exit_runner == NULL) { + return; + } + + rust_scheduler *sched = get_scheduler_by_id(main_sched_id()); + assert(sched); + task = sched->create_task(NULL, "at_exit"); + + final_exit_fns.count = at_exit_fns.size(); + final_exit_fns.start = at_exit_fns.data(); + } + + task->start(at_exit_runner, NULL, &final_exit_fns); +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index 13fd893417261..b1548e92cdb36 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -50,6 +50,7 @@ #include "memory_region.h" #include "rust_log.h" #include "rust_sched_reaper.h" +#include "rust_type.h" #include "util/hash_map.h" class rust_scheduler; @@ -66,6 +67,13 @@ typedef intptr_t rust_port_id; typedef std::map sched_map; +// This is defined as a struct only because we need a single pointer to pass +// to the Rust function that runs the at_exit functions +struct exit_functions { + size_t count; + fn_env_pair **start; +}; + class rust_kernel { memory_region _region; rust_log _log; @@ -126,6 +134,14 @@ class rust_kernel { // Used to serialize access to getenv/setenv uintptr_t global_env_chan; + lock_and_signal at_exit_lock; + spawn_fn at_exit_runner; + bool at_exit_started; + std::vector at_exit_fns; + exit_functions final_exit_fns; + + void run_exit_functions(); + public: struct rust_env *env; @@ -175,6 +191,8 @@ class rust_kernel { uintptr_t* get_global_loop() { return &global_loop_chan; } uintptr_t* get_global_env_chan() { return &global_env_chan; } + + void register_exit_function(spawn_fn runner, fn_env_pair *f); }; template struct kernel_owned { diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index cce4e411e02c7..719505079e65f 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -210,3 +210,4 @@ linenoiseHistorySave linenoiseHistoryLoad rust_raw_thread_start rust_raw_thread_join_delete +rust_register_exit_function From db1abbec4ca9f18a224441c483cf23bb4f8361fd Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 12 Jan 2013 23:27:46 -0800 Subject: [PATCH 03/31] core: Add private global data interface. #3915 --- src/libcore/private.rs | 8 ++ src/libcore/private/global.rs | 257 ++++++++++++++++++++++++++++++++++ src/rt/rust_builtin.cpp | 6 + src/rt/rust_kernel.cpp | 4 +- src/rt/rust_kernel.h | 1 + src/rt/rustrt.def.in | 1 + 6 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 src/libcore/private/global.rs diff --git a/src/libcore/private.rs b/src/libcore/private.rs index 48489dab4880b..ef25cb52e8ba0 100644 --- a/src/libcore/private.rs +++ b/src/libcore/private.rs @@ -30,6 +30,8 @@ use uint; #[path = "private/at_exit.rs"] pub mod at_exit; +#[path = "private/global.rs"] +pub mod global; extern mod rustrt { #[legacy_exports]; @@ -522,6 +524,12 @@ pub unsafe fn clone_shared_mutable_state(rc: &SharedMutableState) ArcDestruct((*rc).data) } +impl SharedMutableState: Clone { + fn clone(&self) -> SharedMutableState unsafe { + clone_shared_mutable_state(self) + } +} + /****************************************************************************/ #[allow(non_camel_case_types)] // runtime type diff --git a/src/libcore/private/global.rs b/src/libcore/private/global.rs new file mode 100644 index 0000000000000..8c1500353ae67 --- /dev/null +++ b/src/libcore/private/global.rs @@ -0,0 +1,257 @@ +/*! +Global data + +An interface for creating and retrieving values with global +(per-runtime) scope. + +Global values are stored in a map and protected by a single global +mutex. Operations are provided for accessing and cloning the value +under the mutex. + +Because all globals go through a single mutex, they should be used +sparingly. The interface is intended to be used with clonable, +atomically reference counted synchronization types, like ARCs, in +which case the value should be cached locally whenever possible to +avoid hitting the mutex. +*/ + +use cast::{transmute, reinterpret_cast}; +use clone::Clone; +use kinds::Owned; +use libc::{c_void, uintptr_t}; +use option::{Option, Some, None}; +use ops::Drop; +use pipes; +use private::{Exclusive, exclusive}; +use private::{SharedMutableState, shared_mutable_state}; +use private::{get_shared_immutable_state}; +use private::at_exit::at_exit; +use send_map::linear::LinearMap; +use sys::Closure; +use task::spawn; +use uint; + +pub type GlobalDataKey = &fn(v: T); + +pub unsafe fn global_data_clone_create( + key: GlobalDataKey, create: &fn() -> ~T) -> T { + /*! + * Clone a global value or, if it has not been created, + * first construct the value then return a clone. + * + * # Safety note + * + * Both the clone operation and the constructor are + * called while the global lock is held. Recursive + * use of the global interface in either of these + * operations will result in deadlock. + */ + global_data_clone_create_(key_ptr(key), create) +} + +unsafe fn global_data_clone_create_( + key: uint, create: &fn() -> ~T) -> T { + + let mut clone_value: Option = None; + do global_data_modify_(key) |value: Option<~T>| { + match value { + None => { + let value = create(); + clone_value = Some(value.clone()); + Some(value) + } + Some(value) => { + clone_value = Some(value.clone()); + Some(value) + } + } + } + return clone_value.unwrap(); +} + +unsafe fn global_data_modify( + key: GlobalDataKey, op: &fn(Option<~T>) -> Option<~T>) { + + global_data_modify_(key_ptr(key), op) +} + +unsafe fn global_data_modify_( + key: uint, op: &fn(Option<~T>) -> Option<~T>) { + + let mut old_dtor = None; + do get_global_state().with |gs| unsafe { + let (maybe_new_value, maybe_dtor) = match gs.map.pop(&key) { + Some((ptr, dtor)) => { + let value: ~T = transmute(ptr); + (op(Some(value)), Some(dtor)) + } + None => { + (op(None), None) + } + }; + match maybe_new_value { + Some(value) => { + let data: *c_void = transmute(value); + let dtor: ~fn() = match maybe_dtor { + Some(dtor) => dtor, + None => { + let dtor: ~fn() = || unsafe { + let _destroy_value: ~T = transmute(data); + }; + dtor + } + }; + let value = (data, dtor); + gs.map.insert(key, value); + } + None => { + match maybe_dtor { + Some(dtor) => old_dtor = Some(dtor), + None => () + } + } + } + } +} + +// GlobalState is a map from keys to unique pointers and a +// destructor. Keys are pointers derived from the type of the +// global value. There is a single GlobalState instance per runtime. +struct GlobalState { + map: LinearMap +} + +impl GlobalState: Drop { + fn finalize(&self) { + for self.map.each_value |v| { + match v { + &(_, ref dtor) => (*dtor)() + } + } + } +} + +fn get_global_state() -> Exclusive unsafe { + + const POISON: int = -1; + + // XXX: Doing atomic_cxchg to initialize the global state + // lazily, which wouldn't be necessary with a runtime written + // in Rust + let global_ptr = rust_get_global_data_ptr(); + + if *global_ptr == 0 { + // Global state doesn't exist yet, probably + + // The global state object + let state = GlobalState { + map: LinearMap() + }; + + // It's under a reference-counted mutex + let state = ~exclusive(state); + + // Convert it to an integer + let state_ptr: &Exclusive = state; + let state_i: int = transmute(state_ptr); + + // Swap our structure into the global pointer + let prev_i = atomic_cxchg(&mut *global_ptr, 0, state_i); + + // Sanity check that we're not trying to reinitialize after shutdown + assert prev_i != POISON; + + if prev_i == 0 { + // Successfully installed the global pointer + + // Take a handle to return + let clone = state.clone(); + + // Install a runtime exit function to destroy the global object + do at_exit || unsafe { + // Poison the global pointer + let prev_i = atomic_cxchg(&mut *global_ptr, state_i, POISON); + assert prev_i == state_i; + + // Capture the global state object in the at_exit closure + // so that it is destroyed at the right time + let _capture_global_state = &state; + }; + return clone; + } else { + // Somebody else initialized the globals first + let state: &Exclusive = transmute(prev_i); + return state.clone(); + } + } else { + let state: &Exclusive = transmute(*global_ptr); + return state.clone(); + } +} + +fn key_ptr(key: GlobalDataKey) -> uint unsafe { + let closure: Closure = reinterpret_cast(&key); + return transmute(closure.code); +} + +extern { + fn rust_get_global_data_ptr() -> *mut int; +} + +#[abi = "rust-intrinsic"] +extern { + fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int; +} + +#[test] +fn test_clone_rc() unsafe { + type MyType = SharedMutableState; + + fn key(_v: SharedMutableState) { } + + for uint::range(0, 100) |_| { + do spawn unsafe { + let val = do global_data_clone_create(key) { + ~shared_mutable_state(10) + }; + + assert get_shared_immutable_state(&val) == &10; + } + } +} + +#[test] +fn test_modify() unsafe { + type MyType = SharedMutableState; + + fn key(_v: SharedMutableState) { } + + do global_data_modify(key) |v| unsafe { + match v { + None => { + Some(~shared_mutable_state(10)) + } + _ => fail + } + } + + do global_data_modify(key) |v| { + match v { + Some(sms) => { + let v = get_shared_immutable_state(sms); + assert *v == 10; + None + }, + _ => fail + } + } + + do global_data_modify(key) |v| unsafe { + match v { + None => { + Some(~shared_mutable_state(10)) + } + _ => fail + } + } +} diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index a37aea13e4061..221afb89b237d 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -1032,6 +1032,12 @@ rust_register_exit_function(spawn_fn runner, fn_env_pair *f) { task->kernel->register_exit_function(runner, f); } +extern "C" void * +rust_get_global_data_ptr() { + rust_task *task = rust_get_current_task(); + return &task->kernel->global_data; +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index 3042b006a92cf..9c6ba9dcda3ef 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -38,8 +38,8 @@ rust_kernel::rust_kernel(rust_env *env) : global_env_chan(0), at_exit_runner(NULL), at_exit_started(false), - env(env) - + env(env), + global_data(0) { // Create the single threaded scheduler that will run on the platform's // main thread diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index b1548e92cdb36..99b230f7872bd 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -144,6 +144,7 @@ class rust_kernel { public: struct rust_env *env; + uintptr_t global_data; rust_kernel(rust_env *env); diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 719505079e65f..8c26832f3498c 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -211,3 +211,4 @@ linenoiseHistoryLoad rust_raw_thread_start rust_raw_thread_join_delete rust_register_exit_function +rust_get_global_data_ptr \ No newline at end of file From 1bf8e579436941a82e4a4806b74dfd27ed4d1d74 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 15 Jan 2013 17:11:16 -0800 Subject: [PATCH 04/31] Add `finally` method for deferred execution --- src/libcore/private.rs | 2 + src/libcore/private/finally.rs | 88 ++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/libcore/private/finally.rs diff --git a/src/libcore/private.rs b/src/libcore/private.rs index ef25cb52e8ba0..3eadce1c30ccc 100644 --- a/src/libcore/private.rs +++ b/src/libcore/private.rs @@ -32,6 +32,8 @@ use uint; pub mod at_exit; #[path = "private/global.rs"] pub mod global; +#[path = "private/finally.rs"] +pub mod finally; extern mod rustrt { #[legacy_exports]; diff --git a/src/libcore/private/finally.rs b/src/libcore/private/finally.rs new file mode 100644 index 0000000000000..f4d76dfd54db0 --- /dev/null +++ b/src/libcore/private/finally.rs @@ -0,0 +1,88 @@ +/*! +The Finally trait provides a method, `finally` on +stack closures that emulates Java-style try/finally blocks. + +# Example + +~~~ +do || { + ... +}.finally { + alway_run_this(); +} +~~~ +*/ + +use ops::Drop; +use task::{spawn, failing}; + +pub trait Finally { + fn finally(&self, +dtor: &fn()) -> T; +} + +impl &fn() -> T: Finally { + // XXX: Should not require a mode here + fn finally(&self, +dtor: &fn()) -> T { + let _d = Finallyalizer { + dtor: dtor + }; + + (*self)() + } +} + +struct Finallyalizer { + dtor: &fn() +} + +impl Finallyalizer: Drop { + fn finalize(&self) { + (self.dtor)(); + } +} + +#[test] +fn test_success() { + let mut i = 0; + do (|| { + i = 10; + }).finally { + assert !failing(); + assert i == 10; + i = 20; + } + assert i == 20; +} + +#[test] +#[ignore(cfg(windows))] +#[should_fail] +fn test_fail() { + let mut i = 0; + do (|| { + i = 10; + fail; + }).finally { + assert failing(); + assert i == 10; + } +} + +#[test] +fn test_retval() { + let i = do (fn&() -> int { + 10 + }).finally { }; + assert i == 10; +} + +#[test] +fn test_compact() { + // XXX Should be able to use a fn item instead + // of a closure for do_some_fallible_work, + // but it's a type error. + let do_some_fallible_work: &fn() = || { }; + fn but_always_run_this_function() { } + do_some_fallible_work.finally( + but_always_run_this_function); +} \ No newline at end of file From 8852279a9ecac970e30b6d92d7efdcbd5485769c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 15 Jan 2013 19:53:35 -0800 Subject: [PATCH 05/31] core: Add new weak task API --- src/libcore/pipes.rs | 10 ++ src/libcore/private.rs | 2 + src/libcore/private/weak_task.rs | 187 +++++++++++++++++++++++++++++++ src/rt/rust_builtin.cpp | 12 ++ src/rt/rust_kernel.cpp | 24 ++-- src/rt/rust_kernel.h | 2 + src/rt/rustrt.def.in | 4 +- 7 files changed, 233 insertions(+), 8 deletions(-) create mode 100644 src/libcore/private/weak_task.rs diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 2ff4effbd6ee0..2865c9421380b 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -1234,6 +1234,16 @@ pub fn oneshot() -> (PortOne, ChanOne) { (port, chan) } +impl PortOne { + fn recv(self) -> T { recv_one(self) } + fn try_recv(self) -> Option { try_recv_one(self) } +} + +impl ChanOne { + fn send(self, data: T) { send_one(self, data) } + fn try_send(self, data: T) -> bool { try_send_one(self, data) } +} + /** * Receive a message from a oneshot pipe, failing if the connection was * closed. diff --git a/src/libcore/private.rs b/src/libcore/private.rs index 3eadce1c30ccc..aa976ee745d3d 100644 --- a/src/libcore/private.rs +++ b/src/libcore/private.rs @@ -34,6 +34,8 @@ pub mod at_exit; pub mod global; #[path = "private/finally.rs"] pub mod finally; +#[path = "private/weak_task.rs"] +pub mod weak_task; extern mod rustrt { #[legacy_exports]; diff --git a/src/libcore/private/weak_task.rs b/src/libcore/private/weak_task.rs new file mode 100644 index 0000000000000..868361b0e6078 --- /dev/null +++ b/src/libcore/private/weak_task.rs @@ -0,0 +1,187 @@ +/*! +Weak tasks + +Weak tasks are a runtime feature for building global services that +do not keep the runtime alive. Normally the runtime exits when all +tasks exits, but if a task is weak then the runtime may exit while +it is running, sending a notification to the task that the runtime +is trying to shut down. +*/ + +use option::{Some, None, swap_unwrap}; +use private::at_exit::at_exit; +use private::global::global_data_clone_create; +use private::finally::Finally; +use pipes::{Port, Chan, SharedChan, stream}; +use task::{Task, task, spawn}; +use task::rt::{task_id, get_task_id}; +use send_map::linear::LinearMap; +use ops::Drop; + +type ShutdownMsg = (); + +// XXX: This could be a PortOne but I've experienced bugginess +// with oneshot pipes and try_send +pub unsafe fn weaken_task(f: &fn(Port)) { + let service = global_data_clone_create(global_data_key, + create_global_service); + let (shutdown_port, shutdown_chan) = stream::(); + let shutdown_port = ~mut Some(shutdown_port); + let task = get_task_id(); + // Expect the weak task service to be alive + assert service.try_send(RegisterWeakTask(task, shutdown_chan)); + unsafe { rust_inc_weak_task_count(); } + do fn&() { + let shutdown_port = swap_unwrap(&mut *shutdown_port); + f(shutdown_port) + }.finally || { + unsafe { rust_dec_weak_task_count(); } + // Service my have already exited + service.send(UnregisterWeakTask(task)); + } +} + +type WeakTaskService = SharedChan; +type TaskHandle = task_id; + +fn global_data_key(_v: WeakTaskService) { } + +enum ServiceMsg { + RegisterWeakTask(TaskHandle, Chan), + UnregisterWeakTask(TaskHandle), + Shutdown +} + +fn create_global_service() -> ~WeakTaskService { + + debug!("creating global weak task service"); + let (port, chan) = stream::(); + let port = ~mut Some(port); + let chan = SharedChan(chan); + let chan_clone = chan.clone(); + + do task().unlinked().spawn { + debug!("running global weak task service"); + let port = swap_unwrap(&mut *port); + let port = ~mut Some(port); + do fn&() { + let port = swap_unwrap(&mut *port); + // The weak task service is itself a weak task + debug!("weakening the weak service task"); + unsafe { rust_inc_weak_task_count(); } + run_weak_task_service(port); + }.finally { + debug!("unweakening the weak service task"); + unsafe { rust_dec_weak_task_count(); } + } + } + + do at_exit { + debug!("shutting down weak task service"); + chan.send(Shutdown); + } + + return ~chan_clone; +} + +fn run_weak_task_service(port: Port) { + + let mut shutdown_map = LinearMap(); + + loop { + match port.recv() { + RegisterWeakTask(task, shutdown_chan) => { + let previously_unregistered = + shutdown_map.insert(task, shutdown_chan); + assert previously_unregistered; + } + UnregisterWeakTask(task) => { + match shutdown_map.pop(&task) { + Some(shutdown_chan) => { + // Oneshot pipes must send, even though + // nobody will receive this + shutdown_chan.send(()); + } + None => fail + } + } + Shutdown => break + } + } + + do shutdown_map.consume |_, shutdown_chan| { + // Weak task may have already exited + shutdown_chan.send(()); + } +} + +extern { + unsafe fn rust_inc_weak_task_count(); + unsafe fn rust_dec_weak_task_count(); +} + +#[test] +fn test_simple() unsafe { + let (port, chan) = stream(); + do spawn unsafe { + do weaken_task |_signal| { + } + chan.send(()); + } + port.recv(); +} + +#[test] +fn test_weak_weak() unsafe { + let (port, chan) = stream(); + do spawn unsafe { + do weaken_task |_signal| { + } + do weaken_task |_signal| { + } + chan.send(()); + } + port.recv(); +} + +#[test] +fn test_wait_for_signal() unsafe { + do spawn unsafe { + do weaken_task |signal| { + signal.recv(); + } + } +} + +#[test] +fn test_wait_for_signal_many() unsafe { + use uint; + for uint::range(0, 100) |_| { + do spawn unsafe { + do weaken_task |signal| { + signal.recv(); + } + } + } +} + +#[test] +fn test_select_stream_and_oneshot() unsafe { + use pipes::select2i; + use either::{Left, Right}; + + let (port, chan) = stream(); + let (waitport, waitchan) = stream(); + do spawn unsafe { + do weaken_task |signal| { + match select2i(&port, &signal) { + Left(*) => (), + Right(*) => fail + } + } + waitchan.send(()); + } + chan.send(()); + waitport.recv(); +} + diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 221afb89b237d..a5e1260d4a557 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -1038,6 +1038,18 @@ rust_get_global_data_ptr() { return &task->kernel->global_data; } +extern "C" void +rust_inc_weak_task_count() { + rust_task *task = rust_get_current_task(); + task->kernel->inc_weak_task_count(); +} + +extern "C" void +rust_dec_weak_task_count() { + rust_task *task = rust_get_current_task(); + task->kernel->dec_weak_task_count(); +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index 9c6ba9dcda3ef..d270ac0763315 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -377,17 +377,12 @@ rust_kernel::weaken_task(rust_port_id chan) { KLOG_("Weakening task with channel %" PRIdPTR, chan); weak_task_chans.push_back(chan); } - uintptr_t new_non_weak_tasks = sync::decrement(non_weak_tasks); - KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); - if (new_non_weak_tasks == 0) { - begin_shutdown(); - } + inc_weak_task_count(); } void rust_kernel::unweaken_task(rust_port_id chan) { - uintptr_t new_non_weak_tasks = sync::increment(non_weak_tasks); - KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); + dec_weak_task_count(); { scoped_lock with(weak_task_lock); KLOG_("Unweakening task with channel %" PRIdPTR, chan); @@ -399,6 +394,21 @@ rust_kernel::unweaken_task(rust_port_id chan) { } } +void +rust_kernel::inc_weak_task_count() { + uintptr_t new_non_weak_tasks = sync::decrement(non_weak_tasks); + KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); + if (new_non_weak_tasks == 0) { + begin_shutdown(); + } +} + +void +rust_kernel::dec_weak_task_count() { + uintptr_t new_non_weak_tasks = sync::increment(non_weak_tasks); + KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); +} + void rust_kernel::end_weak_tasks() { std::vector chancopies; diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index 99b230f7872bd..f90ecf01a7b3c 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -187,6 +187,8 @@ class rust_kernel { void unregister_task(); void weaken_task(rust_port_id chan); void unweaken_task(rust_port_id chan); + void inc_weak_task_count(); + void dec_weak_task_count(); bool send_to_port(rust_port_id chan, void *sptr); diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 8c26832f3498c..5be823d8fded9 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -211,4 +211,6 @@ linenoiseHistoryLoad rust_raw_thread_start rust_raw_thread_join_delete rust_register_exit_function -rust_get_global_data_ptr \ No newline at end of file +rust_get_global_data_ptr +rust_inc_weak_task_count +rust_dec_weak_task_count \ No newline at end of file From fb9299346af9b951890db80e47eb65625997f160 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 19 Jan 2013 22:54:29 -0800 Subject: [PATCH 06/31] core: Convert getenv/setenv to use a mutex This much simpler implementation uses a global mutex and eliminates the kernel environment channel. --- src/libcore/os.rs | 204 ++++++++++++++-------------------------- src/rt/rust_builtin.cpp | 6 -- src/rt/rust_kernel.cpp | 1 - src/rt/rust_kernel.h | 3 - src/rt/rustrt.def.in | 1 - 5 files changed, 68 insertions(+), 147 deletions(-) diff --git a/src/libcore/os.rs b/src/libcore/os.rs index ff3253a8223ff..2de7ecf7dff1e 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -139,169 +139,101 @@ pub mod win32 { } } -pub fn getenv(n: &str) -> Option<~str> { - global_env::getenv(n) -} +/* +Accessing environment variables is not generally threadsafe. +This uses a per-runtime lock to serialize access. +XXX: It would probably be appropriate to make this a real global +*/ +fn with_env_lock(f: &fn() -> T) -> T { + use private::global::global_data_clone_create; + use private::{Exclusive, exclusive}; + + struct SharedValue(()); + type ValueMutex = Exclusive; + fn key(_: ValueMutex) { } -pub fn setenv(n: &str, v: &str) { - global_env::setenv(n, v) -} + unsafe { + let lock: ValueMutex = global_data_clone_create(key, || { + ~exclusive(SharedValue(())) + }); -pub fn env() -> ~[(~str,~str)] { - global_env::env() + lock.with_imm(|_| f() ) + } } -mod global_env { - //! Internal module for serializing access to getenv/setenv - use either; - use libc; - use oldcomm; - use option::Option; - use private; - use str; - use task; - +pub fn env() -> ~[(~str,~str)] { extern mod rustrt { - unsafe fn rust_global_env_chan_ptr() -> *libc::uintptr_t; - } - - enum Msg { - MsgGetEnv(~str, oldcomm::Chan>), - MsgSetEnv(~str, ~str, oldcomm::Chan<()>), - MsgEnv(oldcomm::Chan<~[(~str,~str)]>) - } - - pub fn getenv(n: &str) -> Option<~str> { - let env_ch = get_global_env_chan(); - let po = oldcomm::Port(); - oldcomm::send(env_ch, MsgGetEnv(str::from_slice(n), - oldcomm::Chan(&po))); - oldcomm::recv(po) - } - - pub fn setenv(n: &str, v: &str) { - let env_ch = get_global_env_chan(); - let po = oldcomm::Port(); - oldcomm::send(env_ch, MsgSetEnv(str::from_slice(n), - str::from_slice(v), - oldcomm::Chan(&po))); - oldcomm::recv(po) + unsafe fn rust_env_pairs() -> ~[~str]; } - pub fn env() -> ~[(~str,~str)] { - let env_ch = get_global_env_chan(); - let po = oldcomm::Port(); - oldcomm::send(env_ch, MsgEnv(oldcomm::Chan(&po))); - oldcomm::recv(po) - } - - fn get_global_env_chan() -> oldcomm::Chan { - unsafe { - let global_ptr = rustrt::rust_global_env_chan_ptr(); - private::chan_from_global_ptr(global_ptr, || { - // FIXME (#2621): This would be a good place to use a very - // small foreign stack - task::task().sched_mode(task::SingleThreaded).unlinked() - }, global_env_task) - } - } - - fn global_env_task(msg_po: oldcomm::Port) { - unsafe { - do private::weaken_task |weak_po| { - loop { - match oldcomm::select2(msg_po, weak_po) { - either::Left(MsgGetEnv(ref n, resp_ch)) => { - oldcomm::send(resp_ch, impl_::getenv(*n)) - } - either::Left(MsgSetEnv(ref n, ref v, resp_ch)) => { - oldcomm::send(resp_ch, impl_::setenv(*n, *v)) - } - either::Left(MsgEnv(resp_ch)) => { - oldcomm::send(resp_ch, impl_::env()) - } - either::Right(_) => break - } - } + unsafe { + do with_env_lock { + let mut pairs = ~[]; + for vec::each(rustrt::rust_env_pairs()) |p| { + let vs = str::splitn_char(*p, '=', 1u); + assert vec::len(vs) == 2u; + pairs.push((copy vs[0], copy vs[1])); } + move pairs } } +} - mod impl_ { - use cast; - use libc; - use option::Option; - use option; - use ptr; - use str; - use vec; - - extern mod rustrt { - unsafe fn rust_env_pairs() -> ~[~str]; - } - - pub fn env() -> ~[(~str,~str)] { - unsafe { - let mut pairs = ~[]; - for vec::each(rustrt::rust_env_pairs()) |p| { - let vs = str::splitn_char(*p, '=', 1u); - assert vec::len(vs) == 2u; - pairs.push((copy vs[0], copy vs[1])); - } - move pairs - } - } - - #[cfg(unix)] - pub fn getenv(n: &str) -> Option<~str> { - unsafe { - let s = str::as_c_str(n, |s| libc::getenv(s)); - return if ptr::null::() == cast::reinterpret_cast(&s) { - option::None::<~str> - } else { - let s = cast::reinterpret_cast(&s); - option::Some::<~str>(str::raw::from_buf(s)) - }; +#[cfg(unix)] +pub fn getenv(n: &str) -> Option<~str> { + unsafe { + do with_env_lock { + let s = str::as_c_str(n, |s| libc::getenv(s)); + if ptr::null::() == cast::reinterpret_cast(&s) { + option::None::<~str> + } else { + let s = cast::reinterpret_cast(&s); + option::Some::<~str>(str::raw::from_buf(s)) } } + } +} - #[cfg(windows)] - pub fn getenv(n: &str) -> Option<~str> { - unsafe { - use os::win32::{as_utf16_p, fill_utf16_buf_and_decode}; - do as_utf16_p(n) |u| { - do fill_utf16_buf_and_decode() |buf, sz| { - libc::GetEnvironmentVariableW(u, buf, sz) - } +#[cfg(windows)] +pub fn getenv(n: &str) -> Option<~str> { + unsafe { + do with_env_lock { + use os::win32::{as_utf16_p, fill_utf16_buf_and_decode}; + do as_utf16_p(n) |u| { + do fill_utf16_buf_and_decode() |buf, sz| { + libc::GetEnvironmentVariableW(u, buf, sz) } } } + } +} - #[cfg(unix)] - pub fn setenv(n: &str, v: &str) { - unsafe { - do str::as_c_str(n) |nbuf| { - do str::as_c_str(v) |vbuf| { - libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1); - } +#[cfg(unix)] +pub fn setenv(n: &str, v: &str) { + unsafe { + do with_env_lock { + do str::as_c_str(n) |nbuf| { + do str::as_c_str(v) |vbuf| { + libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1); } } } + } +} - #[cfg(windows)] - pub fn setenv(n: &str, v: &str) { - unsafe { - use os::win32::as_utf16_p; - do as_utf16_p(n) |nbuf| { - do as_utf16_p(v) |vbuf| { - libc::SetEnvironmentVariableW(nbuf, vbuf); - } +#[cfg(windows)] +pub fn setenv(n: &str, v: &str) { + unsafe { + do with_env_lock { + use os::win32::as_utf16_p; + do as_utf16_p(n) |nbuf| { + do as_utf16_p(v) |vbuf| { + libc::SetEnvironmentVariableW(nbuf, vbuf); } } } - } } diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index a5e1260d4a557..327337f441d8d 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -870,12 +870,6 @@ rust_task_unweaken(rust_port_id chan) { task->kernel->unweaken_task(chan); } -extern "C" CDECL uintptr_t* -rust_global_env_chan_ptr() { - rust_task *task = rust_get_current_task(); - return task->kernel->get_global_env_chan(); -} - extern "C" void rust_task_inhibit_kill(rust_task *task) { task->inhibit_kill(); diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index d270ac0763315..7e34287884111 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -35,7 +35,6 @@ rust_kernel::rust_kernel(rust_env *env) : osmain_driver(NULL), non_weak_tasks(0), global_loop_chan(0), - global_env_chan(0), at_exit_runner(NULL), at_exit_started(false), env(env), diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index f90ecf01a7b3c..477e59d1b3e63 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -131,8 +131,6 @@ class rust_kernel { // Used to communicate with the process-side, global libuv loop uintptr_t global_loop_chan; - // Used to serialize access to getenv/setenv - uintptr_t global_env_chan; lock_and_signal at_exit_lock; spawn_fn at_exit_runner; @@ -193,7 +191,6 @@ class rust_kernel { bool send_to_port(rust_port_id chan, void *sptr); uintptr_t* get_global_loop() { return &global_loop_chan; } - uintptr_t* get_global_env_chan() { return &global_env_chan; } void register_exit_function(spawn_fn runner, fn_env_pair *f); }; diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 5be823d8fded9..dd84e5ff6e7c6 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -174,7 +174,6 @@ rust_dbg_do_nothing rust_dbg_breakpoint rust_osmain_sched_id rust_compare_and_swap_ptr -rust_global_env_chan_ptr rust_port_take rust_port_drop rust_port_task From b9608fe4232c4014daa540849d471b1791b41fa6 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 19 Jan 2013 23:38:17 -0800 Subject: [PATCH 07/31] std: Convert uv_global_loop to use pipes --- src/libcore/private/global.rs | 15 ++++ src/libstd/flatpipes.rs | 3 +- src/libstd/net_ip.rs | 6 +- src/libstd/net_tcp.rs | 74 ++++++++++-------- src/libstd/timer.rs | 21 ++--- src/libstd/uv_global_loop.rs | 106 +++++++++++++------------- src/libstd/uv_iotask.rs | 72 ++++++++++------- src/rt/rust_kernel.cpp | 1 - src/rt/rust_kernel.h | 5 -- src/rt/rust_uv.cpp | 9 --- src/rt/rustrt.def.in | 1 - src/test/run-pass/pipe-detect-term.rs | 2 +- src/test/run-pass/pipe-select.rs | 2 +- src/test/run-pass/pipe-sleep.rs | 2 +- 14 files changed, 172 insertions(+), 147 deletions(-) diff --git a/src/libcore/private/global.rs b/src/libcore/private/global.rs index 8c1500353ae67..d9230e08dc76d 100644 --- a/src/libcore/private/global.rs +++ b/src/libcore/private/global.rs @@ -114,6 +114,21 @@ unsafe fn global_data_modify_( } } +pub unsafe fn global_data_clone( + key: GlobalDataKey) -> Option { + let mut maybe_clone: Option = None; + do global_data_modify(key) |current| { + match ¤t { + &Some(~ref value) => { + maybe_clone = Some(value.clone()); + } + &None => () + } + current + } + return maybe_clone; +} + // GlobalState is a map from keys to unique pointers and a // destructor. Keys are pointers derived from the type of the // global value. There is a single GlobalState instance per runtime. diff --git a/src/libstd/flatpipes.rs b/src/libstd/flatpipes.rs index 0607055db5c03..cc788dfee22f3 100644 --- a/src/libstd/flatpipes.rs +++ b/src/libstd/flatpipes.rs @@ -782,7 +782,6 @@ mod test { let (finish_port, finish_chan) = pipes::stream(); let addr = ip::v4::parse_addr("127.0.0.1"); - let iotask = uv::global_loop::get(); let begin_connect_chan = Cell(move begin_connect_chan); let accept_chan = Cell(move accept_chan); @@ -790,6 +789,7 @@ mod test { // The server task do task::spawn |copy addr, move begin_connect_chan, move accept_chan| { + let iotask = &uv::global_loop::get(); let begin_connect_chan = begin_connect_chan.take(); let accept_chan = accept_chan.take(); let listen_res = do tcp::listen( @@ -821,6 +821,7 @@ mod test { begin_connect_port.recv(); debug!("connecting"); + let iotask = &uv::global_loop::get(); let connect_result = tcp::connect(copy addr, port, iotask); assert connect_result.is_ok(); let sock = result::unwrap(move connect_result); diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index fad583a668b3b..080c5514ac8bc 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -114,7 +114,7 @@ enum IpGetAddrErr { * a vector of `ip_addr` results, in the case of success, or an error * object in the case of failure */ -pub fn get_addr(node: &str, iotask: iotask) +pub fn get_addr(node: &str, iotask: &iotask) -> result::Result<~[IpAddr], IpGetAddrErr> { do oldcomm::listen |output_ch| { do str::as_buf(node) |node_ptr, len| unsafe { @@ -413,7 +413,7 @@ mod test { #[ignore(reason = "valgrind says it's leaky")] fn test_ip_get_addr() { let localhost_name = ~"localhost"; - let iotask = uv::global_loop::get(); + let iotask = &uv::global_loop::get(); let ga_result = get_addr(localhost_name, iotask); if result::is_err(&ga_result) { fail ~"got err result from net::ip::get_addr();" @@ -439,7 +439,7 @@ mod test { #[ignore(reason = "valgrind says it's leaky")] fn test_ip_get_addr_bad_input() { let localhost_name = ~"sjkl234m,./sdf"; - let iotask = uv::global_loop::get(); + let iotask = &uv::global_loop::get(); let ga_result = get_addr(localhost_name, iotask); assert result::is_err(&ga_result); } diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 847962c1773a9..75c7a7cbfb9f2 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -142,7 +142,7 @@ pub enum TcpConnectErrData { * `net::tcp::tcp_connect_err_data` instance will be returned */ pub fn connect(input_ip: ip::IpAddr, port: uint, - iotask: IoTask) + iotask: &IoTask) -> result::Result unsafe { let result_po = oldcomm::Port::(); let closed_signal_po = oldcomm::Port::<()>(); @@ -164,7 +164,7 @@ pub fn connect(input_ip: ip::IpAddr, port: uint, ip::Ipv4(_) => { false } ip::Ipv6(_) => { true } }, - iotask: iotask + iotask: iotask.clone() }; let socket_data_ptr = ptr::addr_of(&(*socket_data)); log(debug, fmt!("tcp_connect result_ch %?", conn_data.result_ch)); @@ -496,17 +496,17 @@ pub fn accept(new_conn: TcpNewConnection) let server_data_ptr = uv::ll::get_data_for_uv_handle( server_handle_ptr) as *TcpListenFcData; let reader_po = oldcomm::Port(); - let iotask = (*server_data_ptr).iotask; + let iotask = &(*server_data_ptr).iotask; let stream_handle_ptr = malloc_uv_tcp_t(); *(stream_handle_ptr as *mut uv::ll::uv_tcp_t) = uv::ll::tcp_t(); - let client_socket_data = @{ + let client_socket_data: @TcpSocketData = @{ reader_po: reader_po, reader_ch: oldcomm::Chan(&reader_po), stream_handle_ptr : stream_handle_ptr, connect_req : uv::ll::connect_t(), write_req : uv::ll::write_t(), ipv6: (*server_data_ptr).ipv6, - iotask : iotask + iotask : iotask.clone() }; let client_socket_data_ptr = ptr::addr_of(&(*client_socket_data)); let client_stream_handle_ptr = @@ -588,10 +588,10 @@ pub fn accept(new_conn: TcpNewConnection) * of listen exiting because of an error */ pub fn listen(host_ip: ip::IpAddr, port: uint, backlog: uint, - iotask: IoTask, - on_establish_cb: fn~(oldcomm::Chan>), - new_connect_cb: fn~(TcpNewConnection, - oldcomm::Chan>)) + iotask: &IoTask, + on_establish_cb: fn~(oldcomm::Chan>), + new_connect_cb: fn~(TcpNewConnection, + oldcomm::Chan>)) -> result::Result<(), TcpListenErrData> unsafe { do listen_common(move host_ip, port, backlog, iotask, move on_establish_cb) @@ -606,7 +606,7 @@ pub fn listen(host_ip: ip::IpAddr, port: uint, backlog: uint, } fn listen_common(host_ip: ip::IpAddr, port: uint, backlog: uint, - iotask: IoTask, + iotask: &IoTask, on_establish_cb: fn~(oldcomm::Chan>), on_connect_cb: fn~(*uv::ll::uv_tcp_t)) -> result::Result<(), TcpListenErrData> unsafe { @@ -615,12 +615,12 @@ fn listen_common(host_ip: ip::IpAddr, port: uint, backlog: uint, let kill_ch = oldcomm::Chan(&kill_po); let server_stream = uv::ll::tcp_t(); let server_stream_ptr = ptr::addr_of(&server_stream); - let server_data = { + let server_data: TcpListenFcData = { server_stream_ptr: server_stream_ptr, stream_closed_ch: oldcomm::Chan(&stream_closed_po), kill_ch: kill_ch, on_connect_cb: move on_connect_cb, - iotask: iotask, + iotask: iotask.clone(), ipv6: match &host_ip { &ip::Ipv4(_) => { false } &ip::Ipv6(_) => { true } @@ -895,7 +895,7 @@ fn tear_down_socket_data(socket_data: @TcpSocketData) unsafe { }; let close_data_ptr = ptr::addr_of(&close_data); let stream_handle_ptr = (*socket_data).stream_handle_ptr; - do iotask::interact((*socket_data).iotask) |loop_ptr| unsafe { + do iotask::interact(&(*socket_data).iotask) |loop_ptr| unsafe { log(debug, fmt!("interact dtor for tcp_socket stream %? loop %?", stream_handle_ptr, loop_ptr)); uv::ll::set_data_for_uv_handle(stream_handle_ptr, @@ -916,7 +916,7 @@ fn read_common_impl(socket_data: *TcpSocketData, timeout_msecs: uint) use timer; log(debug, ~"starting tcp::read"); - let iotask = (*socket_data).iotask; + let iotask = &(*socket_data).iotask; let rs_result = read_start_common_impl(socket_data); if result::is_err(&rs_result) { let err_data = result::get_err(&rs_result); @@ -956,7 +956,7 @@ fn read_stop_common_impl(socket_data: *TcpSocketData) -> let stream_handle_ptr = (*socket_data).stream_handle_ptr; let stop_po = oldcomm::Port::>(); let stop_ch = oldcomm::Chan(&stop_po); - do iotask::interact((*socket_data).iotask) |loop_ptr| unsafe { + do iotask::interact(&(*socket_data).iotask) |loop_ptr| unsafe { log(debug, ~"in interact cb for tcp::read_stop"); match uv::ll::read_stop(stream_handle_ptr as *uv::ll::uv_stream_t) { 0i32 => { @@ -984,7 +984,7 @@ fn read_start_common_impl(socket_data: *TcpSocketData) let start_po = oldcomm::Port::>(); let start_ch = oldcomm::Chan(&start_po); log(debug, ~"in tcp::read_start before interact loop"); - do iotask::interact((*socket_data).iotask) |loop_ptr| unsafe { + do iotask::interact(&(*socket_data).iotask) |loop_ptr| unsafe { log(debug, fmt!("in tcp::read_start interact cb %?", loop_ptr)); match uv::ll::read_start(stream_handle_ptr as *uv::ll::uv_stream_t, on_alloc_cb, @@ -1024,7 +1024,7 @@ fn write_common_impl(socket_data_ptr: *TcpSocketData, result_ch: oldcomm::Chan(&result_po) }; let write_data_ptr = ptr::addr_of(&write_data); - do iotask::interact((*socket_data_ptr).iotask) |loop_ptr| unsafe { + do iotask::interact(&(*socket_data_ptr).iotask) |loop_ptr| unsafe { log(debug, fmt!("in interact cb for tcp::write %?", loop_ptr)); match uv::ll::write(write_req_ptr, stream_handle_ptr, @@ -1369,7 +1369,7 @@ pub mod test { } } pub fn impl_gl_tcp_ipv4_server_and_client() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 8888u; let expected_req = ~"ping"; @@ -1381,6 +1381,7 @@ pub mod test { let cont_po = oldcomm::Port::<()>(); let cont_ch = oldcomm::Chan(&cont_po); // server + let hl_loop_clone = hl_loop.clone(); do task::spawn_sched(task::ManualThreads(1u)) { let actual_req = do oldcomm::listen |server_ch| { run_tcp_test_server( @@ -1389,7 +1390,7 @@ pub mod test { expected_resp, server_ch, cont_ch, - hl_loop) + &hl_loop_clone) }; server_result_ch.send(actual_req); }; @@ -1415,7 +1416,7 @@ pub mod test { assert str::contains(actual_resp, expected_resp); } pub fn impl_gl_tcp_ipv4_get_peer_addr() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 8887u; let expected_resp = ~"pong"; @@ -1426,6 +1427,7 @@ pub mod test { let cont_po = oldcomm::Port::<()>(); let cont_ch = oldcomm::Chan(&cont_po); // server + let hl_loop_clone = hl_loop.clone(); do task::spawn_sched(task::ManualThreads(1u)) { let actual_req = do oldcomm::listen |server_ch| { run_tcp_test_server( @@ -1434,7 +1436,7 @@ pub mod test { expected_resp, server_ch, cont_ch, - hl_loop) + &hl_loop_clone) }; server_result_ch.send(actual_req); }; @@ -1445,10 +1447,11 @@ pub mod test { let server_ip_addr = ip::v4::parse_addr(server_ip); let iotask = uv::global_loop::get(); let connect_result = connect(move server_ip_addr, server_port, - iotask); + &iotask); let sock = result::unwrap(move connect_result); + debug!("testing peer address"); // This is what we are actually testing! assert net::ip::format_addr(&sock.get_peer_addr()) == ~"127.0.0.1"; @@ -1457,12 +1460,14 @@ pub mod test { // Fulfill the protocol the test server expects let resp_bytes = str::to_bytes(~"ping"); tcp_write_single(&sock, resp_bytes); + debug!("message sent"); let read_result = sock.read(0u); client_ch.send(str::from_bytes(read_result.get())); + debug!("result read"); }; } pub fn impl_gl_tcp_ipv4_client_error_connection_refused() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 8889u; let expected_req = ~"ping"; @@ -1482,7 +1487,7 @@ pub mod test { } } pub fn impl_gl_tcp_ipv4_server_address_in_use() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 8890u; let expected_req = ~"ping"; @@ -1494,6 +1499,7 @@ pub mod test { let cont_po = oldcomm::Port::<()>(); let cont_ch = oldcomm::Chan(&cont_po); // server + let hl_loop_clone = hl_loop.clone(); do task::spawn_sched(task::ManualThreads(1u)) { let actual_req = do oldcomm::listen |server_ch| { run_tcp_test_server( @@ -1502,7 +1508,7 @@ pub mod test { expected_resp, server_ch, cont_ch, - hl_loop) + &hl_loop_clone) }; server_result_ch.send(actual_req); }; @@ -1533,7 +1539,7 @@ pub mod test { } } pub fn impl_gl_tcp_ipv4_server_access_denied() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 80u; // this one should fail.. @@ -1553,7 +1559,7 @@ pub mod test { } pub fn impl_gl_tcp_ipv4_server_client_reader_writer() { - let iotask = uv::global_loop::get(); + let iotask = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 8891u; let expected_req = ~"ping"; @@ -1565,6 +1571,7 @@ pub mod test { let cont_po = oldcomm::Port::<()>(); let cont_ch = oldcomm::Chan(&cont_po); // server + let iotask_clone = iotask.clone(); do task::spawn_sched(task::ManualThreads(1u)) { let actual_req = do oldcomm::listen |server_ch| { run_tcp_test_server( @@ -1573,7 +1580,7 @@ pub mod test { expected_resp, server_ch, cont_ch, - iotask) + &iotask_clone) }; server_result_ch.send(actual_req); }; @@ -1604,7 +1611,7 @@ pub mod test { pub fn impl_tcp_socket_impl_reader_handles_eof() { use core::io::{Reader,ReaderUtil}; - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let server_ip = ~"127.0.0.1"; let server_port = 10041u; let expected_req = ~"GET /"; @@ -1616,6 +1623,7 @@ pub mod test { let cont_po = oldcomm::Port::<()>(); let cont_ch = oldcomm::Chan(&cont_po); // server + let hl_loop_clone = hl_loop.clone(); do task::spawn_sched(task::ManualThreads(1u)) { let actual_req = do oldcomm::listen |server_ch| { run_tcp_test_server( @@ -1624,7 +1632,7 @@ pub mod test { expected_resp, server_ch, cont_ch, - hl_loop) + &hl_loop_clone) }; server_result_ch.send(actual_req); }; @@ -1664,7 +1672,7 @@ pub mod test { fn run_tcp_test_server(server_ip: &str, server_port: uint, resp: ~str, server_ch: oldcomm::Chan<~str>, cont_ch: oldcomm::Chan<()>, - iotask: IoTask) -> ~str { + iotask: &IoTask) -> ~str { let server_ip_addr = ip::v4::parse_addr(server_ip); let listen_result = listen(move server_ip_addr, server_port, 128, iotask, @@ -1751,7 +1759,7 @@ pub mod test { } fn run_tcp_test_server_fail(server_ip: &str, server_port: uint, - iotask: IoTask) -> TcpListenErrData { + iotask: &IoTask) -> TcpListenErrData { let server_ip_addr = ip::v4::parse_addr(server_ip); let listen_result = listen(move server_ip_addr, server_port, 128, iotask, @@ -1775,7 +1783,7 @@ pub mod test { fn run_tcp_test_client(server_ip: &str, server_port: uint, resp: &str, client_ch: oldcomm::Chan<~str>, - iotask: IoTask) -> result::Result<~str, + iotask: &IoTask) -> result::Result<~str, TcpConnectErrData> { let server_ip_addr = ip::v4::parse_addr(server_ip); diff --git a/src/libstd/timer.rs b/src/libstd/timer.rs index 18c623c2bd8ce..0f0aa2a011eaf 100644 --- a/src/libstd/timer.rs +++ b/src/libstd/timer.rs @@ -39,7 +39,7 @@ use core; * * ch - a channel of type T to send a `val` on * * val - a value of type T to send over the provided `ch` */ -pub fn delayed_send(iotask: IoTask, +pub fn delayed_send(iotask: &IoTask, msecs: uint, ch: oldcomm::Chan, val: T) { @@ -90,7 +90,7 @@ pub fn delayed_send(iotask: IoTask, * * `iotask` - a `uv::iotask` that the tcp request will run on * * msecs - an amount of time, in milliseconds, for the current task to block */ -pub fn sleep(iotask: IoTask, msecs: uint) { +pub fn sleep(iotask: &IoTask, msecs: uint) { let exit_po = oldcomm::Port::<()>(); let exit_ch = oldcomm::Chan(&exit_po); delayed_send(iotask, msecs, exit_ch, ()); @@ -117,7 +117,7 @@ pub fn sleep(iotask: IoTask, msecs: uint) { * on the provided port in the allotted timeout period, then the result will * be a `some(T)`. If not, then `none` will be returned. */ -pub fn recv_timeout(iotask: IoTask, +pub fn recv_timeout(iotask: &IoTask, msecs: uint, wait_po: oldcomm::Port) -> Option { @@ -177,13 +177,13 @@ mod test { #[test] fn test_gl_timer_simple_sleep_test() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); sleep(hl_loop, 1u); } #[test] fn test_gl_timer_sleep_stress1() { - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); for iter::repeat(50u) { sleep(hl_loop, 1u); } @@ -193,7 +193,7 @@ mod test { fn test_gl_timer_sleep_stress2() { let po = oldcomm::Port(); let ch = oldcomm::Chan(&po); - let hl_loop = uv::global_loop::get(); + let hl_loop = &uv::global_loop::get(); let repeat = 20u; let spec = { @@ -208,11 +208,12 @@ mod test { for spec.each |spec| { let (times, maxms) = *spec; + let hl_loop_clone = hl_loop.clone(); do task::spawn { use rand::*; let rng = Rng(); for iter::repeat(times) { - sleep(hl_loop, rng.next() as uint % maxms); + sleep(&hl_loop_clone, rng.next() as uint % maxms); } oldcomm::send(ch, ()); } @@ -271,12 +272,12 @@ mod test { let expected = rand::Rng().gen_str(16u); let test_po = oldcomm::Port::<~str>(); let test_ch = oldcomm::Chan(&test_po); - + let hl_loop_clone = hl_loop.clone(); do task::spawn() { - delayed_send(hl_loop, 50u, test_ch, expected); + delayed_send(&hl_loop_clone, 50u, test_ch, expected); }; - match recv_timeout(hl_loop, 1u, test_po) { + match recv_timeout(&hl_loop, 1u, test_po) { None => successes += 1, _ => failures += 1 }; diff --git a/src/libstd/uv_global_loop.rs b/src/libstd/uv_global_loop.rs index 276cb9cab6431..097e923225af1 100644 --- a/src/libstd/uv_global_loop.rs +++ b/src/libstd/uv_global_loop.rs @@ -19,16 +19,16 @@ use uv_iotask::{IoTask, spawn_iotask}; use core::either::{Left, Right}; use core::libc; -use core::oldcomm::{Port, Chan, select2, listen}; -use core::private::{chan_from_global_ptr, weaken_task}; +use core::pipes::{Port, Chan, SharedChan, select2i}; +use core::private::global::{global_data_clone_create, + global_data_clone}; +use core::private::weak_task::weaken_task; use core::str; -use core::task::TaskBuilder; +use core::task::{task, SingleThreaded, spawn}; use core::task; use core::vec; - -extern mod rustrt { - unsafe fn rust_uv_get_kernel_global_chan_ptr() -> *libc::uintptr_t; -} +use core::clone::Clone; +use core::option::{Some, None}; /** * Race-free helper to get access to a global task where a libuv @@ -49,64 +49,58 @@ pub fn get() -> IoTask { #[doc(hidden)] fn get_monitor_task_gl() -> IoTask unsafe { - let monitor_loop_chan_ptr = rustrt::rust_uv_get_kernel_global_chan_ptr(); + type MonChan = Chan; - debug!("ENTERING global_loop::get() loop chan: %?", - monitor_loop_chan_ptr); + struct GlobalIoTask(IoTask); - debug!("before priv::chan_from_global_ptr"); - type MonChan = Chan; + impl GlobalIoTask: Clone { + fn clone(&self) -> GlobalIoTask { + GlobalIoTask((**self).clone()) + } + } - let monitor_ch = - do chan_from_global_ptr::(monitor_loop_chan_ptr, - || { - task::task().sched_mode - (task::SingleThreaded) - .unlinked() - }) |msg_po| unsafe { - debug!("global monitor task starting"); - - // As a weak task the runtime will notify us when to exit - do weaken_task() |weak_exit_po| { - debug!("global monitor task is now weak"); - let hl_loop = spawn_loop(); - loop { - debug!("in outer_loop..."); - match select2(weak_exit_po, msg_po) { - Left(weak_exit) => { - // all normal tasks have ended, tell the - // libuv loop to tear_down, then exit - debug!("weak_exit_po recv'd msg: %?", weak_exit); - iotask::exit(hl_loop); - break; - } - Right(fetch_ch) => { - debug!("hl_loop req recv'd: %?", fetch_ch); - fetch_ch.send(hl_loop); - } + fn key(_: GlobalIoTask) { } + + match global_data_clone(key) { + Some(GlobalIoTask(iotask)) => iotask, + None => { + let iotask: IoTask = spawn_loop(); + let mut installed = false; + let final_iotask = do global_data_clone_create(key) { + installed = true; + ~GlobalIoTask(iotask.clone()) + }; + if installed { + do task().unlinked().spawn() unsafe { + debug!("global monitor task starting"); + // As a weak task the runtime will notify us when to exit + do weaken_task |weak_exit_po| { + debug!("global monitor task is now weak"); + weak_exit_po.recv(); + iotask::exit(&iotask); + debug!("global monitor task is leaving weakend state"); + }; + debug!("global monitor task exiting"); } + } else { + iotask::exit(&iotask); } - debug!("global monitor task is leaving weakend state"); - }; - debug!("global monitor task exiting"); - }; - // once we have a chan to the monitor loop, we ask it for - // the libuv loop's async handle - do listen |fetch_ch| { - monitor_ch.send(fetch_ch); - fetch_ch.recv() + match final_iotask { + GlobalIoTask(iotask) => iotask + } + } } } fn spawn_loop() -> IoTask { - let builder = do task::task().add_wrapper |task_body| { + let builder = do task().add_wrapper |task_body| { fn~(move task_body) { // The I/O loop task also needs to be weak so it doesn't keep // the runtime alive unsafe { - do weaken_task |weak_exit_po| { - debug!("global libuv task is now weak %?", weak_exit_po); + do weaken_task |_| { + debug!("global libuv task is now weak"); task_body(); // We don't wait for the exit message on weak_exit_po @@ -118,6 +112,7 @@ fn spawn_loop() -> IoTask { } } }; + let builder = builder.unlinked(); spawn_iotask(move builder) } @@ -147,7 +142,7 @@ mod test { _status: libc::c_int) unsafe { log(debug, ~"in simple timer cb"); ll::timer_stop(timer_ptr); - let hl_loop = get_gl(); + let hl_loop = &get_gl(); do iotask::interact(hl_loop) |_loop_ptr| unsafe { log(debug, ~"closing timer"); ll::close(timer_ptr, simple_timer_close_cb); @@ -157,7 +152,7 @@ mod test { log(debug, ~"exiting simple timer cb"); } - fn impl_uv_hl_simple_timer(iotask: IoTask) unsafe { + fn impl_uv_hl_simple_timer(iotask: &IoTask) unsafe { let exit_po = oldcomm::Port::(); let exit_ch = oldcomm::Chan(&exit_po); let exit_ch_ptr = ptr::addr_of(&exit_ch); @@ -190,10 +185,11 @@ mod test { #[test] fn test_gl_uv_global_loop_high_level_global_timer() unsafe { - let hl_loop = get_gl(); + let hl_loop = &get_gl(); let exit_po = oldcomm::Port::<()>(); let exit_ch = oldcomm::Chan(&exit_po); task::spawn_sched(task::ManualThreads(1u), || { + let hl_loop = &get_gl(); impl_uv_hl_simple_timer(hl_loop); oldcomm::send(exit_ch, ()); }); @@ -206,12 +202,12 @@ mod test { #[test] #[ignore] fn test_stress_gl_uv_global_loop_high_level_global_timer() unsafe { - let hl_loop = get_gl(); let exit_po = oldcomm::Port::<()>(); let exit_ch = oldcomm::Chan(&exit_po); let cycles = 5000u; for iter::repeat(cycles) { task::spawn_sched(task::ManualThreads(1u), || { + let hl_loop = &get_gl(); impl_uv_hl_simple_timer(hl_loop); oldcomm::send(exit_ch, ()); }); diff --git a/src/libstd/uv_iotask.rs b/src/libstd/uv_iotask.rs index 409d73c2539bb..c50a19cc5c17c 100644 --- a/src/libstd/uv_iotask.rs +++ b/src/libstd/uv_iotask.rs @@ -20,7 +20,7 @@ use ll = uv_ll; use core::libc::c_void; use core::libc; -use core::oldcomm::{Port, Chan, listen}; +use core::pipes::{stream, Port, Chan, SharedChan}; use core::prelude::*; use core::ptr::addr_of; use core::task::TaskBuilder; @@ -30,22 +30,30 @@ use core::task; pub enum IoTask { IoTask_({ async_handle: *ll::uv_async_t, - op_chan: Chan + op_chan: SharedChan }) } +impl IoTask: Clone { + fn clone(&self) -> IoTask { + IoTask_({ + async_handle: self.async_handle, + op_chan: self.op_chan.clone() + }) + } +} + pub fn spawn_iotask(task: task::TaskBuilder) -> IoTask { - do listen |iotask_ch| { + let (iotask_port, iotask_chan) = stream(); - do task.sched_mode(task::SingleThreaded).spawn { - debug!("entering libuv task"); - run_loop(iotask_ch); - debug!("libuv task exiting"); - }; + do task.sched_mode(task::SingleThreaded).spawn { + debug!("entering libuv task"); + run_loop(&iotask_chan); + debug!("libuv task exiting"); + }; - iotask_ch.recv() - } + iotask_port.recv() } @@ -71,7 +79,7 @@ pub fn spawn_iotask(task: task::TaskBuilder) -> IoTask { * module. It is not safe to send the `loop_ptr` param to this callback out * via ports/chans. */ -pub unsafe fn interact(iotask: IoTask, +pub unsafe fn interact(iotask: &IoTask, cb: fn~(*c_void)) { send_msg(iotask, Interaction(move cb)); } @@ -83,7 +91,7 @@ pub unsafe fn interact(iotask: IoTask, * async handle and do a sanity check to make sure that all other handles are * closed, causing a failure otherwise. */ -pub fn exit(iotask: IoTask) unsafe { +pub fn exit(iotask: &IoTask) unsafe { send_msg(iotask, TeardownLoop); } @@ -96,8 +104,9 @@ enum IoTaskMsg { } /// Run the loop and begin handling messages -fn run_loop(iotask_ch: Chan) unsafe { +fn run_loop(iotask_ch: &Chan) unsafe { + debug!("creating loop"); let loop_ptr = ll::loop_new(); // set up the special async handle we'll use to allow multi-task @@ -108,10 +117,12 @@ fn run_loop(iotask_ch: Chan) unsafe { // associate the async handle with the loop ll::async_init(loop_ptr, async_handle, wake_up_cb); + let (msg_po, msg_ch) = stream::(); + // initialize our loop data and store it in the loop let data: IoTaskLoopData = { async_handle: async_handle, - msg_po: Port() + msg_po: msg_po }; ll::set_data_for_uv_handle(async_handle, addr_of(&data)); @@ -119,7 +130,7 @@ fn run_loop(iotask_ch: Chan) unsafe { // while we dwell in the I/O loop let iotask = IoTask_({ async_handle: async_handle, - op_chan: data.msg_po.chan() + op_chan: SharedChan(msg_ch) }); iotask_ch.send(iotask); @@ -136,7 +147,7 @@ type IoTaskLoopData = { msg_po: Port }; -fn send_msg(iotask: IoTask, +fn send_msg(iotask: &IoTask, msg: IoTaskMsg) unsafe { iotask.op_chan.send(move msg); ll::async_send(iotask.async_handle); @@ -151,7 +162,7 @@ extern fn wake_up_cb(async_handle: *ll::uv_async_t, let loop_ptr = ll::get_loop_for_uv_handle(async_handle); let data = ll::get_data_for_uv_handle(async_handle) as *IoTaskLoopData; - let msg_po = (*data).msg_po; + let msg_po = &(*data).msg_po; while msg_po.peek() { match msg_po.recv() { @@ -203,34 +214,37 @@ mod test { iotask: IoTask, exit_ch: oldcomm::Chan<()> }; - fn impl_uv_iotask_async(iotask: IoTask) unsafe { + fn impl_uv_iotask_async(iotask: &IoTask) unsafe { let async_handle = ll::async_t(); let ah_ptr = ptr::addr_of(&async_handle); let exit_po = oldcomm::Port::<()>(); let exit_ch = oldcomm::Chan(&exit_po); let ah_data = { - iotask: iotask, + iotask: iotask.clone(), exit_ch: exit_ch }; - let ah_data_ptr = ptr::addr_of(&ah_data); + let ah_data_ptr: *AhData = ptr::to_unsafe_ptr(&ah_data); + debug!("about to interact"); do interact(iotask) |loop_ptr| unsafe { + debug!("interacting"); ll::async_init(loop_ptr, ah_ptr, async_handle_cb); ll::set_data_for_uv_handle(ah_ptr, ah_data_ptr as *libc::c_void); ll::async_send(ah_ptr); }; + debug!("waiting for async close"); oldcomm::recv(exit_po); } // this fn documents the bear minimum neccesary to roll your own // high_level_loop unsafe fn spawn_test_loop(exit_ch: oldcomm::Chan<()>) -> IoTask { - let iotask_port = oldcomm::Port::(); - let iotask_ch = oldcomm::Chan(&iotask_port); + let (iotask_port, iotask_ch) = stream::(); do task::spawn_sched(task::ManualThreads(1u)) { - run_loop(iotask_ch); + debug!("about to run a test loop"); + run_loop(&iotask_ch); exit_ch.send(()); }; - return oldcomm::recv(iotask_port); + return iotask_port.recv(); } extern fn lifetime_handle_close(handle: *libc::c_void) unsafe { @@ -247,7 +261,9 @@ mod test { fn test_uv_iotask_async() unsafe { let exit_po = oldcomm::Port::<()>(); let exit_ch = oldcomm::Chan(&exit_po); - let iotask = spawn_test_loop(exit_ch); + let iotask = &spawn_test_loop(exit_ch); + + debug!("spawned iotask"); // using this handle to manage the lifetime of the high_level_loop, // as it will exit the first time one of the impl_uv_hl_async() is @@ -258,12 +274,16 @@ mod test { let work_exit_po = oldcomm::Port::<()>(); let work_exit_ch = oldcomm::Chan(&work_exit_po); for iter::repeat(7u) { + let iotask_clone = iotask.clone(); do task::spawn_sched(task::ManualThreads(1u)) { - impl_uv_iotask_async(iotask); + debug!("async"); + impl_uv_iotask_async(&iotask_clone); + debug!("done async"); oldcomm::send(work_exit_ch, ()); }; }; for iter::repeat(7u) { + debug!("waiting"); oldcomm::recv(work_exit_po); }; log(debug, ~"sending teardown_loop msg.."); diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index 7e34287884111..8ca49ea6a57c3 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -34,7 +34,6 @@ rust_kernel::rust_kernel(rust_env *env) : sched_reaper(this), osmain_driver(NULL), non_weak_tasks(0), - global_loop_chan(0), at_exit_runner(NULL), at_exit_started(false), env(env), diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index 477e59d1b3e63..8ba0405b86e07 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -129,9 +129,6 @@ class rust_kernel { void end_weak_tasks(); void begin_shutdown(); - // Used to communicate with the process-side, global libuv loop - uintptr_t global_loop_chan; - lock_and_signal at_exit_lock; spawn_fn at_exit_runner; bool at_exit_started; @@ -190,8 +187,6 @@ class rust_kernel { bool send_to_port(rust_port_id chan, void *sptr); - uintptr_t* get_global_loop() { return &global_loop_chan; } - void register_exit_function(spawn_fn runner, fn_env_pair *f); }; diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 53d8177bcf82f..2dc70088628f6 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -513,15 +513,6 @@ rust_uv_ip6_port(struct sockaddr_in6* src) { return ntohs(src->sin6_port); } -extern "C" uintptr_t* -rust_uv_get_kernel_global_chan_ptr() { - uintptr_t* result = rust_get_current_task()->kernel->get_global_loop(); - rust_task* task = rust_get_current_task(); - LOG(task, stdlib, "global loop: %lu", (unsigned long int)result); - LOG(task, stdlib,"global loop val: %lu", (unsigned long int)*result); - return result; -} - extern "C" void* rust_uv_current_kernel_malloc(size_t size) { return current_kernel_malloc(size, "rust_uv_current_kernel_malloc"); diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index dd84e5ff6e7c6..8e8ce9ee509e2 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -158,7 +158,6 @@ rust_uv_get_data_for_req rust_uv_set_data_for_req rust_uv_get_base_from_buf rust_uv_get_len_from_buf -rust_uv_get_kernel_global_chan_ptr rust_uv_current_kernel_malloc rust_uv_current_kernel_free rust_uv_getaddrinfo diff --git a/src/test/run-pass/pipe-detect-term.rs b/src/test/run-pass/pipe-detect-term.rs index c2d4be04191bc..10b13d8757fa2 100644 --- a/src/test/run-pass/pipe-detect-term.rs +++ b/src/test/run-pass/pipe-detect-term.rs @@ -27,7 +27,7 @@ proto! oneshot ( ) fn main() { - let iotask = uv::global_loop::get(); + let iotask = &uv::global_loop::get(); pipes::spawn_service(oneshot::init, |p| { match try_recv(move p) { diff --git a/src/test/run-pass/pipe-select.rs b/src/test/run-pass/pipe-select.rs index e71d0c4931dc7..e138f2562aaef 100644 --- a/src/test/run-pass/pipe-select.rs +++ b/src/test/run-pass/pipe-select.rs @@ -35,7 +35,7 @@ fn main() { use oneshot::client::*; use stream::client::*; - let iotask = uv::global_loop::get(); + let iotask = &uv::global_loop::get(); let c = pipes::spawn_service(stream::init, |p| { error!("waiting for pipes"); diff --git a/src/test/run-pass/pipe-sleep.rs b/src/test/run-pass/pipe-sleep.rs index 4a6e7b4ce36a8..ae7e4e7fb0ca7 100644 --- a/src/test/run-pass/pipe-sleep.rs +++ b/src/test/run-pass/pipe-sleep.rs @@ -27,7 +27,7 @@ fn main() { let c = pipes::spawn_service(oneshot::init, |p| { recv(move p); }); - let iotask = uv::global_loop::get(); + let iotask = &uv::global_loop::get(); sleep(iotask, 500); signal(move c); From a3e087cefacb1b92476543fe7d6ef68f0ca82dd8 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 21 Jan 2013 19:16:01 -0800 Subject: [PATCH 08/31] core: Remove private::chan_from_global_ptr. #3915 --- src/libcore/private.rs | 152 ----------------------------------- src/libstd/uv_global_loop.rs | 4 +- 2 files changed, 2 insertions(+), 154 deletions(-) diff --git a/src/libcore/private.rs b/src/libcore/private.rs index aa976ee745d3d..c3068d6f61b0d 100644 --- a/src/libcore/private.rs +++ b/src/libcore/private.rs @@ -95,163 +95,11 @@ fn test_run_in_bare_thread() unsafe { #[allow(non_camel_case_types)] // runtime type type rust_port_id = uint; -type GlobalPtr = *libc::uintptr_t; - fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool { let old = rusti::atomic_cxchg(address, oldval, newval); old == oldval } -/** - * Atomically gets a channel from a pointer to a pointer-sized memory location - * or, if no channel exists creates and installs a new channel and sets up a - * new task to receive from it. - */ -pub unsafe fn chan_from_global_ptr( - global: GlobalPtr, - task_fn: fn() -> task::TaskBuilder, - f: fn~(oldcomm::Port) -) -> oldcomm::Chan { - - enum Msg { - Proceed, - Abort - } - - log(debug,~"ENTERING chan_from_global_ptr, before is_prob_zero check"); - let is_probably_zero = *global == 0u; - log(debug,~"after is_prob_zero check"); - if is_probably_zero { - log(debug,~"is probably zero..."); - // There's no global channel. We must make it - - let (setup1_po, setup1_ch) = pipes::stream(); - let (setup2_po, setup2_ch) = pipes::stream(); - - // FIXME #4422: Ugly type inference hint - let setup2_po: pipes::Port = setup2_po; - - do task_fn().spawn |move f, move setup1_ch, move setup2_po| { - let po = oldcomm::Port::(); - let ch = oldcomm::Chan(&po); - setup1_ch.send(ch); - - // Wait to hear if we are the official instance of - // this global task - match setup2_po.recv() { - Proceed => f(move po), - Abort => () - } - }; - - log(debug,~"before setup recv.."); - // This is the proposed global channel - let ch = setup1_po.recv(); - // 0 is our sentinal value. It is not a valid channel - assert *ch != 0; - - // Install the channel - log(debug,~"BEFORE COMPARE AND SWAP"); - let swapped = compare_and_swap( - cast::reinterpret_cast(&global), - 0, cast::reinterpret_cast(&ch)); - log(debug,fmt!("AFTER .. swapped? %?", swapped)); - - if swapped { - // Success! - setup2_ch.send(Proceed); - ch - } else { - // Somebody else got in before we did - setup2_ch.send(Abort); - cast::reinterpret_cast(&*global) - } - } else { - log(debug, ~"global != 0"); - cast::reinterpret_cast(&*global) - } -} - -#[test] -pub fn test_from_global_chan1() { - - // This is unreadable, right? - - // The global channel - let globchan = 0; - let globchanp = ptr::addr_of(&globchan); - - // Create the global channel, attached to a new task - let ch = unsafe { - do chan_from_global_ptr(globchanp, task::task) |po| { - let ch = oldcomm::recv(po); - oldcomm::send(ch, true); - let ch = oldcomm::recv(po); - oldcomm::send(ch, true); - } - }; - // Talk to it - let po = oldcomm::Port(); - oldcomm::send(ch, oldcomm::Chan(&po)); - assert oldcomm::recv(po) == true; - - // This one just reuses the previous channel - let ch = unsafe { - do chan_from_global_ptr(globchanp, task::task) |po| { - let ch = oldcomm::recv(po); - oldcomm::send(ch, false); - } - }; - - // Talk to the original global task - let po = oldcomm::Port(); - oldcomm::send(ch, oldcomm::Chan(&po)); - assert oldcomm::recv(po) == true; -} - -#[test] -pub fn test_from_global_chan2() { - - for iter::repeat(100) { - // The global channel - let globchan = 0; - let globchanp = ptr::addr_of(&globchan); - - let resultpo = oldcomm::Port(); - let resultch = oldcomm::Chan(&resultpo); - - // Spawn a bunch of tasks that all want to compete to - // create the global channel - for uint::range(0, 10) |i| { - do task::spawn { - let ch = unsafe { - do chan_from_global_ptr( - globchanp, task::task) |po| { - - for uint::range(0, 10) |_j| { - let ch = oldcomm::recv(po); - oldcomm::send(ch, {i}); - } - } - }; - let po = oldcomm::Port(); - oldcomm::send(ch, oldcomm::Chan(&po)); - // We are The winner if our version of the - // task was installed - let winner = oldcomm::recv(po); - oldcomm::send(resultch, winner == i); - } - } - // There should be only one winner - let mut winners = 0u; - for uint::range(0u, 10u) |_i| { - let res = oldcomm::recv(resultpo); - if res { winners += 1u }; - } - assert winners == 1u; - } -} - /** * Convert the current task to a 'weak' task temporarily * diff --git a/src/libstd/uv_global_loop.rs b/src/libstd/uv_global_loop.rs index 097e923225af1..c99bcaa54fac6 100644 --- a/src/libstd/uv_global_loop.rs +++ b/src/libstd/uv_global_loop.rs @@ -75,10 +75,10 @@ fn get_monitor_task_gl() -> IoTask unsafe { debug!("global monitor task starting"); // As a weak task the runtime will notify us when to exit do weaken_task |weak_exit_po| { - debug!("global monitor task is now weak"); + debug!("global monitor task is weak"); weak_exit_po.recv(); iotask::exit(&iotask); - debug!("global monitor task is leaving weakend state"); + debug!("global monitor task is unweak"); }; debug!("global monitor task exiting"); } From cc9ab2c0339aa00566ee6c5d12383278c7bd7eef Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 21 Jan 2013 19:22:55 -0800 Subject: [PATCH 09/31] Remove old comm-based weak task interface --- src/libcore/private.rs | 102 ---------------------------------------- src/rt/rust_builtin.cpp | 12 ----- src/rt/rust_kernel.cpp | 42 ----------------- src/rt/rust_kernel.h | 7 --- src/rt/rustrt.def.in | 2 - 5 files changed, 165 deletions(-) diff --git a/src/libcore/private.rs b/src/libcore/private.rs index c3068d6f61b0d..03207330f31c7 100644 --- a/src/libcore/private.rs +++ b/src/libcore/private.rs @@ -39,8 +39,6 @@ pub mod weak_task; extern mod rustrt { #[legacy_exports]; - unsafe fn rust_task_weaken(ch: rust_port_id); - unsafe fn rust_task_unweaken(ch: rust_port_id); unsafe fn rust_create_little_lock() -> rust_little_lock; unsafe fn rust_destroy_little_lock(lock: rust_little_lock); @@ -92,111 +90,11 @@ fn test_run_in_bare_thread() unsafe { } } -#[allow(non_camel_case_types)] // runtime type -type rust_port_id = uint; - fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool { let old = rusti::atomic_cxchg(address, oldval, newval); old == oldval } -/** - * Convert the current task to a 'weak' task temporarily - * - * As a weak task it will not be counted towards the runtime's set - * of live tasks. When there are no more outstanding live (non-weak) tasks - * the runtime will send an exit message on the provided channel. - * - * This function is super-unsafe. Do not use. - * - * # Safety notes - * - * * Weak tasks must either die on their own or exit upon receipt of - * the exit message. Failure to do so will cause the runtime to never - * exit - * * Tasks must not call `weaken_task` multiple times. This will - * break the kernel's accounting of live tasks. - * * Weak tasks must not be supervised. A supervised task keeps - * a reference to its parent, so the parent will not die. - */ -pub unsafe fn weaken_task(f: fn(oldcomm::Port<()>)) { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); - unsafe { - rustrt::rust_task_weaken(cast::reinterpret_cast(&ch)); - } - let _unweaken = Unweaken(ch); - f(po); - - struct Unweaken { - ch: oldcomm::Chan<()>, - drop unsafe { - rustrt::rust_task_unweaken(cast::reinterpret_cast(&self.ch)); - } - } - - fn Unweaken(ch: oldcomm::Chan<()>) -> Unweaken { - Unweaken { - ch: ch - } - } -} - -#[test] -pub fn test_weaken_task_then_unweaken() { - do task::try { - unsafe { - do weaken_task |_po| { - } - } - }; -} - -#[test] -pub fn test_weaken_task_wait() { - do task::spawn_unlinked { - unsafe { - do weaken_task |po| { - oldcomm::recv(po); - } - } - } -} - -#[test] -pub fn test_weaken_task_stress() { - // Create a bunch of weak tasks - for iter::repeat(100u) { - do task::spawn { - unsafe { - do weaken_task |_po| { - } - } - } - do task::spawn_unlinked { - unsafe { - do weaken_task |po| { - // Wait for it to tell us to die - oldcomm::recv(po); - } - } - } - } -} - -#[test] -#[ignore(cfg(windows))] -pub fn test_weaken_task_fail() { - let res = do task::try { - unsafe { - do weaken_task |_po| { - fail; - } - } - }; - assert result::is_err(&res); -} - /**************************************************************************** * Shared state & exclusive ARC ****************************************************************************/ diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 327337f441d8d..4fcfc11b32568 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -858,18 +858,6 @@ rust_compare_and_swap_ptr(intptr_t *address, return sync::compare_and_swap(address, oldval, newval); } -extern "C" CDECL void -rust_task_weaken(rust_port_id chan) { - rust_task *task = rust_get_current_task(); - task->kernel->weaken_task(chan); -} - -extern "C" CDECL void -rust_task_unweaken(rust_port_id chan) { - rust_task *task = rust_get_current_task(); - task->kernel->unweaken_task(chan); -} - extern "C" void rust_task_inhibit_kill(rust_task *task) { task->inhibit_kill(); diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index 8ca49ea6a57c3..c365f3cca1ef4 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -368,30 +368,6 @@ rust_kernel::unregister_task() { } } -void -rust_kernel::weaken_task(rust_port_id chan) { - { - scoped_lock with(weak_task_lock); - KLOG_("Weakening task with channel %" PRIdPTR, chan); - weak_task_chans.push_back(chan); - } - inc_weak_task_count(); -} - -void -rust_kernel::unweaken_task(rust_port_id chan) { - dec_weak_task_count(); - { - scoped_lock with(weak_task_lock); - KLOG_("Unweakening task with channel %" PRIdPTR, chan); - std::vector::iterator iter = - std::find(weak_task_chans.begin(), weak_task_chans.end(), chan); - if (iter != weak_task_chans.end()) { - weak_task_chans.erase(iter); - } - } -} - void rust_kernel::inc_weak_task_count() { uintptr_t new_non_weak_tasks = sync::decrement(non_weak_tasks); @@ -407,23 +383,6 @@ rust_kernel::dec_weak_task_count() { KLOG_("New non-weak tasks %" PRIdPTR, new_non_weak_tasks); } -void -rust_kernel::end_weak_tasks() { - std::vector chancopies; - { - scoped_lock with(weak_task_lock); - chancopies = weak_task_chans; - weak_task_chans.clear(); - } - while (!chancopies.empty()) { - rust_port_id chan = chancopies.back(); - chancopies.pop_back(); - KLOG_("Notifying weak task " PRIdPTR, chan); - uintptr_t token = 0; - send_to_port(chan, &token); - } -} - void rust_kernel::begin_shutdown() { { @@ -439,7 +398,6 @@ rust_kernel::begin_shutdown() { run_exit_functions(); allow_scheduler_exit(); - end_weak_tasks(); } bool diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index 8ba0405b86e07..c25cef9fef98c 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -119,14 +119,9 @@ class rust_kernel { // An atomically updated count of the live, 'non-weak' tasks uintptr_t non_weak_tasks; - // Protects weak_task_chans - lock_and_signal weak_task_lock; - // A list of weak tasks that need to be told when to exit - std::vector weak_task_chans; rust_scheduler* get_scheduler_by_id_nolock(rust_sched_id id); void allow_scheduler_exit(); - void end_weak_tasks(); void begin_shutdown(); lock_and_signal at_exit_lock; @@ -180,8 +175,6 @@ class rust_kernel { void register_task(); void unregister_task(); - void weaken_task(rust_port_id chan); - void unweaken_task(rust_port_id chan); void inc_weak_task_count(); void dec_weak_task_count(); diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 8e8ce9ee509e2..eb9db6c1d5755 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -61,8 +61,6 @@ rust_task_yield rust_task_is_unwinding rust_get_task rust_get_stack_segment -rust_task_weaken -rust_task_unweaken rust_log_str start_task vec_reserve_shared_actual From bc0c5bb447ac8eba0a80599305c23db6c8a1ed6a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 22 Jan 2013 12:38:08 -0800 Subject: [PATCH 10/31] core: Stop using oldcomm --- src/libcore/private.rs | 1 - src/libcore/run.rs | 13 +++-- src/libcore/task/mod.rs | 119 +++++++++++++++++--------------------- src/libcore/task/spawn.rs | 10 ++-- 4 files changed, 64 insertions(+), 79 deletions(-) diff --git a/src/libcore/private.rs b/src/libcore/private.rs index 03207330f31c7..23268b1b778d8 100644 --- a/src/libcore/private.rs +++ b/src/libcore/private.rs @@ -18,7 +18,6 @@ use cast; use iter; use libc; -use oldcomm; use option; use pipes; use prelude::*; diff --git a/src/libcore/run.rs b/src/libcore/run.rs index 54bce77d30885..07071e948922b 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -17,7 +17,7 @@ use io; use io::ReaderUtil; use libc; use libc::{pid_t, c_void, c_int}; -use oldcomm; +use pipes::{stream, SharedChan}; use option::{Some, None}; use os; use prelude::*; @@ -333,22 +333,23 @@ pub fn program_output(prog: &str, args: &[~str]) -> // in parallel so we don't deadlock while blocking on one // or the other. FIXME (#2625): Surely there's a much more // clever way to do this. - let p = oldcomm::Port(); - let ch = oldcomm::Chan(&p); + let (p, ch) = stream(); + let ch = SharedChan(ch); + let ch_clone = ch.clone(); do task::spawn_sched(task::SingleThreaded) { let errput = readclose(pipe_err.in); - oldcomm::send(ch, (2, move errput)); + ch.send((2, move errput)); }; do task::spawn_sched(task::SingleThreaded) { let output = readclose(pipe_out.in); - oldcomm::send(ch, (1, move output)); + ch_clone.send((1, move output)); }; let status = run::waitpid(pid); let mut errs = ~""; let mut outs = ~""; let mut count = 2; while count > 0 { - let stream = oldcomm::recv(p); + let stream = p.recv(); match stream { (1, copy s) => { outs = move s; diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 86d38a18c50b5..315a2843af6e1 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -43,10 +43,9 @@ use cmp; use cmp::Eq; use iter; use libc; -use oldcomm; use option; use result::Result; -use pipes::{stream, Chan, Port}; +use pipes::{stream, Chan, Port, SharedChan}; use pipes; use prelude::*; use ptr; @@ -427,18 +426,17 @@ impl TaskBuilder { * Fails if a future_result was already set for this task. */ fn try(f: fn~() -> T) -> Result { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream::(); let mut result = None; let fr_task_builder = self.future_result(|+r| { result = Some(move r); }); - do fr_task_builder.spawn |move f| { - oldcomm::send(ch, f()); + do fr_task_builder.spawn |move f, move ch| { + ch.send(f()); } match option::unwrap(move result).recv() { - Success => result::Ok(oldcomm::recv(po)), + Success => result::Ok(po.recv()), Failure => result::Err(()) } } @@ -665,17 +663,18 @@ fn test_cant_dup_task_builder() { #[test] #[ignore(cfg(windows))] fn test_spawn_unlinked_unsup_no_fail_down() { // grandchild sends on a port - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream(); + let ch = SharedChan(ch); do spawn_unlinked { + let ch = ch.clone(); do spawn_unlinked { // Give middle task a chance to fail-but-not-kill-us. for iter::repeat(16) { task::yield(); } - oldcomm::send(ch, ()); // If killed first, grandparent hangs. + ch.send(()); // If killed first, grandparent hangs. } fail; // Shouldn't kill either (grand)parent or (grand)child. } - oldcomm::recv(po); + po.recv(); } #[test] #[ignore(cfg(windows))] fn test_spawn_unlinked_unsup_no_fail_up() { // child unlinked fails @@ -695,8 +694,7 @@ fn test_spawn_unlinked_sup_fail_down() { #[test] #[should_fail] #[ignore(cfg(windows))] fn test_spawn_linked_sup_fail_up() { // child fails; parent fails - let po = oldcomm::Port::<()>(); - let _ch = oldcomm::Chan(&po); + let (po, _ch) = stream::<()>(); // Unidirectional "parenting" shouldn't override bidirectional linked. // We have to cheat with opts - the interface doesn't support them because // they don't make sense (redundant with task().supervised()). @@ -714,7 +712,7 @@ fn test_spawn_linked_sup_fail_up() { // child fails; parent fails .. b0 }; do b1.spawn { fail; } - oldcomm::recv(po); // We should get punted awake + po.recv(); // We should get punted awake } #[test] #[should_fail] #[ignore(cfg(windows))] fn test_spawn_linked_sup_fail_down() { // parent fails; child fails @@ -738,11 +736,10 @@ fn test_spawn_linked_sup_fail_down() { // parent fails; child fails } #[test] #[should_fail] #[ignore(cfg(windows))] fn test_spawn_linked_unsup_fail_up() { // child fails; parent fails - let po = oldcomm::Port::<()>(); - let _ch = oldcomm::Chan(&po); + let (po, _ch) = stream::<()>(); // Default options are to spawn linked & unsupervised. do spawn { fail; } - oldcomm::recv(po); // We should get punted awake + po.recv(); // We should get punted awake } #[test] #[should_fail] #[ignore(cfg(windows))] fn test_spawn_linked_unsup_fail_down() { // parent fails; child fails @@ -810,27 +807,25 @@ fn test_spawn_linked_sup_propagate_sibling() { #[test] fn test_run_basic() { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream::<()>(); do task().spawn { - oldcomm::send(ch, ()); + ch.send(()); } - oldcomm::recv(po); + po.recv(); } #[test] fn test_add_wrapper() { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream::<()>(); let b0 = task(); let b1 = do b0.add_wrapper |body| { fn~(move body) { body(); - oldcomm::send(ch, ()); + ch.send(()); } }; do b1.spawn { } - oldcomm::recv(po); + po.recv(); } #[test] @@ -883,10 +878,10 @@ fn test_spawn_sched_no_threads() { #[test] fn test_spawn_sched() { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream::<()>(); + let ch = SharedChan(ch); - fn f(i: int, ch: oldcomm::Chan<()>) { + fn f(i: int, ch: SharedChan<()>) { let parent_sched_id = rt::rust_get_sched_id(); do spawn_sched(SingleThreaded) { @@ -894,21 +889,20 @@ fn test_spawn_sched() { assert parent_sched_id != child_sched_id; if (i == 0) { - oldcomm::send(ch, ()); + ch.send(()); } else { - f(i - 1, ch); + f(i - 1, ch.clone()); } }; } f(10, ch); - oldcomm::recv(po); + po.recv(); } #[test] fn test_spawn_sched_childs_on_default_sched() { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream(); // Assuming tests run on the default scheduler let default_id = rt::rust_get_sched_id(); @@ -919,11 +913,11 @@ fn test_spawn_sched_childs_on_default_sched() { let child_sched_id = rt::rust_get_sched_id(); assert parent_sched_id != child_sched_id; assert child_sched_id == default_id; - oldcomm::send(ch, ()); + ch.send(()); }; }; - oldcomm::recv(po); + po.recv(); } #[nolink] @@ -945,10 +939,8 @@ fn test_spawn_sched_blocking() { // without affecting other schedulers for iter::repeat(20u) { - let start_po = oldcomm::Port(); - let start_ch = oldcomm::Chan(&start_po); - let fin_po = oldcomm::Port(); - let fin_ch = oldcomm::Chan(&fin_po); + let (start_po, start_ch) = stream(); + let (fin_po, fin_ch) = stream(); let lock = testrt::rust_dbg_lock_create(); @@ -956,44 +948,42 @@ fn test_spawn_sched_blocking() { unsafe { testrt::rust_dbg_lock_lock(lock); - oldcomm::send(start_ch, ()); + start_ch.send(()); // Block the scheduler thread testrt::rust_dbg_lock_wait(lock); testrt::rust_dbg_lock_unlock(lock); - oldcomm::send(fin_ch, ()); + fin_ch.send(()); } }; // Wait until the other task has its lock - oldcomm::recv(start_po); + start_po.recv(); - fn pingpong(po: oldcomm::Port, ch: oldcomm::Chan) { + fn pingpong(po: &Port, ch: &Chan) { let mut val = 20; while val > 0 { - val = oldcomm::recv(po); - oldcomm::send(ch, val - 1); + val = po.recv(); + ch.send(val - 1); } } - let setup_po = oldcomm::Port(); - let setup_ch = oldcomm::Chan(&setup_po); - let parent_po = oldcomm::Port(); - let parent_ch = oldcomm::Chan(&parent_po); + let (setup_po, setup_ch) = stream(); + let (parent_po, parent_ch) = stream(); do spawn { - let child_po = oldcomm::Port(); - oldcomm::send(setup_ch, oldcomm::Chan(&child_po)); - pingpong(child_po, parent_ch); + let (child_po, child_ch) = stream(); + setup_ch.send(child_ch); + pingpong(&child_po, &parent_ch); }; - let child_ch = oldcomm::recv(setup_po); - oldcomm::send(child_ch, 20); - pingpong(parent_po, child_ch); + let child_ch = setup_po.recv(); + child_ch.send(20); + pingpong(&parent_po, &child_ch); testrt::rust_dbg_lock_lock(lock); testrt::rust_dbg_lock_signal(lock); testrt::rust_dbg_lock_unlock(lock); - oldcomm::recv(fin_po); + fin_po.recv(); testrt::rust_dbg_lock_destroy(lock); } } @@ -1001,18 +991,17 @@ fn test_spawn_sched_blocking() { #[cfg(test)] fn avoid_copying_the_body(spawnfn: fn(v: fn~())) { - let p = oldcomm::Port::(); - let ch = oldcomm::Chan(&p); + let (p, ch) = stream::(); let x = ~1; let x_in_parent = ptr::addr_of(&(*x)) as uint; do spawnfn |move x| { let x_in_child = ptr::addr_of(&(*x)) as uint; - oldcomm::send(ch, x_in_child); + ch.send(x_in_child); } - let x_in_child = oldcomm::recv(p); + let x_in_child = p.recv(); assert x_in_parent == x_in_child; } @@ -1050,20 +1039,18 @@ fn test_avoid_copying_the_body_unlinked() { #[test] fn test_platform_thread() { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream(); do task().sched_mode(PlatformThread).spawn { - oldcomm::send(ch, ()); + ch.send(()); } - oldcomm::recv(po); + po.recv(); } #[test] #[ignore(cfg(windows))] #[should_fail] fn test_unkillable() { - let po = oldcomm::Port(); - let ch = po.chan(); + let (po, ch) = stream(); // We want to do this after failing do spawn_unlinked { diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs index e3afa7c45353e..a844542c214ec 100644 --- a/src/libcore/task/spawn.rs +++ b/src/libcore/task/spawn.rs @@ -74,9 +74,8 @@ #[warn(deprecated_mode)]; use cast; -use oldcomm; use option; -use pipes::{Chan, Port}; +use pipes::{stream, Chan, Port}; use pipes; use prelude::*; use private; @@ -667,12 +666,11 @@ pub fn spawn_raw(opts: TaskOpts, f: fn~()) { #[test] fn test_spawn_raw_simple() { - let po = oldcomm::Port(); - let ch = oldcomm::Chan(&po); + let (po, ch) = stream(); do spawn_raw(default_task_opts()) { - oldcomm::send(ch, ()); + ch.send(()); } - oldcomm::recv(po); + po.recv(); } #[test] From 19aa88cd64c81b77b874f9396a43fedfa28f14ee Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 24 Jan 2013 23:53:42 -0800 Subject: [PATCH 11/31] Stop using oldcomm in uv_global_loop tests --- src/libstd/uv_global_loop.rs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/libstd/uv_global_loop.rs b/src/libstd/uv_global_loop.rs index c99bcaa54fac6..8637470dd5407 100644 --- a/src/libstd/uv_global_loop.rs +++ b/src/libstd/uv_global_loop.rs @@ -126,15 +126,17 @@ mod test { use core::iter; use core::libc; - use core::oldcomm; use core::ptr; use core::task; + use core::cast::transmute; + use core::libc::c_void; + use core::pipes::{stream, SharedChan, Chan}; extern fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) unsafe { let exit_ch_ptr = ll::get_data_for_uv_handle( - timer_ptr as *libc::c_void) as *oldcomm::Chan; - let exit_ch = *exit_ch_ptr; - oldcomm::send(exit_ch, true); + timer_ptr as *libc::c_void); + let exit_ch = transmute::<*c_void, ~Chan>(exit_ch_ptr); + exit_ch.send(true); log(debug, fmt!("EXIT_CH_PTR simple_timer_close_cb exit_ch_ptr: %?", exit_ch_ptr)); } @@ -153,9 +155,8 @@ mod test { } fn impl_uv_hl_simple_timer(iotask: &IoTask) unsafe { - let exit_po = oldcomm::Port::(); - let exit_ch = oldcomm::Chan(&exit_po); - let exit_ch_ptr = ptr::addr_of(&exit_ch); + let (exit_po, exit_ch) = stream::(); + let exit_ch_ptr: *libc::c_void = transmute(~exit_ch); log(debug, fmt!("EXIT_CH_PTR newly created exit_ch_ptr: %?", exit_ch_ptr)); let timer_handle = ll::timer_t(); @@ -166,7 +167,7 @@ mod test { if(init_status == 0i32) { ll::set_data_for_uv_handle( timer_ptr as *libc::c_void, - exit_ch_ptr as *libc::c_void); + exit_ch_ptr); let start_status = ll::timer_start(timer_ptr, simple_timer_cb, 1u, 0u); if(start_status == 0i32) { @@ -179,22 +180,21 @@ mod test { fail ~"failure on ll::timer_init()"; } }; - oldcomm::recv(exit_po); + exit_po.recv(); log(debug, ~"global_loop timer test: msg recv on exit_po, done.."); } #[test] fn test_gl_uv_global_loop_high_level_global_timer() unsafe { let hl_loop = &get_gl(); - let exit_po = oldcomm::Port::<()>(); - let exit_ch = oldcomm::Chan(&exit_po); + let (exit_po, exit_ch) = stream::<()>(); task::spawn_sched(task::ManualThreads(1u), || { let hl_loop = &get_gl(); impl_uv_hl_simple_timer(hl_loop); - oldcomm::send(exit_ch, ()); + exit_ch.send(()); }); impl_uv_hl_simple_timer(hl_loop); - oldcomm::recv(exit_po); + exit_po.recv(); } // keeping this test ignored until some kind of stress-test-harness @@ -202,18 +202,19 @@ mod test { #[test] #[ignore] fn test_stress_gl_uv_global_loop_high_level_global_timer() unsafe { - let exit_po = oldcomm::Port::<()>(); - let exit_ch = oldcomm::Chan(&exit_po); + let (exit_po, exit_ch) = stream::<()>(); + let exit_ch = SharedChan(exit_ch); let cycles = 5000u; for iter::repeat(cycles) { + let exit_ch_clone = exit_ch.clone(); task::spawn_sched(task::ManualThreads(1u), || { let hl_loop = &get_gl(); impl_uv_hl_simple_timer(hl_loop); - oldcomm::send(exit_ch, ()); + exit_ch_clone.send(()); }); }; for iter::repeat(cycles) { - oldcomm::recv(exit_po); + exit_po.recv(); }; log(debug, ~"test_stress_gl_uv_global_loop_high_level_global_timer"+ ~" exiting sucessfully!"); From d4fd30c6ace41638f10e415f6cad175997ec21c4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 24 Jan 2013 16:24:45 -0800 Subject: [PATCH 12/31] Link the lifetimes of regions resulting from borrows of the contents of other borrowed pointers to the lifetimes of the borrowed value. Fixes #3148. r=catamorphism --- src/librustc/middle/mem_categorization.rs | 2 + src/librustc/middle/resolve.rs | 35 ++ src/librustc/middle/ty.rs | 9 + src/librustc/middle/typeck/check/mod.rs | 13 +- src/librustc/middle/typeck/check/regionck.rs | 514 ++++++++++++++++-- src/librustc/util/ppaux.rs | 6 + src/libsyntax/ext/auto_encode.rs | 2 +- src/libsyntax/ext/build.rs | 8 +- src/libsyntax/ext/deriving.rs | 3 +- src/test/run-pass/region-dependent-addr-of.rs | 112 ++++ ...egion-return-interior-of-option-in-self.rs | 30 - 11 files changed, 640 insertions(+), 94 deletions(-) create mode 100644 src/test/run-pass/region-dependent-addr-of.rs delete mode 100644 src/test/run-pass/region-return-interior-of-option-in-self.rs diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 909d1f95fde4b..6cd14d332bf55 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -111,6 +111,8 @@ enum special_kind { // a complete categorization of a value indicating where it originated // and how it is located, as well as the mutability of the memory in // which the value is stored. +// +// note: cmt stands for "categorized mutable type". type cmt_ = {id: ast::node_id, // id of expr/pat producing this value span: span, // span of same expr/pat cat: categorization, // categorization of expr diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 68198ae3f3fc9..60ed64b1c1d5e 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -25,6 +25,7 @@ use core::str; use core::vec; use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm}; use syntax::ast::{binding_mode, bitand, bitor, bitxor, blk, capture_clause}; +use syntax::ast::{bind_by_value, bind_infer, bind_by_ref, bind_by_move}; use syntax::ast::{crate, crate_num, decl_item, def, def_arg, def_binding}; use syntax::ast::{def_const, def_foreign_mod, def_fn, def_id, def_label}; use syntax::ast::{def_local, def_mod, def_prim_ty, def_region, def_self}; @@ -4521,6 +4522,10 @@ impl Resolver { struct or enum variant", self.session.str_of(ident)); + self.enforce_default_binding_mode( + pattern, + binding_mode, + "an enum variant"); self.record_def(pattern.id, def); } FoundStructOrEnumVariant(_) => { @@ -4537,6 +4542,10 @@ impl Resolver { constant", self.session.str_of(ident)); + self.enforce_default_binding_mode( + pattern, + binding_mode, + "a constant"); self.record_def(pattern.id, def); } FoundConst(_) => { @@ -5371,6 +5380,32 @@ impl Resolver { self.def_map.insert(node_id, def); } + fn enforce_default_binding_mode(pat: @pat, + pat_binding_mode: binding_mode, + descr: &str) { + match pat_binding_mode { + bind_infer => {} + bind_by_value => { + self.session.span_err( + pat.span, + fmt!("cannot use `copy` binding mode with %s", + descr)); + } + bind_by_move => { + self.session.span_err( + pat.span, + fmt!("cannot use `move` binding mode with %s", + descr)); + } + bind_by_ref(*) => { + self.session.span_err( + pat.span, + fmt!("cannot use `ref` binding mode with %s", + descr)); + } + } + } + // // main function checking // diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c82825795869a..2e0d7026769ef 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -119,6 +119,7 @@ export ty_opaque_box, mk_opaque_box; export ty_float, mk_float, mk_mach_float, type_is_fp; export ty_fn, FnTy, FnTyBase, FnMeta, FnSig, mk_fn; export ty_fn_proto, ty_fn_purity, ty_fn_ret, tys_in_fn_sig; +export ty_vstore; export replace_fn_return_type; export ty_int, mk_int, mk_mach_int, mk_char; export mk_i8, mk_u8, mk_i16, mk_u16, mk_i32, mk_u32, mk_i64, mk_u64; @@ -3005,6 +3006,14 @@ fn is_fn_ty(fty: t) -> bool { } } +pure fn ty_vstore(ty: t) -> vstore { + match get(ty).sty { + ty_evec(_, vstore) => vstore, + ty_estr(vstore) => vstore, + ref s => fail fmt!("ty_vstore() called on invalid sty: %?", s) + } +} + fn ty_region(ty: t) -> Region { match get(ty).sty { ty_rptr(r, _) => r, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 43f609dd2f0a3..be6559640d724 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -105,7 +105,7 @@ use middle::typeck::{isr_alist, lookup_def_ccx, method_map_entry}; use middle::typeck::{method_origin, method_self, method_trait, no_params}; use middle::typeck::{require_same_types}; use util::common::{block_query, indenter, loop_query}; -use util::ppaux::{bound_region_to_str, expr_repr}; +use util::ppaux::{bound_region_to_str, expr_repr, pat_repr}; use util::ppaux; use core::either; @@ -127,7 +127,6 @@ use syntax::ast_util; use syntax::codemap::span; use syntax::codemap; use syntax::parse::token::special_idents; -use syntax::print::pprust::{expr_to_str, pat_to_str}; use syntax::print::pprust; use syntax::visit; use syntax; @@ -469,7 +468,7 @@ fn check_fn(ccx: @crate_ctxt, }; assign(local.span, local.node.id, o_ty); debug!("Local variable %s is assigned to %s", - pat_to_str(local.node.pat, tcx.sess.intr()), + fcx.pat_to_str(local.node.pat), fcx.inh.locals.get(local.node.id).to_str()); visit::visit_local(local, e, v); }; @@ -756,6 +755,10 @@ impl @fn_ctxt { expr_repr(self.tcx(), expr) } + fn pat_to_str(pat: @ast::pat) -> ~str { + pat_repr(self.tcx(), pat) + } + fn expr_ty(ex: @ast::expr) -> ty::t { match self.inh.node_types.find(ex.id) { Some(t) => t, @@ -1600,7 +1603,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, let fty = ty::mk_fn(tcx, copy fn_ty); debug!("check_expr_fn_with_unifier %s fty=%s", - expr_to_str(expr, tcx.sess.intr()), + fcx.expr_to_str(expr), fcx.infcx().ty_to_str(fty)); fcx.write_ty(expr.id, fty); @@ -2713,7 +2716,7 @@ fn check_enum_variants(ccx: @crate_ctxt, do v.node.disr_expr.iter |e_ref| { let e = *e_ref; debug!("disr expr, checking %s", - expr_to_str(e, ccx.tcx.sess.intr())); + pprust::expr_to_str(e, ccx.tcx.sess.intr())); let declty = ty::mk_int(ccx.tcx); let fcx = blank_fn_ctxt(ccx, rty, e.id); check_const_with_ty(fcx, e.span, e, declty); diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 05f23bddb0860..419e6269957cf 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -30,7 +30,7 @@ this point a bit better. use core::prelude::*; use middle::freevars::get_freevars; -use middle::pat_util::pat_bindings; +use middle::pat_util::{pat_bindings, pat_is_binding}; use middle::ty::{encl_region, re_scope}; use middle::ty::{ty_fn_proto, vstore_box, vstore_fixed, vstore_slice}; use middle::ty::{vstore_uniq}; @@ -73,35 +73,44 @@ fn encl_region_of_def(fcx: @fn_ctxt, def: ast::def) -> ty::Region { } impl @rcx { - /// Try to resolve the type for the given node. - /// - /// Note one important point: we do not attempt to resolve *region - /// variables* here. This is because regionck is essentially adding - /// constraints to those region variables and so may yet influence - /// how they are resolved. - /// - /// Consider this silly example: - /// - /// fn borrow(x: &int) -> &int {x} - /// fn foo(x: @int) -> int { /* block: B */ - /// let b = borrow(x); /* region: */ - /// *b - /// } - /// - /// Here, the region of `b` will be ``. `` is constrainted - /// to be some subregion of the block B and some superregion of - /// the call. If we forced it now, we'd choose the smaller region - /// (the call). But that would make the *b illegal. Since we don't - /// resolve, the type of b will be `&.int` and then `*b` will require - /// that `` be bigger than the let and the `*b` expression, so we - /// will effectively resolve `` to be the block B. - fn resolve_type(unresolved_ty: ty::t) -> fres { - resolve_type(self.fcx.infcx(), unresolved_ty, - resolve_and_force_all_but_regions) + fn resolve_type(unresolved_ty: ty::t) -> Option { + /*! + * Try to resolve the type for the given node, returning + * None if an error results. Note that we never care + * about the details of the error, the same error will be + * detected and reported in the writeback phase. + * + * Note one important point: we do not attempt to resolve + * *region variables* here. This is because regionck is + * essentially adding constraints to those region variables + * and so may yet influence how they are resolved. + * + * Consider this silly example: + * + * fn borrow(x: &int) -> &int {x} + * fn foo(x: @int) -> int { // block: B + * let b = borrow(x); // region: + * *b + * } + * + * Here, the region of `b` will be ``. `` is + * constrainted to be some subregion of the block B and some + * superregion of the call. If we forced it now, we'd choose + * the smaller region (the call). But that would make the *b + * illegal. Since we don't resolve, the type of b will be + * `&.int` and then `*b` will require that `` be + * bigger than the let and the `*b` expression, so we will + * effectively resolve `` to be the block B. + */ + match resolve_type(self.fcx.infcx(), unresolved_ty, + resolve_and_force_all_but_regions) { + Ok(t) => Some(t), + Err(_) => None + } } /// Try to resolve the type for the given node. - fn resolve_node_type(id: ast::node_id) -> fres { + fn resolve_node_type(id: ast::node_id) -> Option { self.resolve_type(self.fcx.node_ty(id)) } } @@ -170,8 +179,7 @@ fn visit_block(b: ast::blk, &&rcx: @rcx, v: rvt) { } fn visit_expr(expr: @ast::expr, &&rcx: @rcx, v: rvt) { - debug!("visit_expr(e=%s)", - pprust::expr_to_str(expr, rcx.fcx.tcx().sess.intr())); + debug!("visit_expr(e=%s)", rcx.fcx.expr_to_str(expr)); match /*bad*/copy expr.node { ast::expr_path(*) => { @@ -242,40 +250,36 @@ fn visit_expr(expr: @ast::expr, &&rcx: @rcx, v: rvt) { // particular case. There is an extensive comment on the // function check_cast_for_escaping_regions() in kind.rs // explaining how it goes about doing that. - match rcx.resolve_node_type(expr.id) { - result::Err(_) => { return; /*typeck will fail anyhow*/ } - result::Ok(target_ty) => { - match ty::get(target_ty).sty { - ty::ty_trait(_, _, vstore_slice(trait_region)) => { - let source_ty = rcx.fcx.expr_ty(source); - constrain_regions_in_type(rcx, trait_region, - expr.span, source_ty); - } - _ => () + for rcx.resolve_node_type(expr.id).each |target_ty| { + match ty::get(*target_ty).sty { + ty::ty_trait(_, _, vstore_slice(trait_region)) => { + let source_ty = rcx.fcx.expr_ty(source); + constrain_regions_in_type(rcx, trait_region, + expr.span, source_ty); } + _ => () } - }; + } + } + + ast::expr_addr_of(_, base) => { + guarantor::for_addr_of(rcx, expr, base); } - ast::expr_addr_of(*) => { - // FIXME(#3148) -- in some cases, we need to capture a - // dependency between the regions found in operand the - // resulting region type. See #3148 for more details. + ast::expr_match(discr, ref arms) => { + guarantor::for_match(rcx, discr, *arms); } ast::expr_fn(*) | ast::expr_fn_block(*) => { - match rcx.resolve_node_type(expr.id) { - result::Err(_) => return, // Typechecking will fail anyhow. - result::Ok(function_type) => { - match ty::get(function_type).sty { - ty::ty_fn(ref fn_ty) => { - if fn_ty.meta.proto == ast::ProtoBorrowed { - constrain_free_variables( - rcx, fn_ty.meta.region, expr); - } + for rcx.resolve_node_type(expr.id).each |function_type| { + match ty::get(*function_type).sty { + ty::ty_fn(ref fn_ty) => { + if fn_ty.meta.proto == ast::ProtoBorrowed { + constrain_free_variables( + rcx, fn_ty.meta.region, expr); } - _ => () } + _ => () } } } @@ -406,8 +410,8 @@ fn constrain_regions_in_type_of_node( // is going to fail anyway, so just stop here and let typeck // report errors later on in the writeback phase. let ty = match rcx.resolve_node_type(id) { - result::Err(_) => return true, - result::Ok(ty) => ty + None => { return true; } + Some(ty) => { ty } }; debug!("constrain_regions_in_type_of_node(\ @@ -477,3 +481,401 @@ fn constrain_regions_in_type( } } } + +mod guarantor { + /*! + * + * The routines in this module are aiming to deal with the case + * where the lifetime resulting from a borrow is linked to the + * lifetime of the thing being borrowed. Imagine you have a + * borrowed pointer `b` with lifetime L1 and you have an + * expression `&*b`. The result of this borrow will be another + * borrowed pointer with lifetime L2 (which is an inference + * variable). The borrow checker is going to enforce the + * constraint that L2 < L1, because otherwise you are re-borrowing + * data for a lifetime larger than the original loan. However, + * without the routines in this module, the region inferencer would + * not know of this dependency and thus it might infer the + * lifetime of L2 to be greater than L1 (issue #3148). + * + * There are a number of troublesome scenarios in the test + * `region-dependent-addr-of.rs`, but here is one example: + * + * struct Foo { i: int } + * struct Bar { foo: Foo } + * fn get_i(x: &a/Bar) -> &a/int { + * let foo = &x.foo; // Lifetime L1 + * &foo.i // Lifetime L2 + * } + * + * Note that this comes up either with `&` expressions, `ref` + * bindings, and `autorefs`, which are the three ways to introduce + * a borrow. + * + * The key point here is that when you are borrowing a value that + * is "guaranteed" by a borrowed pointer, you must link the + * lifetime of that borrowed pointer (L1, here) to the lifetime of + * the borrow itself (L2). What do I mean by "guaranteed" by a + * borrowed pointer? Well, I would say the data "owned" by the + * borrowed pointer, except that a borrowed pointer never owns its + * contents, but the relation is the same. That is, I mean any + * data that is reached by first derefencing a borrowed pointer + * and then either traversing interior offsets or owned pointers. + * We say that the guarantor of such data it the region of the borrowed + * pointer that was traversed. + * + * NB: I really wanted to use the `mem_categorization` code here + * but I cannot because final type resolution hasn't happened yet. + * So this is very similar logic to what you would find there, + * but more special purpose. + */ + + pub fn for_addr_of(rcx: @rcx, expr: @ast::expr, base: @ast::expr) { + /*! + * + * Computes the guarantor for an expression `&base` and then + * ensures that the lifetime of the resulting pointer is linked. + */ + + debug!("guarantor::for_addr_of(base=%s)", rcx.fcx.expr_to_str(base)); + let _i = ::util::common::indenter(); + + let guarantor = guarantor(rcx, base); + link(rcx, expr.span, expr.id, guarantor); + } + + pub fn for_match(rcx: @rcx, discr: @ast::expr, arms: &[ast::arm]) { + /*! + * + * Computes the guarantors for any ref bindings in a match and + * then ensures that the lifetime of the resulting pointer is + * linked. + */ + + let discr_guarantor = guarantor(rcx, discr); + for arms.each |arm| { + for arm.pats.each |pat| { + link_ref_bindings_in_pat(rcx, *pat, discr_guarantor); + } + } + } + + fn link( + rcx: @rcx, + span: span, + id: ast::node_id, + guarantor: Option) + { + /*! + * + * Links the lifetime of the borrowed pointer resulting from a borrow + * to the lifetime of its guarantor. + */ + + debug!("opt_constrain_region(id=%?, guarantor=%?)", id, guarantor); + + let bound = match guarantor { + None => { return; } + Some(r) => { r } + }; + + // this routine is used for the result of ref bindings and & + // expressions, both of which always yield a region variable, so + // mk_subr should never fail. + for rcx.resolve_node_type(id).each |rptr_ty| { + debug!("rptr_ty=%s", ty_to_str(rcx.fcx.ccx.tcx, *rptr_ty)); + let r = ty::ty_region(*rptr_ty); + infallibly_mk_subr(rcx, true, span, r, bound); + } + } + + enum PointerCat { + NotPointer, + OwnedPointer, + BorrowedPointer(ty::Region), + OtherPointer + } + + struct ExprCategorization { + guarantor: Option, + pointer: PointerCat + } + + fn guarantor(rcx: @rcx, expr: @ast::expr) -> Option { + debug!("guarantor(expr=%s)", rcx.fcx.expr_to_str(expr)); + match expr.node { + ast::expr_unary(ast::deref, b) => { + let cat = categorize(rcx, b); + guarantor_of_deref(&cat) + } + ast::expr_field(b, _, _) => { + categorize(rcx, b).guarantor + } + ast::expr_index(b, _) => { + let cat = categorize(rcx, b); + guarantor_of_deref(&cat) + } + + ast::expr_paren(e) => { + guarantor(rcx, e) + } + + ast::expr_path(*) => { + // Either a variable or constant and hence resides + // in constant memory or on the stack frame. Either way, + // not guaranteed by a region pointer. + None + } + + // All of these expressions are rvalues and hence their + // value is not guaranteed by a region pointer. + ast::expr_mac(*) | + ast::expr_lit(_) | + ast::expr_unary(*) | + ast::expr_addr_of(*) | + ast::expr_binary(*) | + ast::expr_vstore(*) | + ast::expr_break(*) | + ast::expr_again(*) | + ast::expr_ret(*) | + ast::expr_log(*) | + ast::expr_fail(*) | + ast::expr_assert(*) | + ast::expr_while(*) | + ast::expr_loop(*) | + ast::expr_assign(*) | + ast::expr_swap(*) | + ast::expr_assign_op(*) | + ast::expr_cast(*) | + ast::expr_call(*) | + ast::expr_method_call(*) | + ast::expr_rec(*) | + ast::expr_struct(*) | + ast::expr_tup(*) | + ast::expr_if(*) | + ast::expr_match(*) | + ast::expr_fn(*) | + ast::expr_fn_block(*) | + ast::expr_loop_body(*) | + ast::expr_do_body(*) | + ast::expr_block(*) | + ast::expr_copy(*) | + ast::expr_unary_move(*) | + ast::expr_repeat(*) | + ast::expr_vec(*) => { + assert !ty::expr_is_lval( + rcx.fcx.tcx(), rcx.fcx.ccx.method_map, expr); + None + } + } + } + + fn categorize(rcx: @rcx, + expr: @ast::expr) -> ExprCategorization + { + debug!("categorize(expr=%s)", rcx.fcx.expr_to_str(expr)); + let _i = ::util::common::indenter(); + + let tcx = rcx.fcx.ccx.tcx; + if rcx.fcx.ccx.method_map.contains_key(expr.id) { + debug!("method call"); + return id_categorization(rcx, None, expr.id); + } + + let expr_ty = match rcx.resolve_node_type(expr.id) { + None => { return id_categorization(rcx, None, expr.id); } + Some(t) => { t } + }; + let mut cat = ExprCategorization { + guarantor: guarantor(rcx, expr), + pointer: pointer_categorize(expr_ty) + }; + + debug!("before adjustments, cat=%?", cat); + + for rcx.fcx.inh.adjustments.find(expr.id).each |adjustment| { + debug!("adjustment=%?", adjustment); + for uint::range(0, adjustment.autoderefs) |_| { + cat.guarantor = guarantor_of_deref(&cat); + + match ty::deref(tcx, expr_ty, true) { + Some(t) => { + cat.pointer = pointer_categorize(t.ty); + } + None => { + tcx.sess.span_bug( + expr.span, + fmt!("Autoderef but type not derefable: %s", + ty_to_str(tcx, expr_ty))); + } + } + + debug!("autoderef, cat=%?", cat); + } + + for adjustment.autoref.each |autoref| { + cat.guarantor = None; + cat.pointer = BorrowedPointer(autoref.region); + debug!("autoref, cat=%?", cat); + } + } + + debug!("result=%?", cat); + return cat; + } + + fn pointer_categorize(ty: ty::t) -> PointerCat { + match ty::get(ty).sty { + ty::ty_rptr(r, _) | ty::ty_evec(_, vstore_slice(r)) | + ty::ty_estr(vstore_slice(r)) => { + BorrowedPointer(r) + } + ty::ty_uniq(*) | ty::ty_estr(vstore_uniq) | + ty::ty_evec(_, vstore_uniq) => { + OwnedPointer + } + ty::ty_box(*) | ty::ty_ptr(*) | + ty::ty_evec(_, vstore_box) | + ty::ty_estr(vstore_box) => { + OtherPointer + } + _ => { + NotPointer + } + } + } + + fn id_categorization(rcx: @rcx, + guarantor: Option, + id: ast::node_id) -> ExprCategorization + { + let pointer = match rcx.resolve_node_type(id) { + None => NotPointer, + Some(t) => pointer_categorize(t) + }; + + ExprCategorization {guarantor: guarantor, + pointer: pointer} + } + + fn guarantor_of_deref(cat: &ExprCategorization) -> Option { + match cat.pointer { + NotPointer => cat.guarantor, + BorrowedPointer(r) => Some(r), + OwnedPointer => cat.guarantor, + OtherPointer => None + } + } + + fn link_ref_bindings_in_pat( + rcx: @rcx, + pat: @ast::pat, + guarantor: Option) + { + /*! + * + * Descends through the pattern, tracking the guarantor + * of the value being matched. When a ref binding is encountered, + * links the lifetime of that ref binding to the lifetime of + * the guarantor. We begin with the guarantor of the + * discriminant but of course as we go we may pass through + * other pointers. + */ + + debug!("link_ref_bindings_in_pat(pat=%s, guarantor=%?)", + rcx.fcx.pat_to_str(pat), guarantor); + let _i = ::util::common::indenter(); + + match pat.node { + ast::pat_wild => {} + ast::pat_ident(ast::bind_by_ref(_), _, opt_p) => { + link(rcx, pat.span, pat.id, guarantor); + + for opt_p.each |p| { + link_ref_bindings_in_pat(rcx, *p, guarantor); + } + } + ast::pat_ident(_, _, opt_p) => { + for opt_p.each |p| { + link_ref_bindings_in_pat(rcx, *p, guarantor); + } + } + ast::pat_enum(*) => {} + ast::pat_rec(ref fpats, _) | + ast::pat_struct(_, ref fpats, _) => { + for fpats.each |fpat| { + link_ref_bindings_in_pat(rcx, fpat.pat, guarantor); + } + } + ast::pat_tup(ref ps) => { + link_ref_bindings_in_pats(rcx, ps, guarantor) + } + ast::pat_box(p) => { + link_ref_bindings_in_pat(rcx, p, None) + } + ast::pat_uniq(p) => { + link_ref_bindings_in_pat(rcx, p, guarantor) + } + ast::pat_region(p) => { + for rcx.resolve_node_type(pat.id).each |rptr_ty| { + let r = ty::ty_region(*rptr_ty); + link_ref_bindings_in_pat(rcx, p, Some(r)); + } + } + ast::pat_lit(*) => {} + ast::pat_range(*) => {} + ast::pat_vec(ref ps, ref opt_tail_pat) => { + for rcx.resolve_node_type(pat.id).each |vec_ty| { + let vstore = ty::ty_vstore(*vec_ty); + let guarantor1 = match vstore { + vstore_fixed(_) | vstore_uniq => guarantor, + vstore_slice(r) => Some(r), + vstore_box => None + }; + + link_ref_bindings_in_pats(rcx, ps, guarantor1); + + for opt_tail_pat.each |p| { + link_ref_bindings_in_pat(rcx, *p, guarantor); + } + } + } + } + } + + fn link_ref_bindings_in_pats(rcx: @rcx, + pats: &~[@ast::pat], + guarantor: Option) + { + for pats.each |pat| { + link_ref_bindings_in_pat(rcx, *pat, guarantor); + } + } + +} + +fn infallibly_mk_subr(rcx: @rcx, + a_is_expected: bool, + span: span, + a: ty::Region, + b: ty::Region) +{ + /*! + * + * Constraints `a` to be a subregion of `b`. In many cases, we + * know that this can never yield an error due to the way that + * region inferencing works. Therefore just report a bug if we + * ever see `Err(_)`. + */ + + match rcx.fcx.mk_subr(a_is_expected, span, a, b) { + result::Ok(()) => {} + result::Err(e) => { + rcx.fcx.ccx.tcx.sess.span_bug( + span, + fmt!("Supposedly infallible attempt to \ + make %? < %? failed: %?", + a, b, e)); + } + } +} \ No newline at end of file diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 6b6912915fd25..ac079f8f04450 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -270,6 +270,12 @@ fn expr_repr(cx: ctxt, expr: @ast::expr) -> ~str { pprust::expr_to_str(expr, cx.sess.intr())) } +fn pat_repr(cx: ctxt, pat: @ast::pat) -> ~str { + fmt!("pat(%d: %s)", + pat.id, + pprust::pat_to_str(pat, cx.sess.intr())) +} + fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str { let tstrs = ts.map(|t| ty_to_str(cx, *t)); fmt!("(%s)", str::connect(tstrs, ", ")) diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index 77f230311358e..1bb516e831fd5 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -879,7 +879,7 @@ fn ser_variant( let pat_node = if pats.is_empty() { ast::pat_ident( - ast::bind_by_ref(ast::m_imm), + ast::bind_infer, cx.path(span, ~[v_name]), None ) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5a8a1d8753dee..5ff6953960619 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -267,8 +267,14 @@ fn mk_pat(cx: ext_ctxt, span: span, +pat: ast::pat_) -> @ast::pat { @ast::pat { id: cx.next_id(), node: pat, span: span } } fn mk_pat_ident(cx: ext_ctxt, span: span, ident: ast::ident) -> @ast::pat { + mk_pat_ident_with_binding_mode(cx, span, ident, ast::bind_by_value) +} +fn mk_pat_ident_with_binding_mode(cx: ext_ctxt, + span: span, + ident: ast::ident, + bm: ast::binding_mode) -> @ast::pat { let path = mk_raw_path(span, ~[ ident ]); - let pat = ast::pat_ident(ast::bind_by_value, path, None); + let pat = ast::pat_ident(bm, path, None); mk_pat(cx, span, move pat) } fn mk_pat_enum(cx: ext_ctxt, diff --git a/src/libsyntax/ext/deriving.rs b/src/libsyntax/ext/deriving.rs index d7059fc197783..d542b104e541e 100644 --- a/src/libsyntax/ext/deriving.rs +++ b/src/libsyntax/ext/deriving.rs @@ -363,7 +363,8 @@ fn create_enum_variant_pattern(cx: ext_ctxt, match variant.node.kind { tuple_variant_kind(ref variant_args) => { if variant_args.len() == 0 { - return build::mk_pat_ident(cx, span, variant_ident); + return build::mk_pat_ident_with_binding_mode( + cx, span, variant_ident, ast::bind_infer); } let matching_path = build::mk_raw_path(span, ~[ variant_ident ]); diff --git a/src/test/run-pass/region-dependent-addr-of.rs b/src/test/run-pass/region-dependent-addr-of.rs new file mode 100644 index 0000000000000..594556fffed95 --- /dev/null +++ b/src/test/run-pass/region-dependent-addr-of.rs @@ -0,0 +1,112 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct A { + value: B +} + +struct B { + v1: int, + v2: [int * 3], + v3: ~[int], + v4: C, + v5: ~C, + v6: Option +} + +struct C { + f: int +} + +fn get_v1(a: &v/A) -> &v/int { + // Region inferencer must deduce that &v < L2 < L1 + let foo = &a.value; // L1 + &foo.v1 // L2 +} + +fn get_v2(a: &v/A, i: uint) -> &v/int { + let foo = &a.value; + &foo.v2[i] +} + +fn get_v3(a: &v/A, i: uint) -> &v/int { + let foo = &a.value; + &foo.v3[i] +} + +fn get_v4(a: &v/A, i: uint) -> &v/int { + let foo = &a.value; + &foo.v4.f +} + +fn get_v5(a: &v/A, i: uint) -> &v/int { + let foo = &a.value; + &foo.v5.f +} + +fn get_v6_a(a: &v/A, i: uint) -> &v/int { + match a.value.v6 { + Some(ref v) => &v.f, + None => fail + } +} + +fn get_v6_b(a: &v/A, i: uint) -> &v/int { + match *a { + A { value: B { v6: Some(ref v), _ } } => &v.f, + _ => fail + } +} + +fn get_v6_c(a: &v/A, i: uint) -> &v/int { + match a { + &A { value: B { v6: Some(ref v), _ } } => &v.f, + _ => fail + } +} + +fn get_v5_ref(a: &v/A, i: uint) -> &v/int { + match &a.value { + &B {v5: ~C {f: ref v}, _} => v + } +} + +fn main() { + let a = A {value: B {v1: 22, + v2: [23, 24, 25], + v3: ~[26, 27, 28], + v4: C { f: 29 }, + v5: ~C { f: 30 }, + v6: Some(C { f: 31 })}}; + + let p = get_v1(&a); + assert *p == a.value.v1; + + let p = get_v2(&a, 1); + assert *p == a.value.v2[1]; + + let p = get_v3(&a, 1); + assert *p == a.value.v3[1]; + + let p = get_v4(&a, 1); + assert *p == a.value.v4.f; + + let p = get_v5(&a, 1); + assert *p == a.value.v5.f; + + let p = get_v6_a(&a, 1); + assert *p == a.value.v6.get().f; + + let p = get_v6_b(&a, 1); + assert *p == a.value.v6.get().f; + + let p = get_v6_c(&a, 1); + assert *p == a.value.v6.get().f; +} diff --git a/src/test/run-pass/region-return-interior-of-option-in-self.rs b/src/test/run-pass/region-return-interior-of-option-in-self.rs deleted file mode 100644 index 8ed85b957ee73..0000000000000 --- a/src/test/run-pass/region-return-interior-of-option-in-self.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-test (#3148) - -struct cell { - value: T; -} - -struct cells { - vals: ~[Option>]; -} - -impl &cells { - fn get(idx: uint) -> &self/T { - match self.vals[idx] { - Some(ref v) => &v.value, - None => fail - } - } -} - -fn main() {} From 2e10ea58c3c4954e2343363f392d65db1482ad90 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 24 Jan 2013 19:33:48 -0800 Subject: [PATCH 13/31] Integrate vec patterns into borrow checker. The tail portion of the pattern effectively borrows a vector, but the borrow checker knew nothing about this. r=catamorphism --- src/librustc/middle/borrowck/gather_loans.rs | 42 +++++++++++++ src/librustc/middle/borrowck/mod.rs | 8 ++- src/librustc/middle/mem_categorization.rs | 60 +++++++++++-------- src/librustc/middle/ty.rs | 4 +- src/librustc/middle/typeck/check/regionck.rs | 29 +++++---- ...s => borrowck-vec-pattern-element-loan.rs} | 6 +- .../borrowck-vec-pattern-loan-from-mut.rs | 12 ++++ .../borrowck-vec-pattern-nesting.rs | 21 +++++++ ...borrowck-vec-pattern-tail-element-loan.rs} | 4 +- src/test/run-pass/region-dependent-addr-of.rs | 3 + .../vec-matching-legal-tail-element-borrow.rs | 2 +- 11 files changed, 144 insertions(+), 47 deletions(-) rename src/test/compile-fail/{alt-vec-illegal-tail-loan.rs => borrowck-vec-pattern-element-loan.rs} (67%) create mode 100644 src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs create mode 100644 src/test/compile-fail/borrowck-vec-pattern-nesting.rs rename src/test/compile-fail/{alt-vec-illegal-tail-element-loan.rs => borrowck-vec-pattern-tail-element-loan.rs} (65%) diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs index 967b1681b1bfb..0fff0c66a3846 100644 --- a/src/librustc/middle/borrowck/gather_loans.rs +++ b/src/librustc/middle/borrowck/gather_loans.rs @@ -591,11 +591,53 @@ impl gather_loan_ctxt { } } + ast::pat_vec(_, Some(tail_pat)) => { + // The `tail_pat` here creates a slice into the + // original vector. This is effectively a borrow of + // the elements of the vector being matched. + + let tail_ty = self.tcx().ty(tail_pat); + let (tail_mutbl, tail_r) = + self.vec_slice_info(tail_pat, tail_ty); + let mcx = self.bccx.mc_ctxt(); + let cmt_index = mcx.cat_index(tail_pat, cmt); + self.guarantee_valid(cmt_index, tail_mutbl, tail_r); + } + _ => {} } } } + fn vec_slice_info(&self, + pat: @ast::pat, + tail_ty: ty::t) -> (ast::mutability, ty::Region) + { + /*! + * + * In a pattern like [a, b, ..c], normally `c` has slice type, + * but if you have [a, b, ..ref c], then the type of `ref c` + * will be `&&[]`, so to extract the slice details we have + * to recurse through rptrs. + */ + + match ty::get(tail_ty).sty { + ty::ty_evec(tail_mt, ty::vstore_slice(tail_r)) => { + (tail_mt.mutbl, tail_r) + } + + ty::ty_rptr(_, ref mt) => { + self.vec_slice_info(pat, mt.ty) + } + + _ => { + self.tcx().sess.span_bug( + pat.span, + fmt!("Type of tail pattern is not a slice")); + } + } + } + fn pat_is_variant_or_struct(&self, pat: @ast::pat) -> bool { pat_util::pat_is_variant_or_struct(self.bccx.tcx.def_map, pat) } diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 35c1c96befae5..a01c04a8abf15 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -504,9 +504,13 @@ impl borrowck_ctxt { return @{cat:cat_discr(cmt, match_id),.. *cmt}; } + fn mc_ctxt() -> mem_categorization_ctxt { + mem_categorization_ctxt {tcx: self.tcx, + method_map: self.method_map} + } + fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) { - let mc = &mem_categorization_ctxt {tcx: self.tcx, - method_map: self.method_map}; + let mc = self.mc_ctxt(); mc.cat_pattern(cmt, pat, op); } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 6cd14d332bf55..7c1e96e5c0e44 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -521,8 +521,8 @@ impl &mem_categorization_ctxt { ty: self.tcx.ty(arg)} } - fn cat_rvalue(expr: @ast::expr, expr_ty: ty::t) -> cmt { - @{id:expr.id, span:expr.span, + fn cat_rvalue(elt: N, expr_ty: ty::t) -> cmt { + @{id:elt.id(), span:elt.span(), cat:cat_rvalue, lp:None, mutbl:m_imm, ty:expr_ty} } @@ -643,12 +643,12 @@ impl &mem_categorization_ctxt { } } - fn cat_index(expr: @ast::expr, base_cmt: cmt) -> cmt { + fn cat_index(elt: N, base_cmt: cmt) -> cmt { let mt = match ty::index(self.tcx, base_cmt.ty) { Some(mt) => mt, None => { self.tcx.sess.span_bug( - expr.span, + elt.span(), fmt!("Explicit index of non-index type `%s`", ty_to_str(self.tcx, base_cmt.ty))); } @@ -675,25 +675,27 @@ impl &mem_categorization_ctxt { }; // (c) the deref is explicit in the resulting cmt - let deref_cmt = @{id:expr.id, span:expr.span, + let deref_cmt = @{id:elt.id(), span:elt.span(), cat:cat_deref(base_cmt, 0u, ptr), lp:deref_lp, mutbl:m, ty:mt.ty}; - comp(expr, deref_cmt, base_cmt.ty, m, mt.ty) + comp(elt, deref_cmt, base_cmt.ty, m, mt.ty) } deref_comp(_) => { // fixed-length vectors have no deref let m = self.inherited_mutability(base_cmt.mutbl, mt.mutbl); - comp(expr, base_cmt, base_cmt.ty, m, mt.ty) + comp(elt, base_cmt, base_cmt.ty, m, mt.ty) } }; - fn comp(expr: @ast::expr, of_cmt: cmt, - vect: ty::t, mutbl: ast::mutability, ty: ty::t) -> cmt { + fn comp(elt: N, of_cmt: cmt, + vect: ty::t, mutbl: ast::mutability, + ty: ty::t) -> cmt + { let comp = comp_index(vect, mutbl); let index_lp = of_cmt.lp.map(|lp| @lp_comp(*lp, comp) ); - @{id:expr.id, span:expr.span, + @{id:elt.id(), span:elt.span(), cat:cat_comp(of_cmt, comp), lp:index_lp, mutbl:mutbl, ty:ty} } @@ -723,8 +725,6 @@ impl &mem_categorization_ctxt { fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) { - op(cmt, pat); - // Here, `cmt` is the categorization for the value being // matched and pat is the pattern it is being matched against. // @@ -759,13 +759,15 @@ impl &mem_categorization_ctxt { // and the id of `local(x)->@->@` is the id of the `y` pattern. - let _i = indenter(); let tcx = self.tcx; debug!("cat_pattern: id=%d pat=%s cmt=%s", pat.id, pprust::pat_to_str(pat, tcx.sess.intr()), self.cmt_to_repr(cmt)); + let _i = indenter(); - match /*bad*/copy pat.node { + op(cmt, pat); + + match pat.node { ast::pat_wild => { // _ } @@ -773,7 +775,7 @@ impl &mem_categorization_ctxt { ast::pat_enum(_, None) => { // variant(*) } - ast::pat_enum(_, Some(subpats)) => { + ast::pat_enum(_, Some(ref subpats)) => { match self.tcx.def_map.find(pat.id) { Some(ast::def_variant(enum_did, _)) => { // variant(x, y, z) @@ -805,7 +807,8 @@ impl &mem_categorization_ctxt { // nullary variant or identifier: ignore } - ast::pat_rec(field_pats, _) => { + ast::pat_rec(ref field_pats, _) | + ast::pat_struct(_, ref field_pats, _) => { // {f1: p1, ..., fN: pN} for field_pats.each |fp| { let cmt_field = self.cat_field(fp.pat, cmt, fp.ident, pat.id); @@ -813,15 +816,7 @@ impl &mem_categorization_ctxt { } } - ast::pat_struct(_, field_pats, _) => { - // {f1: p1, ..., fN: pN} - for field_pats.each |fp| { - let cmt_field = self.cat_field(fp.pat, cmt, fp.ident, pat.id); - self.cat_pattern(cmt_field, fp.pat, op); - } - } - - ast::pat_tup(subpats) => { + ast::pat_tup(ref subpats) => { // (p1, ..., pN) for subpats.each |subpat| { let subcmt = self.cat_tuple_elt(*subpat, cmt); @@ -836,7 +831,20 @@ impl &mem_categorization_ctxt { self.cat_pattern(subcmt, subpat, op); } - ast::pat_vec(*) | ast::pat_lit(_) | ast::pat_range(_, _) => { + ast::pat_vec(ref pats, opt_tail_pat) => { + for pats.each |pat| { + let elt_cmt = self.cat_index(*pat, cmt); + self.cat_pattern(elt_cmt, *pat, op); + } + + for opt_tail_pat.each |tail_pat| { + let tail_ty = self.tcx.ty(*tail_pat); + let tail_cmt = self.cat_rvalue(*tail_pat, tail_ty); + self.cat_pattern(tail_cmt, *tail_pat, op); + } + } + + ast::pat_lit(_) | ast::pat_range(_, _) => { /*always ok*/ } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 2e0d7026769ef..840726b804179 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3017,7 +3017,9 @@ pure fn ty_vstore(ty: t) -> vstore { fn ty_region(ty: t) -> Region { match get(ty).sty { ty_rptr(r, _) => r, - ref s => fail fmt!("ty_region() invoked on non-rptr: %?", (*s)) + ty_evec(_, vstore_slice(r)) => r, + ty_estr(vstore_slice(r)) => r, + ref s => fail fmt!("ty_region() invoked on in appropriate ty: %?", (*s)) } } diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 419e6269957cf..a4aa645da0b59 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -530,6 +530,13 @@ mod guarantor { * but more special purpose. */ + use core::prelude::*; + use middle::typeck::check::regionck::{rcx, infallibly_mk_subr}; + use middle::ty; + use syntax::ast; + use syntax::codemap::span; + use util::ppaux::{ty_to_str}; + pub fn for_addr_of(rcx: @rcx, expr: @ast::expr, base: @ast::expr) { /*! * @@ -726,17 +733,17 @@ mod guarantor { fn pointer_categorize(ty: ty::t) -> PointerCat { match ty::get(ty).sty { - ty::ty_rptr(r, _) | ty::ty_evec(_, vstore_slice(r)) | - ty::ty_estr(vstore_slice(r)) => { + ty::ty_rptr(r, _) | ty::ty_evec(_, ty::vstore_slice(r)) | + ty::ty_estr(ty::vstore_slice(r)) => { BorrowedPointer(r) } - ty::ty_uniq(*) | ty::ty_estr(vstore_uniq) | - ty::ty_evec(_, vstore_uniq) => { + ty::ty_uniq(*) | ty::ty_estr(ty::vstore_uniq) | + ty::ty_evec(_, ty::vstore_uniq) => { OwnedPointer } ty::ty_box(*) | ty::ty_ptr(*) | - ty::ty_evec(_, vstore_box) | - ty::ty_estr(vstore_box) => { + ty::ty_evec(_, ty::vstore_box) | + ty::ty_estr(ty::vstore_box) => { OtherPointer } _ => { @@ -828,9 +835,9 @@ mod guarantor { for rcx.resolve_node_type(pat.id).each |vec_ty| { let vstore = ty::ty_vstore(*vec_ty); let guarantor1 = match vstore { - vstore_fixed(_) | vstore_uniq => guarantor, - vstore_slice(r) => Some(r), - vstore_box => None + ty::vstore_fixed(_) | ty::vstore_uniq => guarantor, + ty::vstore_slice(r) => Some(r), + ty::vstore_box => None }; link_ref_bindings_in_pats(rcx, ps, guarantor1); @@ -844,8 +851,8 @@ mod guarantor { } fn link_ref_bindings_in_pats(rcx: @rcx, - pats: &~[@ast::pat], - guarantor: Option) + pats: &~[@ast::pat], + guarantor: Option) { for pats.each |pat| { link_ref_bindings_in_pat(rcx, *pat, guarantor); diff --git a/src/test/compile-fail/alt-vec-illegal-tail-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs similarity index 67% rename from src/test/compile-fail/alt-vec-illegal-tail-loan.rs rename to src/test/compile-fail/borrowck-vec-pattern-element-loan.rs index 01f2707721677..358917de85fb9 100644 --- a/src/test/compile-fail/alt-vec-illegal-tail-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs @@ -1,9 +1,7 @@ -// xfail-test - fn a() -> &[int] { let vec = [1, 2, 3, 4]; - let tail = match vec { - [_a, ..tail] => tail, //~ ERROR illegal borrow + let tail = match vec { //~ ERROR illegal borrow + [_a, ..tail] => tail, _ => fail ~"foo" }; move tail diff --git a/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs new file mode 100644 index 0000000000000..27902100373a9 --- /dev/null +++ b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs @@ -0,0 +1,12 @@ +fn a() { + let mut v = ~[1, 2, 3]; + match v { + [_a, ..tail] => { + v.push(tail[0] + tail[1]); //~ ERROR conflicts with prior loan + } + _ => {} + }; +} + +fn main() {} + diff --git a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs new file mode 100644 index 0000000000000..50feff707adfa --- /dev/null +++ b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs @@ -0,0 +1,21 @@ +fn a() { + let mut vec = [~1, ~2, ~3]; + match vec { + [~ref _a] => { + vec[0] = ~4; //~ ERROR prohibited due to outstanding loan + } + _ => fail ~"foo" + } +} + +fn b() { + let mut vec = [~1, ~2, ~3]; + match vec { + [.._b] => { + vec[0] = ~4; //~ ERROR prohibited due to outstanding loan + } + } +} + +fn main() {} + diff --git a/src/test/compile-fail/alt-vec-illegal-tail-element-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs similarity index 65% rename from src/test/compile-fail/alt-vec-illegal-tail-element-loan.rs rename to src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs index 36d019058ae79..6477fd9fb2cf9 100644 --- a/src/test/compile-fail/alt-vec-illegal-tail-element-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs @@ -1,7 +1,7 @@ fn a() -> &int { let vec = [1, 2, 3, 4]; - let tail = match vec { - [_a, ..tail] => &tail[0], //~ ERROR illegal borrow + let tail = match vec { //~ ERROR illegal borrow + [_a, ..tail] => &tail[0], _ => fail ~"foo" }; move tail diff --git a/src/test/run-pass/region-dependent-addr-of.rs b/src/test/run-pass/region-dependent-addr-of.rs index 594556fffed95..6765c1a11ae78 100644 --- a/src/test/run-pass/region-dependent-addr-of.rs +++ b/src/test/run-pass/region-dependent-addr-of.rs @@ -109,4 +109,7 @@ fn main() { let p = get_v6_c(&a, 1); assert *p == a.value.v6.get().f; + + let p = get_v5_ref(&a, 1); + assert *p == a.value.v5.f; } diff --git a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs index 6b005bf0e1218..0d093a1b4b0fd 100644 --- a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs +++ b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs @@ -2,7 +2,7 @@ fn main() { let x = &[1, 2, 3, 4, 5]; if !x.is_empty() { let el = match x { - [1, ..ref tail] => &tail[0], + [1, ..ref tail] => &tail[0], _ => ::core::util::unreachable() }; io::println(fmt!("%d", *el)); From 0004be9ecad4ce489b84036589cb62e42ce880bb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 24 Jan 2013 22:03:29 -0800 Subject: [PATCH 14/31] Detect "// WARN" in tidy and print out, well, a warning! Useful for notating FIXME-style-situations that you want to be reminded of before you commit. r=catamorphism --- src/etc/tidy.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/etc/tidy.py b/src/etc/tidy.py index e866d80062d51..a823bbb227722 100644 --- a/src/etc/tidy.py +++ b/src/etc/tidy.py @@ -23,6 +23,11 @@ def report_error_name_no(name, no, s): def report_err(s): report_error_name_no(fileinput.filename(), fileinput.filelineno(), s) +def report_warn(s): + print("%s:%d: %s" % (fileinput.filename(), + fileinput.filelineno(), + s)) + def do_license_check(name, contents): if not check_license(name, contents): report_error_name_no(name, 1, "incorrect license") @@ -44,6 +49,9 @@ def do_license_check(name, contents): report_err("FIXME without issue number") if line.find("TODO") != -1: report_err("TODO is deprecated; use FIXME") + if line.find("// WARN") != -1: + mo = re.match("// WARN (.*)", line) + report_warn("WARN: " + mo.group(1)) if (line.find('\t') != -1 and fileinput.filename().find("Makefile") == -1): report_err("tab character") From 8f14d43206fe63752407820ccc85eebc423c69ad Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 25 Jan 2013 06:27:32 -0800 Subject: [PATCH 15/31] Make tidy actually work r=catamorphism --- src/etc/tidy.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/etc/tidy.py b/src/etc/tidy.py index a823bbb227722..2eb32c100acd2 100644 --- a/src/etc/tidy.py +++ b/src/etc/tidy.py @@ -49,9 +49,9 @@ def do_license_check(name, contents): report_err("FIXME without issue number") if line.find("TODO") != -1: report_err("TODO is deprecated; use FIXME") - if line.find("// WARN") != -1: - mo = re.match("// WARN (.*)", line) - report_warn("WARN: " + mo.group(1)) + idx = line.find("// WARN") + if idx != -1: + report_warn("WARN:" + line[idx + len("// WARN"):]) if (line.find('\t') != -1 and fileinput.filename().find("Makefile") == -1): report_err("tab character") From a4ba11189db2773072fbe9e241669a3e9f4b4429 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 25 Jan 2013 10:03:28 -0800 Subject: [PATCH 16/31] Extend region guarantor logic to handle autoref, which will be necessary for reborrowing. r=catamorphism --- src/librustc/middle/typeck/check/regionck.rs | 208 +++++++++++-------- 1 file changed, 125 insertions(+), 83 deletions(-) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index a4aa645da0b59..fe2fd4a6a22a1 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -73,10 +73,10 @@ fn encl_region_of_def(fcx: @fn_ctxt, def: ast::def) -> ty::Region { } impl @rcx { - fn resolve_type(unresolved_ty: ty::t) -> Option { + fn resolve_type(unresolved_ty: ty::t) -> ty::t { /*! * Try to resolve the type for the given node, returning - * None if an error results. Note that we never care + * t_err if an error results. Note that we never care * about the details of the error, the same error will be * detected and reported in the writeback phase. * @@ -104,13 +104,13 @@ impl @rcx { */ match resolve_type(self.fcx.infcx(), unresolved_ty, resolve_and_force_all_but_regions) { - Ok(t) => Some(t), - Err(_) => None + Ok(t) => t, + Err(_) => ty::mk_err(self.fcx.tcx()) } } /// Try to resolve the type for the given node. - fn resolve_node_type(id: ast::node_id) -> Option { + fn resolve_node_type(id: ast::node_id) -> ty::t { self.resolve_type(self.fcx.node_ty(id)) } } @@ -181,6 +181,12 @@ fn visit_block(b: ast::blk, &&rcx: @rcx, v: rvt) { fn visit_expr(expr: @ast::expr, &&rcx: @rcx, v: rvt) { debug!("visit_expr(e=%s)", rcx.fcx.expr_to_str(expr)); + for rcx.fcx.inh.adjustments.find(expr.id).each |adjustment| { + for adjustment.autoref.each |autoref| { + guarantor::for_autoref(rcx, expr, *adjustment, autoref); + } + } + match /*bad*/copy expr.node { ast::expr_path(*) => { // Avoid checking the use of local variables, as we @@ -250,15 +256,14 @@ fn visit_expr(expr: @ast::expr, &&rcx: @rcx, v: rvt) { // particular case. There is an extensive comment on the // function check_cast_for_escaping_regions() in kind.rs // explaining how it goes about doing that. - for rcx.resolve_node_type(expr.id).each |target_ty| { - match ty::get(*target_ty).sty { - ty::ty_trait(_, _, vstore_slice(trait_region)) => { - let source_ty = rcx.fcx.expr_ty(source); - constrain_regions_in_type(rcx, trait_region, - expr.span, source_ty); - } - _ => () + let target_ty = rcx.resolve_node_type(expr.id); + match ty::get(target_ty).sty { + ty::ty_trait(_, _, vstore_slice(trait_region)) => { + let source_ty = rcx.fcx.expr_ty(source); + constrain_regions_in_type(rcx, trait_region, + expr.span, source_ty); } + _ => () } } @@ -271,16 +276,15 @@ fn visit_expr(expr: @ast::expr, &&rcx: @rcx, v: rvt) { } ast::expr_fn(*) | ast::expr_fn_block(*) => { - for rcx.resolve_node_type(expr.id).each |function_type| { - match ty::get(*function_type).sty { - ty::ty_fn(ref fn_ty) => { - if fn_ty.meta.proto == ast::ProtoBorrowed { - constrain_free_variables( - rcx, fn_ty.meta.region, expr); - } + let function_type = rcx.resolve_node_type(expr.id); + match ty::get(function_type).sty { + ty::ty_fn(ref fn_ty) => { + if fn_ty.meta.proto == ast::ProtoBorrowed { + constrain_free_variables( + rcx, fn_ty.meta.region, expr); } - _ => () } + _ => () } } @@ -409,15 +413,10 @@ fn constrain_regions_in_type_of_node( // Try to resolve the type. If we encounter an error, then typeck // is going to fail anyway, so just stop here and let typeck // report errors later on in the writeback phase. - let ty = match rcx.resolve_node_type(id) { - None => { return true; } - Some(ty) => { ty } - }; - + let ty = rcx.resolve_node_type(id); debug!("constrain_regions_in_type_of_node(\ ty=%s, id=%d, encl_region=%?)", ty_to_str(tcx, ty), id, encl_region); - constrain_regions_in_type(rcx, encl_region, span, ty) } @@ -567,6 +566,30 @@ mod guarantor { } } + pub fn for_autoref(rcx: @rcx, + expr: @ast::expr, + adjustment: &ty::AutoAdjustment, + autoref: &ty::AutoRef) + { + /*! + * + * Computes the guarantor for an expression that has an + * autoref adjustment and links it to the lifetime of the + * autoref. This is only important when auto re-borrowing + * region pointers. + */ + + debug!("guarantor::for_autoref(expr=%s)", rcx.fcx.expr_to_str(expr)); + let _i = ::util::common::indenter(); + + let mut expr_ct = categorize_unadjusted(rcx, expr); + expr_ct = apply_autoderefs( + rcx, expr, adjustment.autoderefs, expr_ct); + for expr_ct.cat.guarantor.each |g| { + infallibly_mk_subr(rcx, true, expr.span, autoref.region, *g); + } + } + fn link( rcx: @rcx, span: span, @@ -589,9 +612,10 @@ mod guarantor { // this routine is used for the result of ref bindings and & // expressions, both of which always yield a region variable, so // mk_subr should never fail. - for rcx.resolve_node_type(id).each |rptr_ty| { - debug!("rptr_ty=%s", ty_to_str(rcx.fcx.ccx.tcx, *rptr_ty)); - let r = ty::ty_region(*rptr_ty); + let rptr_ty = rcx.resolve_node_type(id); + if !ty::type_contains_err(rptr_ty) { + debug!("rptr_ty=%s", ty_to_str(rcx.fcx.ccx.tcx, rptr_ty)); + let r = ty::ty_region(rptr_ty); infallibly_mk_subr(rcx, true, span, r, bound); } } @@ -608,6 +632,11 @@ mod guarantor { pointer: PointerCat } + struct ExprCategorizationType { + cat: ExprCategorization, + ty: ty::t + } + fn guarantor(rcx: @rcx, expr: @ast::expr) -> Option { debug!("guarantor(expr=%s)", rcx.fcx.expr_to_str(expr)); match expr.node { @@ -683,52 +712,76 @@ mod guarantor { debug!("categorize(expr=%s)", rcx.fcx.expr_to_str(expr)); let _i = ::util::common::indenter(); - let tcx = rcx.fcx.ccx.tcx; - if rcx.fcx.ccx.method_map.contains_key(expr.id) { - debug!("method call"); - return id_categorization(rcx, None, expr.id); - } - - let expr_ty = match rcx.resolve_node_type(expr.id) { - None => { return id_categorization(rcx, None, expr.id); } - Some(t) => { t } - }; - let mut cat = ExprCategorization { - guarantor: guarantor(rcx, expr), - pointer: pointer_categorize(expr_ty) - }; - - debug!("before adjustments, cat=%?", cat); + let mut expr_ct = categorize_unadjusted(rcx, expr); + debug!("before adjustments, cat=%?", expr_ct.cat); for rcx.fcx.inh.adjustments.find(expr.id).each |adjustment| { debug!("adjustment=%?", adjustment); - for uint::range(0, adjustment.autoderefs) |_| { - cat.guarantor = guarantor_of_deref(&cat); - match ty::deref(tcx, expr_ty, true) { - Some(t) => { - cat.pointer = pointer_categorize(t.ty); - } - None => { - tcx.sess.span_bug( - expr.span, - fmt!("Autoderef but type not derefable: %s", - ty_to_str(tcx, expr_ty))); - } - } + expr_ct = apply_autoderefs( + rcx, expr, adjustment.autoderefs, expr_ct); - debug!("autoderef, cat=%?", cat); + for adjustment.autoref.each |autoref| { + expr_ct.cat.guarantor = None; + expr_ct.cat.pointer = BorrowedPointer(autoref.region); + debug!("autoref, cat=%?", expr_ct.cat); } + } - for adjustment.autoref.each |autoref| { - cat.guarantor = None; - cat.pointer = BorrowedPointer(autoref.region); - debug!("autoref, cat=%?", cat); + debug!("result=%?", expr_ct.cat); + return expr_ct.cat; + } + + fn categorize_unadjusted(rcx: @rcx, + expr: @ast::expr) -> ExprCategorizationType { + debug!("categorize_unadjusted(expr=%s)", rcx.fcx.expr_to_str(expr)); + let _i = ::util::common::indenter(); + + let guarantor = { + if rcx.fcx.ccx.method_map.contains_key(expr.id) { + None + } else { + guarantor(rcx, expr) } + }; + + let expr_ty = rcx.resolve_node_type(expr.id); + ExprCategorizationType { + cat: ExprCategorization { + guarantor: guarantor, + pointer: pointer_categorize(expr_ty) + }, + ty: expr_ty } + } - debug!("result=%?", cat); - return cat; + fn apply_autoderefs( + +rcx: @rcx, + +expr: @ast::expr, + +autoderefs: uint, + +ct: ExprCategorizationType) -> ExprCategorizationType + { + let mut ct = ct; + let tcx = rcx.fcx.ccx.tcx; + for uint::range(0, autoderefs) |_| { + ct.cat.guarantor = guarantor_of_deref(&ct.cat); + + match ty::deref(tcx, ct.ty, true) { + Some(mt) => { + ct.ty = mt.ty; + ct.cat.pointer = pointer_categorize(ct.ty); + } + None => { + tcx.sess.span_bug( + expr.span, + fmt!("Autoderef but type not derefable: %s", + ty_to_str(tcx, ct.ty))); + } + } + + debug!("autoderef, cat=%?", ct.cat); + } + return ct; } fn pointer_categorize(ty: ty::t) -> PointerCat { @@ -752,19 +805,6 @@ mod guarantor { } } - fn id_categorization(rcx: @rcx, - guarantor: Option, - id: ast::node_id) -> ExprCategorization - { - let pointer = match rcx.resolve_node_type(id) { - None => NotPointer, - Some(t) => pointer_categorize(t) - }; - - ExprCategorization {guarantor: guarantor, - pointer: pointer} - } - fn guarantor_of_deref(cat: &ExprCategorization) -> Option { match cat.pointer { NotPointer => cat.guarantor, @@ -824,16 +864,18 @@ mod guarantor { link_ref_bindings_in_pat(rcx, p, guarantor) } ast::pat_region(p) => { - for rcx.resolve_node_type(pat.id).each |rptr_ty| { - let r = ty::ty_region(*rptr_ty); + let rptr_ty = rcx.resolve_node_type(pat.id); + if !ty::type_contains_err(rptr_ty) { + let r = ty::ty_region(rptr_ty); link_ref_bindings_in_pat(rcx, p, Some(r)); } } ast::pat_lit(*) => {} ast::pat_range(*) => {} ast::pat_vec(ref ps, ref opt_tail_pat) => { - for rcx.resolve_node_type(pat.id).each |vec_ty| { - let vstore = ty::ty_vstore(*vec_ty); + let vec_ty = rcx.resolve_node_type(pat.id); + if !ty::type_contains_err(vec_ty) { + let vstore = ty::ty_vstore(vec_ty); let guarantor1 = match vstore { ty::vstore_fixed(_) | ty::vstore_uniq => guarantor, ty::vstore_slice(r) => Some(r), From 08bc19cbcd2638f41a5a613150b3d8a7d32072ea Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 22 Jan 2013 07:01:17 -0800 Subject: [PATCH 17/31] Remove bounds from type decl of smallintmap r=brson --- src/libstd/smallintmap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/smallintmap.rs b/src/libstd/smallintmap.rs index feabb678d6686..5f16f7155b61c 100644 --- a/src/libstd/smallintmap.rs +++ b/src/libstd/smallintmap.rs @@ -25,11 +25,11 @@ use core::prelude::*; // FIXME (#2347): Should not be @; there's a bug somewhere in rustc that // requires this to be. -struct SmallIntMap_ { +struct SmallIntMap_ { v: DVec>, } -pub enum SmallIntMap { +pub enum SmallIntMap { SmallIntMap_(@SmallIntMap_) } From 19e015c44a9f5b911ac7ffa105395d442ece8fda Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 22 Jan 2013 07:01:43 -0800 Subject: [PATCH 18/31] Add to_str() definitions for some AST types r=brson --- src/libsyntax/ast.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 65216e55493ce..502a372b330c3 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -973,6 +973,12 @@ enum trait_method { #[auto_decode] enum int_ty { ty_i, ty_char, ty_i8, ty_i16, ty_i32, ty_i64, } +impl int_ty : ToStr { + pure fn to_str() -> ~str { + ::ast_util::int_ty_to_str(self) + } +} + impl int_ty : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { (*self as u8).iter_bytes(lsb0, f) @@ -1003,6 +1009,12 @@ impl int_ty : cmp::Eq { #[auto_decode] enum uint_ty { ty_u, ty_u8, ty_u16, ty_u32, ty_u64, } +impl uint_ty : ToStr { + pure fn to_str() -> ~str { + ::ast_util::uint_ty_to_str(self) + } +} + impl uint_ty : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { (*self as u8).iter_bytes(lsb0, f) @@ -1031,6 +1043,12 @@ impl uint_ty : cmp::Eq { #[auto_decode] enum float_ty { ty_f, ty_f32, ty_f64, } +impl float_ty : ToStr { + pure fn to_str() -> ~str { + ::ast_util::float_ty_to_str(self) + } +} + impl float_ty : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { (*self as u8).iter_bytes(lsb0, f) From 923b3154c6b69748e951b04d874b7a28eb3cedf9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 22 Jan 2013 07:02:09 -0800 Subject: [PATCH 19/31] Do not try to encode/decode inference types, should not be necessary r=brson --- src/librustc/metadata/tydecode.rs | 3 --- src/librustc/metadata/tyencode.rs | 15 ++------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 6a09ae14d01dc..590dd9f7ea7e0 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -323,9 +323,6 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t { 'f' => { parse_ty_rust_fn(st, conv) } - 'X' => { - return ty::mk_var(st.tcx, ty::TyVid(parse_int(st) as uint)); - } 'Y' => return ty::mk_type(st.tcx), 'C' => { let proto = parse_proto(st); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 154fb8d2de85a..d318f00ad6752 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -298,19 +298,8 @@ fn enc_sty(w: io::Writer, cx: @ctxt, +st: ty::sty) { ty::ty_fn(ref f) => { enc_ty_fn(w, cx, (*f)); } - ty::ty_infer(ty::TyVar(id)) => { - w.write_char('X'); - w.write_uint(id.to_uint()); - } - ty::ty_infer(ty::IntVar(id)) => { - w.write_char('X'); - w.write_char('I'); - w.write_uint(id.to_uint()); - } - ty::ty_infer(ty::FloatVar(id)) => { - w.write_char('X'); - w.write_char('F'); - w.write_uint(id.to_uint()); + ty::ty_infer(_) => { + cx.diag.handler().bug(~"Cannot encode inference variable types"); } ty::ty_param({idx: id, def_id: did}) => { w.write_char('p'); From 05b6df49b86024eb4f41fb94478ad9cd80dc172c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 22 Jan 2013 07:02:40 -0800 Subject: [PATCH 20/31] Refactor to make inference code around unification more readable r=brson --- src/librustc/middle/ty.rs | 94 +++++----- .../middle/typeck/infer/assignment.rs | 8 +- src/librustc/middle/typeck/infer/combine.rs | 121 +++++++------ src/librustc/middle/typeck/infer/lattice.rs | 64 ++++--- src/librustc/middle/typeck/infer/mod.rs | 50 +++--- src/librustc/middle/typeck/infer/resolve.rs | 19 +- src/librustc/middle/typeck/infer/sub.rs | 51 +++--- src/librustc/middle/typeck/infer/to_str.rs | 48 +++--- src/librustc/middle/typeck/infer/unify.rs | 163 +++++++++++++----- 9 files changed, 335 insertions(+), 283 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 840726b804179..0726104788cda 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -55,7 +55,7 @@ export ProvidedMethodSource; export ProvidedMethodInfo; export ProvidedMethodsMap; export InstantiatedTraitRef; -export TyVid, IntVid, FloatVid, FnVid, RegionVid, Vid; +export TyVid, IntVid, FloatVid, RegionVid, Vid; export br_hashmap; export is_instantiable; export node_id_to_type; @@ -215,7 +215,7 @@ export ty_sort_str; export normalize_ty; export to_str; export bound_const; -export terr_no_integral_type, terr_no_floating_point_type; +export terr_int_mismatch, terr_float_mismatch, terr_sigil_mismatch; export terr_ty_param_size, terr_self_substs; export terr_in_field, terr_record_fields, terr_vstores_differ, terr_arg_count; export terr_sorts, terr_vec, terr_str, terr_record_size, terr_tuple_size; @@ -241,6 +241,7 @@ export AutoRef; export AutoRefKind, AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn; export iter_bound_traits_and_supertraits; export count_traits_and_supertraits; +export IntVarValue, IntType, UintType; // Data types @@ -703,6 +704,12 @@ enum sty { ty_unboxed_vec(mt), } +#[deriving_eq] +enum IntVarValue { + IntType(ast::int_ty), + UintType(ast::uint_ty), +} + enum terr_vstore_kind { terr_vec, terr_str, terr_fn, terr_trait } @@ -740,8 +747,8 @@ enum type_err { terr_sorts(expected_found), terr_self_substs, terr_integer_as_char, - terr_no_integral_type, - terr_no_floating_point_type, + terr_int_mismatch(expected_found), + terr_float_mismatch(expected_found) } enum param_bound { @@ -752,10 +759,16 @@ enum param_bound { bound_trait(t), } +#[deriving_eq] enum TyVid = uint; + +#[deriving_eq] enum IntVid = uint; + +#[deriving_eq] enum FloatVid = uint; -enum FnVid = uint; + +#[deriving_eq] #[auto_encode] #[auto_decode] enum RegionVid = uint; @@ -851,14 +864,6 @@ impl FloatVid: ToStr { pure fn to_str() -> ~str { fmt!("", self.to_uint()) } } -impl FnVid: Vid { - pure fn to_uint() -> uint { *self } -} - -impl FnVid: ToStr { - pure fn to_str() -> ~str { fmt!("", self.to_uint()) } -} - impl RegionVid: Vid { pure fn to_uint() -> uint { *self } } @@ -884,33 +889,36 @@ impl InferTy: ToStr { } } -impl RegionVid : to_bytes::IterBytes { - pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - (**self).iter_bytes(lsb0, f) +impl IntVarValue : ToStr { + pure fn to_str() -> ~str { + match self { + IntType(ref v) => v.to_str(), + UintType(ref v) => v.to_str(), + } } } impl TyVid : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - (**self).iter_bytes(lsb0, f) + self.to_uint().iter_bytes(lsb0, f) } } impl IntVid : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - (**self).iter_bytes(lsb0, f) + self.to_uint().iter_bytes(lsb0, f) } } impl FloatVid : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - (**self).iter_bytes(lsb0, f) + self.to_uint().iter_bytes(lsb0, f) } } -impl FnVid : to_bytes::IterBytes { +impl RegionVid : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - (**self).iter_bytes(lsb0, f) + self.to_uint().iter_bytes(lsb0, f) } } @@ -3575,17 +3583,18 @@ fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str { terr_self_substs => { ~"inconsistent self substitution" // XXX this is more of a bug } - terr_no_integral_type => { - ~"couldn't determine an appropriate integral type for integer \ - literal" - } terr_integer_as_char => { - ~"integer literals can't be inferred to char type \ - (try an explicit cast)" + fmt!("expected an integral type but found char") } - terr_no_floating_point_type => { - ~"couldn't determine an appropriate floating point type for \ - floating point literal" + terr_int_mismatch(ref values) => { + fmt!("expected %s but found %s", + values.expected.to_str(), + values.found.to_str()) + } + terr_float_mismatch(ref values) => { + fmt!("expected %s but found %s", + values.expected.to_str(), + values.found.to_str()) } } } @@ -4451,31 +4460,6 @@ impl vstore : cmp::Eq { pure fn ne(&self, other: &vstore) -> bool { !(*self).eq(other) } } -impl TyVid : cmp::Eq { - pure fn eq(&self, other: &TyVid) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &TyVid) -> bool { *(*self) != *(*other) } -} - -impl IntVid : cmp::Eq { - pure fn eq(&self, other: &IntVid) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &IntVid) -> bool { *(*self) != *(*other) } -} - -impl FloatVid : cmp::Eq { - pure fn eq(&self, other: &FloatVid) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &FloatVid) -> bool { *(*self) != *(*other) } -} - -impl FnVid : cmp::Eq { - pure fn eq(&self, other: &FnVid) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &FnVid) -> bool { *(*self) != *(*other) } -} - -impl RegionVid : cmp::Eq { - pure fn eq(&self, other: &RegionVid) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &RegionVid) -> bool { *(*self) != *(*other) } -} - impl Region : cmp::Eq { pure fn eq(&self, other: &Region) -> bool { match (*self) { diff --git a/src/librustc/middle/typeck/infer/assignment.rs b/src/librustc/middle/typeck/infer/assignment.rs index fef63cf9a42cc..cd4514f6a2c5d 100644 --- a/src/librustc/middle/typeck/infer/assignment.rs +++ b/src/librustc/middle/typeck/infer/assignment.rs @@ -103,8 +103,8 @@ impl Assign { } (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => { - let nde_a = self.infcx.get(&self.infcx.ty_var_bindings, a_id); - let nde_b = self.infcx.get(&self.infcx.ty_var_bindings, b_id); + let nde_a = self.infcx.get(a_id); + let nde_b = self.infcx.get(b_id); let a_bounds = nde_a.possible_types; let b_bounds = nde_b.possible_types; @@ -114,7 +114,7 @@ impl Assign { } (ty::ty_infer(TyVar(a_id)), _) => { - let nde_a = self.infcx.get(&self.infcx.ty_var_bindings, a_id); + let nde_a = self.infcx.get(a_id); let a_bounds = nde_a.possible_types; let a_bnd = option::or(a_bounds.ub, a_bounds.lb); @@ -122,7 +122,7 @@ impl Assign { } (_, ty::ty_infer(TyVar(b_id))) => { - let nde_b = self.infcx.get(&self.infcx.ty_var_bindings, b_id); + let nde_b = self.infcx.get(b_id); let b_bounds = nde_b.possible_types; let b_bnd = option::or(b_bounds.lb, b_bounds.ub); diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index c5e99bc5c0362..e9946ae7c13e6 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -57,6 +57,7 @@ use core::prelude::*; use middle::ty::{FloatVar, FnTyBase, FnMeta, FnSig, IntVar, TyVar}; +use middle::ty::{IntType, UintType}; use middle::ty; use middle::typeck::infer::glb::Glb; use middle::typeck::infer::lub::Lub; @@ -112,8 +113,8 @@ pub struct CombineFields { } fn expected_found( - self: &C, +a: T, +b: T) -> ty::expected_found { - + self: &C, +a: T, +b: T) -> ty::expected_found +{ if self.a_is_expected() { ty::expected_found {expected: move a, found: move b} } else { @@ -392,7 +393,7 @@ fn super_tys( self: &C, a: ty::t, b: ty::t) -> cres { let tcx = self.infcx().tcx; - match (/*bad*/copy ty::get(a).sty, /*bad*/copy ty::get(b).sty) { + return match (/*bad*/copy ty::get(a).sty, /*bad*/copy ty::get(b).sty) { // The "subtype" ought to be handling cases involving bot or var: (ty::ty_bot, _) | (_, ty::ty_bot) | @@ -405,53 +406,46 @@ fn super_tys( b.inf_str(self.infcx()))); } - // Relate integral variables to other types - (ty::ty_infer(IntVar(a_id)), ty::ty_infer(IntVar(b_id))) => { - if_ok!(self.infcx().simple_vars(&self.infcx().int_var_bindings, - ty::terr_no_integral_type, - a_id, b_id)); - Ok(a) - } - (ty::ty_infer(IntVar(v_id)), ty::ty_int(v)) | - (ty::ty_int(v), ty::ty_infer(IntVar(v_id))) => { - if v == ast::ty_char { - Err(ty::terr_integer_as_char) - } else { - if_ok!(self.infcx().simple_var_t(&self.infcx().int_var_bindings, - ty::terr_no_integral_type, - v_id, IntType(v))); - Ok(ty::mk_mach_int(tcx, v)) + // Relate integral variables to other types + (ty::ty_infer(IntVar(a_id)), ty::ty_infer(IntVar(b_id))) => { + if_ok!(self.infcx().simple_vars(self.a_is_expected(), + a_id, b_id)); + Ok(a) + } + (ty::ty_infer(IntVar(v_id)), ty::ty_int(v)) => { + unify_integral_variable(self, self.a_is_expected(), + v_id, IntType(v)) + } + (ty::ty_int(v), ty::ty_infer(IntVar(v_id))) => { + unify_integral_variable(self, !self.a_is_expected(), + v_id, IntType(v)) + } + (ty::ty_infer(IntVar(v_id)), ty::ty_uint(v)) => { + unify_integral_variable(self, self.a_is_expected(), + v_id, UintType(v)) + } + (ty::ty_uint(v), ty::ty_infer(IntVar(v_id))) => { + unify_integral_variable(self, !self.a_is_expected(), + v_id, UintType(v)) } - } - (ty::ty_infer(IntVar(v_id)), ty::ty_uint(v)) | - (ty::ty_uint(v), ty::ty_infer(IntVar(v_id))) => { - if_ok!(self.infcx().simple_var_t(&self.infcx().int_var_bindings, - ty::terr_no_integral_type, - v_id, UintType(v))); - Ok(ty::mk_mach_uint(tcx, v)) - } - // Relate floating-point variables to other types - (ty::ty_infer(FloatVar(a_id)), ty::ty_infer(FloatVar(b_id))) => { - if_ok!(self.infcx().simple_vars(&self.infcx().float_var_bindings, - ty::terr_no_floating_point_type, - a_id, b_id)); - Ok(a) - } - (ty::ty_infer(FloatVar(v_id)), ty::ty_float(v)) | - (ty::ty_float(v), ty::ty_infer(FloatVar(v_id))) => { - if_ok!(self.infcx().simple_var_t(&self.infcx().float_var_bindings, - ty::terr_no_floating_point_type, - v_id, v)); - Ok(ty::mk_mach_float(tcx, v)) - } + // Relate floating-point variables to other types + (ty::ty_infer(FloatVar(a_id)), ty::ty_infer(FloatVar(b_id))) => { + if_ok!(self.infcx().simple_vars(self.a_is_expected(), + a_id, b_id)); + Ok(a) + } + (ty::ty_infer(FloatVar(v_id)), ty::ty_float(v)) => { + unify_float_variable(self, self.a_is_expected(), v_id, v) + } + (ty::ty_float(v), ty::ty_infer(FloatVar(v_id))) => { + unify_float_variable(self, !self.a_is_expected(), v_id, v) + } (ty::ty_int(_), _) | (ty::ty_uint(_), _) | (ty::ty_float(_), _) => { - let as_ = /*bad*/copy ty::get(a).sty; - let bs = /*bad*/copy ty::get(b).sty; - if as_ == bs { + if ty::get(a).sty == ty::get(b).sty { Ok(a) } else { Err(ty::terr_sorts(expected_found(self, a, b))) @@ -516,11 +510,9 @@ fn super_tys( } (ty::ty_rptr(a_r, a_mt), ty::ty_rptr(b_r, b_mt)) => { - do self.contraregions(a_r, b_r).chain |r| { - do self.mts(a_mt, b_mt).chain |mt| { - Ok(ty::mk_rptr(tcx, r, mt)) - } - } + let r = if_ok!(self.contraregions(a_r, b_r)); + let mt = if_ok!(self.mts(a_mt, b_mt)); + Ok(ty::mk_rptr(tcx, r, mt)) } (ty::ty_evec(a_mt, vs_a), ty::ty_evec(b_mt, vs_b)) => { @@ -565,5 +557,34 @@ fn super_tys( } _ => Err(ty::terr_sorts(expected_found(self, a, b))) + }; + + fn unify_integral_variable( + self: &C, + vid_is_expected: bool, + vid: ty::IntVid, + val: ty::IntVarValue) -> cres + { + let tcx = self.infcx().tcx; + if val == IntType(ast::ty_char) { + Err(ty::terr_integer_as_char) + } else { + if_ok!(self.infcx().simple_var_t(vid_is_expected, vid, val)); + match val { + IntType(v) => Ok(ty::mk_mach_int(tcx, v)), + UintType(v) => Ok(ty::mk_mach_uint(tcx, v)) + } + } } -} + + fn unify_float_variable( + self: &C, + vid_is_expected: bool, + vid: ty::FloatVid, + val: ast::float_ty) -> cres + { + let tcx = self.infcx().tcx; + if_ok!(self.infcx().simple_var_t(vid_is_expected, vid, val)); + Ok(ty::mk_mach_float(tcx, val)) + } +} \ No newline at end of file diff --git a/src/librustc/middle/typeck/infer/lattice.rs b/src/librustc/middle/typeck/infer/lattice.rs index 54638819f7ccc..6ae10b120fe72 100644 --- a/src/librustc/middle/typeck/infer/lattice.rs +++ b/src/librustc/middle/typeck/infer/lattice.rs @@ -89,9 +89,9 @@ impl FnMeta: LatticeValue { } impl CombineFields { - fn var_sub_var( + fn var_sub_var>>( &self, - vb: &ValsAndBindings>, +a_id: V, +b_id: V) -> ures { @@ -102,8 +102,8 @@ impl CombineFields { * top of infer.rs*/ // Need to make sub_id a subtype of sup_id. - let node_a = self.infcx.get(vb, a_id); - let node_b = self.infcx.get(vb, b_id); + let node_a = self.infcx.get(a_id); + let node_b = self.infcx.get(b_id); let a_id = node_a.root; let b_id = node_b.root; let a_bounds = node_a.possible_types; @@ -135,17 +135,17 @@ impl CombineFields { // A remains a subtype of B. Actually, there are other options, // but that's the route we choose to take. - self.infcx.unify(vb, &node_a, &node_b, |new_root, new_rank| { - self.set_var_to_merged_bounds(vb, new_root, + self.infcx.unify(&node_a, &node_b, |new_root, new_rank| { + self.set_var_to_merged_bounds(new_root, &a_bounds, &b_bounds, new_rank) }) } /// make variable a subtype of T - fn var_sub_t( + fn var_sub_t>>( &self, - vb: &ValsAndBindings>, +a_id: V, +b: T) -> ures { @@ -153,7 +153,7 @@ impl CombineFields { * * Make a variable (`a_id`) a subtype of the concrete type `b` */ - let node_a = self.infcx.get(vb, a_id); + let node_a = self.infcx.get(a_id); let a_id = node_a.root; let a_bounds = &node_a.possible_types; let b_bounds = &{lb: None, ub: Some(b)}; @@ -164,12 +164,12 @@ impl CombineFields { b.inf_str(self.infcx)); self.set_var_to_merged_bounds( - vb, a_id, a_bounds, b_bounds, node_a.rank) + a_id, a_bounds, b_bounds, node_a.rank) } - fn t_sub_var( + fn t_sub_var>>( &self, - vb: &ValsAndBindings>, +a: T, +b_id: V) -> ures { @@ -178,7 +178,7 @@ impl CombineFields { * Make a concrete type (`a`) a subtype of the variable `b_id` */ let a_bounds = &{lb: Some(a), ub: None}; - let node_b = self.infcx.get(vb, b_id); + let node_b = self.infcx.get(b_id); let b_id = node_b.root; let b_bounds = &node_b.possible_types; @@ -188,7 +188,7 @@ impl CombineFields { b_bounds.inf_str(self.infcx)); self.set_var_to_merged_bounds( - vb, b_id, a_bounds, b_bounds, node_b.rank) + b_id, a_bounds, b_bounds, node_b.rank) } fn merge_bnd( @@ -219,10 +219,9 @@ impl CombineFields { } } - fn set_var_to_merged_bounds( + fn set_var_to_merged_bounds>>( &self, - vb: &ValsAndBindings>, +v_id: V, a: &Bounds, b: &Bounds, @@ -278,7 +277,7 @@ impl CombineFields { // the new bounds must themselves // be relatable: let () = if_ok!(self.bnds(&bounds.lb, &bounds.ub)); - self.infcx.set(vb, v_id, Root(bounds, rank)); + self.infcx.set(v_id, Root(bounds, rank)); uok() } @@ -369,8 +368,7 @@ fn super_lattice_tys( (_, ty::ty_bot) => { return self.ty_bot(a); } (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => { - let r = if_ok!(lattice_vars(self, &self.infcx().ty_var_bindings, - a_id, b_id, + let r = if_ok!(lattice_vars(self, a_id, b_id, |x, y| self.tys(*x, *y))); return match r { VarResult(v) => Ok(ty::mk_var(tcx, v)), @@ -379,14 +377,12 @@ fn super_lattice_tys( } (ty::ty_infer(TyVar(a_id)), _) => { - return lattice_var_and_t(self, &self.infcx().ty_var_bindings, - a_id, &b, + return lattice_var_and_t(self, a_id, &b, |x, y| self.tys(*x, *y)); } (_, ty::ty_infer(TyVar(b_id))) => { - return lattice_var_and_t(self, &self.infcx().ty_var_bindings, - b_id, &a, + return lattice_var_and_t(self, b_id, &a, |x, y| self.tys(*x, *y)); } @@ -419,17 +415,16 @@ enum LatticeVarResult { * result is a variable. This is indicated with a `VarResult` * return. */ fn lattice_vars( + T:Copy InferStr LatticeValue, + V:Copy Eq ToStr Vid UnifyVid>>( self: &L, // defines whether we want LUB or GLB - vb: &ValsAndBindings>, // relevant variable bindings +a_vid: V, // first variable +b_vid: V, // second variable lattice_dir_op: LatticeDirOp) // LUB or GLB operation on types -> cres> { - let nde_a = self.infcx().get(vb, a_vid); - let nde_b = self.infcx().get(vb, b_vid); + let nde_a = self.infcx().get(a_vid); + let nde_b = self.infcx().get(b_vid); let a_vid = nde_a.root; let b_vid = nde_b.root; let a_bounds = &nde_a.possible_types; @@ -461,22 +456,21 @@ fn lattice_vars( + T:Copy InferStr LatticeValue, + V:Copy Eq ToStr Vid UnifyVid>>( self: &L, - vb: &ValsAndBindings>, +a_id: V, b: &T, lattice_dir_op: LatticeDirOp) -> cres { - let nde_a = self.infcx().get(vb, a_id); + let nde_a = self.infcx().get(a_id); let a_id = nde_a.root; let a_bounds = &nde_a.possible_types; @@ -501,7 +495,7 @@ fn lattice_var_and_t; // "unify result" type fres = Result; // "fixup result" type ares = cres>; // "assignment result" -#[deriving_eq] -enum IntVarValue { - IntType(ast::int_ty), - UintType(ast::uint_ty), -} - struct InferCtxt { tcx: ty::ctxt, @@ -364,22 +359,14 @@ struct InferCtxt { // types that might instantiate a general type variable have an // order, represented by its upper and lower bounds. ty_var_bindings: ValsAndBindings>, - - // Number of type variables created thus far. mut ty_var_counter: uint, - // The types that might instantiate an integral type variable are - // represented by an int_ty_set. + // Map from integral variable to the kind of integer it represents int_var_bindings: ValsAndBindings>, - - // Number of integral variables created thus far. mut int_var_counter: uint, - // The types that might instantiate a floating-point type variable are - // represented by an float_ty_set. + // Map from floating variable to the kind of float it represents float_var_bindings: ValsAndBindings>, - - // Number of floating-point variables created thus far. mut float_var_counter: uint, // For region variables. @@ -582,6 +569,7 @@ fn rollback_to( struct Snapshot { ty_var_bindings_len: uint, int_var_bindings_len: uint, + float_var_bindings_len: uint, region_vars_snapshot: uint, } @@ -607,6 +595,8 @@ impl @InferCtxt { self.ty_var_bindings.bindings.len(), int_var_bindings_len: self.int_var_bindings.bindings.len(), + float_var_bindings_len: + self.float_var_bindings.bindings.len(), region_vars_snapshot: self.region_vars.start_snapshot(), } @@ -616,9 +606,11 @@ impl @InferCtxt { debug!("rollback!"); rollback_to(&self.ty_var_bindings, snapshot.ty_var_bindings_len); - // FIXME(#3211) -- int_var not transactional + // FIXME(#3211) -- int_var and float_var not transactional //rollback_to(&self.int_var_bindings, // snapshot.int_var_bindings_len); + //rollback_to(&self.float_var_bindings, + // snapshot.float_var_bindings_len); self.region_vars.rollback_to(snapshot.region_vars_snapshot); } @@ -664,6 +656,16 @@ impl @InferCtxt { } } +fn next_simple_var( + +counter: &mut uint, + +bindings: &ValsAndBindings>) -> uint +{ + let id = *counter; + *counter += 1; + bindings.vals.insert(id, Root(None, 0)); + return id; +} + impl @InferCtxt { fn next_ty_var_id() -> TyVid { let id = self.ty_var_counter; @@ -682,11 +684,8 @@ impl @InferCtxt { } fn next_int_var_id() -> IntVid { - let id = self.int_var_counter; - self.int_var_counter += 1; - - self.int_var_bindings.vals.insert(id, Root(None, 0)); - return IntVid(id); + IntVid(next_simple_var(&mut self.int_var_counter, + &self.int_var_bindings)) } fn next_int_var() -> ty::t { @@ -694,11 +693,8 @@ impl @InferCtxt { } fn next_float_var_id() -> FloatVid { - let id = self.float_var_counter; - self.float_var_counter += 1; - - self.float_var_bindings.vals.insert(id, Root(None, 0)); - return FloatVid(id); + FloatVid(next_simple_var(&mut self.float_var_counter, + &self.float_var_bindings)) } fn next_float_var() -> ty::t { diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index 23be3b208271c..01f4b86b48858 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -49,11 +49,10 @@ use core::prelude::*; use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid}; -use middle::ty::{type_is_bot}; +use middle::ty::{type_is_bot, IntType, UintType}; use middle::ty; use middle::typeck::infer::{cyclic_ty, fixup_err, fres, InferCtxt}; use middle::typeck::infer::{region_var_bound_by_region_var, unresolved_ty}; -use middle::typeck::infer::{IntType, UintType}; use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::unify::Root; use util::common::{indent, indenter}; @@ -219,7 +218,7 @@ impl ResolveState { // tend to carry more restrictions or higher // perf. penalties, so it pays to know more. - let nde = self.infcx.get(&self.infcx.ty_var_bindings, vid); + let nde = self.infcx.get(vid); let bounds = nde.possible_types; let t1 = match bounds { @@ -243,7 +242,7 @@ impl ResolveState { return ty::mk_int_var(self.infcx.tcx, vid); } - let node = self.infcx.get(&self.infcx.int_var_bindings, vid); + let node = self.infcx.get(vid); match node.possible_types { Some(IntType(t)) => ty::mk_mach_int(self.infcx.tcx, t), Some(UintType(t)) => ty::mk_mach_uint(self.infcx.tcx, t), @@ -251,9 +250,8 @@ impl ResolveState { if self.should(force_ivar) { // As a last resort, default to int. let ty = ty::mk_int(self.infcx.tcx); - self.infcx.set( - &self.infcx.int_var_bindings, vid, - Root(Some(IntType(ast::ty_i)), node.rank)); + self.infcx.set(vid, + Root(Some(IntType(ast::ty_i)), node.rank)); ty } else { ty::mk_int_var(self.infcx.tcx, vid) @@ -267,17 +265,14 @@ impl ResolveState { return ty::mk_float_var(self.infcx.tcx, vid); } - let node = self.infcx.get(&self.infcx.float_var_bindings, vid); + let node = self.infcx.get(vid); match node.possible_types { Some(t) => ty::mk_mach_float(self.infcx.tcx, t), None => { if self.should(force_fvar) { // As a last resort, default to float. let ty = ty::mk_float(self.infcx.tcx); - self.infcx.set( - &self.infcx.float_var_bindings, - vid, - Root(Some(ast::ty_f), node.rank)); + self.infcx.set(vid, Root(Some(ast::ty_f), node.rank)); ty } else { ty::mk_float_var(self.infcx.tcx, vid) diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index aa6721fb22983..4252580ac46cd 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -102,38 +102,31 @@ impl Sub: Combine { debug!("%s.tys(%s, %s)", self.tag(), a.inf_str(self.infcx), b.inf_str(self.infcx)); if a == b { return Ok(a); } - do indent { - match (ty::get(a).sty, ty::get(b).sty) { - (ty::ty_bot, _) => { - Ok(a) - } + let _indenter = indenter(); + match (ty::get(a).sty, ty::get(b).sty) { + (ty::ty_bot, _) => { + Ok(a) + } - (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => { - do self.var_sub_var(&self.infcx.ty_var_bindings, - a_id, b_id).then { - Ok(a) - } - } - (ty::ty_infer(TyVar(a_id)), _) => { - do self.var_sub_t(&self.infcx.ty_var_bindings, - a_id, b).then { - Ok(a) - } - } - (_, ty::ty_infer(TyVar(b_id))) => { - do self.t_sub_var(&self.infcx.ty_var_bindings, - a, b_id).then { - Ok(a) - } - } + (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => { + if_ok!(self.var_sub_var(a_id, b_id)); + Ok(a) + } + (ty::ty_infer(TyVar(a_id)), _) => { + if_ok!(self.var_sub_t(a_id, b)); + Ok(a) + } + (_, ty::ty_infer(TyVar(b_id))) => { + if_ok!(self.t_sub_var(a, b_id)); + Ok(a) + } - (_, ty::ty_bot) => { - Err(ty::terr_sorts(expected_found(&self, a, b))) - } + (_, ty::ty_bot) => { + Err(ty::terr_sorts(expected_found(&self, a, b))) + } - _ => { - super_tys(&self, a, b) - } + _ => { + super_tys(&self, a, b) } } } diff --git a/src/librustc/middle/typeck/infer/to_str.rs b/src/librustc/middle/typeck/infer/to_str.rs index 42f516fe6d880..a6d316db42872 100644 --- a/src/librustc/middle/typeck/infer/to_str.rs +++ b/src/librustc/middle/typeck/infer/to_str.rs @@ -10,10 +10,10 @@ use core::prelude::*; -use middle::ty::{FnMeta, FnTyBase, FnSig, FnVid, Vid}; +use middle::ty::{FnMeta, FnTyBase, FnSig, Vid}; +use middle::ty::{IntVarValue, IntType, UintType}; use middle::ty; use middle::typeck::infer::{Bound, Bounds}; -use middle::typeck::infer::{IntVarValue, IntType, UintType}; use middle::typeck::infer::InferCtxt; use middle::typeck::infer::unify::{Redirect, Root, VarValue}; use util::ppaux::{mt_to_str, ty_to_str}; @@ -25,23 +25,23 @@ use core::uint; use core::str; pub trait InferStr { - fn inf_str(cx: @InferCtxt) -> ~str; + fn inf_str(&self, cx: &InferCtxt) -> ~str; } impl ty::t : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { - ty_to_str(cx.tcx, self) + fn inf_str(&self, cx: &InferCtxt) -> ~str { + ty_to_str(cx.tcx, *self) } } impl FnMeta : InferStr { - fn inf_str(_cx: @InferCtxt) -> ~str { - fmt!("%?", self) + fn inf_str(&self, _cx: &InferCtxt) -> ~str { + fmt!("%?", *self) } } impl FnSig : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { + fn inf_str(&self, cx: &InferCtxt) -> ~str { fmt!("(%s) -> %s", str::connect(self.inputs.map(|a| a.ty.inf_str(cx)), ", "), self.output.inf_str(cx)) @@ -49,26 +49,26 @@ impl FnSig : InferStr { } impl FnTyBase : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { + fn inf_str(&self, cx: &InferCtxt) -> ~str { fmt!("%s%s", self.meta.inf_str(cx), self.sig.inf_str(cx)) } } impl ty::mt : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { - mt_to_str(cx.tcx, self) + fn inf_str(&self, cx: &InferCtxt) -> ~str { + mt_to_str(cx.tcx, *self) } } impl ty::Region : InferStr { - fn inf_str(_cx: @InferCtxt) -> ~str { - fmt!("%?", self) + fn inf_str(&self, _cx: &InferCtxt) -> ~str { + fmt!("%?", *self) } } impl Bound : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { - match self { + fn inf_str(&self, cx: &InferCtxt) -> ~str { + match *self { Some(ref v) => v.inf_str(cx), None => ~"none" } @@ -76,7 +76,7 @@ impl Bound : InferStr { } impl Bounds : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { + fn inf_str(&self, cx: &InferCtxt) -> ~str { fmt!("{%s <: %s}", self.lb.inf_str(cx), self.ub.inf_str(cx)) @@ -84,8 +84,8 @@ impl Bounds : InferStr { } impl VarValue : InferStr { - fn inf_str(cx: @InferCtxt) -> ~str { - match self { + fn inf_str(&self, cx: &InferCtxt) -> ~str { + match *self { Redirect(ref vid) => fmt!("Redirect(%s)", vid.to_str()), Root(ref pt, rk) => fmt!("Root(%s, %s)", pt.inf_str(cx), uint::to_str(rk, 10u)) @@ -94,17 +94,13 @@ impl VarValue : InferStr { } impl IntVarValue : InferStr { - fn inf_str(_cx: @InferCtxt) -> ~str { - match self { - IntType(t) => ast_util::int_ty_to_str(t), - UintType(t) => ast_util::uint_ty_to_str(t) - } + fn inf_str(&self, _cx: &InferCtxt) -> ~str { + self.to_str() } } impl ast::float_ty : InferStr { - fn inf_str(_cx: @InferCtxt) -> ~str { - ast_util::float_ty_to_str(self) + fn inf_str(&self, _cx: &InferCtxt) -> ~str { + self.to_str() } } - diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs index 77bd46eea2dfd..6c831427b031e 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/typeck/infer/unify.rs @@ -9,24 +9,24 @@ // except according to those terms. use core::prelude::*; +use core::result; +use std::smallintmap::SmallIntMap; -use middle::ty::Vid; +use middle::ty::{Vid, expected_found, IntVarValue}; use middle::ty; use middle::typeck::infer::{Bound, Bounds, cres, uok, ures}; use middle::typeck::infer::combine::Combine; use middle::typeck::infer::InferCtxt; use middle::typeck::infer::to_str::InferStr; +use syntax::ast; use util::common::{indent, indenter}; -use core::result; -use std::smallintmap::SmallIntMap; - enum VarValue { Redirect(V), Root(T, uint), } -struct ValsAndBindings { +struct ValsAndBindings { vals: SmallIntMap>, mut bindings: ~[(V, VarValue)], } @@ -37,11 +37,15 @@ struct Node { rank: uint, } -impl @InferCtxt { - fn get( - vb: &ValsAndBindings, - vid: V) - -> Node +trait UnifyVid { + static fn appropriate_vals_and_bindings(infcx: &v/InferCtxt) + -> &v/ValsAndBindings; +} + +impl InferCtxt { + fn get>( + &self, + +vid: V) -> Node { /*! * @@ -50,6 +54,7 @@ impl @InferCtxt { * http://en.wikipedia.org/wiki/Disjoint-set_data_structure */ + let vb = UnifyVid::appropriate_vals_and_bindings(self); let vid_u = vid.to_uint(); match vb.vals.find(vid_u) { None => { @@ -57,9 +62,9 @@ impl @InferCtxt { } Some(ref var_val) => { match (*var_val) { - Redirect(ref vid) => { - let node = self.get(vb, (*vid)); - if node.root.ne(vid) { + Redirect(vid) => { + let node: Node = self.get(vid); + if node.root != vid { // Path compression vb.vals.insert(vid.to_uint(), Redirect(node.root)); } @@ -73,9 +78,9 @@ impl @InferCtxt { } } - fn set( - vb: &ValsAndBindings, - vid: V, + fn set>( + &self, + +vid: V, +new_v: VarValue) { /*! @@ -83,6 +88,7 @@ impl @InferCtxt { * Sets the value for `vid` to `new_v`. `vid` MUST be a root node! */ + let vb = UnifyVid::appropriate_vals_and_bindings(self); let old_v = vb.vals.get(vid.to_uint()); vb.bindings.push((vid, old_v)); vb.vals.insert(vid.to_uint(), new_v); @@ -91,8 +97,8 @@ impl @InferCtxt { vid.to_str(), old_v.inf_str(self), new_v.inf_str(self)); } - fn unify( - vb: &ValsAndBindings, + fn unify, R>( + &self, node_a: &Node, node_b: &Node, op: &fn(new_root: V, new_rank: uint) -> R @@ -108,17 +114,17 @@ impl @InferCtxt { if node_a.rank > node_b.rank { // a has greater rank, so a should become b's parent, // i.e., b should redirect to a. - self.set(vb, node_b.root, Redirect(node_a.root)); + self.set(node_b.root, Redirect(node_a.root)); op(node_a.root, node_a.rank) } else if node_a.rank < node_b.rank { // b has greater rank, so a should redirect to b. - self.set(vb, node_a.root, Redirect(node_b.root)); + self.set(node_a.root, Redirect(node_b.root)); op(node_b.root, node_b.rank) } else { // If equal, redirect one to the other and increment the // other's rank. assert node_a.rank == node_b.rank; - self.set(vb, node_b.root, Redirect(node_a.root)); + self.set(node_b.root, Redirect(node_a.root)); op(node_a.root, node_a.rank + 1) } } @@ -129,12 +135,30 @@ impl @InferCtxt { // Code to handle simple variables like ints, floats---anything that // doesn't have a subtyping relationship we need to worry about. -impl @InferCtxt { - fn simple_vars( - vb: &ValsAndBindings>, - err: ty::type_err, - a_id: V, - b_id: V) -> ures +trait SimplyUnifiable { + static fn to_type_err(expected_found) -> ty::type_err; +} + +fn mk_err(+a_is_expected: bool, + +a_t: T, + +b_t: T) -> ures +{ + if a_is_expected { + Err(SimplyUnifiable::to_type_err( + ty::expected_found {expected: a_t, found: b_t})) + } else { + Err(SimplyUnifiable::to_type_err( + ty::expected_found {expected: b_t, found: a_t})) + } +} + +impl InferCtxt { + fn simple_vars>>( + &self, + +a_is_expected: bool, + +a_id: V, + +b_id: V) -> ures { /*! * @@ -143,8 +167,8 @@ impl @InferCtxt { * have already been associated with a value, then those two * values must be the same. */ - let node_a = self.get(vb, a_id); - let node_b = self.get(vb, b_id); + let node_a = self.get(a_id); + let node_b = self.get(b_id); let a_id = node_a.root; let b_id = node_b.root; @@ -155,22 +179,24 @@ impl @InferCtxt { (&None, &None) => None, (&Some(ref v), &None) | (&None, &Some(ref v)) => Some(*v), (&Some(ref v1), &Some(ref v2)) => { - if *v1 != *v2 { return Err(err); } + if *v1 != *v2 { + return mk_err(a_is_expected, *v1, *v2); + } Some(*v1) } }; - self.unify(vb, &node_a, &node_b, |new_root, new_rank| { - self.set(vb, new_root, Root(combined, new_rank)); + self.unify(&node_a, &node_b, |new_root, new_rank| { + self.set(new_root, Root(combined, new_rank)); }); return uok(); } - fn simple_var_t( - vb: &ValsAndBindings>, - err: ty::type_err, - a_id: V, - b: T) -> ures + fn simple_var_t>>( + +a_is_expected: bool, + +a_id: V, + +b: T) -> ures { /*! * @@ -179,19 +205,66 @@ impl @InferCtxt { * if `a_id` already has a value, it must be the same as * `b`. */ - let node_a = self.get(vb, a_id); + let node_a = self.get(a_id); let a_id = node_a.root; - if node_a.possible_types.is_none() { - self.set(vb, a_id, Root(Some(b), node_a.rank)); - return uok(); - } + match node_a.possible_types { + None => { + self.set(a_id, Root(Some(b), node_a.rank)); + return uok(); + } - if node_a.possible_types == Some(b) { - return uok(); + Some(ref a_t) => { + if *a_t == b { + return uok(); + } else { + return mk_err(a_is_expected, *a_t, b); + } + } } + } +} - return Err(err); +// ______________________________________________________________________ + +impl ty::TyVid : UnifyVid> { + static fn appropriate_vals_and_bindings(infcx: &v/InferCtxt) + -> &v/ValsAndBindings> + { + return &infcx.ty_var_bindings; + } +} + +impl ty::IntVid : UnifyVid> { + static fn appropriate_vals_and_bindings(infcx: &v/InferCtxt) + -> &v/ValsAndBindings> + { + return &infcx.int_var_bindings; + } +} + +impl IntVarValue : SimplyUnifiable { + static fn to_type_err(err: expected_found) + -> ty::type_err + { + return ty::terr_int_mismatch(err); } } +impl ty::FloatVid : UnifyVid> { + static fn appropriate_vals_and_bindings(infcx: &v/InferCtxt) + -> &v/ValsAndBindings> + { + return &infcx.float_var_bindings; + } +} + +impl ast::float_ty : SimplyUnifiable { + static fn to_type_err(err: expected_found) + -> ty::type_err + { + return ty::terr_float_mismatch(err); + } +} + + From c07ae16de18ad24004e1d1c425c08bcf3e7c4811 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 22 Jan 2013 11:06:20 -0800 Subject: [PATCH 21/31] rename assign to coerce, remove some bad copies r=brson --- src/librustc/middle/typeck/check/demand.rs | 4 +- src/librustc/middle/typeck/check/mod.rs | 16 +-- .../infer/{assignment.rs => coercion.rs} | 116 +++++++++--------- src/librustc/middle/typeck/infer/mod.rs | 26 ++-- 4 files changed, 78 insertions(+), 84 deletions(-) rename src/librustc/middle/typeck/infer/{assignment.rs => coercion.rs} (75%) diff --git a/src/librustc/middle/typeck/check/demand.rs b/src/librustc/middle/typeck/check/demand.rs index e4b232500bbf7..c8aaf2ca61b49 100644 --- a/src/librustc/middle/typeck/check/demand.rs +++ b/src/librustc/middle/typeck/check/demand.rs @@ -49,8 +49,8 @@ fn eqtype(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t) { } } -// Checks that the type `actual` can be assigned to `expected`. -fn assign(fcx: @fn_ctxt, sp: span, expected: ty::t, expr: @ast::expr) { +// Checks that the type `actual` can be coerced to `expected`. +fn coerce(fcx: @fn_ctxt, sp: span, expected: ty::t, expr: @ast::expr) { let expr_ty = fcx.expr_ty(expr); match fcx.mk_assignty(expr, expr_ty, expected) { result::Ok(()) => { /* ok */ } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index be6559640d724..2d823ff02dd91 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -812,7 +812,7 @@ impl @fn_ctxt { fn mk_assignty(expr: @ast::expr, sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { - match infer::mk_assignty(self.infcx(), false, expr.span, sub, sup) { + match infer::mk_coercety(self.infcx(), false, expr.span, sub, sup) { Ok(None) => result::Ok(()), Err(ref e) => result::Err((*e)), Ok(Some(adjustment)) => { @@ -823,7 +823,7 @@ impl @fn_ctxt { } fn can_mk_assignty(sub: ty::t, sup: ty::t) -> Result<(), ty::type_err> { - infer::can_mk_assignty(self.infcx(), sub, sup) + infer::can_mk_coercety(self.infcx(), sub, sup) } fn mk_eqty(a_is_expected: bool, span: span, @@ -986,12 +986,12 @@ fn check_expr_has_type( } } -fn check_expr_assignable_to_type( +fn check_expr_coercable_to_type( fcx: @fn_ctxt, expr: @ast::expr, expected: ty::t) -> bool { do check_expr_with_unifier(fcx, expr, Some(expected)) { - demand::assign(fcx, expr.span, expected, expr) + demand::coerce(fcx, expr.span, expected, expr) } } @@ -1225,7 +1225,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, } // mismatch error happens in here - bot |= check_expr_assignable_to_type( + bot |= check_expr_coercable_to_type( fcx, *arg, formal_ty); } @@ -1243,7 +1243,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, -> bool { let mut bot = check_expr(fcx, lhs); let lhs_type = fcx.expr_ty(lhs); - bot |= check_expr_assignable_to_type(fcx, rhs, lhs_type); + bot |= check_expr_has_type(fcx, rhs, lhs_type); fcx.write_ty(id, ty::mk_nil(fcx.ccx.tcx)); return bot; } @@ -1739,7 +1739,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, ty::lookup_field_type( tcx, class_id, field_id, substitutions); bot |= - check_expr_assignable_to_type( + check_expr_coercable_to_type( fcx, field.node.expr, expected_field_type); @@ -2552,7 +2552,7 @@ fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) { fn check_decl_initializer(fcx: @fn_ctxt, nid: ast::node_id, init: @ast::expr) -> bool { let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.span, nid)); - return check_expr_assignable_to_type(fcx, init, lty); + return check_expr_coercable_to_type(fcx, init, lty); } fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool { diff --git a/src/librustc/middle/typeck/infer/assignment.rs b/src/librustc/middle/typeck/infer/coercion.rs similarity index 75% rename from src/librustc/middle/typeck/infer/assignment.rs rename to src/librustc/middle/typeck/infer/coercion.rs index cd4514f6a2c5d..84fe51b65ec51 100644 --- a/src/librustc/middle/typeck/infer/assignment.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -79,30 +79,23 @@ fn to_ares(+c: cres) -> ares { } } -// Note: Assign is not actually a combiner, in that it does not +// Note: Coerce is not actually a combiner, in that it does not // conform to the same interface, though it performs a similar // function. -enum Assign = CombineFields; +pub enum Coerce = CombineFields; -impl Assign { - fn tys(a: ty::t, b: ty::t) -> ares { - debug!("Assign.tys(%s => %s)", +impl Coerce { + fn tys(&self, a: ty::t, b: ty::t) -> ares { + debug!("Coerce.tys(%s => %s)", a.inf_str(self.infcx), b.inf_str(self.infcx)); - let _r = indenter(); - - debug!("Assign.tys: copying first type"); - let copy_a = copy ty::get(a).sty; - debug!("Assign.tys: copying second type"); - let copy_b = copy ty::get(b).sty; - debug!("Assign.tys: performing match"); - - let r = match (copy_a, copy_b) { - (ty::ty_bot, _) => { + let _indent = indenter(); + let r = match (&ty::get(a).sty, &ty::get(b).sty) { + (&ty::ty_bot, _) => { Ok(None) } - (ty::ty_infer(TyVar(a_id)), ty::ty_infer(TyVar(b_id))) => { + (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => { let nde_a = self.infcx.get(a_id); let nde_b = self.infcx.get(b_id); let a_bounds = nde_a.possible_types; @@ -110,42 +103,45 @@ impl Assign { let a_bnd = option::or(a_bounds.ub, a_bounds.lb); let b_bnd = option::or(b_bounds.lb, b_bounds.ub); - self.assign_tys_or_sub(a, b, a_bnd, b_bnd) + self.coerce_tys_or_sub(a, b, a_bnd, b_bnd) } - (ty::ty_infer(TyVar(a_id)), _) => { + (&ty::ty_infer(TyVar(a_id)), _) => { let nde_a = self.infcx.get(a_id); let a_bounds = nde_a.possible_types; let a_bnd = option::or(a_bounds.ub, a_bounds.lb); - self.assign_tys_or_sub(a, b, a_bnd, Some(b)) + self.coerce_tys_or_sub(a, b, a_bnd, Some(b)) } - (_, ty::ty_infer(TyVar(b_id))) => { + (_, &ty::ty_infer(TyVar(b_id))) => { let nde_b = self.infcx.get(b_id); let b_bounds = nde_b.possible_types; let b_bnd = option::or(b_bounds.lb, b_bounds.ub); - self.assign_tys_or_sub(a, b, Some(a), b_bnd) + self.coerce_tys_or_sub(a, b, Some(a), b_bnd) } (_, _) => { - self.assign_tys_or_sub(a, b, Some(a), Some(b)) + self.coerce_tys_or_sub(a, b, Some(a), Some(b)) } }; - debug!("Assign.tys end"); + debug!("Coerce.tys end"); move r } } -priv impl Assign { - fn assign_tys_or_sub( - a: ty::t, b: ty::t, - +a_bnd: Option, +b_bnd: Option) -> ares { - - debug!("Assign.assign_tys_or_sub(%s => %s, %s => %s)", +impl Coerce { + fn coerce_tys_or_sub( + &self, + +a: ty::t, + +b: ty::t, + +a_bnd: Option, + +b_bnd: Option) -> ares + { + debug!("Coerce.coerce_tys_or_sub(%s => %s, %s => %s)", a.inf_str(self.infcx), b.inf_str(self.infcx), a_bnd.inf_str(self.infcx), b_bnd.inf_str(self.infcx)); let _r = indenter(); @@ -167,59 +163,58 @@ priv impl Assign { match (a_bnd, b_bnd) { (Some(a_bnd), Some(b_bnd)) => { - match (/*bad*/copy ty::get(a_bnd).sty, - /*bad*/copy ty::get(b_bnd).sty) { + match (&ty::get(a_bnd).sty, &ty::get(b_bnd).sty) { // check for a case where a non-region pointer (@, ~) is - // being assigned to a region pointer: - (ty::ty_box(_), ty::ty_rptr(r_b, mt_b)) => { + // being coerceed to a region pointer: + (&ty::ty_box(_), &ty::ty_rptr(r_b, mt_b)) => { let nr_b = ty::mk_box(self.infcx.tcx, ty::mt {ty: mt_b.ty, mutbl: m_const}); - self.try_assign(1, ty::AutoPtr, + self.try_coerce(1, ty::AutoPtr, a, nr_b, mt_b.mutbl, r_b) } - (ty::ty_uniq(_), ty::ty_rptr(r_b, mt_b)) => { + (&ty::ty_uniq(_), &ty::ty_rptr(r_b, mt_b)) => { let nr_b = ty::mk_uniq(self.infcx.tcx, ty::mt {ty: mt_b.ty, mutbl: m_const}); - self.try_assign(1, ty::AutoPtr, + self.try_coerce(1, ty::AutoPtr, a, nr_b, mt_b.mutbl, r_b) } - (ty::ty_estr(vs_a), - ty::ty_estr(ty::vstore_slice(r_b))) + (&ty::ty_estr(vs_a), + &ty::ty_estr(ty::vstore_slice(r_b))) if is_borrowable(vs_a) => { let nr_b = ty::mk_estr(self.infcx.tcx, vs_a); - self.try_assign(0, ty::AutoBorrowVec, + self.try_coerce(0, ty::AutoBorrowVec, a, nr_b, m_imm, r_b) } - (ty::ty_evec(_, vs_a), - ty::ty_evec(mt_b, ty::vstore_slice(r_b))) + (&ty::ty_evec(_, vs_a), + &ty::ty_evec(mt_b, ty::vstore_slice(r_b))) if is_borrowable(vs_a) => { let nr_b = ty::mk_evec(self.infcx.tcx, ty::mt {ty: mt_b.ty, mutbl: m_const}, vs_a); - self.try_assign(0, ty::AutoBorrowVec, + self.try_coerce(0, ty::AutoBorrowVec, a, nr_b, mt_b.mutbl, r_b) } - (ty::ty_fn(ref a_f), ty::ty_fn(ref b_f)) + (&ty::ty_fn(ref a_f), &ty::ty_fn(ref b_f)) if borrowable_protos(a_f.meta.proto, b_f.meta.proto) => { let nr_b = ty::mk_fn(self.infcx.tcx, ty::FnTyBase { meta: ty::FnMeta {proto: a_f.meta.proto, ..b_f.meta}, sig: copy b_f.sig }); - self.try_assign(0, ty::AutoBorrowFn, + self.try_coerce(0, ty::AutoBorrowFn, a, nr_b, m_imm, b_f.meta.region) } - (ty::ty_fn(ref a_f), ty::ty_fn(ref b_f)) + (&ty::ty_fn(ref a_f), &ty::ty_fn(ref b_f)) if a_f.meta.proto == ast::ProtoBare => { let b1_f = ty::FnTyBase { meta: ty::FnMeta {proto: ast::ProtoBare, @@ -229,49 +224,50 @@ priv impl Assign { // Eventually we will need to add some sort of // adjustment here so that trans can add an // extra NULL env pointer: - to_ares(Sub(*self).fns(a_f, &b1_f)) + to_ares(Sub(**self).fns(a_f, &b1_f)) } - // check for &T being assigned to *T: - (ty::ty_rptr(_, ref a_t), ty::ty_ptr(ref b_t)) => { - to_ares(Sub(*self).mts(*a_t, *b_t)) + // check for &T being coerced to *T: + (&ty::ty_rptr(_, ref a_t), &ty::ty_ptr(ref b_t)) => { + to_ares(Sub(**self).mts(*a_t, *b_t)) } - // otherwise, assignment follows normal subtype rules: + // otherwise, coercement follows normal subtype rules: _ => { - to_ares(Sub(*self).tys(a, b)) + to_ares(Sub(**self).tys(a, b)) } } } _ => { // if insufficient bounds were available, just follow // normal subtype rules: - to_ares(Sub(*self).tys(a, b)) + to_ares(Sub(**self).tys(a, b)) } } } - /// Given an assignment from a type like `@a` to `&r_b/m nr_b`, + /// Given an coercement from a type like `@a` to `&r_b/m nr_b`, /// this function checks that `a <: nr_b`. In that case, the - /// assignment is permitted, so it constructs a fresh region - /// variable `r_a >= r_b` and returns a corresponding assignment + /// coercement is permitted, so it constructs a fresh region + /// variable `r_a >= r_b` and returns a corresponding coercement /// record. See the discussion at the top of this file for more /// details. - fn try_assign(autoderefs: uint, + fn try_coerce(&self, + autoderefs: uint, kind: ty::AutoRefKind, a: ty::t, nr_b: ty::t, m: ast::mutability, - r_b: ty::Region) -> ares { - - debug!("try_assign(a=%s, nr_b=%s, m=%?, r_b=%s)", + r_b: ty::Region) -> ares + { + debug!("try_coerce(a=%s, nr_b=%s, m=%?, r_b=%s)", a.inf_str(self.infcx), nr_b.inf_str(self.infcx), m, r_b.inf_str(self.infcx)); do indent { - let sub = Sub(*self); + let sub = Sub(**self); do sub.tys(a, nr_b).chain |_t| { let r_a = self.infcx.next_region_var_nb(self.span); do sub.contraregions(r_a, r_b).chain |_r| { diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index b702448fbf474..8ec7e68176a56 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -217,11 +217,11 @@ when possible but otherwise merge the variables" strategy. In other words, `GLB(A, B)` where `A` and `B` are variables will often result in `A` and `B` being merged and the result being `A`. -## Type assignment +## Type coercion We have a notion of assignability which differs somewhat from subtyping; in particular it may cause region borrowing to occur. See -the big comment later in this file on Type Assignment for specifics. +the big comment later in this file on Type Coercion for specifics. ### In conclusion @@ -254,7 +254,7 @@ use middle::ty::{ty_int, ty_uint, get, terr_fn, TyVar, IntVar, FloatVar}; use middle::ty::IntVarValue; use middle::ty; use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_sig}; -use middle::typeck::infer::assignment::Assign; +use middle::typeck::infer::coercion::Coerce; use middle::typeck::infer::combine::{CombineFields, eq_tys}; use middle::typeck::infer::glb::Glb; use middle::typeck::infer::lub::Lub; @@ -293,17 +293,15 @@ export new_infer_ctxt; export mk_subty, can_mk_subty; export mk_subr; export mk_eqty; -export mk_assignty, can_mk_assignty; +export mk_coercety, can_mk_coercety; export resolve_nested_tvar, resolve_rvar, resolve_ivar, resolve_all; export force_tvar, force_rvar, force_ivar, force_all; export resolve_and_force_all_but_regions, not_regions; export resolve_type, resolve_region; export resolve_borrowings; export cres, fres, fixup_err, fixup_err_to_str; -export assignment; export root, to_str; export int_ty_set_all; -export assignment; export combine; export glb; export integral; @@ -312,6 +310,7 @@ export lub; export region_inference; export resolve; export sub; +export coercion; export to_str; export unify; export uok; @@ -323,8 +322,7 @@ export infer_ctxt; export fixup_err; export IntVarValue, IntType, UintType; -#[legacy_exports] -mod assignment; +mod coercion; #[legacy_exports] mod combine; #[legacy_exports] @@ -458,22 +456,22 @@ fn mk_eqty(cx: @InferCtxt, a_is_expected: bool, span: span, }.to_ures() } -fn mk_assignty(cx: @InferCtxt, a_is_expected: bool, span: span, +fn mk_coercety(cx: @InferCtxt, a_is_expected: bool, span: span, a: ty::t, b: ty::t) -> ares { - debug!("mk_assignty(%s -> %s)", a.inf_str(cx), b.inf_str(cx)); + debug!("mk_coercety(%s -> %s)", a.inf_str(cx), b.inf_str(cx)); do indent { do cx.commit { - Assign(cx.combine_fields(a_is_expected, span)).tys(a, b) + Coerce(cx.combine_fields(a_is_expected, span)).tys(a, b) } } } -fn can_mk_assignty(cx: @InferCtxt, a: ty::t, b: ty::t) -> ures { - debug!("can_mk_assignty(%s -> %s)", a.inf_str(cx), b.inf_str(cx)); +fn can_mk_coercety(cx: @InferCtxt, a: ty::t, b: ty::t) -> ures { + debug!("can_mk_coercety(%s -> %s)", a.inf_str(cx), b.inf_str(cx)); do indent { do cx.probe { let span = ast_util::dummy_sp(); - Assign(cx.combine_fields(true, span)).tys(a, b) + Coerce(cx.combine_fields(true, span)).tys(a, b) } }.to_ures() } From 2b67d88809d9f6ddc4686ee514cb78200db1d737 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 22 Jan 2013 17:20:08 -0800 Subject: [PATCH 22/31] Rewrite the coercion code to be more readable, more sound, and to reborrow when needed. Regarding soundness: there was a subtle bug in how it was done before; see the compile-fail test for an example. Regarding reborrowing: reborrowing allows mut and const slices/borrowed-pointers to be used with pure fns that expect immutable data. r=brson --- src/librustc/middle/typeck/check/_match.rs | 8 +- src/librustc/middle/typeck/check/demand.rs | 5 +- src/librustc/middle/typeck/check/method.rs | 76 ++- src/librustc/middle/typeck/check/mod.rs | 84 ++- src/librustc/middle/typeck/check/writeback.rs | 5 +- src/librustc/middle/typeck/infer/coercion.rs | 555 +++++++++++------- src/librustc/middle/typeck/infer/mod.rs | 9 +- src/librustc/middle/typeck/infer/resolve.rs | 1 + .../borrowck-borrowed-uniq-rvalue.rs | 6 +- src/test/compile-fail/coerce-bad-variance.rs | 17 + src/test/compile-fail/issue-4500.rs | 3 +- .../kindck-owned-trait-contains.rs | 11 +- src/test/compile-fail/regions-scoping.rs | 3 +- .../run-pass/coerce-reborrow-imm-ptr-arg.rs | 17 + .../run-pass/coerce-reborrow-imm-ptr-rcvr.rs | 16 + .../run-pass/coerce-reborrow-imm-vec-arg.rs | 19 + .../run-pass/coerce-reborrow-imm-vec-rcvr.rs | 18 + .../run-pass/coerce-reborrow-mut-ptr-arg.rs | 22 + .../run-pass/coerce-reborrow-mut-ptr-rcvr.rs | 24 + .../run-pass/coerce-reborrow-mut-vec-arg.rs | 15 + .../run-pass/coerce-reborrow-mut-vec-rcvr.rs | 21 + src/test/run-pass/issue-3026.rs | 2 +- src/test/run-pass/let-assignability.rs | 8 - 23 files changed, 643 insertions(+), 302 deletions(-) create mode 100644 src/test/compile-fail/coerce-bad-variance.rs create mode 100644 src/test/run-pass/coerce-reborrow-imm-ptr-arg.rs create mode 100644 src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs create mode 100644 src/test/run-pass/coerce-reborrow-imm-vec-arg.rs create mode 100644 src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs create mode 100644 src/test/run-pass/coerce-reborrow-mut-ptr-arg.rs create mode 100644 src/test/run-pass/coerce-reborrow-mut-ptr-rcvr.rs create mode 100644 src/test/run-pass/coerce-reborrow-mut-vec-arg.rs create mode 100644 src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 2e82d531e1559..ebfce27a4c8bb 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -15,7 +15,7 @@ use middle::pat_util::{pat_is_variant_or_struct}; use middle::ty; use middle::typeck::check::demand; use middle::typeck::check::{check_block, check_expr_has_type, fn_ctxt}; -use middle::typeck::check::{instantiate_path, lookup_def, lookup_local}; +use middle::typeck::check::{instantiate_path, lookup_def}; use middle::typeck::check::{structure_of, valid_range_bounds}; use middle::typeck::require_same_types; @@ -365,8 +365,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { fcx.write_ty(pat.id, const_tpt.ty); } ast::pat_ident(bm, name, sub) if pat_is_binding(tcx.def_map, pat) => { - let vid = lookup_local(fcx, pat.span, pat.id); - let mut typ = ty::mk_var(tcx, vid); + let typ = fcx.local_ty(pat.span, pat.id); match bm { ast::bind_by_ref(mutbl) => { @@ -389,8 +388,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { let canon_id = pcx.map.get(ast_util::path_to_ident(name)); if canon_id != pat.id { - let tv_id = lookup_local(fcx, pat.span, canon_id); - let ct = ty::mk_var(tcx, tv_id); + let ct = fcx.local_ty(pat.span, canon_id); demand::eqtype(fcx, pat.span, ct, typ); } fcx.write_ty(pat.id, typ); diff --git a/src/librustc/middle/typeck/check/demand.rs b/src/librustc/middle/typeck/check/demand.rs index c8aaf2ca61b49..c8a644fef101c 100644 --- a/src/librustc/middle/typeck/check/demand.rs +++ b/src/librustc/middle/typeck/check/demand.rs @@ -50,7 +50,10 @@ fn eqtype(fcx: @fn_ctxt, sp: span, expected: ty::t, actual: ty::t) { } // Checks that the type `actual` can be coerced to `expected`. -fn coerce(fcx: @fn_ctxt, sp: span, expected: ty::t, expr: @ast::expr) { +fn coerce(fcx: @fn_ctxt, + sp: span, + expected: ty::t, + expr: @ast::expr) { let expr_ty = fcx.expr_ty(expr); match fcx.mk_assignty(expr, expr_ty, expected) { result::Ok(()) => { /* ok */ } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 7ef6ae598803e..238e4e8c3f772 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -700,6 +700,8 @@ impl LookupContext { autoderefs: uint) -> Option { + let (self_ty, autoadjust) = + self.consider_reborrow(self_ty, autoderefs); match self.search_for_method(self_ty) { None => None, Some(move mme) => { @@ -707,13 +709,82 @@ impl LookupContext { adjustment (%u) to %d", autoderefs, self.self_expr.id); - self.fcx.write_autoderef_adjustment( - self.self_expr.id, autoderefs); + self.fcx.write_adjustment(self.self_expr.id, @autoadjust); Some(mme) } } } + fn consider_reborrow(&self, + self_ty: ty::t, + autoderefs: uint) -> (ty::t, ty::AutoAdjustment) + { + /*! + * + * In the event that we are invoking a method with a receiver + * of a linear borrowed type like `&mut T` or `&[mut T]`, + * we will "reborrow" the receiver implicitly. For example, if + * you have a call `r.inc()` and where `r` has type `&mut T`, + * then we treat that like `(&mut *r).inc()`. This avoids + * consuming the original pointer. + * + * You might think that this would be a natural byproduct of + * the auto-deref/auto-ref process. This is true for `@mut T` + * but not for an `&mut T` receiver. With `@mut T`, we would + * begin by testing for methods with a self type `@mut T`, + * then autoderef to `T`, then autoref to `&mut T`. But with + * an `&mut T` receiver the process begins with `&mut T`, only + * without any autoadjustments. + */ + + let tcx = self.tcx(); + return match ty::get(self_ty).sty { + ty::ty_rptr(self_r, self_mt) if self_mt.mutbl == m_mutbl => { + let region = fresh_region(self, self_r); + (ty::mk_rptr(tcx, region, self_mt), + ty::AutoAdjustment { + autoderefs: autoderefs+1, + autoref: Some(ty::AutoRef {kind: AutoPtr, + region: region, + mutbl: self_mt.mutbl})}) + } + ty::ty_evec(self_mt, vstore_slice(self_r)) + if self_mt.mutbl == m_mutbl => { + let region = fresh_region(self, self_r); + (ty::mk_evec(tcx, self_mt, vstore_slice(region)), + ty::AutoAdjustment { + autoderefs: autoderefs, + autoref: Some(ty::AutoRef {kind: AutoBorrowVec, + region: region, + mutbl: self_mt.mutbl})}) + } + _ => { + (self_ty, ty::AutoAdjustment {autoderefs: autoderefs, + autoref: None}) + } + }; + + fn fresh_region(self: &LookupContext, + self_r: ty::Region) -> ty::Region { + let region = self.infcx().next_region_var(self.expr.span, + self.expr.id); + + // FIXME(#3148)---in principle this dependency should + // be done more generally as part of regionck + match infer::mk_subr(self.infcx(), true, self.expr.span, + region, self_r) { + Ok(_) => {} + Err(e) => { + self.tcx().sess.span_bug( + self.expr.span, + fmt!("Failed with error: %?", e)); + } + } + + return region; + } + } + fn search_for_autosliced_method( &self, self_ty: ty::t, @@ -729,6 +800,7 @@ impl LookupContext { match ty::get(self_ty).sty { ty_evec(mt, vstore_box) | ty_evec(mt, vstore_uniq) | + ty_evec(mt, vstore_slice(_)) | // NDM(#3148) ty_evec(mt, vstore_fixed(_)) => { // First try to borrow to a slice let entry = self.search_for_some_kind_of_autorefd_method( diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 2d823ff02dd91..cf13fcb86e818 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -139,7 +139,6 @@ export regionck; export demand; export method; export fn_ctxt; -export lookup_local; export impl_self_ty; export DerefArgs; export DontDerefArgs; @@ -189,7 +188,7 @@ type self_info = { /// share the inherited fields. struct inherited { infcx: @infer::InferCtxt, - locals: HashMap, + locals: HashMap, node_types: HashMap, node_type_substs: HashMap, adjustments: HashMap @@ -376,8 +375,7 @@ fn check_fn(ccx: @crate_ctxt, } }; - // XXX: Bad copy. - gather_locals(fcx, decl, body, copy arg_tys, self_info); + gather_locals(fcx, decl, body, arg_tys, self_info); check_block(fcx, body); // We unify the tail expr's type with the @@ -414,30 +412,31 @@ fn check_fn(ccx: @crate_ctxt, fn gather_locals(fcx: @fn_ctxt, decl: &ast::fn_decl, body: ast::blk, - arg_tys: ~[ty::t], + arg_tys: &[ty::t], self_info: Option) { let tcx = fcx.ccx.tcx; - let assign = fn@(span: span, nid: ast::node_id, - ty_opt: Option) { - let var_id = fcx.infcx().next_ty_var_id(); - fcx.inh.locals.insert(nid, var_id); + let assign = fn@(nid: ast::node_id, ty_opt: Option) { match ty_opt { - None => {/* nothing to do */ } + None => { + // infer the variable's type + let var_id = fcx.infcx().next_ty_var_id(); + let var_ty = ty::mk_var(fcx.tcx(), var_id); + fcx.inh.locals.insert(nid, var_ty); + } Some(typ) => { - infer::mk_eqty(fcx.infcx(), false, span, - ty::mk_var(tcx, var_id), typ); + // take type that the user specified + fcx.inh.locals.insert(nid, typ); } } }; // Add the self parameter for self_info.each |self_info| { - assign(self_info.explicit_self.span, - self_info.self_id, - Some(self_info.self_ty)); + assign(self_info.self_id, Some(self_info.self_ty)); debug!("self is assigned to %s", - fcx.inh.locals.get(self_info.self_id).to_str()); + fcx.infcx().ty_to_str( + fcx.inh.locals.get(self_info.self_id))); } // Add formal parameters. @@ -445,7 +444,7 @@ fn check_fn(ccx: @crate_ctxt, // Create type variables for each argument. do pat_util::pat_bindings(tcx.def_map, input.pat) |_bm, pat_id, _sp, _path| { - assign(input.ty.span, pat_id, None); + assign(pat_id, None); } // Check the pattern. @@ -466,10 +465,11 @@ fn check_fn(ccx: @crate_ctxt, ast::ty_infer => None, _ => Some(fcx.to_ty(local.node.ty)) }; - assign(local.span, local.node.id, o_ty); - debug!("Local variable %s is assigned to %s", + assign(local.node.id, o_ty); + debug!("Local variable %s is assigned type %s", fcx.pat_to_str(local.node.pat), - fcx.inh.locals.get(local.node.id).to_str()); + fcx.infcx().ty_to_str( + fcx.inh.locals.get(local.node.id))); visit::visit_local(local, e, v); }; @@ -478,10 +478,11 @@ fn check_fn(ccx: @crate_ctxt, match p.node { ast::pat_ident(_, path, _) if pat_util::pat_is_binding(fcx.ccx.tcx.def_map, p) => { - assign(p.span, p.id, None); + assign(p.id, None); debug!("Pattern binding %s is assigned to %s", tcx.sess.str_of(path.idents[0]), - fcx.inh.locals.get(p.id).to_str()); + fcx.infcx().ty_to_str( + fcx.inh.locals.get(p.id))); } _ => {} } @@ -694,6 +695,17 @@ impl @fn_ctxt: region_scope { impl @fn_ctxt { fn tag() -> ~str { fmt!("%x", ptr::addr_of(&(*self)) as uint) } + fn local_ty(span: span, nid: ast::node_id) -> ty::t { + match self.inh.locals.find(nid) { + Some(t) => t, + None => { + self.tcx().sess.span_bug( + span, + fmt!("No type for local variable %?", nid)); + } + } + } + fn expr_to_str(expr: @ast::expr) -> ~str { fmt!("expr(%?:%s)", expr.id, pprust::expr_to_str(expr, self.tcx().sess.intr())) @@ -1359,10 +1371,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, fn check_for(fcx: @fn_ctxt, local: @ast::local, element_ty: ty::t, body: ast::blk, node_id: ast::node_id) -> bool { - let locid = lookup_local(fcx, local.span, local.node.id); - demand::suptype(fcx, local.span, - ty::mk_var(fcx.ccx.tcx, locid), - element_ty); + let local_ty = fcx.local_ty(local.span, local.node.id); + demand::suptype(fcx, local.span, local_ty, element_ty); let bot = check_decl_local(fcx, local); check_block_no_value(fcx, body); fcx.write_nil(node_id); @@ -2551,15 +2561,15 @@ fn require_integral(fcx: @fn_ctxt, sp: span, t: ty::t) { fn check_decl_initializer(fcx: @fn_ctxt, nid: ast::node_id, init: @ast::expr) -> bool { - let lty = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, init.span, nid)); - return check_expr_coercable_to_type(fcx, init, lty); + let local_ty = fcx.local_ty(init.span, nid); + return check_expr_coercable_to_type(fcx, init, local_ty); } fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool { let mut bot = false; let tcx = fcx.ccx.tcx; - let t = ty::mk_var(tcx, fcx.inh.locals.get(local.node.id)); + let t = fcx.local_ty(local.span, local.node.id); fcx.write_ty(local.node.id, t); match local.node.init { @@ -2819,17 +2829,6 @@ fn check_enum_variants(ccx: @crate_ctxt, check_instantiable(ccx.tcx, sp, id); } -pub fn lookup_local(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> TyVid { - match fcx.inh.locals.find(id) { - Some(x) => x, - _ => { - fcx.ccx.tcx.sess.span_fatal( - sp, - ~"internal error looking up a local var") - } - } -} - fn lookup_def(fcx: @fn_ctxt, sp: span, id: ast::node_id) -> ast::def { lookup_def_ccx(fcx.ccx, sp, id) } @@ -2841,9 +2840,8 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> match defn { ast::def_arg(nid, _, _) | ast::def_local(nid, _) | ast::def_self(nid, _) | ast::def_binding(nid, _) => { - assert (fcx.inh.locals.contains_key(nid)); - let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid)); - return no_params(typ); + let typ = fcx.local_ty(sp, nid); + return no_params(typ); } ast::def_fn(_, ast::extern_fn) => { // extern functions are just u8 pointers diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 1a665aa756611..e5dc91b7f179a 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -16,7 +16,7 @@ use core::prelude::*; use middle::pat_util; use middle::ty; -use middle::typeck::check::{fn_ctxt, lookup_local, self_info}; +use middle::typeck::check::{fn_ctxt, self_info}; use middle::typeck::infer::{force_all, resolve_all, resolve_region}; use middle::typeck::infer::{resolve_type}; use middle::typeck::infer; @@ -216,8 +216,7 @@ fn visit_pat(p: @ast::pat, wbcx: wb_ctxt, v: wb_vt) { } fn visit_local(l: @ast::local, wbcx: wb_ctxt, v: wb_vt) { if !wbcx.success { return; } - let var_id = lookup_local(wbcx.fcx, l.span, l.node.id); - let var_ty = ty::mk_var(wbcx.fcx.tcx(), var_id); + let var_ty = wbcx.fcx.local_ty(l.span, l.node.id); match resolve_type(wbcx.fcx.infcx(), var_ty, resolve_all | force_all) { Ok(lty) => { debug!("Type for local %s (id %d) resolved to %s", diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 84fe51b65ec51..9c319bdc733ae 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -8,280 +8,389 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ______________________________________________________________________ -// Type assignment -// -// True if rvalues of type `a` can be assigned to lvalues of type `b`. -// This may cause borrowing to the region scope enclosing `a_node_id`. -// -// The strategy here is somewhat non-obvious. The problem is -// that the constraint we wish to contend with is not a subtyping -// constraint. Currently, for variables, we only track what it -// must be a subtype of, not what types it must be assignable to -// (or from). Possibly, we should track that, but I leave that -// refactoring for another day. -// -// Instead, we look at each variable involved and try to extract -// *some* sort of bound. Typically, the type a is the argument -// supplied to a call; it typically has a *lower bound* (which -// comes from having been assigned a value). What we'd actually -// *like* here is an upper-bound, but we generally don't have -// one. The type b is the expected type and it typically has a -// lower-bound too, which is good. -// -// The way we deal with the fact that we often don't have the -// bounds we need is to be a bit careful. We try to get *some* -// bound from each side, preferring the upper from a and the -// lower from b. If we fail to get a bound from both sides, then -// we just fall back to requiring that a <: b. -// -// Assuming we have a bound from both sides, we will then examine -// these bounds and see if they have the form (@M_a T_a, &rb.M_b T_b) -// (resp. ~M_a T_a, ~[M_a T_a], etc). If they do not, we fall back to -// subtyping. -// -// If they *do*, then we know that the two types could never be -// subtypes of one another. We will then construct a type @const T_b -// and ensure that type a is a subtype of that. This allows for the -// possibility of assigning from a type like (say) @~[mut T1] to a type -// &~[T2] where T1 <: T2. This might seem surprising, since the `@` -// points at mutable memory but the `&` points at immutable memory. -// This would in fact be unsound, except for the borrowck, which comes -// later and guarantees that such mutability conversions are safe. -// See borrowck for more details. Next we require that the region for -// the enclosing scope be a superregion of the region r. -// -// You might wonder why we don't make the type &e.const T_a where e is -// the enclosing region and check that &e.const T_a <: B. The reason -// is that the type of A is (generally) just a *lower-bound*, so this -// would be imposing that lower-bound also as the upper-bound on type -// A. But this upper-bound might be stricter than what is truly -// needed. +/*! + +# Type Coercion + +Under certain circumstances we will coerce from one type to another, +for example by auto-borrowing. This occurs in situations where the +compiler has a firm 'expected type' that was supplied from the user, +and where the actual type is similar to that expected type in purpose +but not in representation (so actual subtyping is inappropriate). + +## Reborrowing + +Note that if we are expecting a borrowed pointer, we will *reborrow* +even if the argument provided was already a borrowed pointer. This is +useful for freezing mut/const things (that is, when the expected is &T +but you have &const T or &mut T) and also for avoiding the linearity +of mut things (when the expected is &mut T and you have &mut T). See +the various `src/test/run-pass/coerce-reborrow-*.rs` tests for +examples of where this is useful. + +## Subtle note + +When deciding what type coercions to consider, we do not attempt to +resolve any type variables we may encounter. This is because `b` +represents the expected type "as the user wrote it", meaning that if +the user defined a generic function like + + fn foo(a: A, b: A) { ... } + +and then we wrote `foo(&1, @2)`, we will not auto-borrow +either argument. In older code we went to some lengths to +resolve the `b` variable, which could mean that we'd +auto-borrow later arguments but not earlier ones, which +seems very confusing. + +## Subtler note + +However, right now, if the user manually specifies the +values for the type variables, as so: + + foo::<&int>(@1, @2) + +then we *will* auto-borrow, because we can't distinguish this from a +function that declared `&int`. This is inconsistent but it's easiest +at the moment. The right thing to do, I think, is to consider the +*unsubstituted* type when deciding whether to auto-borrow, but the +*substituted* type when considering the bounds and so forth. But most +of our methods don't give access to the unsubstituted type, and +rightly so because they'd be error-prone. So maybe the thing to do is +to actually determine the kind of coercions that should occur +separately and pass them in. Or maybe it's ok as is. Anyway, it's +sort of a minor point so I've opted to leave it for later---after all +we may want to adjust precisely when coercions occur. + +*/ use core::prelude::*; -use middle::ty::TyVar; +use middle::ty::{TyVar, AutoPtr, AutoBorrowVec, AutoBorrowFn}; +use middle::ty::{AutoAdjustment, AutoRef}; +use middle::ty::{vstore_slice, vstore_box, vstore_uniq, vstore_fixed}; +use middle::ty::{FnMeta, FnTyBase, mt}; use middle::ty; -use middle::typeck::infer::{ares, cres}; +use middle::typeck::infer::{CoerceResult, resolve_type}; use middle::typeck::infer::combine::CombineFields; use middle::typeck::infer::sub::Sub; use middle::typeck::infer::to_str::InferStr; +use middle::typeck::infer::resolve::try_resolve_tvar_shallow; use util::common::{indent, indenter}; use core::option; use syntax::ast::{m_const, m_imm, m_mutbl}; use syntax::ast; -fn to_ares(+c: cres) -> ares { - match c { - Ok(_) => Ok(None), - Err(ref e) => Err((*e)) - } -} - // Note: Coerce is not actually a combiner, in that it does not // conform to the same interface, though it performs a similar // function. pub enum Coerce = CombineFields; impl Coerce { - fn tys(&self, a: ty::t, b: ty::t) -> ares { + fn tys(&self, a: ty::t, b: ty::t) -> CoerceResult { debug!("Coerce.tys(%s => %s)", a.inf_str(self.infcx), b.inf_str(self.infcx)); let _indent = indenter(); - let r = match (&ty::get(a).sty, &ty::get(b).sty) { - (&ty::ty_bot, _) => { - Ok(None) + + // Examine the supertype and consider auto-borrowing. + // + // Note: does not attempt to resolve type variables we encounter. + // See above for details. + match ty::get(b).sty { + ty::ty_rptr(_, mt_b) => { + return do self.unpack_actual_value(a) |sty_a| { + self.coerce_borrowed_pointer(a, sty_a, b, mt_b) + }; } - (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => { - let nde_a = self.infcx.get(a_id); - let nde_b = self.infcx.get(b_id); - let a_bounds = nde_a.possible_types; - let b_bounds = nde_b.possible_types; + ty::ty_estr(vstore_slice(_)) => { + return do self.unpack_actual_value(a) |sty_a| { + self.coerce_borrowed_string(a, sty_a, b) + }; + } - let a_bnd = option::or(a_bounds.ub, a_bounds.lb); - let b_bnd = option::or(b_bounds.lb, b_bounds.ub); - self.coerce_tys_or_sub(a, b, a_bnd, b_bnd) + ty::ty_evec(mt_b, vstore_slice(_)) => { + return do self.unpack_actual_value(a) |sty_a| { + self.coerce_borrowed_vector(a, sty_a, b, mt_b) + }; } - (&ty::ty_infer(TyVar(a_id)), _) => { - let nde_a = self.infcx.get(a_id); - let a_bounds = nde_a.possible_types; + ty::ty_fn(ref b_f) if b_f.meta.proto == ast::ProtoBorrowed => { + return do self.unpack_actual_value(a) |sty_a| { + self.coerce_borrowed_fn(a, sty_a, b) + }; + } - let a_bnd = option::or(a_bounds.ub, a_bounds.lb); - self.coerce_tys_or_sub(a, b, a_bnd, Some(b)) + ty::ty_ptr(_) => { + return do self.unpack_actual_value(a) |sty_a| { + self.coerce_unsafe_ptr(a, sty_a, b) + }; } - (_, &ty::ty_infer(TyVar(b_id))) => { - let nde_b = self.infcx.get(b_id); - let b_bounds = nde_b.possible_types; + _ => {} + } - let b_bnd = option::or(b_bounds.lb, b_bounds.ub); - self.coerce_tys_or_sub(a, b, Some(a), b_bnd) + do self.unpack_actual_value(a) |sty_a| { + match *sty_a { + ty::ty_fn(ref a_f) if a_f.meta.proto == ast::ProtoBare => { + // Bare functions are coercable to any closure type. + // + // FIXME(#3320) this should go away and be + // replaced with proper inference, got a patch + // underway - ndm + self.coerce_from_bare_fn(a, a_f, b) + } + _ => { + // Otherwise, just use subtyping rules. + self.subtype(a, b) + } } + } + } + + fn subtype(&self, a: ty::t, b: ty::t) -> CoerceResult { + match Sub(**self).tys(a, b) { + Ok(_) => Ok(None), // No coercion required. + Err(ref e) => Err(*e) + } + } - (_, _) => { - self.coerce_tys_or_sub(a, b, Some(a), Some(b)) + fn unpack_actual_value(&self, + a: ty::t, + f: &fn(&ty::sty) -> CoerceResult) -> CoerceResult + { + match resolve_type(self.infcx, a, try_resolve_tvar_shallow) { + Ok(t) => { + f(&ty::get(t).sty) } - }; + Err(e) => { + self.infcx.tcx.sess.span_bug( + self.span, + fmt!("Failed to resolve even without \ + any force options: %?", e)); + } + } + } + + fn coerce_borrowed_pointer(&self, + a: ty::t, + sty_a: &ty::sty, + b: ty::t, + mt_b: ty::mt) -> CoerceResult + { + debug!("coerce_borrowed_pointer(a=%s, sty_a=%?, b=%s, mt_b=%?)", + a.inf_str(self.infcx), sty_a, + b.inf_str(self.infcx), mt_b); - debug!("Coerce.tys end"); + // If we have a parameter of type `&M T_a` and the value + // provided is `expr`, we will be adding an implicit borrow, + // meaning that we convert `f(expr)` to `f(&M *expr)`. Therefore, + // to type check, we will construct the type that `&M*expr` would + // yield. + + let sub = Sub(**self); + let r_borrow = self.infcx.next_region_var_nb(self.span); + + let inner_ty = match *sty_a { + ty::ty_box(mt_a) => mt_a.ty, + ty::ty_uniq(mt_a) => mt_a.ty, + ty::ty_rptr(r_a, mt_a) => { + // Ensure that the pointer we are borrowing from lives + // at least as long as the borrowed result. + // + // FIXME(#3148)---in principle this dependency should + // be done more generally + if_ok!(sub.contraregions(r_a, r_borrow)); + mt_a.ty + } + _ => { + return self.subtype(a, b); + } + }; - move r + let a_borrowed = ty::mk_rptr(self.infcx.tcx, + r_borrow, + mt {ty: inner_ty, mutbl: mt_b.mutbl}); + if_ok!(sub.tys(a_borrowed, b)); + Ok(Some(@AutoAdjustment { + autoderefs: 1, + autoref: Some(AutoRef { + kind: AutoPtr, + region: r_borrow, + mutbl: mt_b.mutbl + }) + })) } -} -impl Coerce { - fn coerce_tys_or_sub( - &self, - +a: ty::t, - +b: ty::t, - +a_bnd: Option, - +b_bnd: Option) -> ares + fn coerce_borrowed_string(&self, + a: ty::t, + sty_a: &ty::sty, + b: ty::t) -> CoerceResult { - debug!("Coerce.coerce_tys_or_sub(%s => %s, %s => %s)", - a.inf_str(self.infcx), b.inf_str(self.infcx), - a_bnd.inf_str(self.infcx), b_bnd.inf_str(self.infcx)); - let _r = indenter(); - - fn is_borrowable(v: ty::vstore) -> bool { - match v { - ty::vstore_fixed(_) | ty::vstore_uniq | ty::vstore_box => true, - ty::vstore_slice(_) => false + debug!("coerce_borrowed_string(a=%s, sty_a=%?, b=%s)", + a.inf_str(self.infcx), sty_a, + b.inf_str(self.infcx)); + + match *sty_a { + ty::ty_estr(vstore_box) | + ty::ty_estr(vstore_uniq) => {} + _ => { + return self.subtype(a, b); } - } + }; + + let r_a = self.infcx.next_region_var_nb(self.span); + let a_borrowed = ty::mk_estr(self.infcx.tcx, vstore_slice(r_a)); + if_ok!(self.subtype(a_borrowed, b)); + Ok(Some(@AutoAdjustment { + autoderefs: 0, + autoref: Some(AutoRef { + kind: AutoBorrowVec, + region: r_a, + mutbl: m_imm + }) + })) + } - fn borrowable_protos(a_p: ast::Proto, b_p: ast::Proto) -> bool { - match (a_p, b_p) { - (ast::ProtoBox, ast::ProtoBorrowed) => true, - (ast::ProtoUniq, ast::ProtoBorrowed) => true, - _ => false + fn coerce_borrowed_vector(&self, + a: ty::t, + sty_a: &ty::sty, + b: ty::t, + mt_b: ty::mt) -> CoerceResult + { + debug!("coerce_borrowed_vector(a=%s, sty_a=%?, b=%s)", + a.inf_str(self.infcx), sty_a, + b.inf_str(self.infcx)); + + let sub = Sub(**self); + let r_borrow = self.infcx.next_region_var_nb(self.span); + let ty_inner = match *sty_a { + ty::ty_evec(mt, vstore_box) => mt.ty, + ty::ty_evec(mt, vstore_uniq) => mt.ty, + ty::ty_evec(mt, vstore_fixed(_)) => mt.ty, + ty::ty_evec(mt, vstore_slice(r_a)) => { + // Ensure that the pointer we are borrowing from lives + // at least as long as the borrowed result. + // + // FIXME(#3148)---in principle this dependency should + // be done more generally + if_ok!(sub.contraregions(r_a, r_borrow)); + mt.ty } - } + _ => { + return self.subtype(a, b); + } + }; - match (a_bnd, b_bnd) { - (Some(a_bnd), Some(b_bnd)) => { - match (&ty::get(a_bnd).sty, &ty::get(b_bnd).sty) { - // check for a case where a non-region pointer (@, ~) is - // being coerceed to a region pointer: - (&ty::ty_box(_), &ty::ty_rptr(r_b, mt_b)) => { - let nr_b = ty::mk_box(self.infcx.tcx, - ty::mt {ty: mt_b.ty, - mutbl: m_const}); - self.try_coerce(1, ty::AutoPtr, - a, nr_b, - mt_b.mutbl, r_b) - } - (&ty::ty_uniq(_), &ty::ty_rptr(r_b, mt_b)) => { - let nr_b = ty::mk_uniq(self.infcx.tcx, - ty::mt {ty: mt_b.ty, - mutbl: m_const}); - self.try_coerce(1, ty::AutoPtr, - a, nr_b, - mt_b.mutbl, r_b) - } - (&ty::ty_estr(vs_a), - &ty::ty_estr(ty::vstore_slice(r_b))) - if is_borrowable(vs_a) => { - let nr_b = ty::mk_estr(self.infcx.tcx, vs_a); - self.try_coerce(0, ty::AutoBorrowVec, - a, nr_b, - m_imm, r_b) - } - - (&ty::ty_evec(_, vs_a), - &ty::ty_evec(mt_b, ty::vstore_slice(r_b))) - if is_borrowable(vs_a) => { - let nr_b = ty::mk_evec(self.infcx.tcx, - ty::mt {ty: mt_b.ty, - mutbl: m_const}, - vs_a); - self.try_coerce(0, ty::AutoBorrowVec, - a, nr_b, - mt_b.mutbl, r_b) - } - - (&ty::ty_fn(ref a_f), &ty::ty_fn(ref b_f)) - if borrowable_protos(a_f.meta.proto, b_f.meta.proto) => { - let nr_b = ty::mk_fn(self.infcx.tcx, ty::FnTyBase { - meta: ty::FnMeta {proto: a_f.meta.proto, - ..b_f.meta}, - sig: copy b_f.sig - }); - self.try_coerce(0, ty::AutoBorrowFn, - a, nr_b, m_imm, b_f.meta.region) - } - - (&ty::ty_fn(ref a_f), &ty::ty_fn(ref b_f)) - if a_f.meta.proto == ast::ProtoBare => { - let b1_f = ty::FnTyBase { - meta: ty::FnMeta {proto: ast::ProtoBare, - ..b_f.meta}, - sig: copy b_f.sig - }; - // Eventually we will need to add some sort of - // adjustment here so that trans can add an - // extra NULL env pointer: - to_ares(Sub(**self).fns(a_f, &b1_f)) - } - - // check for &T being coerced to *T: - (&ty::ty_rptr(_, ref a_t), &ty::ty_ptr(ref b_t)) => { - to_ares(Sub(**self).mts(*a_t, *b_t)) - } - - // otherwise, coercement follows normal subtype rules: - _ => { - to_ares(Sub(**self).tys(a, b)) - } - } + let a_borrowed = ty::mk_evec(self.infcx.tcx, + mt {ty: ty_inner, mutbl: mt_b.mutbl}, + vstore_slice(r_borrow)); + if_ok!(sub.tys(a_borrowed, b)); + Ok(Some(@AutoAdjustment { + autoderefs: 0, + autoref: Some(AutoRef { + kind: AutoBorrowVec, + region: r_borrow, + mutbl: mt_b.mutbl + }) + })) + } + + fn coerce_borrowed_fn(&self, + a: ty::t, + sty_a: &ty::sty, + b: ty::t) -> CoerceResult + { + debug!("coerce_borrowed_fn(a=%s, sty_a=%?, b=%s)", + a.inf_str(self.infcx), sty_a, + b.inf_str(self.infcx)); + + let fn_ty = match *sty_a { + ty::ty_fn(ref f) if f.meta.proto == ast::ProtoBox => {f} + ty::ty_fn(ref f) if f.meta.proto == ast::ProtoUniq => {f} + ty::ty_fn(ref f) if f.meta.proto == ast::ProtoBare => { + return self.coerce_from_bare_fn(a, f, b); } _ => { - // if insufficient bounds were available, just follow - // normal subtype rules: - to_ares(Sub(**self).tys(a, b)) + return self.subtype(a, b); } + }; + + let r_borrow = self.infcx.next_region_var_nb(self.span); + let meta = FnMeta {proto: ast::ProtoBorrowed, + region: r_borrow, + ..fn_ty.meta}; + let a_borrowed = ty::mk_fn(self.infcx.tcx, + FnTyBase {meta: meta, + sig: copy fn_ty.sig}); + + if_ok!(self.subtype(a_borrowed, b)); + Ok(Some(@AutoAdjustment { + autoderefs: 0, + autoref: Some(AutoRef { + kind: AutoBorrowFn, + region: r_borrow, + mutbl: m_imm + }) + })) + } + + fn coerce_from_bare_fn(&self, + a: ty::t, + fn_ty_a: &ty::FnTy, + b: ty::t) -> CoerceResult + { + do self.unpack_actual_value(b) |sty_b| { + self.coerce_from_bare_fn_post_unpack(a, fn_ty_a, b, sty_b) } } - /// Given an coercement from a type like `@a` to `&r_b/m nr_b`, - /// this function checks that `a <: nr_b`. In that case, the - /// coercement is permitted, so it constructs a fresh region - /// variable `r_a >= r_b` and returns a corresponding coercement - /// record. See the discussion at the top of this file for more - /// details. - fn try_coerce(&self, - autoderefs: uint, - kind: ty::AutoRefKind, - a: ty::t, - nr_b: ty::t, - m: ast::mutability, - r_b: ty::Region) -> ares + fn coerce_from_bare_fn_post_unpack(&self, + a: ty::t, + fn_ty_a: &ty::FnTy, + b: ty::t, + sty_b: &ty::sty) -> CoerceResult { - debug!("try_coerce(a=%s, nr_b=%s, m=%?, r_b=%s)", - a.inf_str(self.infcx), - nr_b.inf_str(self.infcx), - m, - r_b.inf_str(self.infcx)); - - do indent { - let sub = Sub(**self); - do sub.tys(a, nr_b).chain |_t| { - let r_a = self.infcx.next_region_var_nb(self.span); - do sub.contraregions(r_a, r_b).chain |_r| { - Ok(Some(@ty::AutoAdjustment { - autoderefs: autoderefs, - autoref: Some(ty::AutoRef { - kind: kind, - region: r_a, - mutbl: m - }) - })) - } + debug!("coerce_from_bare_fn(a=%s, b=%s)", + a.inf_str(self.infcx), b.inf_str(self.infcx)); + + let fn_ty_b = match *sty_b { + ty::ty_fn(ref f) if f.meta.proto != ast::ProtoBare => {f} + _ => { + return self.subtype(a, b); } - } + }; + + // for now, bare fn and closures have the same + // representation + let a_adapted = ty::mk_fn(self.infcx.tcx, + FnTyBase {meta: copy fn_ty_b.meta, + sig: copy fn_ty_a.sig}); + self.subtype(a_adapted, b) } -} + fn coerce_unsafe_ptr(&self, + a: ty::t, + sty_a: &ty::sty, + b: ty::t) -> CoerceResult + { + debug!("coerce_unsafe_ptr(a=%s, sty_a=%?, b=%s)", + a.inf_str(self.infcx), sty_a, + b.inf_str(self.infcx)); + + let mt_a = match *sty_a { + ty::ty_rptr(_, mt) => mt, + _ => { + return self.subtype(a, b); + } + }; + + // borrowed pointers and unsafe pointers have the same + // representation, so just check that the types which they + // point at are compatible: + let a_unsafe = ty::mk_ptr(self.infcx.tcx, mt_a); + self.subtype(a_unsafe, b) + } +} diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 8ec7e68176a56..cac5fa5feb1c1 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -317,12 +317,11 @@ export uok; export cyclic_ty, unresolved_ty, region_var_bound_by_region_var; export Bound, Bounds; export ures; -export ares; +export CoerceResult; export infer_ctxt; export fixup_err; export IntVarValue, IntType, UintType; -mod coercion; #[legacy_exports] mod combine; #[legacy_exports] @@ -341,6 +340,7 @@ mod sub; mod to_str; #[legacy_exports] mod unify; +mod coercion; type Bound = Option; type Bounds = {lb: Bound, ub: Bound}; @@ -348,7 +348,7 @@ type Bounds = {lb: Bound, ub: Bound}; type cres = Result; // "combine result" type ures = cres<()>; // "unify result" type fres = Result; // "fixup result" -type ares = cres>; // "assignment result" +type CoerceResult = cres>; struct InferCtxt { tcx: ty::ctxt, @@ -457,7 +457,8 @@ fn mk_eqty(cx: @InferCtxt, a_is_expected: bool, span: span, } fn mk_coercety(cx: @InferCtxt, a_is_expected: bool, span: span, - a: ty::t, b: ty::t) -> ares { + a: ty::t, b: ty::t) -> CoerceResult +{ debug!("mk_coercety(%s -> %s)", a.inf_str(cx), b.inf_str(cx)); do indent { do cx.commit { diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index 01f4b86b48858..b25c4db8a90b7 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -78,6 +78,7 @@ const force_all: uint = 0b1111100000; const not_regions: uint = !(force_rvar | resolve_rvar); +const try_resolve_tvar_shallow: uint = 0; const resolve_and_force_all_but_regions: uint = (resolve_all | force_all) & not_regions; diff --git a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs index 839d4137ba923..19cdfe784d2b0 100644 --- a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs +++ b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs @@ -16,9 +16,9 @@ use std::map; fn main() { let buggy_map :HashMap = HashMap::(); - buggy_map.insert(42, ~1); //~ ERROR illegal borrow - + buggy_map.insert(42, &*~1); //~ ERROR illegal borrow + // but it is ok if we use a temporary let tmp = ~2; - buggy_map.insert(43, tmp); + buggy_map.insert(43, &*tmp); } diff --git a/src/test/compile-fail/coerce-bad-variance.rs b/src/test/compile-fail/coerce-bad-variance.rs new file mode 100644 index 0000000000000..c4cdbcb67e2be --- /dev/null +++ b/src/test/compile-fail/coerce-bad-variance.rs @@ -0,0 +1,17 @@ +fn mutate(x: &mut @const int) { + *x = @3; +} + +fn give_away1(y: @mut @mut int) { + mutate(y); //~ ERROR values differ in mutability +} + +fn give_away2(y: @mut @const int) { + mutate(y); +} + +fn give_away3(y: @mut @int) { + mutate(y); //~ ERROR values differ in mutability +} + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/issue-4500.rs b/src/test/compile-fail/issue-4500.rs index 83938293d7548..356a64498219a 100644 --- a/src/test/compile-fail/issue-4500.rs +++ b/src/test/compile-fail/issue-4500.rs @@ -10,6 +10,5 @@ fn main () { let mut _p: & int = & 4; - _p = ~3; //~ ERROR illegal borrow: borrowed value does not live long enough - //~^ NOTE ...but borrowed value is only valid for the statement + _p = &*~3; //~ ERROR illegal borrow } diff --git a/src/test/compile-fail/kindck-owned-trait-contains.rs b/src/test/compile-fail/kindck-owned-trait-contains.rs index c7c6aec9f1df8..69f07e3e77492 100644 --- a/src/test/compile-fail/kindck-owned-trait-contains.rs +++ b/src/test/compile-fail/kindck-owned-trait-contains.rs @@ -20,11 +20,12 @@ fn repeater(v: @A) -> repeat { } fn main() { - // Here, an error results as the type of y is inferred to - // repeater<</3> where lt is the block. - let y = { - let x: &blk/int = &3; //~ ERROR cannot infer an appropriate lifetime + // Error results because the type of is inferred to be + // repeat<&blk/int> where blk is the lifetime of the block below. + + let y = { //~ ERROR reference is not valid + let x: &blk/int = &3; repeater(@x) }; - assert 3 == *(y.get()); + assert 3 == *(y.get()); //~ ERROR reference is not valid } \ No newline at end of file diff --git a/src/test/compile-fail/regions-scoping.rs b/src/test/compile-fail/regions-scoping.rs index 1f59e9a8128cc..f999242973345 100644 --- a/src/test/compile-fail/regions-scoping.rs +++ b/src/test/compile-fail/regions-scoping.rs @@ -25,8 +25,7 @@ fn nested(x: &x/int) { // (1) //~^ ERROR cannot infer an appropriate lifetime return z(y, x, x); - //~^ ERROR mismatched types: expected `&x/int` but found `&y/int` - //~^^ ERROR mismatched types: expected `&y/int` but found `&x/int` + //~^ ERROR cannot infer an appropriate lifetime } ) |foo| { diff --git a/src/test/run-pass/coerce-reborrow-imm-ptr-arg.rs b/src/test/run-pass/coerce-reborrow-imm-ptr-arg.rs new file mode 100644 index 0000000000000..3c9748f29d986 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-imm-ptr-arg.rs @@ -0,0 +1,17 @@ +pure fn negate(x: &int) -> int { + -*x +} + +fn negate_mut(y: &mut int) -> int { + negate(y) +} + +fn negate_imm(y: &int) -> int { + negate(y) +} + +fn negate_const(y: &const int) -> int { + negate(y) +} + +fn main() {} diff --git a/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs new file mode 100644 index 0000000000000..0d8f40677f8b8 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs @@ -0,0 +1,16 @@ +struct SpeechMaker { + speeches: uint +} + +impl SpeechMaker { + pure fn how_many(&self) -> uint { self.speeches } +} + +fn foo(speaker: &const SpeechMaker) -> uint { + speaker.how_many() + 33 +} + +fn main() { + let mut lincoln = SpeechMaker {speeches: 22}; + assert foo(&const lincoln) == 55; +} diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs b/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs new file mode 100644 index 0000000000000..54a6b35b8baa7 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-imm-vec-arg.rs @@ -0,0 +1,19 @@ +pure fn sum(x: &[int]) -> int { + let mut sum = 0; + for x.each |y| { sum += *y; } + return sum; +} + +fn sum_mut(y: &[mut int]) -> int { + sum(y) +} + +fn sum_imm(y: &[int]) -> int { + sum(y) +} + +fn sum_const(y: &[const int]) -> int { + sum(y) +} + +fn main() {} \ No newline at end of file diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs new file mode 100644 index 0000000000000..24fb5cbd88301 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs @@ -0,0 +1,18 @@ +fn foo(v: &[const uint]) -> ~[uint] { + v.to_vec() +} + +fn bar(v: &[mut uint]) -> ~[uint] { + v.to_vec() +} + +fn bip(v: &[uint]) -> ~[uint] { + v.to_vec() +} + +fn main() { + let mut the_vec = ~[1, 2, 3, 100]; + assert the_vec == foo(the_vec); + assert the_vec == bar(the_vec); + assert the_vec == bip(the_vec); +} diff --git a/src/test/run-pass/coerce-reborrow-mut-ptr-arg.rs b/src/test/run-pass/coerce-reborrow-mut-ptr-arg.rs new file mode 100644 index 0000000000000..4579907dfbd49 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-mut-ptr-arg.rs @@ -0,0 +1,22 @@ +struct SpeechMaker { + speeches: uint +} + +fn talk(x: &mut SpeechMaker) { + x.speeches += 1; +} + +fn give_a_few_speeches(speaker: &mut SpeechMaker) { + + // Here speaker is reborrowed for each call, so we don't get errors + // about speaker being moved. + + talk(speaker); + talk(speaker); + talk(speaker); +} + +fn main() { + let mut lincoln = SpeechMaker {speeches: 22}; + give_a_few_speeches(&mut lincoln); +} diff --git a/src/test/run-pass/coerce-reborrow-mut-ptr-rcvr.rs b/src/test/run-pass/coerce-reborrow-mut-ptr-rcvr.rs new file mode 100644 index 0000000000000..c915c01416e8e --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-mut-ptr-rcvr.rs @@ -0,0 +1,24 @@ +struct SpeechMaker { + speeches: uint +} + +impl SpeechMaker { + fn talk(&mut self) { + self.speeches += 1; + } +} + +fn give_a_few_speeches(speaker: &mut SpeechMaker) { + + // Here speaker is reborrowed for each call, so we don't get errors + // about speaker being moved. + + speaker.talk(); + speaker.talk(); + speaker.talk(); +} + +fn main() { + let mut lincoln = SpeechMaker {speeches: 22}; + give_a_few_speeches(&mut lincoln); +} diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs b/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs new file mode 100644 index 0000000000000..0cce52e7dc8d3 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs @@ -0,0 +1,15 @@ +trait Reverser { + fn reverse(&self); +} + +fn bar(v: &[mut uint]) { + vec::reverse(v); + vec::reverse(v); + vec::reverse(v); +} + +fn main() { + let mut the_vec = ~[1, 2, 3, 100]; + bar(the_vec); + assert the_vec == ~[100, 3, 2, 1]; +} diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs new file mode 100644 index 0000000000000..9fb748f049fd6 --- /dev/null +++ b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs @@ -0,0 +1,21 @@ +trait Reverser { + fn reverse(&self); +} + +impl &[mut uint] : Reverser { + fn reverse(&self) { + vec::reverse(*self); + } +} + +fn bar(v: &[mut uint]) { + v.reverse(); + v.reverse(); + v.reverse(); +} + +fn main() { + let mut the_vec = ~[1, 2, 3, 100]; + bar(the_vec); + assert the_vec == ~[100, 3, 2, 1]; +} diff --git a/src/test/run-pass/issue-3026.rs b/src/test/run-pass/issue-3026.rs index 04932676f3d63..8a7ebb8d129e0 100644 --- a/src/test/run-pass/issue-3026.rs +++ b/src/test/run-pass/issue-3026.rs @@ -17,5 +17,5 @@ use std::map; fn main() { let buggy_map :HashMap = HashMap::(); let x = ~1; - buggy_map.insert(42, x); + buggy_map.insert(42, &*x); } diff --git a/src/test/run-pass/let-assignability.rs b/src/test/run-pass/let-assignability.rs index 2978585674524..453d556b13c99 100644 --- a/src/test/run-pass/let-assignability.rs +++ b/src/test/run-pass/let-assignability.rs @@ -14,15 +14,7 @@ fn f() { io::println(b); } -fn g() { - let c = ~"world"; - let d: &str; - d = c; - io::println(d); -} - fn main() { f(); - g(); } From e6cadc4c036a08173c7cc2645c6f4bdb171b3b1c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 25 Jan 2013 10:29:25 -0800 Subject: [PATCH 23/31] remove hacks now that #3148 is fixed r=brson --- src/librustc/middle/typeck/check/method.rs | 30 ++++---------------- src/librustc/middle/typeck/infer/coercion.rs | 23 ++------------- 2 files changed, 8 insertions(+), 45 deletions(-) diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 238e4e8c3f772..86f58edd6c8a8 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -739,8 +739,9 @@ impl LookupContext { let tcx = self.tcx(); return match ty::get(self_ty).sty { - ty::ty_rptr(self_r, self_mt) if self_mt.mutbl == m_mutbl => { - let region = fresh_region(self, self_r); + ty::ty_rptr(_, self_mt) if self_mt.mutbl == m_mutbl => { + let region = self.infcx().next_region_var(self.expr.span, + self.expr.id); (ty::mk_rptr(tcx, region, self_mt), ty::AutoAdjustment { autoderefs: autoderefs+1, @@ -748,9 +749,10 @@ impl LookupContext { region: region, mutbl: self_mt.mutbl})}) } - ty::ty_evec(self_mt, vstore_slice(self_r)) + ty::ty_evec(self_mt, vstore_slice(_)) if self_mt.mutbl == m_mutbl => { - let region = fresh_region(self, self_r); + let region = self.infcx().next_region_var(self.expr.span, + self.expr.id); (ty::mk_evec(tcx, self_mt, vstore_slice(region)), ty::AutoAdjustment { autoderefs: autoderefs, @@ -763,26 +765,6 @@ impl LookupContext { autoref: None}) } }; - - fn fresh_region(self: &LookupContext, - self_r: ty::Region) -> ty::Region { - let region = self.infcx().next_region_var(self.expr.span, - self.expr.id); - - // FIXME(#3148)---in principle this dependency should - // be done more generally as part of regionck - match infer::mk_subr(self.infcx(), true, self.expr.span, - region, self_r) { - Ok(_) => {} - Err(e) => { - self.tcx().sess.span_bug( - self.expr.span, - fmt!("Failed with error: %?", e)); - } - } - - return region; - } } fn search_for_autosliced_method( diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 9c319bdc733ae..fac84281f7fe2 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -196,15 +196,7 @@ impl Coerce { let inner_ty = match *sty_a { ty::ty_box(mt_a) => mt_a.ty, ty::ty_uniq(mt_a) => mt_a.ty, - ty::ty_rptr(r_a, mt_a) => { - // Ensure that the pointer we are borrowing from lives - // at least as long as the borrowed result. - // - // FIXME(#3148)---in principle this dependency should - // be done more generally - if_ok!(sub.contraregions(r_a, r_borrow)); - mt_a.ty - } + ty::ty_rptr(r_a, mt_a) => mt_a.ty, _ => { return self.subtype(a, b); } @@ -267,18 +259,7 @@ impl Coerce { let sub = Sub(**self); let r_borrow = self.infcx.next_region_var_nb(self.span); let ty_inner = match *sty_a { - ty::ty_evec(mt, vstore_box) => mt.ty, - ty::ty_evec(mt, vstore_uniq) => mt.ty, - ty::ty_evec(mt, vstore_fixed(_)) => mt.ty, - ty::ty_evec(mt, vstore_slice(r_a)) => { - // Ensure that the pointer we are borrowing from lives - // at least as long as the borrowed result. - // - // FIXME(#3148)---in principle this dependency should - // be done more generally - if_ok!(sub.contraregions(r_a, r_borrow)); - mt.ty - } + ty::ty_evec(mt, _) => mt.ty, _ => { return self.subtype(a, b); } From b4acde3bf7451cc20d6690ca2d3266f24bf9f477 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 25 Jan 2013 19:02:03 -0800 Subject: [PATCH 24/31] remove unused variable --- src/librustc/middle/typeck/infer/coercion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index fac84281f7fe2..f0fe2deffdfa8 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -196,7 +196,7 @@ impl Coerce { let inner_ty = match *sty_a { ty::ty_box(mt_a) => mt_a.ty, ty::ty_uniq(mt_a) => mt_a.ty, - ty::ty_rptr(r_a, mt_a) => mt_a.ty, + ty::ty_rptr(_, mt_a) => mt_a.ty, _ => { return self.subtype(a, b); } From 4b15bfde8133768d8fc517eeb8064bd2f9bcddd5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 25 Jan 2013 19:02:09 -0800 Subject: [PATCH 25/31] loan: Track whether or not the current path owns the data being lent. We can be more liberal with respect to the scope of the loan if we do not own the data being lent, which used to be impossible but can now occur with `&mut`. r=pcwalton --- src/librustc/middle/borrowck/loan.rs | 184 +++++++++++++++++++-------- 1 file changed, 128 insertions(+), 56 deletions(-) diff --git a/src/librustc/middle/borrowck/loan.rs b/src/librustc/middle/borrowck/loan.rs index 1b274a5241c67..d3dc75aad7f91 100644 --- a/src/librustc/middle/borrowck/loan.rs +++ b/src/librustc/middle/borrowck/loan.rs @@ -8,6 +8,35 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! + +The `Loan` module deals with borrows of *uniquely mutable* data. We +say that data is uniquely mutable if the current activation (stack +frame) controls the only mutable reference to the data. The most +common way that this can occur is if the current activation owns the +data being borrowed, but it can also occur with `&mut` pointers. The +primary characteristic of uniquely mutable data is that, at any given +time, there is at most one path that can be used to mutate it, and +that path is only accessible from the top stack frame. + +Given that some data found at a path P is being borrowed to a borrowed +pointer with mutability M and lifetime L, the job of the code in this +module is to compute the set of *loans* that are necessary to ensure +that (1) the data found at P outlives L and that (2) if M is mutable +then the path P will not be modified directly or indirectly except +through that pointer. A *loan* is the combination of a path P_L, a +mutability M_L, and a lifetime L_L where: + +- The path P_L indicates what data has been lent. +- The mutability M_L indicates the access rights on the data: + - const: the data cannot be moved + - immutable/mutable: the data cannot be moved or mutated +- The lifetime L_L indicates the *scope* of the loan. + +XXX --- much more needed, don't have time to write this all up now + +*/ + // ---------------------------------------------------------------------- // Loan(Ex, M, S) = Ls holds if ToAddr(Ex) will remain valid for the entirety // of the scope S, presuming that the returned set of loans `Ls` are honored. @@ -39,7 +68,7 @@ impl borrowck_ctxt { scope_region: scope_region, loans: ~[] }; - match lc.loan(cmt, mutbl) { + match lc.loan(cmt, mutbl, true) { Err(ref e) => Err((*e)), Ok(()) => { let LoanContext {loans, _} = move lc; @@ -62,46 +91,25 @@ struct LoanContext { impl LoanContext { fn tcx(&self) -> ty::ctxt { self.bccx.tcx } - fn issue_loan(&self, - cmt: cmt, - scope_ub: ty::Region, - req_mutbl: ast::mutability) -> bckres<()> { - if self.bccx.is_subregion_of(self.scope_region, scope_ub) { - match req_mutbl { - m_mutbl => { - // We do not allow non-mutable data to be loaned - // out as mutable under any circumstances. - if cmt.mutbl != m_mutbl { - return Err({cmt:cmt, - code:err_mutbl(req_mutbl)}); - } - } - m_const | m_imm => { - // However, mutable data can be loaned out as - // immutable (and any data as const). The - // `check_loans` pass will then guarantee that no - // writes occur for the duration of the loan. - } - } + fn loan(&self, + cmt: cmt, + req_mutbl: ast::mutability, + owns_lent_data: bool) -> bckres<()> + { + /*! + * + * The main routine. + * + * # Parameters + * + * - `cmt`: the categorization of the data being borrowed + * - `req_mutbl`: the mutability of the borrowed pointer + * that was created + * - `owns_lent_data`: indicates whether `cmt` owns the + * data that is being lent. See + * discussion in `issue_loan()`. + */ - self.loans.push(Loan { - // Note: cmt.lp must be Some(_) because otherwise this - // loan process does not apply at all. - lp: cmt.lp.get(), - cmt: cmt, - mutbl: req_mutbl - }); - return Ok(()); - } else { - // The loan being requested lives longer than the data - // being loaned out! - return Err({cmt:cmt, - code:err_out_of_scope(scope_ub, - self.scope_region)}); - } - } - - fn loan(&self, cmt: cmt, req_mutbl: ast::mutability) -> bckres<()> { debug!("loan(%s, %s)", self.bccx.cmt_to_repr(cmt), self.bccx.mut_to_str(req_mutbl)); @@ -123,13 +131,14 @@ impl LoanContext { } cat_local(local_id) | cat_arg(local_id) | cat_self(local_id) => { let local_scope_id = self.tcx().region_map.get(local_id); - self.issue_loan(cmt, ty::re_scope(local_scope_id), req_mutbl) + self.issue_loan(cmt, ty::re_scope(local_scope_id), req_mutbl, + owns_lent_data) } cat_stack_upvar(cmt) => { - self.loan(cmt, req_mutbl) // NDM correct? + self.loan(cmt, req_mutbl, owns_lent_data) } cat_discr(base, _) => { - self.loan(base, req_mutbl) + self.loan(base, req_mutbl, owns_lent_data) } cat_comp(cmt_base, comp_field(_, m)) | cat_comp(cmt_base, comp_index(_, m)) => { @@ -139,36 +148,41 @@ impl LoanContext { // that case, it must also be embedded in an immutable // location, or else the whole structure could be // overwritten and the component along with it. - self.loan_stable_comp(cmt, cmt_base, req_mutbl, m) + self.loan_stable_comp(cmt, cmt_base, req_mutbl, m, + owns_lent_data) } cat_comp(cmt_base, comp_tuple) | cat_comp(cmt_base, comp_anon_field) => { // As above. - self.loan_stable_comp(cmt, cmt_base, req_mutbl, m_imm) + self.loan_stable_comp(cmt, cmt_base, req_mutbl, m_imm, + owns_lent_data) } cat_comp(cmt_base, comp_variant(enum_did)) => { // For enums, the memory is unstable if there are multiple // variants, because if the enum value is overwritten then // the memory changes type. if ty::enum_is_univariant(self.bccx.tcx, enum_did) { - self.loan_stable_comp(cmt, cmt_base, req_mutbl, m_imm) + self.loan_stable_comp(cmt, cmt_base, req_mutbl, m_imm, + owns_lent_data) } else { - self.loan_unstable_deref(cmt, cmt_base, req_mutbl) + self.loan_unstable_deref(cmt, cmt_base, req_mutbl, + owns_lent_data) } } cat_deref(cmt_base, _, uniq_ptr) => { // For unique pointers, the memory being pointed out is // unstable because if the unique pointer is overwritten // then the memory is freed. - self.loan_unstable_deref(cmt, cmt_base, req_mutbl) + self.loan_unstable_deref(cmt, cmt_base, req_mutbl, + owns_lent_data) } cat_deref(cmt_base, _, region_ptr(ast::m_mutbl, region)) => { // Mutable data can be loaned out as immutable or const. We must // loan out the base as well as the main memory. For example, // if someone borrows `*b`, we want to borrow `b` as immutable // as well. - do self.loan(cmt_base, m_imm).chain |_| { - self.issue_loan(cmt, region, m_const) + do self.loan(cmt_base, m_imm, false).chain |_| { + self.issue_loan(cmt, region, m_const, owns_lent_data) } } cat_deref(_, _, unsafe_ptr) | @@ -189,7 +203,8 @@ impl LoanContext { cmt: cmt, cmt_base: cmt, req_mutbl: ast::mutability, - comp_mutbl: ast::mutability) -> bckres<()> { + comp_mutbl: ast::mutability, + owns_lent_data: bool) -> bckres<()> { // Determine the mutability that the base component must have, // given the required mutability of the pointer (`req_mutbl`) // and the declared mutability of the component (`comp_mutbl`). @@ -243,10 +258,11 @@ impl LoanContext { (m_const, _) => m_const // (5) }; - do self.loan(cmt_base, base_mutbl).chain |_ok| { + do self.loan(cmt_base, base_mutbl, owns_lent_data).chain |_ok| { // can use static for the scope because the base // determines the lifetime, ultimately - self.issue_loan(cmt, ty::re_static, req_mutbl) + self.issue_loan(cmt, ty::re_static, req_mutbl, + owns_lent_data) } } @@ -256,13 +272,69 @@ impl LoanContext { fn loan_unstable_deref(&self, cmt: cmt, cmt_base: cmt, - req_mutbl: ast::mutability) -> bckres<()> { + req_mutbl: ast::mutability, + owns_lent_data: bool) -> bckres<()> + { // Variant components: the base must be immutable, because // if it is overwritten, the types of the embedded data // could change. - do self.loan(cmt_base, m_imm).chain |_| { + do self.loan(cmt_base, m_imm, owns_lent_data).chain |_| { // can use static, as in loan_stable_comp() - self.issue_loan(cmt, ty::re_static, req_mutbl) + self.issue_loan(cmt, ty::re_static, req_mutbl, + owns_lent_data) + } + } + + fn issue_loan(&self, + cmt: cmt, + scope_ub: ty::Region, + req_mutbl: ast::mutability, + owns_lent_data: bool) -> bckres<()> + { + // Subtle: the `scope_ub` is the maximal lifetime of `cmt`. + // Therefore, if `cmt` owns the data being lent, then the + // scope of the loan must be less than `scope_ub`, or else the + // data would be freed while the loan is active. + // + // However, if `cmt` does *not* own the data being lent, then + // it is ok if `cmt` goes out of scope during the loan. This + // can occur when you have an `&mut` parameter that is being + // reborrowed. + + if !owns_lent_data || + self.bccx.is_subregion_of(self.scope_region, scope_ub) + { + match req_mutbl { + m_mutbl => { + // We do not allow non-mutable data to be loaned + // out as mutable under any circumstances. + if cmt.mutbl != m_mutbl { + return Err({cmt:cmt, + code:err_mutbl(req_mutbl)}); + } + } + m_const | m_imm => { + // However, mutable data can be loaned out as + // immutable (and any data as const). The + // `check_loans` pass will then guarantee that no + // writes occur for the duration of the loan. + } + } + + self.loans.push(Loan { + // Note: cmt.lp must be Some(_) because otherwise this + // loan process does not apply at all. + lp: cmt.lp.get(), + cmt: cmt, + mutbl: req_mutbl + }); + return Ok(()); + } else { + // The loan being requested lives longer than the data + // being loaned out! + return Err({cmt:cmt, + code:err_out_of_scope(scope_ub, + self.scope_region)}); } } } From ef4c0605946d11c93390413fe7fc3a7c86f21ac3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 28 Jan 2013 09:55:10 -0800 Subject: [PATCH 26/31] Address @catamorphism's comments regarding docs --- src/librustc/middle/typeck/check/regionck.rs | 80 ++++++++++++-------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index fe2fd4a6a22a1..43c1cb7816694 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -485,17 +485,16 @@ mod guarantor { /*! * * The routines in this module are aiming to deal with the case - * where the lifetime resulting from a borrow is linked to the - * lifetime of the thing being borrowed. Imagine you have a - * borrowed pointer `b` with lifetime L1 and you have an - * expression `&*b`. The result of this borrow will be another - * borrowed pointer with lifetime L2 (which is an inference - * variable). The borrow checker is going to enforce the - * constraint that L2 < L1, because otherwise you are re-borrowing - * data for a lifetime larger than the original loan. However, - * without the routines in this module, the region inferencer would - * not know of this dependency and thus it might infer the - * lifetime of L2 to be greater than L1 (issue #3148). + * where a the contents of a borrowed pointer are re-borrowed. + * Imagine you have a borrowed pointer `b` with lifetime L1 and + * you have an expression `&*b`. The result of this borrow will + * be another borrowed pointer with lifetime L2 (which is an + * inference variable). The borrow checker is going to enforce + * the constraint that L2 < L1, because otherwise you are + * re-borrowing data for a lifetime larger than the original loan. + * However, without the routines in this module, the region + * inferencer would not know of this dependency and thus it might + * infer the lifetime of L2 to be greater than L1 (issue #3148). * * There are a number of troublesome scenarios in the test * `region-dependent-addr-of.rs`, but here is one example: @@ -515,16 +514,17 @@ mod guarantor { * is "guaranteed" by a borrowed pointer, you must link the * lifetime of that borrowed pointer (L1, here) to the lifetime of * the borrow itself (L2). What do I mean by "guaranteed" by a - * borrowed pointer? Well, I would say the data "owned" by the - * borrowed pointer, except that a borrowed pointer never owns its - * contents, but the relation is the same. That is, I mean any - * data that is reached by first derefencing a borrowed pointer - * and then either traversing interior offsets or owned pointers. - * We say that the guarantor of such data it the region of the borrowed - * pointer that was traversed. + * borrowed pointer? I mean any data that is reached by first + * dereferencing a borrowed pointer and then either traversing + * interior offsets or owned pointers. We say that the guarantor + * of such data it the region of the borrowed pointer that was + * traversed. This is essentially the same as the ownership + * relation, except that a borrowed pointer never owns its + * contents. * * NB: I really wanted to use the `mem_categorization` code here - * but I cannot because final type resolution hasn't happened yet. + * but I cannot because final type resolution hasn't happened yet, + * and `mem_categorization` requires that all types be known. * So this is very similar logic to what you would find there, * but more special purpose. */ @@ -540,7 +540,8 @@ mod guarantor { /*! * * Computes the guarantor for an expression `&base` and then - * ensures that the lifetime of the resulting pointer is linked. + * ensures that the lifetime of the resulting pointer is linked + * to the lifetime of its guarantor (if any). */ debug!("guarantor::for_addr_of(base=%s)", rcx.fcx.expr_to_str(base)); @@ -555,7 +556,7 @@ mod guarantor { * * Computes the guarantors for any ref bindings in a match and * then ensures that the lifetime of the resulting pointer is - * linked. + * linked to the lifetime of its guarantor (if any). */ let discr_guarantor = guarantor(rcx, discr); @@ -599,13 +600,18 @@ mod guarantor { /*! * * Links the lifetime of the borrowed pointer resulting from a borrow - * to the lifetime of its guarantor. + * to the lifetime of its guarantor (if any). */ debug!("opt_constrain_region(id=%?, guarantor=%?)", id, guarantor); let bound = match guarantor { - None => { return; } + None => { + // If guarantor is None, then the value being borrowed + // is not guaranteed by a region pointer, so there are + // no lifetimes to link. + return; + } Some(r) => { r } }; @@ -620,24 +626,38 @@ mod guarantor { } } - enum PointerCat { + /// Categorizes types based on what kind of pointer they are. + /// Note that we don't bother to distinguish between rptrs (&T) + /// and slices (&[T], &str)---they are all just `BorrowedPointer`. + enum PointerCategorization { NotPointer, OwnedPointer, BorrowedPointer(ty::Region), OtherPointer } + /// Guarantor of an expression paired with the + /// PointerCategorization` of its type. struct ExprCategorization { guarantor: Option, - pointer: PointerCat + pointer: PointerCategorization } + /// ExprCategorization paired with the full type of the expr struct ExprCategorizationType { cat: ExprCategorization, ty: ty::t } fn guarantor(rcx: @rcx, expr: @ast::expr) -> Option { + /*! + * + * Computes the guarantor of `expr`, or None if `expr` is + * not guaranteed by any region. Here `expr` is some expression + * whose address is being taken (e.g., there is an expression + * `&expr`). + */ + debug!("guarantor(expr=%s)", rcx.fcx.expr_to_str(expr)); match expr.node { ast::expr_unary(ast::deref, b) => { @@ -706,9 +726,7 @@ mod guarantor { } } - fn categorize(rcx: @rcx, - expr: @ast::expr) -> ExprCategorization - { + fn categorize(rcx: @rcx, expr: @ast::expr) -> ExprCategorization { debug!("categorize(expr=%s)", rcx.fcx.expr_to_str(expr)); let _i = ::util::common::indenter(); @@ -722,6 +740,8 @@ mod guarantor { rcx, expr, adjustment.autoderefs, expr_ct); for adjustment.autoref.each |autoref| { + // If there is an autoref, then the result of this + // expression will be some sort of borrowed pointer. expr_ct.cat.guarantor = None; expr_ct.cat.pointer = BorrowedPointer(autoref.region); debug!("autoref, cat=%?", expr_ct.cat); @@ -784,7 +804,7 @@ mod guarantor { return ct; } - fn pointer_categorize(ty: ty::t) -> PointerCat { + fn pointer_categorize(ty: ty::t) -> PointerCategorization { match ty::get(ty).sty { ty::ty_rptr(r, _) | ty::ty_evec(_, ty::vstore_slice(r)) | ty::ty_estr(ty::vstore_slice(r)) => { @@ -911,7 +931,7 @@ fn infallibly_mk_subr(rcx: @rcx, { /*! * - * Constraints `a` to be a subregion of `b`. In many cases, we + * Constrains `a` to be a subregion of `b`. In many cases, we * know that this can never yield an error due to the way that * region inferencing works. Therefore just report a bug if we * ever see `Err(_)`. From e8f36901235ae016aa0de869f2ba67722864dab6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 28 Jan 2013 09:59:58 -0800 Subject: [PATCH 27/31] Change "// WARN" in tidy to "// NOTE" as requested by @catamorphism --- src/etc/tidy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/etc/tidy.py b/src/etc/tidy.py index 2eb32c100acd2..65737c53e613f 100644 --- a/src/etc/tidy.py +++ b/src/etc/tidy.py @@ -49,9 +49,9 @@ def do_license_check(name, contents): report_err("FIXME without issue number") if line.find("TODO") != -1: report_err("TODO is deprecated; use FIXME") - idx = line.find("// WARN") + idx = line.find("// NOTE") if idx != -1: - report_warn("WARN:" + line[idx + len("// WARN"):]) + report_warn("NOTE:" + line[idx + len("// NOTE"):]) if (line.find('\t') != -1 and fileinput.filename().find("Makefile") == -1): report_err("tab character") From 62d27b082cbc94b3617f662ee6d4f897a75a8afa Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 25 Jan 2013 16:57:39 -0800 Subject: [PATCH 28/31] libstd: Remove "dual impls" from the language and enforce coherence rules. "Dual impls" are impls that are both type implementations and trait implementations. They can lead to ambiguity and so this patch removes them from the language. This also enforces coherence rules. Without this patch, records can implement traits not defined in the current crate. This patch fixes this, and updates all of rustc to adhere to the new enforcement. Most of this patch is fixing rustc to obey the coherence rules, which involves converting a bunch of records to structs. --- src/libcore/gc.rs | 1 + src/libcore/hashmap.rs | 2 +- src/libcore/num.rs | 5 + src/libcore/pipes.rs | 3 +- src/libcore/prelude.rs | 2 + src/libcore/private/weak_task.rs | 2 +- src/libcore/task/mod.rs | 2 +- src/libcore/task/spawn.rs | 4 +- src/librustc/metadata/encoder.rs | 1 + src/librustc/metadata/tydecode.rs | 23 +- src/librustc/metadata/tyencode.rs | 4 +- src/librustc/middle/borrowck/check_loans.rs | 7 +- src/librustc/middle/borrowck/gather_loans.rs | 6 +- src/librustc/middle/borrowck/loan.rs | 15 +- src/librustc/middle/borrowck/mod.rs | 28 +- src/librustc/middle/borrowck/preserve.rs | 29 +- src/librustc/middle/mem_categorization.rs | 220 +++++++++----- src/librustc/middle/region.rs | 19 +- src/librustc/middle/trans/_match.rs | 3 +- src/librustc/middle/trans/base.rs | 10 +- src/librustc/middle/trans/common.rs | 9 +- src/librustc/middle/trans/datum.rs | 4 +- src/librustc/middle/trans/expr.rs | 3 +- src/librustc/middle/trans/foreign.rs | 6 +- src/librustc/middle/trans/machine.rs | 13 +- src/librustc/middle/trans/meth.rs | 7 +- src/librustc/middle/ty.rs | 131 ++++---- src/librustc/middle/typeck/astconv.rs | 9 +- src/librustc/middle/typeck/check/method.rs | 48 ++- src/librustc/middle/typeck/check/mod.rs | 42 +-- src/librustc/middle/typeck/check/vtable.rs | 8 +- src/librustc/middle/typeck/check/writeback.rs | 3 +- src/librustc/middle/typeck/coherence.rs | 129 ++++---- src/librustc/middle/typeck/collect.rs | 33 +- src/librustc/middle/typeck/infer/combine.rs | 14 +- src/librustc/middle/typeck/infer/mod.rs | 2 +- src/librustc/util/ppaux.rs | 9 +- src/librustdoc/astsrv.rs | 6 +- src/librustdoc/attr_pass.rs | 18 +- src/librustdoc/config.rs | 14 +- src/librustdoc/desc_to_brief_pass.rs | 10 +- src/librustdoc/doc.rs | 283 +++--------------- src/librustdoc/extract.rs | 33 +- src/librustdoc/fold.rs | 30 +- src/librustdoc/markdown_index_pass.rs | 10 +- src/librustdoc/page_pass.rs | 6 +- src/librustdoc/path_pass.rs | 6 +- src/librustdoc/prune_hidden_pass.rs | 2 +- src/librustdoc/prune_private_pass.rs | 2 +- src/librustdoc/sectionalize_pass.rs | 14 +- src/librustdoc/sort_pass.rs | 2 +- src/librustdoc/text_pass.rs | 14 +- src/librustdoc/tystr_pass.rs | 18 +- src/libstd/bigint.rs | 49 ++- src/libstd/deque.rs | 58 +--- src/libstd/ebml.rs | 1 + src/libstd/json.rs | 1 + src/libstd/map.rs | 6 +- src/libstd/smallintmap.rs | 8 +- src/libsyntax/ast_map.rs | 2 +- src/libsyntax/ast_util.rs | 2 +- src/libsyntax/codemap.rs | 2 +- src/libsyntax/diagnostic.rs | 2 +- src/libsyntax/ext/pipes/ast_builder.rs | 2 +- src/libsyntax/ext/pipes/mod.rs | 1 + src/libsyntax/ext/pipes/pipec.rs | 5 +- src/libsyntax/ext/pipes/proto.rs | 2 +- src/libsyntax/ext/quote.rs | 2 +- src/libsyntax/ext/source_util.rs | 2 +- src/libsyntax/parse/comments.rs | 2 +- src/libsyntax/parse/lexer.rs | 2 +- src/test/auxiliary/issue_2242_b.rs | 19 -- src/test/compile-fail/drop-on-non-struct.rs | 1 + src/test/compile-fail/map-types.rs | 9 +- src/test/run-pass/auto-encode.rs | 11 +- .../class-impl-very-parameterized-trait.rs | 2 +- src/test/run-pass/issue-2242-d.rs | 26 -- 77 files changed, 704 insertions(+), 837 deletions(-) delete mode 100644 src/test/auxiliary/issue_2242_b.rs delete mode 100644 src/test/run-pass/issue-2242-d.rs diff --git a/src/libcore/gc.rs b/src/libcore/gc.rs index 698e264b57a65..181a9d0888d43 100644 --- a/src/libcore/gc.rs +++ b/src/libcore/gc.rs @@ -40,6 +40,7 @@ with destructors. #[forbid(deprecated_pattern)]; use cast; +use container::{Container, Mutable, Map, Set}; use io; use libc::{size_t, uintptr_t}; use option::{None, Option, Some}; diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index ab1c9832d460e..c3af7a99692e5 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -16,7 +16,6 @@ use cmp::Eq; use hash::Hash; -use prelude::*; use to_bytes::IterBytes; /// Open addressing with linear probing. @@ -479,6 +478,7 @@ pub mod linear { #[test] pub mod test { + use container::{Container, Mutable, Map, Set}; use option::{None, Some}; use hashmap::linear::LinearMap; use hashmap::linear; diff --git a/src/libcore/num.rs b/src/libcore/num.rs index 4c2daa458a48d..6eb22e53a2413 100644 --- a/src/libcore/num.rs +++ b/src/libcore/num.rs @@ -23,6 +23,11 @@ pub trait Num { static pure fn from_int(n: int) -> self; } +pub trait IntConvertible { + pure fn to_int(&self) -> int; + static pure fn from_int(n: int) -> self; +} + pub trait Zero { static pure fn zero() -> self; } diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index cecc954cdf3bc..9142c11360a0d 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -93,10 +93,9 @@ use either::{Either, Left, Right}; use kinds::Owned; use libc; use option; -use option::unwrap; +use option::{None, Option, Some, unwrap}; use pipes; use ptr; -use prelude::*; use private; use task; use vec; diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 72aa828ff12a7..d3813d1ae852e 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -35,6 +35,8 @@ pub use vec::{ImmutableEqVector, ImmutableCopyableVector}; pub use vec::{OwnedVector, OwnedCopyableVector}; pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter}; pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times}; +pub use container::{Container, Mutable, Map, Set}; +pub use pipes::{GenericChan, GenericPort}; pub use num::Num; pub use ptr::Ptr; diff --git a/src/libcore/private/weak_task.rs b/src/libcore/private/weak_task.rs index 25a03ff960f46..573a3e54b444b 100644 --- a/src/libcore/private/weak_task.rs +++ b/src/libcore/private/weak_task.rs @@ -22,7 +22,7 @@ use option::{Some, None, swap_unwrap}; use private::at_exit::at_exit; use private::global::global_data_clone_create; use private::finally::Finally; -use pipes::{Port, Chan, SharedChan, stream}; +use pipes::{Port, Chan, SharedChan, GenericSmartChan, stream}; use task::{Task, task, spawn}; use task::rt::{task_id, get_task_id}; use hashmap::linear::LinearMap; diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index aa82309c78aec..9ddafee693898 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -45,7 +45,7 @@ use iter; use libc; use option; use result::Result; -use pipes::{stream, Chan, Port, SharedChan}; +use pipes::{stream, Chan, GenericChan, GenericPort, Port, SharedChan}; use pipes; use prelude::*; use ptr; diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs index a5ab4af40bef7..0a2f6634214e6 100644 --- a/src/libcore/task/spawn.rs +++ b/src/libcore/task/spawn.rs @@ -74,8 +74,10 @@ #[warn(deprecated_mode)]; use cast; +use container::Map; +use oldcomm; use option; -use pipes::{stream, Chan, Port}; +use pipes::{Chan, GenericChan, GenericPort, Port}; use pipes; use prelude::*; use private; diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 79ce755137efc..399184ea8a586 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -37,6 +37,7 @@ use core::to_bytes::IterBytes; use core::uint; use core::vec; use std::map::HashMap; +use std::serialize::Encodable; use std::{ebml, map}; use std; use syntax::ast::*; diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 590dd9f7ea7e0..787a1d3c906c2 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -17,7 +17,8 @@ use core::prelude::*; use middle::ty; -use middle::ty::{FnTyBase, FnMeta, FnSig}; +use middle::ty::{FnTyBase, FnMeta, FnSig, arg, creader_cache_key, field}; +use middle::ty::{substs}; use core::io; use core::str; @@ -174,9 +175,11 @@ fn parse_substs(st: @pstate, conv: conv_did) -> ty::substs { while peek(st) != ']' { params.push(parse_ty(st, conv)); } st.pos = st.pos + 1u; - return {self_r: self_r, - self_ty: self_ty, - tps: params}; + return substs { + self_r: self_r, + self_ty: self_ty, + tps: params + }; } fn parse_bound_region(st: @pstate) -> ty::bound_region { @@ -308,7 +311,7 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t { let mut fields: ~[ty::field] = ~[]; while peek(st) != ']' { let name = st.tcx.sess.ident_of(parse_str(st, '=')); - fields.push({ident: name, mt: parse_mt(st, conv)}); + fields.push(ty::field { ident: name, mt: parse_mt(st, conv) }); } st.pos = st.pos + 1u; return ty::mk_rec(st.tcx, fields); @@ -333,12 +336,13 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t { assert (next(st) == ':'); let len = parse_hex(st); assert (next(st) == '#'); - match st.tcx.rcache.find({cnum: st.crate, pos: pos, len: len}) { + let key = creader_cache_key { cnum: st.crate, pos: pos, len: len }; + match st.tcx.rcache.find(key) { Some(tt) => return tt, None => { let ps = @{pos: pos ,.. copy *st}; let tt = parse_ty(ps, conv); - st.tcx.rcache.insert({cnum: st.crate, pos: pos, len: len}, tt); + st.tcx.rcache.insert(key, tt); return tt; } } @@ -421,8 +425,7 @@ fn parse_onceness(c: char) -> ast::Onceness { } fn parse_arg(st: @pstate, conv: conv_did) -> ty::arg { - {mode: parse_mode(st), - ty: parse_ty(st, conv)} + ty::arg { mode: parse_mode(st), ty: parse_ty(st, conv) } } fn parse_mode(st: @pstate) -> ast::mode { @@ -446,7 +449,7 @@ fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::FnTy { let mut inputs: ~[ty::arg] = ~[]; while peek(st) != ']' { let mode = parse_mode(st); - inputs.push({mode: mode, ty: parse_ty(st, conv)}); + inputs.push(ty::arg { mode: mode, ty: parse_ty(st, conv) }); } st.pos += 1u; // eat the ']' let ret_ty = parse_ty(st, conv); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index d318f00ad6752..04e833d812bd7 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -13,8 +13,8 @@ use core::prelude::*; +use middle::ty::{Vid, param_ty}; use middle::ty; -use middle::ty::Vid; use core::io::WriterUtil; use core::io; @@ -301,7 +301,7 @@ fn enc_sty(w: io::Writer, cx: @ctxt, +st: ty::sty) { ty::ty_infer(_) => { cx.diag.handler().bug(~"Cannot encode inference variable types"); } - ty::ty_param({idx: id, def_id: did}) => { + ty::ty_param(param_ty {idx: id, def_id: did}) => { w.write_char('p'); w.write_str((cx.ds)(did)); w.write_char('|'); diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index ff5854322f456..bdb889b68f116 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -20,7 +20,7 @@ use core::prelude::*; use middle::borrowck::{Loan, bckerr, borrowck_ctxt, cmt, inherent_mutability}; -use middle::borrowck::{req_maps, save_and_restore}; +use middle::borrowck::{req_maps, root_map_key, save_and_restore}; use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref}; use middle::mem_categorization::{cat_local, cat_rvalue, cat_self}; use middle::mem_categorization::{cat_special, gc_ptr, loan_path, lp_arg}; @@ -396,7 +396,10 @@ impl check_loan_ctxt { match ptr_kind { gc_ptr(ast::m_mutbl) => { - let key = { id: base.id, derefs: deref_count }; + let key = root_map_key { + id: base.id, + derefs: deref_count + }; self.bccx.write_guard_map.insert(key, ()); } _ => {} diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs index 0fff0c66a3846..6f913f99e11fd 100644 --- a/src/librustc/middle/borrowck/gather_loans.rs +++ b/src/librustc/middle/borrowck/gather_loans.rs @@ -19,7 +19,8 @@ use core::prelude::*; use middle::borrowck::preserve::{preserve_condition, pc_ok, pc_if_pure}; -use middle::borrowck::{Loan, bckres, borrowck_ctxt, err_mutbl, req_maps}; +use middle::borrowck::{Loan, bckerr, bckres, borrowck_ctxt, err_mutbl}; +use middle::borrowck::{req_maps}; use middle::mem_categorization::{cat_binding, cat_discr, cmt, comp_variant}; use middle::mem_categorization::{mem_categorization_ctxt}; use middle::mem_categorization::{opt_deref_kind}; @@ -452,8 +453,7 @@ impl gather_loan_ctxt { debug!("required is const or they are the same"); Ok(pc_ok) } else { - let e = {cmt: cmt, - code: err_mutbl(req_mutbl)}; + let e = bckerr { cmt: cmt, code: err_mutbl(req_mutbl) }; if req_mutbl == m_imm { // if this is an @mut box, then it's generally OK to borrow as // &imm; this will result in a write guard diff --git a/src/librustc/middle/borrowck/loan.rs b/src/librustc/middle/borrowck/loan.rs index d3dc75aad7f91..48cc0502f6c87 100644 --- a/src/librustc/middle/borrowck/loan.rs +++ b/src/librustc/middle/borrowck/loan.rs @@ -43,7 +43,7 @@ XXX --- much more needed, don't have time to write this all up now use core::prelude::*; -use middle::borrowck::{Loan, bckres, borrowck_ctxt, cmt, err_mutbl}; +use middle::borrowck::{Loan, bckerr, bckres, borrowck_ctxt, cmt, err_mutbl}; use middle::borrowck::{err_out_of_scope}; use middle::mem_categorization::{cat_arg, cat_binding, cat_discr, cat_comp}; use middle::mem_categorization::{cat_deref, cat_discr, cat_local, cat_self}; @@ -309,8 +309,10 @@ impl LoanContext { // We do not allow non-mutable data to be loaned // out as mutable under any circumstances. if cmt.mutbl != m_mutbl { - return Err({cmt:cmt, - code:err_mutbl(req_mutbl)}); + return Err(bckerr { + cmt:cmt, + code:err_mutbl(req_mutbl) + }); } } m_const | m_imm => { @@ -332,9 +334,10 @@ impl LoanContext { } else { // The loan being requested lives longer than the data // being loaned out! - return Err({cmt:cmt, - code:err_out_of_scope(scope_ub, - self.scope_region)}); + return Err(bckerr { + cmt:cmt, + code:err_out_of_scope(scope_ub, self.scope_region) + }); } } } diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index a01c04a8abf15..2afdcc9d47d53 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -344,7 +344,11 @@ type root_map = HashMap; // if you have an expression `x.f` and x has type ~@T, we could add an // entry {id:x, derefs:0} to refer to `x` itself, `{id:x, derefs:1}` // to refer to the deref of the unique pointer, and so on. -type root_map_key = {id: ast::node_id, derefs: uint}; +#[deriving_eq] +struct root_map_key { + id: ast::node_id, + derefs: uint +} // set of ids of local vars / formal arguments that are modified / moved. // this is used in trans for optimization purposes. @@ -411,13 +415,10 @@ impl bckerr_code : cmp::Eq { // Combination of an error code and the categorization of the expression // that caused it -type bckerr = {cmt: cmt, code: bckerr_code}; - -impl bckerr : cmp::Eq { - pure fn eq(&self, other: &bckerr) -> bool { - (*self).cmt == (*other).cmt && (*self).code == (*other).code - } - pure fn ne(&self, other: &bckerr) -> bool { !(*self).eq(other) } +#[deriving_eq] +struct bckerr { + cmt: cmt, + code: bckerr_code } // shorthand for something that fails with `bckerr` or succeeds with `T` @@ -446,15 +447,6 @@ fn save_and_restore(save_and_restore_t: &mut T, f: fn() -> U) -> U { /// Creates and returns a new root_map -impl root_map_key : cmp::Eq { - pure fn eq(&self, other: &root_map_key) -> bool { - (*self).id == (*other).id && (*self).derefs == (*other).derefs - } - pure fn ne(&self, other: &root_map_key) -> bool { - ! ((*self) == (*other)) - } -} - impl root_map_key : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_2(&self.id, &self.derefs, lsb0, f); @@ -501,7 +493,7 @@ impl borrowck_ctxt { } fn cat_discr(cmt: cmt, match_id: ast::node_id) -> cmt { - return @{cat:cat_discr(cmt, match_id),.. *cmt}; + return @cmt_ { cat: cat_discr(cmt, match_id),.. *cmt }; } fn mc_ctxt() -> mem_categorization_ctxt { diff --git a/src/librustc/middle/borrowck/preserve.rs b/src/librustc/middle/borrowck/preserve.rs index 5916588a9a2bb..5edfd294d8477 100644 --- a/src/librustc/middle/borrowck/preserve.rs +++ b/src/librustc/middle/borrowck/preserve.rs @@ -18,7 +18,7 @@ use core::prelude::*; use middle::borrowck::{RootInfo, bckerr, bckerr_code, bckres, borrowck_ctxt}; use middle::borrowck::{cmt, err_mut_uniq, err_mut_variant}; use middle::borrowck::{err_out_of_root_scope, err_out_of_scope}; -use middle::borrowck::{err_root_not_permitted}; +use middle::borrowck::{err_root_not_permitted, root_map_key}; use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref}; use middle::mem_categorization::{cat_discr, cat_local, cat_self, cat_special}; use middle::mem_categorization::{cat_stack_upvar, comp_field, comp_index}; @@ -291,7 +291,7 @@ priv impl &preserve_ctxt { Ok(pc_ok) => { match cmt_base.mutbl { m_mutbl | m_const => { - Ok(pc_if_pure({cmt:cmt, code:code})) + Ok(pc_if_pure(bckerr { cmt: cmt, code: code })) } m_imm => { Ok(pc_ok) @@ -318,8 +318,10 @@ priv impl &preserve_ctxt { if self.bccx.is_subregion_of(self.scope_region, scope_ub) { Ok(pc_ok) } else { - Err({cmt:cmt, code:err_out_of_scope(scope_ub, - self.scope_region)}) + Err(bckerr { + cmt:cmt, + code:err_out_of_scope(scope_ub, self.scope_region) + }) } } @@ -345,7 +347,7 @@ priv impl &preserve_ctxt { // would be sort of pointless to avoid rooting the inner // box by rooting an outer box, as it would just keep more // memory live than necessary, so we set root_ub to none. - return Err({cmt:cmt, code:err_root_not_permitted}); + return Err(bckerr { cmt: cmt, code: err_root_not_permitted }); } let root_region = ty::re_scope(self.root_ub); @@ -359,7 +361,7 @@ priv impl &preserve_ctxt { derefs, scope_id, self.root_ub); if self.bccx.is_subregion_of(self.scope_region, root_region) { debug!("Elected to root"); - let rk = {id: base.id, derefs: derefs}; + let rk = root_map_key { id: base.id, derefs: derefs }; // This code could potentially lead cause boxes to be frozen // for longer than necessarily at runtime. It prevents an // ICE in trans; the fundamental problem is that it's hard @@ -389,17 +391,20 @@ priv impl &preserve_ctxt { return Ok(pc_ok); } else { debug!("Unable to root"); - return Err({cmt:cmt, - code:err_out_of_root_scope(root_region, - self.scope_region)}); + return Err(bckerr { + cmt: cmt, + code: err_out_of_root_scope(root_region, + self.scope_region) + }); } } // we won't be able to root long enough _ => { - return Err({cmt:cmt, - code:err_out_of_root_scope(root_region, - self.scope_region)}); + return Err(bckerr { + cmt:cmt, + code:err_out_of_root_scope(root_region, self.scope_region) + }); } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 7c1e96e5c0e44..9ea03440ad6b4 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -113,27 +113,18 @@ enum special_kind { // which the value is stored. // // note: cmt stands for "categorized mutable type". -type cmt_ = {id: ast::node_id, // id of expr/pat producing this value - span: span, // span of same expr/pat - cat: categorization, // categorization of expr - lp: Option<@loan_path>, // loan path for expr, if any - mutbl: ast::mutability, // mutability of expr as lvalue - ty: ty::t}; // type of the expr +#[deriving_eq] +struct cmt_ { + id: ast::node_id, // id of expr/pat producing this value + span: span, // span of same expr/pat + cat: categorization, // categorization of expr + lp: Option<@loan_path>, // loan path for expr, if any + mutbl: ast::mutability, // mutability of expr as lvalue + ty: ty::t // type of the expr +} type cmt = @cmt_; -impl cmt_ : cmp::Eq { - pure fn eq(&self, other: &cmt_) -> bool { - (*self).id == (*other).id && - (*self).span == (*other).span && - (*self).cat == (*other).cat && - (*self).lp == (*other).lp && - (*self).mutbl == (*other).mutbl && - (*self).ty == (*other).ty - } - pure fn ne(&self, other: &cmt_) -> bool { !(*self).eq(other) } -} - // a loan path is like a category, but it exists only when the data is // interior to the stack frame. loan paths are used as the key to a // map indicating what is borrowed at any point in time. @@ -423,9 +414,14 @@ impl &mem_categorization_ctxt { ast::def_ty_param(*) | ast::def_struct(*) | ast::def_typaram_binder(*) | ast::def_region(_) | ast::def_label(_) | ast::def_self_ty(*) => { - @{id:id, span:span, - cat:cat_special(sk_static_item), lp:None, - mutbl:m_imm, ty:expr_ty} + @cmt_ { + id:id, + span:span, + cat:cat_special(sk_static_item), + lp:None, + mutbl:m_imm, + ty:expr_ty + } } ast::def_arg(vid, mode, mutbl) => { @@ -451,9 +447,14 @@ impl &mem_categorization_ctxt { None } }; - @{id:id, span:span, - cat:cat_arg(vid), lp:lp, - mutbl:m, ty:expr_ty} + @cmt_ { + id:id, + span:span, + cat:cat_arg(vid), + lp:lp, + mutbl:m, + ty:expr_ty + } } ast::def_self(self_id, is_implicit) => { @@ -466,9 +467,14 @@ impl &mem_categorization_ctxt { loan_path = Some(@lp_self); }; - @{id:id, span:span, - cat:cat, lp:loan_path, - mutbl:m_imm, ty:expr_ty} + @cmt_ { + id:id, + span:span, + cat:cat, + lp:loan_path, + mutbl:m_imm, + ty:expr_ty + } } ast::def_upvar(_, inner, fn_node_id, _) => { @@ -477,15 +483,25 @@ impl &mem_categorization_ctxt { match proto { ast::ProtoBorrowed => { let upcmt = self.cat_def(id, span, expr_ty, *inner); - @{id:id, span:span, - cat:cat_stack_upvar(upcmt), lp:upcmt.lp, - mutbl:upcmt.mutbl, ty:upcmt.ty} + @cmt_ { + id:id, + span:span, + cat:cat_stack_upvar(upcmt), + lp:upcmt.lp, + mutbl:upcmt.mutbl, + ty:upcmt.ty + } } ast::ProtoUniq | ast::ProtoBox => { // FIXME #2152 allow mutation of moved upvars - @{id:id, span:span, - cat:cat_special(sk_heap_upvar), lp:None, - mutbl:m_imm, ty:expr_ty} + @cmt_ { + id:id, + span:span, + cat:cat_special(sk_heap_upvar), + lp:None, + mutbl:m_imm, + ty:expr_ty + } } ast::ProtoBare => { self.tcx.sess.span_bug( @@ -497,16 +513,26 @@ impl &mem_categorization_ctxt { ast::def_local(vid, mutbl) => { let m = if mutbl {m_mutbl} else {m_imm}; - @{id:id, span:span, - cat:cat_local(vid), lp:Some(@lp_local(vid)), - mutbl:m, ty:expr_ty} + @cmt_ { + id:id, + span:span, + cat:cat_local(vid), + lp:Some(@lp_local(vid)), + mutbl:m, + ty:expr_ty + } } ast::def_binding(vid, _) => { // by-value/by-ref bindings are local variables - @{id:id, span:span, - cat:cat_local(vid), lp:Some(@lp_local(vid)), - mutbl:m_imm, ty:expr_ty} + @cmt_ { + id:id, + span:span, + cat:cat_local(vid), + lp:Some(@lp_local(vid)), + mutbl:m_imm, + ty:expr_ty + } } } } @@ -514,17 +540,25 @@ impl &mem_categorization_ctxt { fn cat_variant(arg: N, enum_did: ast::def_id, cmt: cmt) -> cmt { - @{id: arg.id(), span: arg.span(), - cat: cat_comp(cmt, comp_variant(enum_did)), - lp: cmt.lp.map(|l| @lp_comp(*l, comp_variant(enum_did)) ), - mutbl: cmt.mutbl, // imm iff in an immutable context - ty: self.tcx.ty(arg)} + @cmt_ { + id: arg.id(), + span: arg.span(), + cat: cat_comp(cmt, comp_variant(enum_did)), + lp: cmt.lp.map(|l| @lp_comp(*l, comp_variant(enum_did)) ), + mutbl: cmt.mutbl, // imm iff in an immutable context + ty: self.tcx.ty(arg) + } } fn cat_rvalue(elt: N, expr_ty: ty::t) -> cmt { - @{id:elt.id(), span:elt.span(), - cat:cat_rvalue, lp:None, - mutbl:m_imm, ty:expr_ty} + @cmt_ { + id:elt.id(), + span:elt.span(), + cat:cat_rvalue, + lp:None, + mutbl:m_imm, + ty:expr_ty + } } /// inherited mutability: used in cases where the mutability of a @@ -559,9 +593,14 @@ impl &mem_categorization_ctxt { let m = self.inherited_mutability(base_cmt.mutbl, f_mutbl); let f_comp = comp_field(f_name, f_mutbl); let lp = base_cmt.lp.map(|lp| @lp_comp(*lp, f_comp) ); - @{id: node.id(), span: node.span(), - cat: cat_comp(base_cmt, f_comp), lp:lp, - mutbl: m, ty: self.tcx.ty(node)} + @cmt_ { + id: node.id(), + span: node.span(), + cat: cat_comp(base_cmt, f_comp), + lp:lp, + mutbl: m, + ty: self.tcx.ty(node) + } } fn cat_deref_fn(node: N, @@ -628,17 +667,27 @@ impl &mem_categorization_ctxt { } }; - @{id:node.id(), span:node.span(), - cat:cat_deref(base_cmt, deref_cnt, ptr), lp:lp, - mutbl:m, ty:mt.ty} + @cmt_ { + id:node.id(), + span:node.span(), + cat:cat_deref(base_cmt, deref_cnt, ptr), + lp:lp, + mutbl:m, + ty:mt.ty + } } deref_comp(comp) => { let lp = base_cmt.lp.map(|l| @lp_comp(*l, comp) ); let m = self.inherited_mutability(base_cmt.mutbl, mt.mutbl); - @{id:node.id(), span:node.span(), - cat:cat_comp(base_cmt, comp), lp:lp, - mutbl:m, ty:mt.ty} + @cmt_ { + id:node.id(), + span:node.span(), + cat:cat_comp(base_cmt, comp), + lp:lp, + mutbl:m, + ty:mt.ty + } } } } @@ -675,9 +724,14 @@ impl &mem_categorization_ctxt { }; // (c) the deref is explicit in the resulting cmt - let deref_cmt = @{id:elt.id(), span:elt.span(), - cat:cat_deref(base_cmt, 0u, ptr), lp:deref_lp, - mutbl:m, ty:mt.ty}; + let deref_cmt = @cmt_ { + id:elt.id(), + span:elt.span(), + cat:cat_deref(base_cmt, 0u, ptr), + lp:deref_lp, + mutbl:m, + ty:mt.ty + }; comp(elt, deref_cmt, base_cmt.ty, m, mt.ty) } @@ -695,32 +749,48 @@ impl &mem_categorization_ctxt { { let comp = comp_index(vect, mutbl); let index_lp = of_cmt.lp.map(|lp| @lp_comp(*lp, comp) ); - @{id:elt.id(), span:elt.span(), - cat:cat_comp(of_cmt, comp), lp:index_lp, - mutbl:mutbl, ty:ty} + @cmt_ { + id:elt.id(), + span:elt.span(), + cat:cat_comp(of_cmt, comp), + lp:index_lp, + mutbl:mutbl, + ty:ty + } } } fn cat_tuple_elt(elt: N, cmt: cmt) -> cmt { - @{id: elt.id(), span: elt.span(), - cat: cat_comp(cmt, comp_tuple), - lp: cmt.lp.map(|l| @lp_comp(*l, comp_tuple) ), - mutbl: cmt.mutbl, // imm iff in an immutable context - ty: self.tcx.ty(elt)} + @cmt_ { + id: elt.id(), + span: elt.span(), + cat: cat_comp(cmt, comp_tuple), + lp: cmt.lp.map(|l| @lp_comp(*l, comp_tuple) ), + mutbl: cmt.mutbl, // imm iff in an immutable context + ty: self.tcx.ty(elt) + } } fn cat_anon_struct_field(elt: N, cmt: cmt) -> cmt { - @{id: elt.id(), span: elt.span(), - cat: cat_comp(cmt, comp_anon_field), - lp: cmt.lp.map(|l| @lp_comp(*l, comp_anon_field)), - mutbl: cmt.mutbl, // imm iff in an immutable context - ty: self.tcx.ty(elt)} + @cmt_ { + id: elt.id(), + span: elt.span(), + cat: cat_comp(cmt, comp_anon_field), + lp: cmt.lp.map(|l| @lp_comp(*l, comp_anon_field)), + mutbl: cmt.mutbl, // imm iff in an immutable context + ty: self.tcx.ty(elt) + } } fn cat_method_ref(expr: @ast::expr, expr_ty: ty::t) -> cmt { - @{id:expr.id, span:expr.span, - cat:cat_special(sk_method), lp:None, - mutbl:m_imm, ty:expr_ty} + @cmt_ { + id:expr.id, + span:expr.span, + cat:cat_special(sk_method), + lp:None, + mutbl:m_imm, + ty:expr_ty + } } fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) { diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index dd355f6df702c..ac3a16b07a0b1 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -397,17 +397,15 @@ fn resolve_crate(sess: Session, def_map: resolve::DefMap, // dependencies until a fixed point is reached. type region_paramd_items = HashMap; -type region_dep = {ambient_variance: region_variance, id: ast::node_id}; -type dep_map = HashMap>; -impl region_dep : cmp::Eq { - pure fn eq(&self, other: ®ion_dep) -> bool { - (*self).ambient_variance == (*other).ambient_variance && - (*self).id == (*other).id - } - pure fn ne(&self, other: ®ion_dep) -> bool { !(*self).eq(other) } +#[deriving_eq] +struct region_dep { + ambient_variance: region_variance, + id: ast::node_id } +type dep_map = HashMap>; + type determine_rp_ctxt_ = { sess: Session, ast_map: ast_map::map, @@ -511,7 +509,10 @@ impl determine_rp_ctxt { vec } }; - let dep = {ambient_variance: self.ambient_variance, id: self.item_id}; + let dep = region_dep { + ambient_variance: self.ambient_variance, + id: self.item_id + }; if !vec.contains(&dep) { vec.push(dep); } } diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index db266464860c3..084f0ba421e08 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -910,7 +910,8 @@ fn root_pats_as_necessary(bcx: block, for vec::each(m) |br| { let pat_id = br.pats[col].id; - match bcx.ccx().maps.root_map.find({id:pat_id, derefs:0u}) { + let key = root_map_key {id: pat_id, derefs: 0u }; + match bcx.ccx().maps.root_map.find(key) { None => (), Some(root_info) => { // Note: the scope_id will always be the id of the match. See diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 3bf1547a7d942..f4814b4657b97 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -61,6 +61,7 @@ use middle::trans::reachable; use middle::trans::shape::*; use middle::trans::tvec; use middle::trans::type_of::*; +use middle::ty::arg; use util::common::indenter; use util::ppaux::{ty_to_str, ty_to_short_str}; use util::ppaux; @@ -2198,9 +2199,12 @@ fn create_main_wrapper(ccx: @crate_ctxt, _sp: span, main_llfn: ValueRef) { fn create_main(ccx: @crate_ctxt, main_llfn: ValueRef) -> ValueRef { let unit_ty = ty::mk_estr(ccx.tcx, ty::vstore_uniq); let vecarg_ty: ty::arg = - {mode: ast::expl(ast::by_val), - ty: ty::mk_evec(ccx.tcx, ty::mt {ty: unit_ty, mutbl: ast::m_imm}, - ty::vstore_uniq)}; + arg { + mode: ast::expl(ast::by_val), + ty: ty::mk_evec(ccx.tcx, + ty::mt {ty: unit_ty, mutbl: ast::m_imm}, + ty::vstore_uniq) + }; let nt = ty::mk_nil(ccx.tcx); let llfty = type_of_fn(ccx, ~[vecarg_ty], nt); let llfdecl = decl_fn(ccx.llmod, ~"_rust_main", diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 0128876a898f5..3babfbd8285fd 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -39,6 +39,7 @@ use middle::trans::reachable; use middle::trans::shape; use middle::trans::type_of; use middle::trans::type_use; +use middle::ty::substs; use middle::ty; use middle::typeck; use util::ppaux::{expr_repr, ty_to_str}; @@ -1459,9 +1460,11 @@ fn find_vtable(tcx: ty::ctxt, ps: ¶m_substs, } fn dummy_substs(+tps: ~[ty::t]) -> ty::substs { - {self_r: Some(ty::re_bound(ty::br_self)), - self_ty: None, - tps: tps} + substs { + self_r: Some(ty::re_bound(ty::br_self)), + self_ty: None, + tps: tps + } } fn struct_field(index: uint) -> [uint * 3] { diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 8c024b364c328..94145be2a1e31 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -98,7 +98,7 @@ use core::prelude::*; use lib::llvm::ValueRef; -use middle::borrowck::RootInfo; +use middle::borrowck::{RootInfo, root_map_key}; use middle::trans::base::*; use middle::trans::build::*; use middle::trans::common::*; @@ -652,7 +652,7 @@ impl Datum { // root the autoderef'd value, if necessary: // // (Note: root'd values are always boxes) - let key = {id:expr_id, derefs:derefs}; + let key = root_map_key { id: expr_id, derefs: derefs }; let bcx = match ccx.maps.root_map.find(key) { None => bcx, Some(root_info) => self.root(bcx, root_info) diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index ea9ddc2e5d0c7..24d8e94abbdba 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -114,6 +114,7 @@ lvalues are *never* stored by value. use core::prelude::*; use lib::llvm::ValueRef; +use middle::borrowck::root_map_key; use middle::resolve; use middle::trans::base::*; use middle::trans::callee::{AutorefArg, DoAutorefArg, DontAutorefArg}; @@ -757,7 +758,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { // If the lvalue must remain rooted, create a scratch datum, copy // the lvalue in there, and then arrange for it to be cleaned up // at the end of the scope with id `scope_id`: - let root_key = {id:expr.id, derefs:0u}; + let root_key = root_map_key { id: expr.id, derefs: 0u }; for bcx.ccx().maps.root_map.find(root_key).each |&root_info| { bcx = unrooted_datum.root(bcx, root_info); } diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index ac641222b3c29..317a64ea52875 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -31,7 +31,7 @@ use middle::trans::machine; use middle::trans::shape; use middle::trans::type_of::*; use middle::trans::type_of; -use middle::ty::{FnTyBase, FnMeta, FnSig}; +use middle::ty::{FnTyBase, FnMeta, FnSig, arg}; use util::ppaux::ty_to_str; use core::libc::c_uint; @@ -546,8 +546,8 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item, onceness: ast::Many, region: ty::re_bound(ty::br_anon(0)), bounds: @~[]}, - sig: FnSig {inputs: ~[{mode: ast::expl(ast::by_val), - ty: star_u8}], + sig: FnSig {inputs: ~[arg {mode: ast::expl(ast::by_val), + ty: star_u8}], output: ty::mk_nil(bcx.tcx())} }); let datum = Datum {val: get_param(decl, first_real_arg), diff --git a/src/librustc/middle/trans/machine.rs b/src/librustc/middle/trans/machine.rs index 5c0498d5a1470..7af3b7a06834a 100644 --- a/src/librustc/middle/trans/machine.rs +++ b/src/librustc/middle/trans/machine.rs @@ -13,6 +13,7 @@ use middle::trans::common::*; use middle::trans::type_of; +use middle::ty::field; use middle::ty; use syntax::parse::token::special_idents; @@ -44,13 +45,17 @@ pub fn simplify_type(tcx: ty::ctxt, typ: ty::t) -> ty::t { ty::ty_struct(did, ref substs) => { let simpl_fields = (if ty::ty_dtor(tcx, did).is_present() { // remember the drop flag - ~[{ident: special_idents::dtor, - mt: ty::mt {ty: ty::mk_u8(tcx), mutbl: ast::m_mutbl}}] } + ~[field { + ident: special_idents::dtor, + mt: ty::mt {ty: ty::mk_u8(tcx), mutbl: ast::m_mutbl} + }] } else { ~[] }) + do ty::lookup_struct_fields(tcx, did).map |f| { let t = ty::lookup_field_type(tcx, did, f.id, substs); - {ident: f.ident, - mt: ty::mt {ty: simplify_type(tcx, t), mutbl: ast::m_const}} + field { + ident: f.ident, + mt: ty::mt {ty: simplify_type(tcx, t), mutbl: ast::m_const + }} }; ty::mk_rec(tcx, simpl_fields) } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 7eccf97f76c31..a90c25abf3dd6 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -28,6 +28,7 @@ use middle::trans::glue; use middle::trans::inline; use middle::trans::monomorphize; use middle::trans::type_of::*; +use middle::ty::arg; use middle::typeck; use util::ppaux::{ty_to_str, tys_to_str}; @@ -154,8 +155,10 @@ fn trans_self_arg(bcx: block, let mut temp_cleanups = ~[]; // Compute the mode and type of self. - let self_arg = {mode: mentry.self_arg.mode, - ty: monomorphize_type(bcx, mentry.self_arg.ty)}; + let self_arg = arg { + mode: mentry.self_arg.mode, + ty: monomorphize_type(bcx, mentry.self_arg.ty) + }; let result = trans_arg_expr(bcx, self_arg, base, &mut temp_cleanups, None, DontAutorefArg); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 0726104788cda..8f1873f628f05 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -242,14 +242,23 @@ export AutoRefKind, AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn; export iter_bound_traits_and_supertraits; export count_traits_and_supertraits; export IntVarValue, IntType, UintType; +export creader_cache_key; // Data types // Note: after typeck, you should use resolved_mode() to convert this mode // into an rmode, which will take into account the results of mode inference. -type arg = {mode: ast::mode, ty: t}; +#[deriving_eq] +struct arg { + mode: ast::mode, + ty: t +} -type field = {ident: ast::ident, mt: mt}; +#[deriving_eq] +struct field { + ident: ast::ident, + mt: mt +} type param_bounds = @~[param_bound]; @@ -292,35 +301,38 @@ pub enum ValueMode { // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. -type creader_cache_key = {cnum: int, pos: uint, len: uint}; -type creader_cache = HashMap; - -impl creader_cache_key : cmp::Eq { - pure fn eq(&self, other: &creader_cache_key) -> bool { - (*self).cnum == (*other).cnum && - (*self).pos == (*other).pos && - (*self).len == (*other).len - } - pure fn ne(&self, other: &creader_cache_key) -> bool { - !((*self) == (*other)) - } +#[deriving_eq] +struct creader_cache_key { + cnum: int, + pos: uint, + len: uint } +type creader_cache = HashMap; + impl creader_cache_key : to_bytes::IterBytes { pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_3(&self.cnum, &self.pos, &self.len, lsb0, f); } } -type intern_key = {sty: *sty, o_def_id: Option}; +struct intern_key { + sty: *sty, + o_def_id: Option +} +// NB: Do not replace this with #[deriving_eq]. The automatically-derived +// implementation will not recurse through sty and you will get stack +// exhaustion. impl intern_key : cmp::Eq { pure fn eq(&self, other: &intern_key) -> bool { unsafe { *self.sty == *other.sty && self.o_def_id == other.o_def_id } } - pure fn ne(&self, other: &intern_key) -> bool { !(*self).eq(other) } + pure fn ne(&self, other: &intern_key) -> bool { + !self.eq(other) + } } impl intern_key : to_bytes::IterBytes { @@ -569,13 +581,10 @@ impl FnTyBase : to_bytes::IterBytes { type FnTy = FnTyBase; -type param_ty = {idx: uint, def_id: def_id}; - -impl param_ty : cmp::Eq { - pure fn eq(&self, other: ¶m_ty) -> bool { - (*self).idx == (*other).idx && (*self).def_id == (*other).def_id - } - pure fn ne(&self, other: ¶m_ty) -> bool { !(*self).eq(other) } +#[deriving_eq] +struct param_ty { + idx: uint, + def_id: def_id } impl param_ty : to_bytes::IterBytes { @@ -661,11 +670,12 @@ type opt_region = Option; * - `self_ty` is the type to which `self` should be remapped, if any. The * `self` type is rather funny in that it can only appear on traits and is * always substituted away to the implementing type for a trait. */ -type substs = { +#[deriving_eq] +struct substs { self_r: opt_region, self_ty: Option, tps: ~[t] -}; +} // NB: If you change this, you'll probably want to change the corresponding // AST structure in libsyntax/ast.rs as well. @@ -1044,7 +1054,7 @@ fn mk_t(cx: ctxt, +st: sty) -> t { mk_t_with_id(cx, st, None) } // Interns a type/name combination, stores the resulting box in cx.interner, // and returns the box as cast to an unsafe ptr (see comments for t above). fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: Option) -> t { - let key = {sty: to_unsafe_ptr(&st), o_def_id: o_def_id}; + let key = intern_key { sty: to_unsafe_ptr(&st), o_def_id: o_def_id }; match cx.interner.find(key) { Some(t) => unsafe { return cast::reinterpret_cast(&t); }, _ => () @@ -1103,7 +1113,7 @@ fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: Option) -> t { let t = @{sty: move st, id: cx.next_id, flags: flags, o_def_id: o_def_id}; - let key = {sty: to_unsafe_ptr(&t.sty), o_def_id: o_def_id}; + let key = intern_key {sty: to_unsafe_ptr(&t.sty), o_def_id: o_def_id}; cx.interner.insert(move key, t); cx.next_id += 1u; @@ -1236,7 +1246,7 @@ fn mk_infer(cx: ctxt, +it: InferTy) -> t { mk_t(cx, ty_infer(it)) } fn mk_self(cx: ctxt) -> t { mk_t(cx, ty_self) } fn mk_param(cx: ctxt, n: uint, k: def_id) -> t { - mk_t(cx, ty_param({idx: n, def_id: k})) + mk_t(cx, ty_param(param_ty { idx: n, def_id: k })) } fn mk_type(cx: ctxt) -> t { mk_t(cx, ty_type) } @@ -1352,7 +1362,7 @@ fn fold_sty_to_ty(tcx: ty::ctxt, sty: &sty, foldop: fn(t) -> t) -> t { fn fold_sig(sig: &FnSig, fldop: fn(t) -> t) -> FnSig { let args = do sig.inputs.map |arg| { - { mode: arg.mode, ty: fldop(arg.ty) } + arg { mode: arg.mode, ty: fldop(arg.ty) } }; FnSig { @@ -1363,9 +1373,9 @@ fn fold_sig(sig: &FnSig, fldop: fn(t) -> t) -> FnSig { fn fold_sty(sty: &sty, fldop: fn(t) -> t) -> sty { fn fold_substs(substs: &substs, fldop: fn(t) -> t) -> substs { - {self_r: substs.self_r, - self_ty: substs.self_ty.map(|t| fldop(*t)), - tps: substs.tps.map(|t| fldop(*t))} + substs {self_r: substs.self_r, + self_ty: substs.self_ty.map(|t| fldop(*t)), + tps: substs.tps.map(|t| fldop(*t))} } match /*bad*/copy *sty { @@ -1393,8 +1403,8 @@ fn fold_sty(sty: &sty, fldop: fn(t) -> t) -> sty { ty_rec(fields) => { let new_fields = do vec::map(fields) |fl| { let new_ty = fldop(fl.mt.ty); - let new_mt = mt {ty: new_ty, mutbl: fl.mt.mutbl}; - {ident: fl.ident, mt: new_mt} + let new_mt = mt { ty: new_ty, mutbl: fl.mt.mutbl }; + field { ident: fl.ident, mt: new_mt } }; ty_rec(new_fields) } @@ -1451,11 +1461,13 @@ fn fold_regions_and_ty( fn fold_substs( substs: &substs, fldr: fn(r: Region) -> Region, - fldt: fn(t: t) -> t) -> substs - { - {self_r: substs.self_r.map(|r| fldr(*r)), - self_ty: substs.self_ty.map(|t| fldt(*t)), - tps: substs.tps.map(|t| fldt(*t))} + fldt: fn(t: t) -> t) + -> substs { + substs { + self_r: substs.self_r.map(|r| fldr(*r)), + self_ty: substs.self_ty.map(|t| fldt(*t)), + tps: substs.tps.map(|t| fldt(*t)) + } } let tb = ty::get(ty); @@ -1671,7 +1683,7 @@ fn subst(cx: ctxt, // Performs substitutions on a set of substitutions (result = sup(sub)) to // yield a new set of substitutions. This is used in trait inheritance. fn subst_substs(cx: ctxt, sup: &substs, sub: &substs) -> substs { - { + substs { self_r: sup.self_r, self_ty: sup.self_ty.map(|typ| subst(cx, sub, *typ)), tps: sup.tps.map(|typ| subst(cx, sub, *typ)) @@ -4152,7 +4164,7 @@ fn struct_item_fields(cx:ctxt, do lookup_struct_fields(cx, did).map |f| { // consider all instance vars mut, because the // constructor may mutate all vars - { + field { ident: f.ident, mt: mt { ty: lookup_field_type(cx, did, f.id, substs), @@ -4281,9 +4293,11 @@ fn normalize_ty(cx: ctxt, t: t) -> t { Some(_) => // Use re_static since trans doesn't care about regions mk_enum(cx, did, - {self_r: Some(ty::re_static), - self_ty: None, - tps: /*bad*/copy (*r).tps}), + substs { + self_r: Some(ty::re_static), + self_ty: None, + tps: /*bad*/copy (*r).tps + }), None => t }, @@ -4292,9 +4306,9 @@ fn normalize_ty(cx: ctxt, t: t) -> t { match (*r).self_r { Some(_) => // Ditto. - mk_struct(cx, did, {self_r: Some(ty::re_static), - self_ty: None, - tps: /*bad*/copy (*r).tps}), + mk_struct(cx, did, substs {self_r: Some(ty::re_static), + self_ty: None, + tps: /*bad*/copy (*r).tps}), None => t }, @@ -4414,20 +4428,6 @@ impl mt : cmp::Eq { pure fn ne(&self, other: &mt) -> bool { !(*self).eq(other) } } -impl arg : cmp::Eq { - pure fn eq(&self, other: &arg) -> bool { - (*self).mode == (*other).mode && (*self).ty == (*other).ty - } - pure fn ne(&self, other: &arg) -> bool { !(*self).eq(other) } -} - -impl field : cmp::Eq { - pure fn eq(&self, other: &field) -> bool { - (*self).ident == (*other).ident && (*self).mt == (*other).mt - } - pure fn ne(&self, other: &field) -> bool { !(*self).eq(other) } -} - impl vstore : cmp::Eq { pure fn eq(&self, other: &vstore) -> bool { match (*self) { @@ -4536,15 +4536,6 @@ impl bound_region : cmp::Eq { pure fn ne(&self, other: &bound_region) -> bool { !(*self).eq(other) } } -impl substs : cmp::Eq { - pure fn eq(&self, other: &substs) -> bool { - (*self).self_r == (*other).self_r && - (*self).self_ty == (*other).self_ty && - (*self).tps == (*other).tps - } - pure fn ne(&self, other: &substs) -> bool { !(*self).eq(other) } -} - impl sty : cmp::Eq { pure fn eq(&self, other: &sty) -> bool { match (/*bad*/copy *self) { diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 7e1c5f54134e1..e845904956d95 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -55,7 +55,8 @@ use core::prelude::*; use middle::pat_util::pat_id_map; -use middle::ty::{FnTyBase, FnMeta, FnSig, ty_param_substs_and_ty}; +use middle::ty::{FnTyBase, FnMeta, FnSig, arg, field, substs}; +use middle::ty::{ty_param_substs_and_ty}; use middle::ty; use middle::typeck::check::fn_ctxt; use middle::typeck::collect; @@ -151,7 +152,7 @@ fn ast_path_to_substs_and_ty( } let tps = path.types.map(|a_t| ast_ty_to_ty(self, rscope, *a_t)); - let substs = {self_r:self_r, self_ty:None, tps:tps}; + let substs = substs {self_r:self_r, self_ty:None, tps:tps}; let ty = ty::subst(tcx, &substs, decl_ty); {substs: substs, ty: ty} } @@ -315,7 +316,7 @@ fn ast_ty_to_ty( ast::ty_rec(ref fields) => { let flds = do (*fields).map |f| { let tm = ast_mt_to_mt(self, rscope, f.node.mt); - {ident: f.node.ident, mt: tm} + field {ident: f.node.ident, mt: tm} }; ty::mk_rec(tcx, flds) } @@ -447,7 +448,7 @@ fn ty_of_arg( } }; - {mode: mode, ty: ty} + arg {mode: mode, ty: ty} } type expected_tys = Option<{inputs: ~[ty::arg], diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 86f58edd6c8a8..543adbd53aac8 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -295,7 +295,11 @@ impl LookupContext { let self_did = self.fcx.self_info.expect( ~"self_impl_def_id is undefined (`self` may not \ be in scope here").def_id; - let substs = {self_r: None, self_ty: None, tps: ~[]}; + let substs = substs { + self_r: None, + self_ty: None, + tps: ~[] + }; self.push_inherent_candidates_from_self( self_ty, self_did, &substs); } @@ -392,7 +396,10 @@ impl LookupContext { // impl or class (where the self type is not permitted), // or from a trait type (in which case methods that refer // to self are not permitted). - let init_substs = {self_ty: Some(rcvr_ty), ..init_substs}; + let init_substs = substs { + self_ty: Some(rcvr_ty), + ..init_substs + }; worklist.push((init_trait_ty, init_substs)); @@ -416,7 +423,10 @@ impl LookupContext { &init_substs); // Again replacing the self type - let new_substs = {self_ty: Some(rcvr_ty), ..new_substs}; + let new_substs = substs { + self_ty: Some(rcvr_ty), + ..new_substs + }; worklist.push((supertrait.tpt.ty, new_substs)); } @@ -506,7 +516,10 @@ impl LookupContext { // `trait_ty` for `self` here, because it allows the compiler // to soldier on. An error will be reported should this // candidate be selected if the method refers to `self`. - let rcvr_substs = {self_ty: Some(self_ty), ../*bad*/copy *substs}; + let rcvr_substs = substs { + self_ty: Some(self_ty), + ../*bad*/copy *substs + }; let (rcvr_ty, rcvr_substs) = self.create_rcvr_ty_and_substs_for_method(method.self_ty, @@ -537,7 +550,10 @@ impl LookupContext { } let method = &methods[index]; - let rcvr_substs = { self_ty: Some(self_ty), ../*bad*/copy *substs }; + let rcvr_substs = substs { + self_ty: Some(self_ty), + ../*bad*/copy *substs + }; let (rcvr_ty, rcvr_substs) = self.create_rcvr_ty_and_substs_for_method( method.self_ty, @@ -628,7 +644,11 @@ impl LookupContext { candidate"); // XXX: Needs to support generics. - let dummy_substs = { self_r: None, self_ty: None, tps: ~[] }; + let dummy_substs = substs { + self_r: None, + self_ty: None, + tps: ~[] + }; let (impl_ty, impl_substs) = self.create_rcvr_ty_and_substs_for_method( provided_method_info.method_info.self_type, @@ -673,11 +693,13 @@ impl LookupContext { move self_substs } sty_region(_) => { - {self_r: - Some(self.infcx().next_region_var( - self.expr.span, - self.expr.id)), - ..self_substs} + substs { + self_r: + Some(self.infcx().next_region_var( + self.expr.span, + self.expr.id)), + ..self_substs + } } } }; @@ -1058,7 +1080,7 @@ impl LookupContext { // Construct the full set of type parameters for the method, // which is equal to the class tps + the method tps. - let all_substs = { + let all_substs = substs { tps: vec::append(/*bad*/copy candidate.rcvr_substs.tps, m_substs), ../*bad*/copy candidate.rcvr_substs @@ -1066,7 +1088,7 @@ impl LookupContext { self.fcx.write_ty_substs(self.callee_id, fty, all_substs); method_map_entry { - self_arg: { + self_arg: arg { mode: ast::expl(candidate.self_mode), ty: candidate.rcvr_ty, }, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index cf13fcb86e818..3d5f6e9d303d9 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -84,7 +84,7 @@ use middle::pat_util::pat_id_map; use middle::pat_util; use middle::ty::{TyVid, Vid, FnTyBase, FnMeta, FnSig, VariantInfo_, field}; use middle::ty::{ty_param_bounds_and_ty, ty_param_substs_and_ty}; -use middle::ty::{re_bound, br_cap_avoid}; +use middle::ty::{re_bound, br_cap_avoid, substs, arg, param_ty}; use middle::ty; use middle::typeck::astconv::{ast_conv, ast_path_to_ty}; use middle::typeck::astconv::{ast_region_to_region, ast_ty_to_ty}; @@ -1059,9 +1059,11 @@ pub fn impl_self_ty(vcx: &VtableContext, {n_tps: ts.len(), region_param: region_param, raw_ty: ty::mk_struct(tcx, local_def(class_id), - {self_r: rscope::bound_self_region(region_param), - self_ty: None, - tps: ty::ty_params_to_tys(tcx, /*bad*/copy *ts)})} + substs { + self_r: rscope::bound_self_region(region_param), + self_ty: None, + tps: ty::ty_params_to_tys(tcx, /*bad*/copy *ts) + })} } _ => { tcx.sess.bug(~"impl_self_ty: unbound item or item that \ doesn't have a self_ty"); } @@ -1081,7 +1083,7 @@ pub fn impl_self_ty(vcx: &VtableContext, }; let tps = vcx.infcx.next_ty_vars(n_tps); - let substs = {self_r: self_r, self_ty: None, tps: tps}; + let substs = substs { self_r: self_r, self_ty: None, tps: tps }; let substd_ty = ty::subst(tcx, &substs, raw_ty); {substs: substs, ty: substd_ty} } @@ -1814,7 +1816,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, let self_region = bound_self_region(region_parameterized); - raw_type = ty::mk_struct(tcx, class_id, { + raw_type = ty::mk_struct(tcx, class_id, substs { self_r: self_region, self_ty: None, tps: ty::ty_params_to_tys( @@ -1840,7 +1842,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, span, ty::re_scope(id)); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); - let substitutions = { + let substitutions = substs { self_r: self_region, self_ty: None, tps: type_parameters @@ -1897,7 +1899,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, let self_region = bound_self_region(region_parameterized); - raw_type = ty::mk_enum(tcx, enum_id, { + raw_type = ty::mk_enum(tcx, enum_id, substs { self_r: self_region, self_ty: None, tps: ty::ty_params_to_tys( @@ -1923,7 +1925,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, span, ty::re_scope(id)); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); - let substitutions = { + let substitutions = substs { self_r: self_region, self_ty: None, tps: type_parameters @@ -2434,7 +2436,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, let expr_mt = ty::mt {ty: expr_t, mutbl: f.node.mutbl}; // for the most precise error message, // should be f.node.expr.span, not f.span - respan(f.node.expr.span, {ident: f.node.ident, mt: expr_mt}) + respan(f.node.expr.span, field {ident: f.node.ident, mt: expr_mt}) }); match base { None => { @@ -2951,7 +2953,7 @@ fn instantiate_path(fcx: @fn_ctxt, pth.types.map(|aty| fcx.to_ty(*aty)) }; - let substs = {self_r: self_r, self_ty: None, tps: tps}; + let substs = substs { self_r: self_r, self_ty: None, tps: tps }; fcx.write_ty_substs(node_id, tpt.ty, substs); debug!("<<<"); @@ -3050,7 +3052,7 @@ fn check_bounds_are_used(ccx: @crate_ctxt, |_r| {}, |t| { match ty::get(t).sty { - ty::ty_param({idx, _}) => { + ty::ty_param(param_ty {idx, _}) => { debug!("Found use of ty param #%u", idx); tps_used[idx] = true; } @@ -3073,7 +3075,7 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) { ty::mk_param(ccx.tcx, n, local_def(0)) } fn arg(m: ast::rmode, ty: ty::t) -> ty::arg { - {mode: ast::expl(m), ty: ty} + arg {mode: ast::expl(m), ty: ty} } let tcx = ccx.tcx; let (n_tps, inputs, output) = match ccx.tcx.sess.str_of(it.ident) { @@ -3136,12 +3138,14 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) { onceness: ast::Once, region: ty::re_bound(ty::br_anon(0)), bounds: @~[]}, - sig: FnSig {inputs: ~[{mode: ast::expl(ast::by_val), - ty: ty::mk_imm_ptr( - ccx.tcx, - ty::mk_mach_uint(ccx.tcx, ast::ty_u8)) - }], - output: ty::mk_nil(ccx.tcx)} + sig: FnSig { + inputs: ~[arg { + mode: ast::expl(ast::by_val), + ty: ty::mk_imm_ptr( + ccx.tcx, + ty::mk_mach_uint(ccx.tcx, ast::ty_u8)) + }], + output: ty::mk_nil(ccx.tcx)} }); (0u, ~[arg(ast::by_ref, fty)], ty::mk_nil(tcx)) } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 9d309d4996bdd..9f6cc6835b715 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -11,6 +11,7 @@ use core::prelude::*; use middle::resolve; +use middle::ty::{param_ty, substs}; use middle::ty; use middle::typeck::check::{fn_ctxt, impl_self_ty}; use middle::typeck::check::{structurally_resolved_type}; @@ -103,7 +104,10 @@ fn lookup_vtables(vcx: &VtableContext, ppaux::ty_to_str(tcx, trait_ty), ty::substs_to_str(tcx, substs)); - let new_substs = {self_ty: Some(*ty), ../*bad*/copy *substs}; + let new_substs = substs { + self_ty: Some(*ty), + ../*bad*/copy *substs + }; let trait_ty = ty::subst(tcx, &new_substs, trait_ty); debug!("after subst: %?", @@ -189,7 +193,7 @@ fn lookup_vtable(vcx: &VtableContext, }; match ty::get(ty).sty { - ty::ty_param({idx: n, def_id: did}) => { + ty::ty_param(param_ty {idx: n, def_id: did}) => { let mut n_bound = 0; let bounds = tcx.ty_param_bounds.get(did.node); for ty::iter_bound_traits_and_supertraits( diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index e5dc91b7f179a..c5374af2dd060 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -15,6 +15,7 @@ use core::prelude::*; use middle::pat_util; +use middle::ty::arg; use middle::ty; use middle::typeck::check::{fn_ctxt, self_info}; use middle::typeck::infer::{force_all, resolve_all, resolve_region}; @@ -65,7 +66,7 @@ fn resolve_method_map_entry(fcx: @fn_ctxt, sp: span, id: ast::node_id) fcx.ccx.method_map.insert( id, method_map_entry { - self_arg: {mode: mme.self_arg.mode, ty: *t}, + self_arg: arg {mode: mme.self_arg.mode, ty: *t}, .. *mme } ); diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index b0c98cfa2b17e..4cd2eaaf003c9 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -25,8 +25,8 @@ use metadata::decoder::{dl_def, dl_field, dl_impl}; use middle::resolve::{Impl, MethodInfo}; use middle::ty::{ProvidedMethodSource, ProvidedMethodInfo, bound_copy, get}; use middle::ty::{kind_can_be_copied, lookup_item_type, param_bounds, subst}; -use middle::ty::{t, ty_bool, ty_bot, ty_box, ty_enum, ty_err, ty_estr}; -use middle::ty::{ty_evec, ty_float, ty_fn, ty_infer, ty_int, ty_nil}; +use middle::ty::{substs, t, ty_bool, ty_bot, ty_box, ty_enum, ty_err}; +use middle::ty::{ty_estr, ty_evec, ty_float, ty_fn, ty_infer, ty_int, ty_nil}; use middle::ty::{ty_opaque_box, ty_param, ty_param_bounds_and_ty, ty_ptr}; use middle::ty::{ty_rec, ty_rptr, ty_self, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_type, ty_uint, ty_uniq}; @@ -34,6 +34,7 @@ use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, type_kind_ext}; use middle::ty::{type_is_ty_var}; use middle::ty; use middle::typeck::crate_ctxt; +use middle::typeck::infer::combine::Combine; use middle::typeck::infer::{InferCtxt, can_mk_subty}; use middle::typeck::infer::{new_infer_ctxt, resolve_ivar}; use middle::typeck::infer::{resolve_nested_tvar, resolve_type}; @@ -286,8 +287,8 @@ impl CoherenceChecker { } // Add the implementation to the mapping from implementation to base - // type def ID, if there is a base type for this implementation. - + // type def ID, if there is a base type for this implementation and + // the implementation does not have any associated traits. match get_base_type_def_id(self.inference_context, item.span, self_type.ty) { @@ -296,16 +297,19 @@ impl CoherenceChecker { } Some(base_type_def_id) => { // XXX: Gather up default methods? - let implementation; - match implementation_opt { - None => { - implementation = self.create_impl_from_item(item); - } - Some(copy existing_implementation) => { - implementation = existing_implementation; + if associated_traits.len() == 0 { + let implementation; + match implementation_opt { + None => { + implementation = self.create_impl_from_item(item); + } + Some(copy existing_implementation) => { + implementation = existing_implementation; + } } + self.add_inherent_method(base_type_def_id, + implementation); } - self.add_inherent_method(base_type_def_id, implementation); self.base_type_def_ids.insert(local_def(item.id), base_type_def_id); @@ -510,7 +514,7 @@ impl CoherenceChecker { let type_parameters = self.inference_context.next_ty_vars(bounds_count); - let substitutions = { + let substitutions = substs { self_r: self_region, self_ty: None, tps: type_parameters @@ -520,7 +524,8 @@ impl CoherenceChecker { polytype.ty); // Get our type parameters back. - let { self_r: _, self_ty: _, tps: type_parameters } = substitutions; + let substs { self_r: _, self_ty: _, tps: type_parameters } = + substitutions; UniversalQuantificationResult { monotype: monotype, @@ -597,6 +602,7 @@ impl CoherenceChecker { visit_mod(module_, item.span, item.id, (), visitor); } item_impl(_, opt_trait, _, _) => { + let mut ok = false; match self.base_type_def_ids.find( local_def(item.id)) { @@ -611,57 +617,50 @@ impl CoherenceChecker { // Record that this implementation is OK. self.privileged_implementations.insert (item.id, ()); - } else { - // This implementation is not in scope of - // its base type. This still might be OK - // if the traits are defined in the same - // crate. - - match opt_trait { - None => { - // There is no trait to implement, so - // this is an error. - - let session = - self.crate_context.tcx.sess; - session.span_err(item.span, - ~"cannot implement \ - inherent methods \ - for a type outside \ - the crate the type \ - was defined in; \ - define and \ - implement a trait \ - or new type \ - instead"); - } - _ => () - } - - do opt_trait.iter() |trait_ref| { - // This is OK if and only if the - // trait was defined in this - // crate. - - let trait_def_id = - self.trait_ref_to_trait_def_id( - *trait_ref); - - if trait_def_id.crate != local_crate { - let session = - self.crate_context.tcx.sess; - session.span_err(item.span, - ~"cannot \ - provide an \ - extension \ - implementa\ - tion \ - for a trait \ - not defined \ - in this \ - crate"); - } - } + ok = true; + } + } + } + + if !ok { + // This implementation is not in scope of its base + // type. This still might be OK if the trait is + // defined in the same crate. + + match opt_trait { + None => { + // There is no trait to implement, so + // this is an error. + + let session = self.crate_context.tcx.sess; + session.span_err(item.span, + ~"cannot implement \ + inherent methods for a \ + type outside the crate \ + the type was defined \ + in; define and \ + implement a trait or \ + new type instead"); + } + _ => () + } + + do opt_trait.iter() |trait_ref| { + // This is OK if and only if the trait was + // defined in this crate. + + let trait_def_id = + self.trait_ref_to_trait_def_id( + *trait_ref); + + if trait_def_id.crate != local_crate { + let session = self.crate_context.tcx.sess; + session.span_err(item.span, + ~"cannot provide an \ + extension \ + implementation for a \ + trait not defined in \ + this crate"); } } } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index ba34846ca97ce..ce0c7a94c7cc0 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -33,8 +33,8 @@ are represented as `ty_param()` instances. use core::prelude::*; use metadata::csearch; -use middle::ty::{FnMeta, FnSig, FnTyBase, InstantiatedTraitRef}; -use middle::ty::{ty_param_substs_and_ty}; +use middle::ty::{FnMeta, FnSig, FnTyBase, InstantiatedTraitRef, arg}; +use middle::ty::{substs, ty_param_substs_and_ty}; use middle::ty; use middle::typeck::astconv::{ast_conv, ty_of_fn_decl, ty_of_arg}; use middle::typeck::astconv::{ast_ty_to_ty}; @@ -75,7 +75,11 @@ fn collect_item_types(ccx: @crate_ctxt, crate: @ast::crate) { for m.items.each |intrinsic_item| { let def_id = ast::def_id { crate: ast::local_crate, node: intrinsic_item.id }; - let substs = {self_r: None, self_ty: None, tps: ~[]}; + let substs = substs { + self_r: None, + self_ty: None, + tps: ~[] + }; match intrinsic_item.node { ast::item_trait(*) => { @@ -164,7 +168,7 @@ fn get_enum_variant_types(ccx: @crate_ctxt, let rs = type_rscope(rp); let args = args.map(|va| { let arg_ty = ccx.to_ty(rs, va.ty); - {mode: ast::expl(ast::by_copy), ty: arg_ty} + arg { mode: ast::expl(ast::by_copy), ty: arg_ty } }); result_ty = Some(ty::mk_fn(tcx, FnTyBase { meta: FnMeta {purity: ast::pure_fn, @@ -195,8 +199,9 @@ fn get_enum_variant_types(ccx: @crate_ctxt, variant.node.id); // Compute the ctor arg types from the struct fields let struct_fields = do struct_def.fields.map |struct_field| { - {mode: ast::expl(ast::by_val), - ty: ty::node_id_to_type(ccx.tcx, (*struct_field).node.id) + arg { + mode: ast::expl(ast::by_val), + ty: ty::node_id_to_type(ccx.tcx, struct_field.node.id) } }; result_ty = Some(ty::mk_fn(tcx, FnTyBase { @@ -265,8 +270,11 @@ fn ensure_trait_methods(ccx: @crate_ctxt, id: ast::node_id, trait_ty: ty::t) { ty::mk_param(ccx.tcx, i + 1, dummy_defid) }; - let substs = { self_r: None, self_ty: Some(self_param), - tps: non_shifted_trait_tps + shifted_method_tps }; + let substs = substs { + self_r: None, + self_ty: Some(self_param), + tps: non_shifted_trait_tps + shifted_method_tps + }; let ty = ty::subst(ccx.tcx, &substs, ty::mk_fn(ccx.tcx, /*bad*/copy m.fty)); @@ -462,7 +470,7 @@ fn compare_impl_method(tcx: ty::ctxt, }; let trait_tps = trait_substs.tps.map( |t| replace_bound_self(tcx, *t, dummy_self_r)); - let substs = { + let substs = substs { self_r: Some(dummy_self_r), self_ty: Some(self_ty), tps: vec::append(trait_tps, dummy_tps) @@ -705,7 +713,7 @@ fn convert_struct(ccx: @crate_ctxt, }, sig: FnSig { inputs: do struct_def.fields.map |field| { - { + arg { mode: ast::expl(ast::by_copy), ty: ccx.tcx.tcache.get (local_def(field.node.id)).ty @@ -1002,5 +1010,8 @@ fn mk_substs(ccx: @crate_ctxt, -> {bounds: @~[ty::param_bounds], substs: ty::substs} { let {bounds, params} = mk_ty_params(ccx, atps); let self_r = rscope::bound_self_region(rp); - {bounds: bounds, substs: {self_r: self_r, self_ty: None, tps: params}} + { + bounds: bounds, + substs: substs { self_r: self_r, self_ty: None, tps: params } + } } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index e9946ae7c13e6..d1c57a21a3b2f 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -57,7 +57,7 @@ use core::prelude::*; use middle::ty::{FloatVar, FnTyBase, FnMeta, FnSig, IntVar, TyVar}; -use middle::ty::{IntType, UintType}; +use middle::ty::{IntType, UintType, arg, substs}; use middle::ty; use middle::typeck::infer::glb::Glb; use middle::typeck::infer::lub::Lub; @@ -233,7 +233,11 @@ fn super_substs( do relate_region_param(self, did, a.self_r, b.self_r).chain |self_r| { - Ok({self_r: self_r, self_ty: self_ty, tps: /*bad*/copy tps}) + Ok(substs { + self_r: self_r, + self_ty: self_ty, + tps: /*bad*/copy tps + }) } } } @@ -295,7 +299,7 @@ fn super_flds( if a.ident == b.ident { self.mts(a.mt, b.mt) - .chain(|mt| Ok({ident: a.ident, mt: mt}) ) + .chain(|mt| Ok(ty::field {ident: a.ident, mt: mt}) ) .chain_err(|e| Err(ty::terr_in_field(@e, a.ident)) ) } else { Err(ty::terr_record_fields( @@ -317,7 +321,7 @@ fn super_args( do self.modes(a.mode, b.mode).chain |m| { do self.contratys(a.ty, b.ty).chain |t| { - Ok({mode: m, ty: t}) + Ok(arg {mode: m, ty: t}) } } } @@ -587,4 +591,4 @@ fn super_tys( if_ok!(self.infcx().simple_var_t(vid_is_expected, vid, val)); Ok(ty::mk_mach_float(tcx, val)) } -} \ No newline at end of file +} diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index cac5fa5feb1c1..cab40ce21b154 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -255,7 +255,7 @@ use middle::ty::IntVarValue; use middle::ty; use middle::typeck::check::regionmanip::{replace_bound_regions_in_fn_sig}; use middle::typeck::infer::coercion::Coerce; -use middle::typeck::infer::combine::{CombineFields, eq_tys}; +use middle::typeck::infer::combine::{Combine, CombineFields, eq_tys}; use middle::typeck::infer::glb::Glb; use middle::typeck::infer::lub::Lub; use middle::typeck::infer::region_inference::{RegionVarBindings}; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index ac079f8f04450..fb9e0f36c2f25 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -17,7 +17,7 @@ use middle::ty::{bound_copy, bound_const, bound_durable, bound_owned, use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid, br_fresh}; use middle::ty::{ctxt, field, method}; -use middle::ty::{mt, t, param_bound}; +use middle::ty::{mt, t, param_bound, param_ty}; use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region}; use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{ty_bool, ty_bot, ty_box, ty_struct, ty_enum}; @@ -292,9 +292,8 @@ fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str { } fn ty_to_str(cx: ctxt, typ: t) -> ~str { - fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) -> - ~str { - let {mode, ty} = input; + fn fn_input_to_str(cx: ctxt, input: ty::arg) -> ~str { + let ty::arg {mode: mode, ty: ty} = input; let modestr = match canon_mode(cx, mode) { ast::infer(_) => ~"", ast::expl(m) => { @@ -423,7 +422,7 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str { } ty_infer(infer_ty) => infer_ty.to_str(), ty_err => ~"[type error]", - ty_param({idx: id, _}) => { + ty_param(param_ty {idx: id, _}) => { ~"'" + str::from_bytes(~[('a' as u8) + (id as u8)]) } ty_self => ~"self", diff --git a/src/librustdoc/astsrv.rs b/src/librustdoc/astsrv.rs index 99cf301f18248..bc332615eaa0e 100644 --- a/src/librustdoc/astsrv.rs +++ b/src/librustdoc/astsrv.rs @@ -155,9 +155,9 @@ fn build_error_handlers( codemap: @codemap::CodeMap ) -> ErrorHandlers { - type DiagnosticHandler = { + struct DiagnosticHandler { inner: diagnostic::handler, - }; + } impl DiagnosticHandler: diagnostic::handler { fn fatal(msg: &str) -> ! { self.inner.fatal(msg) } @@ -182,7 +182,7 @@ fn build_error_handlers( diagnostic::emit(cmsp, msg, lvl); }; let inner_handler = diagnostic::mk_handler(Some(emitter)); - let handler = { + let handler = DiagnosticHandler { inner: inner_handler, }; let span_handler = diagnostic::mk_span_handler( diff --git a/src/librustdoc/attr_pass.rs b/src/librustdoc/attr_pass.rs index 1ab3ce2d6f368..39a893a4076cb 100644 --- a/src/librustdoc/attr_pass.rs +++ b/src/librustdoc/attr_pass.rs @@ -69,9 +69,9 @@ fn fold_crate( attr_parser::parse_crate(attrs) }; - { - topmod: doc::ModDoc_({ - item: { + doc::CrateDoc { + topmod: doc::ModDoc_(doc::ModDoc_ { + item: doc::ItemDoc { name: option::get_or_default(attrs.name, doc.topmod.name()), .. doc.topmod.item }, @@ -103,7 +103,7 @@ fn fold_item( parse_item_attrs(srv, doc.id, attr_parser::parse_desc) }; - { + doc::ItemDoc { desc: desc, .. doc } @@ -162,7 +162,7 @@ fn fold_enum( let doc_id = doc.id(); let doc = fold::default_seq_fold_enum(fold, doc); - { + doc::EnumDoc { variants: do par::map(doc.variants) |variant| { let variant = *variant; let desc = do astsrv::exec(srv) |ctxt| { @@ -182,7 +182,7 @@ fn fold_enum( } }; - { + doc::VariantDoc { desc: desc, .. variant } @@ -211,7 +211,7 @@ fn fold_trait( let srv = fold.ctxt; let doc = fold::default_seq_fold_trait(fold, doc); - { + doc::TraitDoc { methods: merge_method_attrs(srv, doc.id(), doc.methods), .. doc } @@ -256,7 +256,7 @@ fn merge_method_attrs( assert doc.name == attrs.first(); let desc = attrs.second(); - { + doc::MethodDoc { desc: desc, ..*doc } @@ -287,7 +287,7 @@ fn fold_impl( let srv = fold.ctxt; let doc = fold::default_seq_fold_impl(fold, doc); - { + doc::ImplDoc { methods: merge_method_attrs(srv, doc.id(), doc.methods), .. doc } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index ebd5c047df372..0ad048d49bb4c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -50,13 +50,13 @@ impl OutputStyle : cmp::Eq { } /// The configuration for a rustdoc session -pub type Config = { +pub struct Config { input_crate: Path, output_dir: Path, output_format: OutputFormat, output_style: OutputStyle, pandoc_cmd: Option<~str> -}; +} pub impl Config: Clone { fn clone(&self) -> Config { copy *self } @@ -95,7 +95,7 @@ pub fn usage() { } pub fn default_config(input_crate: &Path) -> Config { - { + Config { input_crate: *input_crate, output_dir: Path("."), output_format: PandocHtml, @@ -155,7 +155,7 @@ fn config_from_opts( let result = do result::chain(result) |config| { let output_dir = getopts::opt_maybe_str(matches, opt_output_dir()); let output_dir = output_dir.map(|s| Path(*s)); - result::Ok({ + result::Ok(Config { output_dir: output_dir.get_or_default(config.output_dir), .. config }) @@ -168,7 +168,7 @@ fn config_from_opts( do result::chain(parse_output_format(*output_format)) |output_format| { - result::Ok({ + result::Ok(Config { output_format: output_format, .. config }) @@ -182,7 +182,7 @@ fn config_from_opts( |output_style| { do result::chain(parse_output_style(*output_style)) |output_style| { - result::Ok({ + result::Ok(Config { output_style: output_style, .. config }) @@ -195,7 +195,7 @@ fn config_from_opts( let pandoc_cmd = maybe_find_pandoc( &config, pandoc_cmd, move program_output.take()); do result::chain(pandoc_cmd) |pandoc_cmd| { - result::Ok({ + result::Ok(Config { pandoc_cmd: pandoc_cmd, .. config }) diff --git a/src/librustdoc/desc_to_brief_pass.rs b/src/librustdoc/desc_to_brief_pass.rs index f53e0058b63be..93f4be10a5c36 100644 --- a/src/librustdoc/desc_to_brief_pass.rs +++ b/src/librustdoc/desc_to_brief_pass.rs @@ -51,7 +51,7 @@ pub fn run( fn fold_item(fold: &fold::Fold<()>, +doc: doc::ItemDoc) -> doc::ItemDoc { let doc = fold::default_seq_fold_item(fold, doc); - { + doc::ItemDoc { brief: extract(doc.desc), .. doc } @@ -60,8 +60,8 @@ fn fold_item(fold: &fold::Fold<()>, +doc: doc::ItemDoc) -> doc::ItemDoc { fn fold_trait(fold: &fold::Fold<()>, +doc: doc::TraitDoc) -> doc::TraitDoc { let doc =fold::default_seq_fold_trait(fold, doc); - { - methods: par::map(doc.methods, |doc| { + doc::TraitDoc { + methods: par::map(doc.methods, |doc| doc::MethodDoc { brief: extract(doc.desc), .. *doc }), @@ -72,8 +72,8 @@ fn fold_trait(fold: &fold::Fold<()>, +doc: doc::TraitDoc) -> doc::TraitDoc { fn fold_impl(fold: &fold::Fold<()>, +doc: doc::ImplDoc) -> doc::ImplDoc { let doc =fold::default_seq_fold_impl(fold, doc); - { - methods: par::map(doc.methods, |doc| { + doc::ImplDoc { + methods: par::map(doc.methods, |doc| doc::MethodDoc { brief: extract(doc.desc), .. *doc }), diff --git a/src/librustdoc/doc.rs b/src/librustdoc/doc.rs index 18742720b90c9..247694fb26a50 100644 --- a/src/librustdoc/doc.rs +++ b/src/librustdoc/doc.rs @@ -21,94 +21,47 @@ use core::vec; pub type AstId = int; -pub type Doc_ = { +#[deriving_eq] +pub struct Doc_ { pages: ~[Page] -}; - -impl Doc_ : cmp::Eq { - pure fn eq(&self, other: &Doc_) -> bool { - (*self).pages == (*other).pages - } - pure fn ne(&self, other: &Doc_) -> bool { !(*self).eq(other) } } +#[deriving_eq] pub enum Doc { Doc_(Doc_) } -impl Doc : cmp::Eq { - pure fn eq(&self, other: &Doc) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &Doc) -> bool { *(*self) != *(*other) } -} - +#[deriving_eq] pub enum Page { CratePage(CrateDoc), ItemPage(ItemTag) } -impl Page : cmp::Eq { - pure fn eq(&self, other: &Page) -> bool { - match (*self) { - CratePage(e0a) => { - match (*other) { - CratePage(e0b) => e0a == e0b, - _ => false - } - } - ItemPage(e0a) => { - match (*other) { - ItemPage(e0b) => e0a == e0b, - _ => false - } - } - } - } - pure fn ne(&self, other: &Page) -> bool { !(*self).eq(other) } -} - +#[deriving_eq] pub enum Implementation { Required, Provided, } -impl Implementation : cmp::Eq { - pure fn eq(&self, other: &Implementation) -> bool { - ((*self) as uint) == ((*other) as uint) - } - pure fn ne(&self, other: &Implementation) -> bool { !(*self).eq(other) } -} - - /** * Most rustdocs can be parsed into 'sections' according to their markdown * headers */ -pub type Section = { +#[deriving_eq] +pub struct Section { header: ~str, body: ~str -}; - -impl Section : cmp::Eq { - pure fn eq(&self, other: &Section) -> bool { - (*self).header == (*other).header && (*self).body == (*other).body - } - pure fn ne(&self, other: &Section) -> bool { !(*self).eq(other) } } // FIXME (#2596): We currently give topmod the name of the crate. There // would probably be fewer special cases if the crate had its own name // and topmod's name was the empty string. -pub type CrateDoc = { - topmod: ModDoc, -}; - -impl CrateDoc : cmp::Eq { - pure fn eq(&self, other: &CrateDoc) -> bool { - (*self).topmod == (*other).topmod - } - pure fn ne(&self, other: &CrateDoc) -> bool { !(*self).eq(other) } +#[deriving_eq] +pub struct CrateDoc { + topmod: ModDoc } +#[deriving_eq] pub enum ItemTag { ModTag(ModDoc), NmodTag(NmodDoc), @@ -121,69 +74,8 @@ pub enum ItemTag { StructTag(StructDoc) } -impl ItemTag : cmp::Eq { - pure fn eq(&self, other: &ItemTag) -> bool { - match (*self) { - ModTag(e0a) => { - match (*other) { - ModTag(e0b) => e0a == e0b, - _ => false - } - } - NmodTag(e0a) => { - match (*other) { - NmodTag(e0b) => e0a == e0b, - _ => false - } - } - ConstTag(e0a) => { - match (*other) { - ConstTag(e0b) => e0a == e0b, - _ => false - } - } - FnTag(e0a) => { - match (*other) { - FnTag(e0b) => e0a == e0b, - _ => false - } - } - EnumTag(e0a) => { - match (*other) { - EnumTag(e0b) => e0a == e0b, - _ => false - } - } - TraitTag(e0a) => { - match (*other) { - TraitTag(e0b) => e0a == e0b, - _ => false - } - } - ImplTag(e0a) => { - match (*other) { - ImplTag(e0b) => e0a == e0b, - _ => false - } - } - TyTag(e0a) => { - match (*other) { - TyTag(e0b) => e0a == e0b, - _ => false - } - } - StructTag(e0a) => { - match (*other) { - StructTag(e0b) => e0a == e0b, - _ => false - } - } - } - } - pure fn ne(&self, other: &ItemTag) -> bool { !(*self).eq(other) } -} - -pub type ItemDoc = { +#[deriving_eq] +pub struct ItemDoc { id: AstId, name: ~str, path: ~[~str], @@ -192,179 +84,86 @@ pub type ItemDoc = { sections: ~[Section], // Indicates that this node is a reexport of a different item reexport: bool -}; - -impl ItemDoc : cmp::Eq { - pure fn eq(&self, other: &ItemDoc) -> bool { - (*self).id == (*other).id && - (*self).name == (*other).name && - (*self).path == (*other).path && - (*self).brief == (*other).brief && - (*self).desc == (*other).desc && - (*self).sections == (*other).sections && - (*self).reexport == (*other).reexport - } - pure fn ne(&self, other: &ItemDoc) -> bool { !(*self).eq(other) } } -pub type SimpleItemDoc = { +#[deriving_eq] +pub struct SimpleItemDoc { item: ItemDoc, sig: Option<~str> -}; - -impl SimpleItemDoc : cmp::Eq { - pure fn eq(&self, other: &SimpleItemDoc) -> bool { - (*self).item == (*other).item && (*self).sig == (*other).sig - } - pure fn ne(&self, other: &SimpleItemDoc) -> bool { !(*self).eq(other) } } -pub type ModDoc_ = { +#[deriving_eq] +pub struct ModDoc_ { item: ItemDoc, items: ~[ItemTag], index: Option -}; - -impl ModDoc_ : cmp::Eq { - pure fn eq(&self, other: &ModDoc_) -> bool { - (*self).item == (*other).item && - (*self).items == (*other).items && - (*self).index == (*other).index - } - pure fn ne(&self, other: &ModDoc_) -> bool { !(*self).eq(other) } } +#[deriving_eq] pub enum ModDoc { ModDoc_(ModDoc_) } -impl ModDoc : cmp::Eq { - pure fn eq(&self, other: &ModDoc) -> bool { *(*self) == *(*other) } - pure fn ne(&self, other: &ModDoc) -> bool { *(*self) != *(*other) } -} - -pub type NmodDoc = { +#[deriving_eq] +pub struct NmodDoc { item: ItemDoc, fns: ~[FnDoc], index: Option -}; - -impl NmodDoc : cmp::Eq { - pure fn eq(&self, other: &NmodDoc) -> bool { - (*self).item == (*other).item && - (*self).fns == (*other).fns && - (*self).index == (*other).index - } - pure fn ne(&self, other: &NmodDoc) -> bool { !(*self).eq(other) } } pub type ConstDoc = SimpleItemDoc; pub type FnDoc = SimpleItemDoc; -pub type EnumDoc = { +#[deriving_eq] +pub struct EnumDoc { item: ItemDoc, variants: ~[VariantDoc] -}; - -impl EnumDoc : cmp::Eq { - pure fn eq(&self, other: &EnumDoc) -> bool { - (*self).item == (*other).item && (*self).variants == (*other).variants - } - pure fn ne(&self, other: &EnumDoc) -> bool { !(*self).eq(other) } } -pub type VariantDoc = { +#[deriving_eq] +pub struct VariantDoc { name: ~str, desc: Option<~str>, sig: Option<~str> -}; - -impl VariantDoc : cmp::Eq { - pure fn eq(&self, other: &VariantDoc) -> bool { - (*self).name == (*other).name && - (*self).desc == (*other).desc && - (*self).sig == (*other).sig - } - pure fn ne(&self, other: &VariantDoc) -> bool { !(*self).eq(other) } } -pub type TraitDoc = { +#[deriving_eq] +pub struct TraitDoc { item: ItemDoc, methods: ~[MethodDoc] -}; - -impl TraitDoc : cmp::Eq { - pure fn eq(&self, other: &TraitDoc) -> bool { - (*self).item == (*other).item && (*self).methods == (*other).methods - } - pure fn ne(&self, other: &TraitDoc) -> bool { !(*self).eq(other) } } -pub type MethodDoc = { +#[deriving_eq] +pub struct MethodDoc { name: ~str, brief: Option<~str>, desc: Option<~str>, sections: ~[Section], sig: Option<~str>, implementation: Implementation, -}; - -impl MethodDoc : cmp::Eq { - pure fn eq(&self, other: &MethodDoc) -> bool { - (*self).name == (*other).name && - (*self).brief == (*other).brief && - (*self).desc == (*other).desc && - (*self).sections == (*other).sections && - (*self).sig == (*other).sig && - (*self).implementation == (*other).implementation - } - pure fn ne(&self, other: &MethodDoc) -> bool { !(*self).eq(other) } } -pub type ImplDoc = { +#[deriving_eq] +pub struct ImplDoc { item: ItemDoc, trait_types: ~[~str], self_ty: Option<~str>, methods: ~[MethodDoc] -}; - -impl ImplDoc : cmp::Eq { - pure fn eq(&self, other: &ImplDoc) -> bool { - (*self).item == (*other).item && - (*self).trait_types == (*other).trait_types && - (*self).self_ty == (*other).self_ty && - (*self).methods == (*other).methods - } - pure fn ne(&self, other: &ImplDoc) -> bool { !(*self).eq(other) } } pub type TyDoc = SimpleItemDoc; -pub type StructDoc = { +#[deriving_eq] +pub struct StructDoc { item: ItemDoc, fields: ~[~str], sig: Option<~str> -}; - -impl StructDoc : cmp::Eq { - pure fn eq(&self, other: &StructDoc) -> bool { - return (*self).item == other.item - && (*self).fields == other.fields - && (*self).sig == other.sig; - } - pure fn ne(&self, other: &StructDoc) -> bool { !(*self).eq(other) } } -pub type Index = { +#[deriving_eq] +pub struct Index { entries: ~[IndexEntry] -}; - -impl Index : cmp::Eq { - pure fn eq(&self, other: &Index) -> bool { - (*self).entries == (*other).entries - } - pure fn ne(&self, other: &Index) -> bool { !(*self).eq(other) } } /** @@ -377,21 +176,12 @@ impl Index : cmp::Eq { * * brief - The brief description * * link - A format-specific string representing the link target */ -pub type IndexEntry = { +#[deriving_eq] +pub struct IndexEntry { kind: ~str, name: ~str, brief: Option<~str>, link: ~str -}; - -impl IndexEntry : cmp::Eq { - pure fn eq(&self, other: &IndexEntry) -> bool { - (*self).kind == (*other).kind && - (*self).name == (*other).name && - (*self).brief == (*other).brief && - (*self).link == (*other).link - } - pure fn ne(&self, other: &IndexEntry) -> bool { !(*self).eq(other) } } impl Doc { @@ -411,7 +201,6 @@ impl Doc { /// Some helper methods on ModDoc, mostly for testing impl ModDoc { - fn mods() -> ~[ModDoc] { do vec::filter_map(self.items) |itemtag| { match *itemtag { diff --git a/src/librustdoc/extract.rs b/src/librustdoc/extract.rs index 444949cfb7f0c..93226cb5ed8c8 100644 --- a/src/librustdoc/extract.rs +++ b/src/librustdoc/extract.rs @@ -57,9 +57,9 @@ pub fn extract( crate: @ast::crate, +default_name: ~str ) -> doc::Doc { - doc::Doc_({ + doc::Doc_(doc::Doc_ { pages: ~[ - doc::CratePage({ + doc::CratePage(doc::CrateDoc { topmod: top_moddoc_from_crate(crate, default_name), }) ] @@ -75,7 +75,7 @@ fn top_moddoc_from_crate( } fn mk_itemdoc(id: ast::node_id, +name: ~str) -> doc::ItemDoc { - { + doc::ItemDoc { id: id, name: name, path: ~[], @@ -90,7 +90,7 @@ fn moddoc_from_mod( +itemdoc: doc::ItemDoc, module_: ast::_mod ) -> doc::ModDoc { - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { item: itemdoc, items: do vec::filter_map(module_.items) |item| { let ItemDoc = mk_itemdoc(item.id, to_str(item.ident)); @@ -161,7 +161,7 @@ fn nmoddoc_from_mod( ast::foreign_item_const(*) => {} // XXX: Not implemented. } } - { + doc:: NmodDoc { item: itemdoc, fns: fns, index: None @@ -169,14 +169,14 @@ fn nmoddoc_from_mod( } fn fndoc_from_fn(+itemdoc: doc::ItemDoc) -> doc::FnDoc { - { + doc::SimpleItemDoc { item: itemdoc, sig: None } } fn constdoc_from_const(+itemdoc: doc::ItemDoc) -> doc::ConstDoc { - { + doc::SimpleItemDoc { item: itemdoc, sig: None } @@ -193,7 +193,7 @@ fn enumdoc_from_enum( +itemdoc: doc::ItemDoc, +variants: ~[ast::variant] ) -> doc::EnumDoc { - { + doc::EnumDoc { item: itemdoc, variants: variantdocs_from_variants(variants) } @@ -206,8 +206,7 @@ fn variantdocs_from_variants( } fn variantdoc_from_variant(variant: &ast::variant) -> doc::VariantDoc { - - { + doc::VariantDoc { name: to_str(variant.node.name), desc: None, sig: None @@ -231,12 +230,12 @@ fn traitdoc_from_trait( +itemdoc: doc::ItemDoc, +methods: ~[ast::trait_method] ) -> doc::TraitDoc { - { + doc::TraitDoc { item: itemdoc, methods: do vec::map(methods) |method| { match *method { ast::required(ty_m) => { - { + doc::MethodDoc { name: to_str(ty_m.ident), brief: None, desc: None, @@ -246,7 +245,7 @@ fn traitdoc_from_trait( } } ast::provided(m) => { - { + doc::MethodDoc { name: to_str(m.ident), brief: None, desc: None, @@ -276,12 +275,12 @@ fn impldoc_from_impl( +itemdoc: doc::ItemDoc, methods: ~[@ast::method] ) -> doc::ImplDoc { - { + doc::ImplDoc { item: itemdoc, trait_types: ~[], self_ty: None, methods: do vec::map(methods) |method| { - { + doc::MethodDoc { name: to_str(method.ident), brief: None, desc: None, @@ -302,7 +301,7 @@ fn should_extract_impl_methods() { fn tydoc_from_ty( +itemdoc: doc::ItemDoc ) -> doc::TyDoc { - { + doc::SimpleItemDoc { item: itemdoc, sig: None } @@ -318,7 +317,7 @@ fn structdoc_from_struct( +itemdoc: doc::ItemDoc, struct_def: @ast::struct_def ) -> doc::StructDoc { - { + doc::StructDoc { item: itemdoc, fields: do struct_def.fields.map |field| { match field.node.kind { diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 29c53e0af2555..f352ed7f7e7c3 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -158,7 +158,7 @@ pub fn default_par_fold(+ctxt: T) -> Fold { } pub fn default_seq_fold_doc(fold: &Fold, +doc: doc::Doc) -> doc::Doc { - doc::Doc_({ + doc::Doc_(doc::Doc_ { pages: do vec::map(doc.pages) |page| { match *page { doc::CratePage(doc) => { @@ -177,7 +177,7 @@ pub fn default_seq_fold_crate( fold: &Fold, +doc: doc::CrateDoc ) -> doc::CrateDoc { - { + doc::CrateDoc { topmod: (fold.fold_mod)(fold, doc.topmod) } } @@ -194,7 +194,7 @@ pub fn default_any_fold_mod( +doc: doc::ModDoc ) -> doc::ModDoc { let fold_copy = fold.clone(); - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { item: (fold.fold_item)(fold, doc.item), items: par::map(doc.items, |ItemTag, move fold_copy| { fold_ItemTag(&fold_copy, *ItemTag) @@ -207,7 +207,7 @@ pub fn default_seq_fold_mod( fold: &Fold, +doc: doc::ModDoc ) -> doc::ModDoc { - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { item: (fold.fold_item)(fold, doc.item), items: vec::map(doc.items, |ItemTag| { fold_ItemTag(fold, *ItemTag) @@ -221,7 +221,7 @@ pub fn default_par_fold_mod( +doc: doc::ModDoc ) -> doc::ModDoc { let fold_copy = fold.clone(); - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { item: (fold.fold_item)(fold, doc.item), items: par::map(doc.items, |ItemTag, move fold_copy| { fold_ItemTag(&fold_copy, *ItemTag) @@ -235,7 +235,7 @@ pub fn default_any_fold_nmod( +doc: doc::NmodDoc ) -> doc::NmodDoc { let fold_copy = fold.clone(); - { + doc::NmodDoc { item: (fold.fold_item)(fold, doc.item), fns: par::map(doc.fns, |FnDoc, move fold_copy| { (fold_copy.fold_fn)(&fold_copy, *FnDoc) @@ -248,7 +248,7 @@ pub fn default_seq_fold_nmod( fold: &Fold, +doc: doc::NmodDoc ) -> doc::NmodDoc { - { + doc::NmodDoc { item: (fold.fold_item)(fold, doc.item), fns: vec::map(doc.fns, |FnDoc| { (fold.fold_fn)(fold, *FnDoc) @@ -262,7 +262,7 @@ pub fn default_par_fold_nmod( +doc: doc::NmodDoc ) -> doc::NmodDoc { let fold_copy = fold.clone(); - { + doc::NmodDoc { item: (fold.fold_item)(fold, doc.item), fns: par::map(doc.fns, |FnDoc, move fold_copy| { (fold_copy.fold_fn)(&fold_copy, *FnDoc) @@ -307,7 +307,7 @@ pub fn default_seq_fold_fn( fold: &Fold, +doc: doc::FnDoc ) -> doc::FnDoc { - { + doc::SimpleItemDoc { item: (fold.fold_item)(fold, doc.item), .. doc } @@ -317,7 +317,7 @@ pub fn default_seq_fold_const( fold: &Fold, +doc: doc::ConstDoc ) -> doc::ConstDoc { - { + doc::SimpleItemDoc { item: (fold.fold_item)(fold, doc.item), .. doc } @@ -327,7 +327,7 @@ pub fn default_seq_fold_enum( fold: &Fold, +doc: doc::EnumDoc ) -> doc::EnumDoc { - { + doc::EnumDoc { item: (fold.fold_item)(fold, doc.item), .. doc } @@ -337,7 +337,7 @@ pub fn default_seq_fold_trait( fold: &Fold, +doc: doc::TraitDoc ) -> doc::TraitDoc { - { + doc::TraitDoc { item: (fold.fold_item)(fold, doc.item), .. doc } @@ -347,7 +347,7 @@ pub fn default_seq_fold_impl( fold: &Fold, +doc: doc::ImplDoc ) -> doc::ImplDoc { - { + doc::ImplDoc { item: (fold.fold_item)(fold, doc.item), .. doc } @@ -357,7 +357,7 @@ pub fn default_seq_fold_type( fold: &Fold, +doc: doc::TyDoc ) -> doc::TyDoc { - { + doc::SimpleItemDoc { item: (fold.fold_item)(fold, doc.item), .. doc } @@ -367,7 +367,7 @@ pub fn default_seq_fold_struct( fold: &Fold, +doc: doc::StructDoc ) -> doc::StructDoc { - { + doc::StructDoc { item: (fold.fold_item)(fold, doc.item), .. doc } diff --git a/src/librustdoc/markdown_index_pass.rs b/src/librustdoc/markdown_index_pass.rs index 1f4e1be62fc3b..b0b4278a91e0a 100644 --- a/src/librustdoc/markdown_index_pass.rs +++ b/src/librustdoc/markdown_index_pass.rs @@ -54,7 +54,7 @@ fn fold_mod( let doc = fold::default_any_fold_mod(fold, doc); - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { index: Some(build_mod_index(doc, fold.ctxt)), .. *doc }) @@ -67,7 +67,7 @@ fn fold_nmod( let doc = fold::default_any_fold_nmod(fold, doc); - { + doc::NmodDoc { index: Some(build_nmod_index(doc, fold.ctxt)), .. doc } @@ -77,7 +77,7 @@ fn build_mod_index( +doc: doc::ModDoc, +config: config::Config ) -> doc::Index { - { + doc::Index { entries: par::map(doc.items, |doc| { item_to_entry(*doc, config) }) @@ -88,7 +88,7 @@ fn build_nmod_index( +doc: doc::NmodDoc, +config: config::Config ) -> doc::Index { - { + doc::Index { entries: par::map(doc.fns, |doc| { item_to_entry(doc::FnTag(*doc), config) }) @@ -109,7 +109,7 @@ fn item_to_entry( } }; - { + doc::IndexEntry { kind: markdown_pass::header_kind(doc), name: markdown_pass::header_name(doc), brief: doc.brief(), diff --git a/src/librustdoc/page_pass.rs b/src/librustdoc/page_pass.rs index 2629d45635e0b..d121d7e847893 100644 --- a/src/librustdoc/page_pass.rs +++ b/src/librustdoc/page_pass.rs @@ -76,7 +76,7 @@ fn make_doc_from_pages(page_port: PagePort) -> doc::Doc { break; } } - doc::Doc_({ + doc::Doc_(doc::Doc_ { pages: pages }) } @@ -100,7 +100,7 @@ fn fold_crate( let doc = fold::default_seq_fold_crate(fold, doc); - let page = doc::CratePage({ + let page = doc::CratePage(doc::CrateDoc { topmod: strip_mod(doc.topmod), .. doc }); @@ -128,7 +128,7 @@ fn fold_mod( } fn strip_mod(doc: doc::ModDoc) -> doc::ModDoc { - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { items: do doc.items.filtered |item| { match *item { doc::ModTag(_) => false, diff --git a/src/librustdoc/path_pass.rs b/src/librustdoc/path_pass.rs index 48ed187877126..bc69ea7ed5a8d 100644 --- a/src/librustdoc/path_pass.rs +++ b/src/librustdoc/path_pass.rs @@ -54,7 +54,7 @@ fn run(srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc { } fn fold_item(fold: &fold::Fold, +doc: doc::ItemDoc) -> doc::ItemDoc { - { + doc::ItemDoc { path: fold.ctxt.path, .. doc } @@ -68,7 +68,7 @@ fn fold_mod(fold: &fold::Fold, +doc: doc::ModDoc) -> doc::ModDoc { let doc = fold::default_any_fold_mod(fold, doc); if !is_topmod { fold.ctxt.path.pop(); } - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { item: (fold.fold_item)(fold, doc.item), .. *doc }) @@ -79,7 +79,7 @@ fn fold_nmod(fold: &fold::Fold, +doc: doc::NmodDoc) -> doc::NmodDoc { let doc = fold::default_seq_fold_nmod(fold, doc); fold.ctxt.path.pop(); - { + doc::NmodDoc { item: (fold.fold_item)(fold, doc.item), .. doc } diff --git a/src/librustdoc/prune_hidden_pass.rs b/src/librustdoc/prune_hidden_pass.rs index 3a924e3bddf69..c3d31d4a5b0ad 100644 --- a/src/librustdoc/prune_hidden_pass.rs +++ b/src/librustdoc/prune_hidden_pass.rs @@ -42,7 +42,7 @@ fn fold_mod( ) -> doc::ModDoc { let doc = fold::default_any_fold_mod(fold, doc); - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { items: do doc.items.filtered |ItemTag| { !is_hidden(fold.ctxt, ItemTag.item()) }, diff --git a/src/librustdoc/prune_private_pass.rs b/src/librustdoc/prune_private_pass.rs index 3b11437acebaf..a18530a74603a 100644 --- a/src/librustdoc/prune_private_pass.rs +++ b/src/librustdoc/prune_private_pass.rs @@ -48,7 +48,7 @@ fn fold_mod( ) -> doc::ModDoc { let doc = fold::default_any_fold_mod(fold, doc); - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { items: doc.items.filtered(|ItemTag| { is_visible(fold.ctxt, ItemTag.item()) }), diff --git a/src/librustdoc/sectionalize_pass.rs b/src/librustdoc/sectionalize_pass.rs index eeadd82371fd9..706aecf49b95b 100644 --- a/src/librustdoc/sectionalize_pass.rs +++ b/src/librustdoc/sectionalize_pass.rs @@ -46,7 +46,7 @@ fn fold_item(fold: &fold::Fold<()>, +doc: doc::ItemDoc) -> doc::ItemDoc { let doc = fold::default_seq_fold_item(fold, doc); let (desc, sections) = sectionalize(doc.desc); - { + doc::ItemDoc { desc: desc, sections: sections, .. doc @@ -56,11 +56,11 @@ fn fold_item(fold: &fold::Fold<()>, +doc: doc::ItemDoc) -> doc::ItemDoc { fn fold_trait(fold: &fold::Fold<()>, +doc: doc::TraitDoc) -> doc::TraitDoc { let doc = fold::default_seq_fold_trait(fold, doc); - { + doc::TraitDoc { methods: do par::map(doc.methods) |method| { let (desc, sections) = sectionalize(method.desc); - { + doc::MethodDoc { desc: desc, sections: sections, .. *method @@ -73,11 +73,11 @@ fn fold_trait(fold: &fold::Fold<()>, +doc: doc::TraitDoc) -> doc::TraitDoc { fn fold_impl(fold: &fold::Fold<()>, +doc: doc::ImplDoc) -> doc::ImplDoc { let doc = fold::default_seq_fold_impl(fold, doc); - { + doc::ImplDoc { methods: do par::map(doc.methods) |method| { let (desc, sections) = sectionalize(method.desc); - { + doc::MethodDoc { desc: desc, sections: sections, .. *method @@ -121,7 +121,7 @@ fn sectionalize(desc: Option<~str>) -> (Option<~str>, ~[doc::Section]) { if current_section.is_some() { sections += ~[current_section.get()]; } - current_section = Some({ + current_section = Some(doc::Section { header: header, body: ~"" }); @@ -129,7 +129,7 @@ fn sectionalize(desc: Option<~str>) -> (Option<~str>, ~[doc::Section]) { None => { match copy current_section { Some(section) => { - current_section = Some({ + current_section = Some(doc::Section { body: section.body + ~"\n" + *line, .. section }); diff --git a/src/librustdoc/sort_pass.rs b/src/librustdoc/sort_pass.rs index b3ecb8173fee7..42759be68ad32 100644 --- a/src/librustdoc/sort_pass.rs +++ b/src/librustdoc/sort_pass.rs @@ -55,7 +55,7 @@ fn fold_mod( +doc: doc::ModDoc ) -> doc::ModDoc { let doc = fold::default_any_fold_mod(fold, doc); - doc::ModDoc_({ + doc::ModDoc_(doc::ModDoc_ { items: sort::merge_sort(doc.items, fold.ctxt.op), .. *doc }) diff --git a/src/librustdoc/text_pass.rs b/src/librustdoc/text_pass.rs index 5627bfead9f45..fb55641b764f4 100644 --- a/src/librustdoc/text_pass.rs +++ b/src/librustdoc/text_pass.rs @@ -62,7 +62,7 @@ fn fold_item( ) -> doc::ItemDoc { let doc = fold::default_seq_fold_item(fold, doc); - { + doc::ItemDoc { brief: maybe_apply_op(fold.ctxt, doc.brief), desc: maybe_apply_op(fold.ctxt, doc.desc), sections: apply_to_sections(fold.ctxt, doc.sections), @@ -74,7 +74,7 @@ fn apply_to_sections( op: NominalOp, sections: ~[doc::Section] ) -> ~[doc::Section] { - par::map(sections, |section, copy op| { + par::map(sections, |section, copy op| doc::Section { header: (op.op)(section.header), body: (op.op)(section.body) }) @@ -86,9 +86,9 @@ fn fold_enum( let doc = fold::default_seq_fold_enum(fold, doc); let fold_copy = copy *fold; - { + doc::EnumDoc { variants: do par::map(doc.variants) |variant, copy fold_copy| { - { + doc::VariantDoc { desc: maybe_apply_op(fold_copy.ctxt, variant.desc), .. *variant } @@ -103,7 +103,7 @@ fn fold_trait( ) -> doc::TraitDoc { let doc = fold::default_seq_fold_trait(fold, doc); - { + doc::TraitDoc { methods: apply_to_methods(fold.ctxt, doc.methods), .. doc } @@ -114,7 +114,7 @@ fn apply_to_methods( docs: ~[doc::MethodDoc] ) -> ~[doc::MethodDoc] { do par::map(docs) |doc, copy op| { - { + doc::MethodDoc { brief: maybe_apply_op(op, doc.brief), desc: maybe_apply_op(op, doc.desc), sections: apply_to_sections(op, doc.sections), @@ -129,7 +129,7 @@ fn fold_impl( ) -> doc::ImplDoc { let doc = fold::default_seq_fold_impl(fold, doc); - { + doc::ImplDoc { methods: apply_to_methods(fold.ctxt, doc.methods), .. doc } diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs index 5d92ed14c18df..3b9991d18274e 100644 --- a/src/librustdoc/tystr_pass.rs +++ b/src/librustdoc/tystr_pass.rs @@ -59,7 +59,7 @@ fn fold_fn( let srv = fold.ctxt; - { + doc::SimpleItemDoc { sig: get_fn_sig(srv, doc.id()), .. doc } @@ -101,7 +101,7 @@ fn fold_const( ) -> doc::ConstDoc { let srv = fold.ctxt; - { + doc::SimpleItemDoc { sig: Some(do astsrv::exec(srv) |ctxt| { match ctxt.ast_map.get(doc.id()) { ast_map::node_item(@ast::item { @@ -129,7 +129,7 @@ fn fold_enum( let doc_id = doc.id(); let srv = fold.ctxt; - { + doc::EnumDoc { variants: do par::map(doc.variants) |variant| { let variant = *variant; let sig = do astsrv::exec(srv) |ctxt| { @@ -148,7 +148,7 @@ fn fold_enum( } }; - { + doc::VariantDoc { sig: Some(sig), .. variant } @@ -167,7 +167,7 @@ fn fold_trait( fold: &fold::Fold, +doc: doc::TraitDoc ) -> doc::TraitDoc { - { + doc::TraitDoc { methods: merge_methods(fold.ctxt, doc.id(), doc.methods), .. doc } @@ -179,7 +179,7 @@ fn merge_methods( docs: ~[doc::MethodDoc] ) -> ~[doc::MethodDoc] { do par::map(docs) |doc| { - { + doc::MethodDoc { sig: get_method_sig(srv, item_id, doc.name), .. *doc } @@ -276,7 +276,7 @@ fn fold_impl( } }; - { + doc::ImplDoc { trait_types: trait_types, self_ty: self_ty, methods: merge_methods(fold.ctxt, doc.id(), doc.methods), @@ -316,7 +316,7 @@ fn fold_type( let srv = fold.ctxt; - { + doc::SimpleItemDoc { sig: do astsrv::exec(srv) |ctxt| { match ctxt.ast_map.get(doc.id()) { ast_map::node_item(@ast::item { @@ -349,7 +349,7 @@ fn fold_struct( ) -> doc::StructDoc { let srv = fold.ctxt; - { + doc::StructDoc { sig: do astsrv::exec(srv) |ctxt| { match ctxt.ast_map.get(doc.id()) { ast_map::node_item(item, _) => { diff --git a/src/libstd/bigint.rs b/src/libstd/bigint.rs index fc7834291267b..4283a7e402bce 100644 --- a/src/libstd/bigint.rs +++ b/src/libstd/bigint.rs @@ -17,7 +17,7 @@ A BigInt is a combination of BigUint and Sign. */ use core::cmp::{Eq, Ord}; -use core::num::{Num, Zero, One}; +use core::num::{IntConvertible, Zero, One}; use core::*; /** @@ -121,7 +121,7 @@ impl BigUint : One { static pub pure fn one() -> BigUint { BigUint::new(~[1]) } } -impl BigUint : Num { +impl BigUint : Add { pure fn add(&self, other: &BigUint) -> BigUint { let new_len = uint::max(self.data.len(), other.data.len()); @@ -138,7 +138,9 @@ impl BigUint : Num { if carry == 0 { return BigUint::new(sum) }; return BigUint::new(sum + [carry]); } +} +impl BigUint : Sub { pure fn sub(&self, other: &BigUint) -> BigUint { let new_len = uint::max(self.data.len(), other.data.len()); @@ -161,7 +163,9 @@ impl BigUint : Num { assert borrow == 0; // <=> assert (self >= other); return BigUint::new(diff); } +} +impl BigUint : Mul { pure fn mul(&self, other: &BigUint) -> BigUint { if self.is_zero() || other.is_zero() { return Zero::zero(); } @@ -224,18 +228,27 @@ impl BigUint : Num { } } } +} +impl BigUint : Div { pure fn div(&self, other: &BigUint) -> BigUint { let (d, _) = self.divmod(other); return d; } +} + +impl BigUint : Modulo { pure fn modulo(&self, other: &BigUint) -> BigUint { let (_, m) = self.divmod(other); return m; } +} +impl BigUint : Neg { pure fn neg(&self) -> BigUint { fail } +} +impl BigUint : IntConvertible { pure fn to_int(&self) -> int { uint::min(self.to_uint(), int::max_value as uint) as int } @@ -625,7 +638,7 @@ impl BigInt : One { } } -impl BigInt : Num { +impl BigInt : Add { pure fn add(&self, other: &BigInt) -> BigInt { match (self.sign, other.sign) { (Zero, _) => copy *other, @@ -637,6 +650,9 @@ impl BigInt : Num { (Minus, Minus) => -((-self) + (-*other)) } } +} + +impl BigInt : Sub { pure fn sub(&self, other: &BigInt) -> BigInt { match (self.sign, other.sign) { (Zero, _) => -other, @@ -654,6 +670,9 @@ impl BigInt : Num { (Minus, Minus) => (-other) - (-*self) } } +} + +impl BigInt : Mul { pure fn mul(&self, other: &BigInt) -> BigInt { match (self.sign, other.sign) { (Zero, _) | (_, Zero) => Zero::zero(), @@ -665,18 +684,29 @@ impl BigInt : Num { } } } +} + +impl BigInt : Div { pure fn div(&self, other: &BigInt) -> BigInt { let (d, _) = self.divmod(other); return d; } +} + +impl BigInt : Modulo { pure fn modulo(&self, other: &BigInt) -> BigInt { let (_, m) = self.divmod(other); return m; } +} + +impl BigInt : Neg { pure fn neg(&self) -> BigInt { BigInt::from_biguint(self.sign.neg(), copy self.data) } +} +impl BigInt : IntConvertible { pure fn to_int(&self) -> int { match self.sign { Plus => uint::min(self.to_uint(), int::max_value as uint) as int, @@ -834,7 +864,7 @@ pub impl BigInt { mod biguint_tests { use core::*; - use core::num::{Num, Zero, One}; + use num::{IntConvertible, Zero, One}; use super::{BigInt, BigUint, BigDigit}; #[test] @@ -974,7 +1004,7 @@ mod biguint_tests { fn test_convert_int() { fn check(v: ~[BigDigit], i: int) { let b = BigUint::new(v); - assert b == Num::from_int(i); + assert b == IntConvertible::from_int(i); assert b.to_int() == i; } @@ -1244,7 +1274,7 @@ mod bigint_tests { use super::{BigInt, BigUint, BigDigit, Sign, Minus, Zero, Plus}; use core::*; - use core::num::{Num, Zero, One}; + use core::num::{IntConvertible, Zero, One}; #[test] fn test_from_biguint() { @@ -1303,7 +1333,7 @@ mod bigint_tests { #[test] fn test_convert_int() { fn check(b: BigInt, i: int) { - assert b == Num::from_int(i); + assert b == IntConvertible::from_int(i); assert b.to_int() == i; } @@ -1563,7 +1593,8 @@ mod bigint_tests { #[test] fn test_to_str_radix() { fn check(n: int, ans: &str) { - assert ans == Num::from_int::(n).to_str_radix(10); + assert ans == IntConvertible::from_int::( + n).to_str_radix(10); } check(10, "10"); check(1, "1"); @@ -1576,7 +1607,7 @@ mod bigint_tests { #[test] fn test_from_str_radix() { fn check(s: &str, ans: Option) { - let ans = ans.map(|&n| Num::from_int(n)); + let ans = ans.map(|&n| IntConvertible::from_int(n)); assert BigInt::from_str_radix(s, 10) == ans; } check("10", Some(10)); diff --git a/src/libstd/deque.rs b/src/libstd/deque.rs index b4217dfb39d4a..2abd59523a104 100644 --- a/src/libstd/deque.rs +++ b/src/libstd/deque.rs @@ -249,69 +249,19 @@ mod tests { assert deq.get(3) == d; } + #[deriving_eq] enum Taggy { One(int), Two(int, int), Three(int, int, int), } + #[deriving_eq] enum Taggypar { Onepar(int), Twopar(int, int), Threepar(int, int, int), } + #[deriving_eq] struct RecCy { x: int, y: int, - t: Taggy, - } - - impl Taggy : Eq { - pure fn eq(&self, other: &Taggy) -> bool { - match (*self) { - One(a1) => match (*other) { - One(b1) => return a1 == b1, - _ => return false - }, - Two(a1, a2) => match (*other) { - Two(b1, b2) => return a1 == b1 && a2 == b2, - _ => return false - }, - Three(a1, a2, a3) => match (*other) { - Three(b1, b2, b3) => return a1 == b1 && a2 == b2 && a3 == b3, - _ => return false - } - } - } - pure fn ne(&self, other: &Taggy) -> bool { !(*self).eq(other) } - } - - impl Taggypar : Eq { - //let eq4: EqFn> = |x,y| taggypareq::(x, y); - pure fn eq(&self, other: &Taggypar) -> bool { - match (*self) { - Onepar::(a1) => match (*other) { - Onepar::(b1) => return a1 == b1, - _ => return false - }, - Twopar::(a1, a2) => match (*other) { - Twopar::(b1, b2) => return a1 == b1 && a2 == b2, - _ => return false - }, - Threepar::(a1, a2, a3) => match (*other) { - Threepar::(b1, b2, b3) => { - return a1 == b1 && a2 == b2 && a3 == b3 - } - _ => return false - } - } - } - pure fn ne(&self, other: &Taggypar) -> bool { - !(*self).eq(other) - } - } - - impl RecCy : Eq { - pure fn eq(&self, other: &RecCy) -> bool { - return (*self).x == (*other).x && (*self).y == (*other).y && - (*self).t == (*other).t; - } - pure fn ne(&self, other: &RecCy) -> bool { !(*self).eq(other) } + t: Taggy } #[test] diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index dc379cec21b59..f93705c0c62b6 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -676,6 +676,7 @@ pub mod writer { mod tests { use ebml::reader; use ebml::writer; + use serialize::Encodable; use serialize; use core::io; diff --git a/src/libstd/json.rs b/src/libstd/json.rs index 45d467095fb85..1361d8647b574 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -15,6 +15,7 @@ //! json serialization +use serialize::Encodable; use serialize; use sort::Sort; diff --git a/src/libstd/map.rs b/src/libstd/map.rs index 3c890ef06541f..f3016e9df21a8 100644 --- a/src/libstd/map.rs +++ b/src/libstd/map.rs @@ -28,7 +28,7 @@ pub type Set = HashMap; pub type HashMap = chained::T; -pub trait Map { +pub trait StdMap { /// Return the number of elements in the map pure fn size() -> uint; @@ -124,7 +124,7 @@ pub mod util { // FIXME (#2344): package this up and export it as a datatype usable for // external code that doesn't want to pay the cost of a box. pub mod chained { - use map::{Map, util}; + use map::{StdMap, util}; use core::io; use core::ops; @@ -239,7 +239,7 @@ pub mod chained { } } - impl T: Map { + impl T: StdMap { pure fn size() -> uint { self.count } pure fn contains_key(k: K) -> bool { diff --git a/src/libstd/smallintmap.rs b/src/libstd/smallintmap.rs index 5f16f7155b61c..f17fce28ea93b 100644 --- a/src/libstd/smallintmap.rs +++ b/src/libstd/smallintmap.rs @@ -15,7 +15,7 @@ #[forbid(deprecated_mode)]; use map; -use map::Map; +use map::StdMap; use core::dvec::DVec; use core::ops; @@ -81,7 +81,7 @@ pub pure fn contains_key(self: SmallIntMap, key: uint) -> bool { } /// Implements the map::map interface for smallintmap -impl SmallIntMap: map::Map { +impl SmallIntMap: map::StdMap { pure fn size() -> uint { let mut sz = 0u; for self.v.each |item| { @@ -165,8 +165,8 @@ impl SmallIntMap: ops::Index { } /// Cast the given smallintmap to a map::map -pub fn as_map(s: SmallIntMap) -> map::Map { - s as map::Map:: +pub fn as_map(s: SmallIntMap) -> map::StdMap { + s as map::StdMap:: } #[cfg(test)] diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index ddd0f846f9d6c..201d53c0c3f36 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -12,7 +12,7 @@ use core::prelude::*; use ast::*; use ast; -use ast_util::{path_to_ident, stmt_id}; +use ast_util::{inlined_item_utils, path_to_ident, stmt_id}; use ast_util; use attr; use codemap; diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 23ea27e7c5cfc..7b134a8db2424 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -376,7 +376,7 @@ pure fn struct_field_visibility(field: ast::struct_field) -> visibility { } } -trait inlined_item_utils { +pub trait inlined_item_utils { fn ident() -> ident; fn id() -> ast::node_id; fn accept(e: E, v: visit::vt); diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 7a7c2312f5640..7e3cbd18f5273 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -33,7 +33,7 @@ use core::uint; use core::vec; use std::serialize::{Encodable, Decodable, Encoder, Decoder}; -trait Pos { +pub trait Pos { static pure fn from_uint(n: uint) -> self; pure fn to_uint(&self) -> uint; } diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 6112313cf4808..4c0cc161fdd03 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -10,7 +10,7 @@ use core::prelude::*; -use codemap::span; +use codemap::{Pos, span}; use codemap; use core::cmp; diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs index 343ce4b039b51..8a5b8a127d035 100644 --- a/src/libsyntax/ext/pipes/ast_builder.rs +++ b/src/libsyntax/ext/pipes/ast_builder.rs @@ -66,7 +66,7 @@ impl @ast::path: append_types { } } -trait ext_ctxt_ast_builder { +pub trait ext_ctxt_ast_builder { fn ty_param(id: ast::ident, +bounds: ~[ast::ty_param_bound]) -> ast::ty_param; fn arg(name: ident, ty: @ast::Ty) -> ast::arg; diff --git a/src/libsyntax/ext/pipes/mod.rs b/src/libsyntax/ext/pipes/mod.rs index 8eef065395e06..f91ec1ea48f85 100644 --- a/src/libsyntax/ext/pipes/mod.rs +++ b/src/libsyntax/ext/pipes/mod.rs @@ -49,6 +49,7 @@ use codemap::span; use ext::base; use ext::base::ext_ctxt; use ext::pipes::parse_proto::proto_parser; +use ext::pipes::pipec::gen_init; use ext::pipes::proto::{visit, protocol}; use parse::lexer::{new_tt_reader, reader}; use parse::parser::Parser; diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs index e53057cb312e3..774a559625828 100644 --- a/src/libsyntax/ext/pipes/pipec.rs +++ b/src/libsyntax/ext/pipes/pipec.rs @@ -13,7 +13,8 @@ use ast::ident; use ast_util::dummy_sp; use ext::base::ext_ctxt; -use ext::pipes::ast_builder::{append_types, path, path_global}; +use ext::pipes::ast_builder::{append_types, ext_ctxt_ast_builder, path}; +use ext::pipes::ast_builder::{path_global}; use ext::pipes::proto::*; use ext::quote::rt::*; use parse::*; @@ -35,7 +36,7 @@ trait to_type_decls { fn to_endpoint_decls(cx: ext_ctxt, dir: direction) -> ~[@ast::item]; } -trait gen_init { +pub trait gen_init { fn gen_init(cx: ext_ctxt) -> @ast::item; fn compile(cx: ext_ctxt) -> @ast::item; fn buffer_ty_path(cx: ext_ctxt) -> @ast::Ty; diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs index 26638cd8cd64f..9d24b3db72437 100644 --- a/src/libsyntax/ext/pipes/proto.rs +++ b/src/libsyntax/ext/pipes/proto.rs @@ -13,7 +13,7 @@ use core::prelude::*; use ast; use codemap::span; use ext::base::ext_ctxt; -use ext::pipes::ast_builder::{path, append_types}; +use ext::pipes::ast_builder::{append_types, ext_ctxt_ast_builder, path}; use core::cmp; use core::dvec::DVec; diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 3354d015476e5..7605e01fbf024 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -10,7 +10,7 @@ use ast; use attr; -use codemap::{span, BytePos}; +use codemap::{BytePos, Pos, span}; use ext::base::ext_ctxt; use ext::base; use ext::build; diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 3ade0bf86b122..4ecbbdc9760ba 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -9,7 +9,7 @@ // except according to those terms. use codemap; -use codemap::{span, Loc, FileMap}; +use codemap::{FileMap, Loc, Pos, span}; use ext::base::*; use ext::base; use ext::build::{mk_base_vec_e, mk_uint, mk_u8, mk_base_str}; diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs index 66c3111b30960..fbe258852e273 100644 --- a/src/libsyntax/parse/comments.rs +++ b/src/libsyntax/parse/comments.rs @@ -11,7 +11,7 @@ use core::prelude::*; use ast; -use codemap::{BytePos, CharPos, CodeMap, FileMap}; +use codemap::{BytePos, CharPos, CodeMap, FileMap, Pos}; use diagnostic; use parse::lexer::{is_whitespace, get_str_from, reader}; use parse::lexer::{string_reader, bump, is_eof, nextch}; diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 1574a037a4638..5a0f40f3c12f5 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -12,7 +12,7 @@ use core::prelude::*; use ast; use ast_util; -use codemap::{span, CodeMap, CharPos, BytePos}; +use codemap::{BytePos, CharPos, CodeMap, Pos, span}; use codemap; use diagnostic::span_handler; use ext::tt::transcribe::{tt_next_token}; diff --git a/src/test/auxiliary/issue_2242_b.rs b/src/test/auxiliary/issue_2242_b.rs deleted file mode 100644 index 73ec1f47230fe..0000000000000 --- a/src/test/auxiliary/issue_2242_b.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[link(name = "b", vers = "0.1")]; -#[crate_type = "lib"]; - -extern mod a; -use a::to_strz; - -impl int: to_strz { - fn to_strz() -> ~str { fmt!("%?", self) } -} diff --git a/src/test/compile-fail/drop-on-non-struct.rs b/src/test/compile-fail/drop-on-non-struct.rs index 95512a2da6068..6988027235074 100644 --- a/src/test/compile-fail/drop-on-non-struct.rs +++ b/src/test/compile-fail/drop-on-non-struct.rs @@ -11,6 +11,7 @@ type Foo = @[u8]; impl Foo : Drop { //~ ERROR the Drop trait may only be implemented +//~^ ERROR cannot provide an extension implementation fn finalize(&self) { io::println("kaboom"); } diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs index 89377eb3d152a..7161e85444792 100644 --- a/src/test/compile-fail/map-types.rs +++ b/src/test/compile-fail/map-types.rs @@ -11,12 +11,13 @@ extern mod std; use std::map; use std::map::HashMap; -use std::map::Map; +use std::map::StdMap; // Test that trait types printed in error msgs include the type arguments. fn main() { - let x: Map<~str,~str> = map::HashMap::<~str,~str>() as Map::<~str,~str>; - let y: Map = x; - //~^ ERROR mismatched types: expected `@std::map::Map` + let x: StdMap<~str,~str> = map::HashMap::<~str,~str>() as + StdMap::<~str,~str>; + let y: StdMap = x; + //~^ ERROR mismatched types: expected `@std::map::StdMap` } diff --git a/src/test/run-pass/auto-encode.rs b/src/test/run-pass/auto-encode.rs index 6ea08d200e77d..ec73704ca27ba 100644 --- a/src/test/run-pass/auto-encode.rs +++ b/src/test/run-pass/auto-encode.rs @@ -128,19 +128,16 @@ impl CLike : cmp::Eq { #[auto_encode] #[auto_decode] +#[deriving_eq] struct Spanned { lo: uint, hi: uint, node: T, } -impl Spanned : cmp::Eq { - pure fn eq(&self, other: &Spanned) -> bool { - self.lo == other.lo && - self.hi == other.hi && - self.node == other.node - } - pure fn ne(&self, other: &Spanned) -> bool { !self.eq(other) } +enum AnEnum { + AVariant, + AnotherVariant } #[auto_encode] diff --git a/src/test/run-pass/class-impl-very-parameterized-trait.rs b/src/test/run-pass/class-impl-very-parameterized-trait.rs index b802b9708923e..6bc881884522a 100644 --- a/src/test/run-pass/class-impl-very-parameterized-trait.rs +++ b/src/test/run-pass/class-impl-very-parameterized-trait.rs @@ -51,7 +51,7 @@ impl cat { } } -impl cat : Map { +impl cat : StdMap { pure fn size() -> uint { self.meows as uint } fn insert(+k: int, +_v: T) -> bool { self.meows += k; diff --git a/src/test/run-pass/issue-2242-d.rs b/src/test/run-pass/issue-2242-d.rs deleted file mode 100644 index 006a33ebb65ed..0000000000000 --- a/src/test/run-pass/issue-2242-d.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-fast (aux-build) -// aux-build:issue_2242_a.rs -// aux-build:issue_2242_b.rs -// aux-build:issue_2242_c.rs - -extern mod a; -extern mod b; -extern mod c; - -use a::to_strz; - -fn main() { - io::println((~"foo").to_strz()); - io::println(1.to_strz()); - io::println(true.to_strz()); -} From 2c31c787fcfb7604de6d0c57f34f41a7fd0b785e Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 28 Jan 2013 10:46:43 -0800 Subject: [PATCH 29/31] librustc: Disallow trait bounds in types, enumerations, and structure definitions --- src/libcore/hashmap.rs | 6 +- src/libcore/io.rs | 2 +- src/libcore/oldcomm.rs | 8 +- src/libcore/pipes.rs | 294 +++++++++++++++++- src/libcore/private.rs | 6 +- src/libcore/private/global.rs | 2 +- src/libcore/reflect.rs | 2 +- src/libcore/task/local_data.rs | 2 +- src/libcore/task/spawn.rs | 2 +- src/librustc/middle/ty.rs | 2 +- src/librustc/middle/typeck/collect.rs | 22 ++ src/librustc/middle/typeck/infer/unify.rs | 2 +- src/libstd/arc.rs | 14 +- src/libstd/comm.rs | 9 +- src/libstd/flatpipes.rs | 33 +- src/libstd/map.rs | 8 +- src/libstd/priority_queue.rs | 2 +- src/libstd/sync.rs | 4 +- src/libstd/treemap.rs | 10 +- src/libstd/workcache.rs | 7 + src/libsyntax/ext/pipes/ast_builder.rs | 7 + src/libsyntax/ext/pipes/pipec.rs | 8 +- src/libsyntax/parse/obsolete.rs | 18 +- src/libsyntax/util/interner.rs | 2 +- src/test/auxiliary/issue-2526.rs | 2 +- src/test/auxiliary/test_comm.rs | 4 +- .../bench/task-perf-word-count-generic.rs | 12 +- src/test/compile-fail/issue-2718-a.rs | 2 +- src/test/run-fail/bug-811.rs | 2 +- src/test/run-fail/issue-2444.rs | 2 +- src/test/run-pass/auto-encode.rs | 5 - src/test/run-pass/box-unbox.rs | 2 +- .../class-impl-very-parameterized-trait.rs | 2 +- src/test/run-pass/generic-exterior-box.rs | 2 +- src/test/run-pass/generic-exterior-unique.rs | 2 +- src/test/run-pass/issue-2288.rs | 2 +- src/test/run-pass/issue-2311-2.rs | 2 +- src/test/run-pass/issue-2445-b.rs | 2 +- src/test/run-pass/issue-2445.rs | 2 +- src/test/run-pass/issue-2718.rs | 6 +- src/test/run-pass/issue-3149.rs | 2 +- src/test/run-pass/reflect-visit-data.rs | 2 +- src/test/run-pass/resource-generic.rs | 2 +- src/test/run-pass/send-type-inference.rs | 2 +- 44 files changed, 424 insertions(+), 107 deletions(-) diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index c3af7a99692e5..a22b21a1e2acf 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -35,13 +35,13 @@ pub mod linear { const INITIAL_CAPACITY: uint = 32u; // 2^5 - struct Bucket { + struct Bucket { hash: uint, key: K, value: V, } - pub struct LinearMap { + pub struct LinearMap { k0: u64, k1: u64, resize_at: uint, @@ -423,7 +423,7 @@ pub mod linear { pure fn ne(&self, other: &LinearMap) -> bool { !self.eq(other) } } - pub struct LinearSet { + pub struct LinearSet { priv map: LinearMap } diff --git a/src/libcore/io.rs b/src/libcore/io.rs index fedcb9511960e..933c38b5499b5 100644 --- a/src/libcore/io.rs +++ b/src/libcore/io.rs @@ -1111,7 +1111,7 @@ pub mod fsync { // Artifacts that need to fsync on destruction - pub struct Res { + pub struct Res { arg: Arg, } diff --git a/src/libcore/oldcomm.rs b/src/libcore/oldcomm.rs index c221df293dcdb..1473aa6da0782 100644 --- a/src/libcore/oldcomm.rs +++ b/src/libcore/oldcomm.rs @@ -68,7 +68,7 @@ use vec; * transmitted. If a port value is copied, both copies refer to the same * port. Ports may be associated with multiple `chan`s. */ -pub enum Port { +pub enum Port { Port_(@PortPtr) } @@ -84,7 +84,7 @@ pub enum Port { * data will be silently dropped. Channels may be duplicated and * themselves transmitted over other channels. */ -pub enum Chan { +pub enum Chan { Chan_(port_id) } @@ -120,7 +120,7 @@ pub fn listen(f: fn(Chan) -> U) -> U { f(po.chan()) } -struct PortPtr { +struct PortPtr { po: *rust_port, drop { unsafe { @@ -238,7 +238,7 @@ fn peek_chan(ch: Chan) -> bool { } /// Receive on a raw port pointer -fn recv_(p: *rust_port) -> T { +fn recv_(p: *rust_port) -> T { unsafe { let yield = 0; let yieldp = ptr::addr_of(&yield); diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 9142c11360a0d..20a2cadaa2bd5 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -148,7 +148,7 @@ type Buffer = { #[cfg(stage1)] #[cfg(stage2)] #[cfg(stage3)] -pub struct Buffer { +pub struct Buffer { header: BufferHeader, data: T, } @@ -209,10 +209,18 @@ impl PacketHeader { } #[doc(hidden)] +#[cfg(stage0)] pub struct Packet { header: PacketHeader, mut payload: Option, } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +pub struct Packet { + header: PacketHeader, + mut payload: Option, +} #[doc(hidden)] pub trait HasBuffer { @@ -253,12 +261,11 @@ fn unibuffer() -> ~Buffer> { } move b } - #[doc(hidden)] #[cfg(stage1)] #[cfg(stage2)] #[cfg(stage3)] -fn unibuffer() -> ~Buffer> { +fn unibuffer() -> ~Buffer> { let b = ~Buffer { header: BufferHeader(), data: Packet { @@ -274,6 +281,7 @@ fn unibuffer() -> ~Buffer> { } #[doc(hidden)] +#[cfg(stage0)] pub fn packet() -> *Packet { let b = unibuffer(); let p = ptr::addr_of(&(b.data)); @@ -281,6 +289,16 @@ pub fn packet() -> *Packet { unsafe { forget(move b) } p } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +pub fn packet() -> *Packet { + let b = unibuffer(); + let p = ptr::addr_of(&(b.data)); + // We'll take over memory management from here. + unsafe { forget(move b) } + p +} #[doc(hidden)] pub fn entangle_buffer( @@ -384,11 +402,19 @@ fn swap_state_rel(dst: &mut State, src: State) -> State { } #[doc(hidden)] +#[cfg(stage0)] pub unsafe fn get_buffer(p: *PacketHeader) -> ~Buffer { transmute((*p).buf_header()) } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +pub unsafe fn get_buffer(p: *PacketHeader) -> ~Buffer { + transmute((*p).buf_header()) +} // This could probably be done with SharedMutableState to avoid move_it!(). +#[cfg(stage0)] struct BufferResource { buffer: ~Buffer, @@ -410,7 +436,31 @@ struct BufferResource { } } } +#[cfg(stage1)] +#[cfg(stage2)] +struct BufferResource { + buffer: ~Buffer, + drop { + unsafe { + let b = move_it!(self.buffer); + //let p = ptr::addr_of(*b); + //error!("drop %?", p); + let old_count = atomic_sub_rel(&mut b.header.ref_count, 1); + //let old_count = atomic_xchng_rel(b.header.ref_count, 0); + if old_count == 1 { + // The new count is 0. + + // go go gadget drop glue + } + else { + forget(move b) + } + } + } +} + +#[cfg(stage0)] fn BufferResource(b: ~Buffer) -> BufferResource { //let p = ptr::addr_of(*b); //error!("take %?", p); @@ -421,8 +471,21 @@ fn BufferResource(b: ~Buffer) -> BufferResource { buffer: move b } } +#[cfg(stage1)] +#[cfg(stage2)] +fn BufferResource(b: ~Buffer) -> BufferResource { + //let p = ptr::addr_of(*b); + //error!("take %?", p); + atomic_add_acq(&mut b.header.ref_count, 1); + + BufferResource { + // tjc: ???? + buffer: move b + } +} #[doc(hidden)] +#[cfg(stage0)] pub fn send(p: SendPacketBuffered, payload: T) -> bool { let header = p.header(); @@ -464,6 +527,49 @@ pub fn send(p: SendPacketBuffered, } } } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +pub fn send(p: SendPacketBuffered, payload: T) -> bool { + let header = p.header(); + let p_ = p.unwrap(); + let p = unsafe { &*p_ }; + assert ptr::addr_of(&(p.header)) == header; + assert p.payload.is_none(); + p.payload = move Some(move payload); + let old_state = swap_state_rel(&mut p.header.state, Full); + match old_state { + Empty => { + // Yay, fastpath. + + // The receiver will eventually clean this up. + //unsafe { forget(p); } + return true; + } + Full => fail ~"duplicate send", + Blocked => { + debug!("waking up task for %?", p_); + let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); + if !old_task.is_null() { + unsafe { + rustrt::task_signal_event( + old_task, + ptr::addr_of(&(p.header)) as *libc::c_void); + rustrt::rust_task_deref(old_task); + } + } + + // The receiver will eventually clean this up. + //unsafe { forget(p); } + return true; + } + Terminated => { + // The receiver will never receive this. Rely on drop_glue + // to clean everything up. + return false; + } + } +} /** Receives a message from a pipe. @@ -809,13 +915,24 @@ pub fn select(endpoints: ~[RecvPacketBuffered]) message. */ +#[cfg(stage0)] pub type SendPacket = SendPacketBuffered>; +#[cfg(stage1)] +#[cfg(stage2)] +pub type SendPacket = SendPacketBuffered>; #[doc(hidden)] +#[cfg(stage0)] pub fn SendPacket(p: *Packet) -> SendPacket { SendPacketBuffered(p) } +#[cfg(stage1)] +#[cfg(stage2)] +pub fn SendPacket(p: *Packet) -> SendPacket { + SendPacketBuffered(p) +} +#[cfg(stage0)] pub struct SendPacketBuffered { mut p: Option<*Packet>, mut buffer: Option>, @@ -834,7 +951,31 @@ pub struct SendPacketBuffered { // } else { "some" }); } } } +#[cfg(stage1)] +#[cfg(stage2)] +pub struct SendPacketBuffered { + mut p: Option<*Packet>, + mut buffer: Option>, +} +impl SendPacketBuffered : ::ops::Drop { + fn finalize(&self) { + //if self.p != none { + // debug!("drop send %?", option::get(self.p)); + //} + if self.p != None { + let mut p = None; + p <-> self.p; + sender_terminate(option::unwrap(move p)) + } + //unsafe { error!("send_drop: %?", + // if self.buffer == none { + // "none" + // } else { "some" }); } + } +} + +#[cfg(stage0)] pub fn SendPacketBuffered(p: *Packet) -> SendPacketBuffered { //debug!("take send %?", p); @@ -846,8 +987,50 @@ pub fn SendPacketBuffered(p: *Packet) } } } +#[cfg(stage1)] +#[cfg(stage2)] +pub fn SendPacketBuffered(p: *Packet) + -> SendPacketBuffered { + //debug!("take send %?", p); + SendPacketBuffered { + p: Some(p), + buffer: unsafe { + Some(BufferResource( + get_buffer(ptr::addr_of(&((*p).header))))) + } + } +} + +#[cfg(stage0)] +impl SendPacketBuffered { + fn unwrap() -> *Packet { + let mut p = None; + p <-> self.p; + option::unwrap(move p) + } + + pure fn header() -> *PacketHeader { + match self.p { + Some(packet) => unsafe { + let packet = &*packet; + let header = ptr::addr_of(&(packet.header)); + //forget(packet); + header + }, + None => fail ~"packet already consumed" + } + } -impl SendPacketBuffered { + fn reuse_buffer() -> BufferResource { + //error!("send reuse_buffer"); + let mut tmp = None; + tmp <-> self.buffer; + option::unwrap(move tmp) + } +} +#[cfg(stage1)] +#[cfg(stage2)] +impl SendPacketBuffered { fn unwrap() -> *Packet { let mut p = None; p <-> self.p; @@ -876,13 +1059,25 @@ impl SendPacketBuffered { /// Represents the receive end of a pipe. It can receive exactly one /// message. +#[cfg(stage0)] pub type RecvPacket = RecvPacketBuffered>; +#[cfg(stage1)] +#[cfg(stage2)] +pub type RecvPacket = RecvPacketBuffered>; #[doc(hidden)] +#[cfg(stage0)] pub fn RecvPacket(p: *Packet) -> RecvPacket { RecvPacketBuffered(p) } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +pub fn RecvPacket(p: *Packet) -> RecvPacket { + RecvPacketBuffered(p) +} +#[cfg(stage0)] pub struct RecvPacketBuffered { mut p: Option<*Packet>, mut buffer: Option>, @@ -901,6 +1096,29 @@ pub struct RecvPacketBuffered { // } else { "some" }); } } } +#[cfg(stage1)] +#[cfg(stage2)] +pub struct RecvPacketBuffered { + mut p: Option<*Packet>, + mut buffer: Option>, +} + +impl RecvPacketBuffered : ::ops::Drop { + fn finalize(&self) { + //if self.p != none { + // debug!("drop recv %?", option::get(self.p)); + //} + if self.p != None { + let mut p = None; + p <-> self.p; + receiver_terminate(option::unwrap(move p)) + } + //unsafe { error!("recv_drop: %?", + // if self.buffer == none { + // "none" + // } else { "some" }); } + } +} impl RecvPacketBuffered { fn unwrap() -> *Packet { @@ -931,6 +1149,7 @@ impl RecvPacketBuffered : Selectable { } } +#[cfg(stage0)] pub fn RecvPacketBuffered(p: *Packet) -> RecvPacketBuffered { //debug!("take recv %?", p); @@ -942,12 +1161,33 @@ pub fn RecvPacketBuffered(p: *Packet) } } } +#[cfg(stage1)] +#[cfg(stage2)] +pub fn RecvPacketBuffered(p: *Packet) + -> RecvPacketBuffered { + //debug!("take recv %?", p); + RecvPacketBuffered { + p: Some(p), + buffer: unsafe { + Some(BufferResource( + get_buffer(ptr::addr_of(&((*p).header))))) + } + } +} #[doc(hidden)] +#[cfg(stage0)] pub fn entangle() -> (SendPacket, RecvPacket) { let p = packet(); (SendPacket(p), RecvPacket(p)) } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +pub fn entangle() -> (SendPacket, RecvPacket) { + let p = packet(); + (SendPacket(p), RecvPacket(p)) +} /** Spawn a task to provide a service. @@ -1039,24 +1279,50 @@ pub trait Peekable { } #[doc(hidden)] +#[cfg(stage0)] struct Chan_ { - mut endp: Option>, + mut endp: Option> +} +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +struct Chan_ { + mut endp: Option> } /// An endpoint that can send many messages. +#[cfg(stage0)] pub enum Chan { Chan_(Chan_) } +#[cfg(stage1)] +#[cfg(stage2)] +pub enum Chan { + Chan_(Chan_) +} #[doc(hidden)] +#[cfg(stage0)] struct Port_ { mut endp: Option>, } +#[doc(hidden)] +#[cfg(stage1)] +#[cfg(stage2)] +struct Port_ { + mut endp: Option>, +} /// An endpoint that can receive many messages. +#[cfg(stage0)] pub enum Port { Port_(Port_) } +#[cfg(stage1)] +#[cfg(stage2)] +pub enum Port { + Port_(Port_) +} /** Creates a `(chan, port)` pair. @@ -1142,9 +1408,15 @@ impl Port: Selectable { } /// Treat many ports as one. +#[cfg(stage0)] pub struct PortSet { mut ports: ~[pipes::Port], } +#[cfg(stage1)] +#[cfg(stage2)] +pub struct PortSet { + mut ports: ~[pipes::Port], +} pub fn PortSet() -> PortSet{ PortSet { @@ -1207,7 +1479,11 @@ impl PortSet : Peekable { } /// A channel that can be shared between many senders. +#[cfg(stage0)] pub type SharedChan = private::Exclusive>; +#[cfg(stage1)] +#[cfg(stage2)] +pub type SharedChan = private::Exclusive>; impl SharedChan: GenericChan { fn send(x: T) { @@ -1275,9 +1551,17 @@ proto! oneshot ( ) /// The send end of a oneshot pipe. +#[cfg(stage0)] pub type ChanOne = oneshot::client::Oneshot; +#[cfg(stage1)] +#[cfg(stage2)] +pub type ChanOne = oneshot::client::Oneshot; /// The receive end of a oneshot pipe. +#[cfg(stage0)] pub type PortOne = oneshot::server::Oneshot; +#[cfg(stage1)] +#[cfg(stage2)] +pub type PortOne = oneshot::server::Oneshot; /// Initialiase a (send-endpoint, recv-endpoint) oneshot pipe pair. pub fn oneshot() -> (PortOne, ChanOne) { diff --git a/src/libcore/private.rs b/src/libcore/private.rs index 332c763f151e8..b6ac711d7649c 100644 --- a/src/libcore/private.rs +++ b/src/libcore/private.rs @@ -238,7 +238,7 @@ pub unsafe fn unwrap_shared_mutable_state(rc: SharedMutableState) * Data races between tasks can result in crashes and, with sufficient * cleverness, arbitrary type coercion. */ -pub type SharedMutableState = ArcDestruct; +pub type SharedMutableState = ArcDestruct; pub unsafe fn shared_mutable_state(data: T) -> SharedMutableState { @@ -341,11 +341,11 @@ impl LittleLock { } } -struct ExData { lock: LittleLock, mut failed: bool, mut data: T, } +struct ExData { lock: LittleLock, mut failed: bool, mut data: T, } /** * An arc over mutable data that is protected by a lock. For library use only. */ -pub struct Exclusive { x: SharedMutableState> } +pub struct Exclusive { x: SharedMutableState> } pub fn exclusive(user_data: T) -> Exclusive { let data = ExData { diff --git a/src/libcore/private/global.rs b/src/libcore/private/global.rs index 69319abc00930..ee20fb665bea6 100644 --- a/src/libcore/private/global.rs +++ b/src/libcore/private/global.rs @@ -41,7 +41,7 @@ use sys::Closure; use task::spawn; use uint; -pub type GlobalDataKey = &fn(v: T); +pub type GlobalDataKey = &fn(v: T); pub unsafe fn global_data_clone_create( key: GlobalDataKey, create: &fn() -> ~T) -> T { diff --git a/src/libcore/reflect.rs b/src/libcore/reflect.rs index 55eb53bc0266a..81a36e1ae13ee 100644 --- a/src/libcore/reflect.rs +++ b/src/libcore/reflect.rs @@ -41,7 +41,7 @@ pub fn align(size: uint, align: uint) -> uint { } /// Adaptor to wrap around visitors implementing MovePtr. -pub struct MovePtrAdaptor { +pub struct MovePtrAdaptor { inner: V } pub fn MovePtrAdaptor(v: V) -> MovePtrAdaptor { diff --git a/src/libcore/task/local_data.rs b/src/libcore/task/local_data.rs index 05a4e35b249e4..42765ef139ff5 100644 --- a/src/libcore/task/local_data.rs +++ b/src/libcore/task/local_data.rs @@ -45,7 +45,7 @@ use task; * * These two cases aside, the interface is safe. */ -pub type LocalDataKey = &fn(v: @T); +pub type LocalDataKey = &fn(v: @T); /** * Remove a task-local data value from the table, returning the diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs index 0a2f6634214e6..3db6fa00f16dd 100644 --- a/src/libcore/task/spawn.rs +++ b/src/libcore/task/spawn.rs @@ -77,7 +77,7 @@ use cast; use container::Map; use oldcomm; use option; -use pipes::{Chan, GenericChan, GenericPort, Port}; +use pipes::{Chan, GenericChan, GenericPort, Port, stream}; use pipes; use prelude::*; use private; diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8f1873f628f05..1bdaa984914db 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -568,7 +568,7 @@ struct FnSig { * by the meta information because, in some cases, the * meta information is inferred. */ #[deriving_eq] -struct FnTyBase { +struct FnTyBase { meta: M, // Either FnMeta or FnVid sig: FnSig // Types of arguments/return type } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index ce0c7a94c7cc0..8374a65f63c30 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -598,6 +598,20 @@ fn convert_methods(ccx: @crate_ctxt, } } +fn ensure_no_ty_param_bounds(ccx: @crate_ctxt, + span: span, + ty_params: &[ast::ty_param], + thing: &static/str) { + for ty_params.each |ty_param| { + if ty_param.bounds.len() > 0 { + ccx.tcx.sess.span_err( + span, + fmt!("trait bounds are not allowed in %s definitions", + thing)); + } + } +} + fn convert(ccx: @crate_ctxt, it: @ast::item) { let tcx = ccx.tcx; let rp = tcx.region_paramd_items.find(it.id); @@ -607,6 +621,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) { // These don't define types. ast::item_foreign_mod(_) | ast::item_mod(_) => {} ast::item_enum(ref enum_definition, ref ty_params) => { + ensure_no_ty_param_bounds(ccx, it.span, *ty_params, "enumeration"); let tpt = ty_of_item(ccx, it); write_ty_to_tcx(tcx, it.id, tpt.ty); get_enum_variant_types(ccx, @@ -644,6 +659,8 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) { let _ = convert_methods(ccx, provided_methods, rp, bounds); } ast::item_struct(struct_def, tps) => { + ensure_no_ty_param_bounds(ccx, it.span, tps, "structure"); + // Write the class type let tpt = ty_of_item(ccx, it); write_ty_to_tcx(tcx, it.id, tpt.ty); @@ -651,6 +668,11 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) { convert_struct(ccx, rp, struct_def, tps, tpt, it.id); } + ast::item_ty(_, ref ty_params) => { + ensure_no_ty_param_bounds(ccx, it.span, *ty_params, "type"); + let tpt = ty_of_item(ccx, it); + write_ty_to_tcx(tcx, it.id, tpt.ty); + } _ => { // This call populates the type cache with the converted type // of the item in passing. All we have to do here is to write diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs index 6c831427b031e..b2b1188388f45 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/typeck/infer/unify.rs @@ -31,7 +31,7 @@ struct ValsAndBindings { mut bindings: ~[(V, VarValue)], } -struct Node { +struct Node { root: V, possible_types: T, rank: uint, diff --git a/src/libstd/arc.rs b/src/libstd/arc.rs index 0c40fe283af0b..edffa32e501ee 100644 --- a/src/libstd/arc.rs +++ b/src/libstd/arc.rs @@ -79,7 +79,7 @@ impl &Condvar { ****************************************************************************/ /// An atomically reference counted wrapper for shared immutable state. -struct ARC { x: SharedMutableState } +struct ARC { x: SharedMutableState } /// Create an atomically reference counted wrapper. pub fn ARC(data: T) -> ARC { @@ -130,9 +130,9 @@ impl ARC: Clone { ****************************************************************************/ #[doc(hidden)] -struct MutexARCInner { lock: Mutex, failed: bool, data: T } +struct MutexARCInner { lock: Mutex, failed: bool, data: T } /// An ARC with mutable data protected by a blocking mutex. -struct MutexARC { x: SharedMutableState> } +struct MutexARC { x: SharedMutableState> } /// Create a mutex-protected ARC with the supplied data. pub fn MutexARC(user_data: T) -> MutexARC { @@ -267,14 +267,14 @@ fn PoisonOnFail(failed: &r/mut bool) -> PoisonOnFail { ****************************************************************************/ #[doc(hidden)] -struct RWARCInner { lock: RWlock, failed: bool, data: T } +struct RWARCInner { lock: RWlock, failed: bool, data: T } /** * A dual-mode ARC protected by a reader-writer lock. The data can be accessed * mutably or immutably, and immutably-accessing tasks may run concurrently. * * Unlike mutex_arcs, rw_arcs are safe, because they cannot be nested. */ -struct RWARC { +struct RWARC { x: SharedMutableState>, mut cant_nest: () } @@ -426,10 +426,10 @@ fn borrow_rwlock(state: &r/mut RWARCInner) -> &r/RWlock { // FIXME (#3154) ice with struct/& prevents these from being structs. /// The "write permission" token used for RWARC.write_downgrade(). -pub enum RWWriteMode = +pub enum RWWriteMode = (&mut T, sync::RWlockWriteMode, PoisonOnFail); /// The "read permission" token used for RWARC.write_downgrade(). -pub enum RWReadMode = (&T, sync::RWlockReadMode); +pub enum RWReadMode = (&T, sync::RWlockReadMode); impl &RWWriteMode { /// Access the pre-downgrade RWARC in write mode. diff --git a/src/libstd/comm.rs b/src/libstd/comm.rs index 3118a0c1ba545..16e8b63da8174 100644 --- a/src/libstd/comm.rs +++ b/src/libstd/comm.rs @@ -23,7 +23,14 @@ use core::pipes; use core::prelude::*; /// An extension of `pipes::stream` that allows both sending and receiving. -pub struct DuplexStream { +#[cfg(stage0)] +pub struct DuplexStream { + priv chan: Chan, + priv port: Port, +} +#[cfg(stage1)] +#[cfg(stage2)] +pub struct DuplexStream { priv chan: Chan, priv port: Port, } diff --git a/src/libstd/flatpipes.rs b/src/libstd/flatpipes.rs index afc3e72e636cb..bd684baf6b300 100644 --- a/src/libstd/flatpipes.rs +++ b/src/libstd/flatpipes.rs @@ -63,7 +63,7 @@ and an `Unflattener` that converts the bytes to a value. Create using the constructors in the `serial` and `pod` modules. */ -pub struct FlatPort, P: BytePort> { +pub struct FlatPort { unflattener: U, byte_port: P } @@ -74,7 +74,7 @@ byte vectors, and a `ByteChan` that transmits the bytes. Create using the constructors in the `serial` and `pod` modules. */ -pub struct FlatChan, C: ByteChan> { +pub struct FlatChan { flattener: F, byte_chan: C } @@ -181,14 +181,12 @@ pub mod pod { use core::pipes; use core::prelude::*; - pub type ReaderPort = + pub type ReaderPort = FlatPort, ReaderBytePort>; - pub type WriterChan = + pub type WriterChan = FlatChan, WriterByteChan>; - pub type PipePort = - FlatPort, PipeBytePort>; - pub type PipeChan = - FlatChan, PipeByteChan>; + pub type PipePort = FlatPort, PipeBytePort>; + pub type PipeChan = FlatChan, PipeByteChan>; /// Create a `FlatPort` from a `Reader` pub fn reader_port( @@ -352,11 +350,11 @@ pub mod flatteners { // FIXME #4074: Copy + Owned != POD - pub struct PodUnflattener { + pub struct PodUnflattener { bogus: () } - pub struct PodFlattener { + pub struct PodFlattener { bogus: () } @@ -398,14 +396,13 @@ pub mod flatteners { pub type DeserializeBuffer = ~fn(buf: &[u8]) -> T; - pub struct DeserializingUnflattener> { + pub struct DeserializingUnflattener { deserialize_buffer: DeserializeBuffer } pub type SerializeValue = ~fn(val: &T) -> ~[u8]; - pub struct SerializingFlattener> { + pub struct SerializingFlattener { serialize_value: SerializeValue } @@ -518,11 +515,11 @@ pub mod bytepipes { use core::pipes; use core::prelude::*; - pub struct ReaderBytePort { + pub struct ReaderBytePort { reader: R } - pub struct WriterByteChan { + pub struct WriterByteChan { writer: W } @@ -767,9 +764,9 @@ mod test { test_some_tcp_stream(reader_port, writer_chan, 9667); } - type ReaderPortFactory> = + type ReaderPortFactory = ~fn(TcpSocketBuf) -> FlatPort>; - type WriterChanFactory> = + type WriterChanFactory = ~fn(TcpSocketBuf) -> FlatChan>; fn test_some_tcp_stream, F: Flattener>( @@ -893,7 +890,7 @@ mod test { use core::sys; use core::task; - type PortLoader = + type PortLoader

= ~fn(~[u8]) -> FlatPort, P>; fn reader_port_loader(bytes: ~[u8] diff --git a/src/libstd/map.rs b/src/libstd/map.rs index f3016e9df21a8..2fa2825eb4cd7 100644 --- a/src/libstd/map.rs +++ b/src/libstd/map.rs @@ -24,9 +24,9 @@ use core::uint; use core::vec; /// A convenience type to treat a hashmap as a set -pub type Set = HashMap; +pub type Set = HashMap; -pub type HashMap = chained::T; +pub type HashMap = chained::T; pub trait StdMap { /// Return the number of elements in the map @@ -142,12 +142,12 @@ pub mod chained { mut next: Option<@Entry> } - struct HashMap_ { + struct HashMap_ { mut count: uint, mut chains: ~[mut Option<@Entry>] } - pub type T = @HashMap_; + pub type T = @HashMap_; enum SearchResult { NotFound, diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index 01b62797a8d76..59ba9ad61540d 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -22,7 +22,7 @@ extern "C" mod rusti { fn init() -> T; } -pub struct PriorityQueue { +pub struct PriorityQueue { priv data: ~[T], } diff --git a/src/libstd/sync.rs b/src/libstd/sync.rs index 03ef98d09c5c0..6ded82d5ae4c4 100644 --- a/src/libstd/sync.rs +++ b/src/libstd/sync.rs @@ -83,7 +83,7 @@ struct SemInner { blocked: Q } #[doc(hidden)] -enum Sem = Exclusive>; +enum Sem = Exclusive>; #[doc(hidden)] fn new_sem(count: int, q: Q) -> Sem { @@ -167,7 +167,7 @@ impl &Sem<~[mut Waitqueue]> { #[doc(hidden)] type SemRelease = SemReleaseGeneric<()>; type SemAndSignalRelease = SemReleaseGeneric<~[mut Waitqueue]>; -struct SemReleaseGeneric { sem: &Sem } +struct SemReleaseGeneric { sem: &Sem } impl SemReleaseGeneric : Drop { fn finalize(&self) { diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 36d919494f13d..5d0c83859f0a5 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -39,7 +39,7 @@ use core::prelude::*; // * symmetric difference: ^ // These would be convenient since the methods work like `each` -pub struct TreeMap { +pub struct TreeMap { priv root: Option<~TreeNode>, priv length: uint } @@ -167,7 +167,7 @@ impl TreeMap { } /// Lazy forward iterator over a map -pub struct TreeMapIterator { +pub struct TreeMapIterator { priv stack: ~[&~TreeNode], priv node: &Option<~TreeNode>, priv current: Option<&~TreeNode> @@ -205,7 +205,7 @@ impl TreeMapIterator { } } -pub struct TreeSet { +pub struct TreeSet { priv map: TreeMap } @@ -472,7 +472,7 @@ impl TreeSet { } /// Lazy forward iterator over a set -pub struct TreeSetIterator { +pub struct TreeSetIterator { priv iter: TreeMapIterator } @@ -494,7 +494,7 @@ impl TreeSetIterator { // Nodes keep track of their level in the tree, starting at 1 in the // leaves and with a red child sharing the level of the parent. -struct TreeNode { +struct TreeNode { key: K, value: V, left: Option<~TreeNode>, diff --git a/src/libstd/workcache.rs b/src/libstd/workcache.rs index fbd695aee762c..79a22f34d31f9 100644 --- a/src/libstd/workcache.rs +++ b/src/libstd/workcache.rs @@ -223,10 +223,17 @@ struct Exec { discovered_outputs: WorkMap } +#[cfg(stage0)] struct Work { prep: @Mut, res: Option>> } +#[cfg(stage1)] +#[cfg(stage2)] +struct Work { + prep: @Mut, + res: Option>> +} fn json_encode>(t: &T) -> ~str { do io::with_str_writer |wr| { diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs index 8a5b8a127d035..0433aab51fc3e 100644 --- a/src/libsyntax/ext/pipes/ast_builder.rs +++ b/src/libsyntax/ext/pipes/ast_builder.rs @@ -110,6 +110,7 @@ pub trait ext_ctxt_ast_builder { fn ty_option(ty: @ast::Ty) -> @ast::Ty; fn ty_infer() -> @ast::Ty; fn ty_nil_ast_builder() -> @ast::Ty; + fn strip_bounds(bounds: &[ast::ty_param]) -> ~[ast::ty_param]; } impl ext_ctxt: ext_ctxt_ast_builder { @@ -370,6 +371,12 @@ impl ext_ctxt: ext_ctxt_ast_builder { } } + fn strip_bounds(bounds: &[ast::ty_param]) -> ~[ast::ty_param] { + do bounds.map |ty_param| { + ast::ty_param { bounds: @~[], ..copy *ty_param } + } + } + fn item_ty_poly(name: ident, span: span, ty: @ast::Ty, diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs index 774a559625828..e7a8cbb9891f8 100644 --- a/src/libsyntax/ext/pipes/pipec.rs +++ b/src/libsyntax/ext/pipes/pipec.rs @@ -248,7 +248,7 @@ impl state: to_type_decls { ast::enum_def(enum_def_ { variants: items_msg, common: None }), - self.ty_params + cx.strip_bounds(self.ty_params) ) ] } @@ -281,7 +281,7 @@ impl state: to_type_decls { self.data_name()], dummy_sp()) .add_tys(cx.ty_vars_global(self.ty_params))))), - self.ty_params)); + cx.strip_bounds(self.ty_params))); } else { items.push( @@ -299,7 +299,7 @@ impl state: to_type_decls { dummy_sp()) .add_tys(cx.ty_vars_global(self.ty_params))), self.proto.buffer_ty_path(cx)])), - self.ty_params)); + cx.strip_bounds(self.ty_params))); }; items } @@ -417,7 +417,7 @@ impl protocol: gen_init { cx.ident_of(~"__Buffer"), dummy_sp(), cx.ty_rec(fields), - params) + cx.strip_bounds(params)) } fn compile(cx: ext_ctxt) -> @ast::item { diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index 67f6c4bed3f95..86dea693f8af6 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -33,6 +33,7 @@ use core::str; use core::to_bytes; /// The specific types of unsupported syntax +#[deriving_eq] pub enum ObsoleteSyntax { ObsoleteLowerCaseKindBounds, ObsoleteLet, @@ -45,16 +46,8 @@ pub enum ObsoleteSyntax { ObsoleteModeInFnType, ObsoleteMoveInit, ObsoleteBinaryMove, - ObsoleteUnsafeBlock -} - -impl ObsoleteSyntax : cmp::Eq { - pure fn eq(&self, other: &ObsoleteSyntax) -> bool { - (*self) as uint == (*other) as uint - } - pure fn ne(&self, other: &ObsoleteSyntax) -> bool { - !(*self).eq(other) - } + ObsoleteUnsafeBlock, + ObsoleteUnenforcedBound } impl ObsoleteSyntax: to_bytes::IterBytes { @@ -123,6 +116,11 @@ impl Parser { ObsoleteUnsafeBlock => ( "non-standalone unsafe block", "use an inner `unsafe { ... }` block instead" + ), + ObsoleteUnenforcedBound => ( + "unenforced type parameter bound", + "use trait bounds on the functions that take the type as \ + arguments, not on the types themselves" ) }; diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index e4a09c3c349b8..9de875485db53 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -18,7 +18,7 @@ use core::dvec::DVec; use std::map::HashMap; use std::map; -type hash_interner = +type hash_interner = {map: HashMap, vect: DVec}; diff --git a/src/test/auxiliary/issue-2526.rs b/src/test/auxiliary/issue-2526.rs index a14cc3758b19b..fc5cf1275183b 100644 --- a/src/test/auxiliary/issue-2526.rs +++ b/src/test/auxiliary/issue-2526.rs @@ -17,7 +17,7 @@ extern mod std; export context; -struct arc_destruct { +struct arc_destruct { _data: int, } diff --git a/src/test/auxiliary/test_comm.rs b/src/test/auxiliary/test_comm.rs index af321b9959f2b..6fd39368baecd 100644 --- a/src/test/auxiliary/test_comm.rs +++ b/src/test/auxiliary/test_comm.rs @@ -24,7 +24,7 @@ use core::libc::size_t; * transmitted. If a port value is copied, both copies refer to the same * port. Ports may be associated with multiple `chan`s. */ -pub enum port { +pub enum port { port_t(@port_ptr) } @@ -35,7 +35,7 @@ pub fn port() -> port { } } -struct port_ptr { +struct port_ptr { po: *rust_port, } diff --git a/src/test/bench/task-perf-word-count-generic.rs b/src/test/bench/task-perf-word-count-generic.rs index a817414314600..b617f6acec6e5 100644 --- a/src/test/bench/task-perf-word-count-generic.rs +++ b/src/test/bench/task-perf-word-count-generic.rs @@ -120,15 +120,15 @@ mod map_reduce { use std::map::HashMap; use std::map; - pub type putter = fn(&K, V); + pub type putter = fn(&K, V); - pub type mapper = fn~(K1, putter); + pub type mapper = fn~(K1, putter); - pub type getter = fn() -> Option; + pub type getter = fn() -> Option; - pub type reducer = fn~(&K, getter); + pub type reducer = fn~(&K, getter); - enum ctrl_proto { + enum ctrl_proto { find_reducer(K, Chan>>), mapper_done } @@ -146,7 +146,7 @@ mod map_reduce { } ) - pub enum reduce_proto { + pub enum reduce_proto { emit_val(V), done, addref, diff --git a/src/test/compile-fail/issue-2718-a.rs b/src/test/compile-fail/issue-2718-a.rs index 2332d54037fbd..925350d9b8804 100644 --- a/src/test/compile-fail/issue-2718-a.rs +++ b/src/test/compile-fail/issue-2718-a.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub struct send_packet { +pub struct send_packet { p: T } diff --git a/src/test/run-fail/bug-811.rs b/src/test/run-fail/bug-811.rs index 739bf097d4fda..31158df4185f7 100644 --- a/src/test/run-fail/bug-811.rs +++ b/src/test/run-fail/bug-811.rs @@ -14,7 +14,7 @@ fn test00_start(ch: chan_t, message: int) { send(ch, message); } type task_id = int; type port_id = int; -enum chan_t = {task: task_id, port: port_id}; +enum chan_t = {task: task_id, port: port_id}; fn send(ch: chan_t, data: T) { fail; } diff --git a/src/test/run-fail/issue-2444.rs b/src/test/run-fail/issue-2444.rs index b1d8c99faa519..9172364a2f916 100644 --- a/src/test/run-fail/issue-2444.rs +++ b/src/test/run-fail/issue-2444.rs @@ -13,7 +13,7 @@ extern mod std; use std::arc; -enum e { e(arc::ARC) } +enum e { e(arc::ARC) } fn foo() -> e {fail;} diff --git a/src/test/run-pass/auto-encode.rs b/src/test/run-pass/auto-encode.rs index ec73704ca27ba..ee8cf89d528a5 100644 --- a/src/test/run-pass/auto-encode.rs +++ b/src/test/run-pass/auto-encode.rs @@ -135,11 +135,6 @@ struct Spanned { node: T, } -enum AnEnum { - AVariant, - AnotherVariant -} - #[auto_encode] #[auto_decode] struct SomeStruct { v: ~[uint] } diff --git a/src/test/run-pass/box-unbox.rs b/src/test/run-pass/box-unbox.rs index 3558501471318..ad32ffc75c9c1 100644 --- a/src/test/run-pass/box-unbox.rs +++ b/src/test/run-pass/box-unbox.rs @@ -10,7 +10,7 @@ -struct Box {c: @T} +struct Box {c: @T} fn unbox(b: Box) -> T { return *b.c; } diff --git a/src/test/run-pass/class-impl-very-parameterized-trait.rs b/src/test/run-pass/class-impl-very-parameterized-trait.rs index 6bc881884522a..bccb42c493892 100644 --- a/src/test/run-pass/class-impl-very-parameterized-trait.rs +++ b/src/test/run-pass/class-impl-very-parameterized-trait.rs @@ -27,7 +27,7 @@ impl cat_type : cmp::Eq { // for any int value that's less than the meows field // ok: T should be in scope when resolving the trait ref for map -struct cat { +struct cat { // Yes, you can have negative meows priv mut meows : int, diff --git a/src/test/run-pass/generic-exterior-box.rs b/src/test/run-pass/generic-exterior-box.rs index 738bb73b0be4f..c2abcc7528300 100644 --- a/src/test/run-pass/generic-exterior-box.rs +++ b/src/test/run-pass/generic-exterior-box.rs @@ -10,7 +10,7 @@ -struct Recbox {x: @T} +struct Recbox {x: @T} fn reclift(t: T) -> Recbox { return Recbox {x: @t}; } diff --git a/src/test/run-pass/generic-exterior-unique.rs b/src/test/run-pass/generic-exterior-unique.rs index 2095578aefad8..a4a576abc758c 100644 --- a/src/test/run-pass/generic-exterior-unique.rs +++ b/src/test/run-pass/generic-exterior-unique.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Recbox {x: ~T} +struct Recbox {x: ~T} fn reclift(t: T) -> Recbox { return Recbox {x: ~t}; } diff --git a/src/test/run-pass/issue-2288.rs b/src/test/run-pass/issue-2288.rs index 52b3baba58e36..0fa06e2f2129b 100644 --- a/src/test/run-pass/issue-2288.rs +++ b/src/test/run-pass/issue-2288.rs @@ -11,7 +11,7 @@ trait clam { fn chowder(y: A); } -struct foo { +struct foo { x: A, } diff --git a/src/test/run-pass/issue-2311-2.rs b/src/test/run-pass/issue-2311-2.rs index 10befa7422836..21201d0a95705 100644 --- a/src/test/run-pass/issue-2311-2.rs +++ b/src/test/run-pass/issue-2311-2.rs @@ -9,7 +9,7 @@ // except according to those terms. trait clam { } -struct foo { +struct foo { x: A, } diff --git a/src/test/run-pass/issue-2445-b.rs b/src/test/run-pass/issue-2445-b.rs index 35d3d0897098b..f1b7d45e440ec 100644 --- a/src/test/run-pass/issue-2445-b.rs +++ b/src/test/run-pass/issue-2445-b.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct c1 { +struct c1 { x: T, } diff --git a/src/test/run-pass/issue-2445.rs b/src/test/run-pass/issue-2445.rs index 7cf681c9f94ef..fada6a7b02e11 100644 --- a/src/test/run-pass/issue-2445.rs +++ b/src/test/run-pass/issue-2445.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct c1 { +struct c1 { x: T, } diff --git a/src/test/run-pass/issue-2718.rs b/src/test/run-pass/issue-2718.rs index f8f2fc461c3ff..68a318eab4e3e 100644 --- a/src/test/run-pass/issue-2718.rs +++ b/src/test/run-pass/issue-2718.rs @@ -34,7 +34,7 @@ pub mod pipes { pure fn ne(&self, other: &state) -> bool { !(*self).eq(other) } } - pub type packet = { + pub type packet = { mut state: state, mut blocked_task: Option, mut payload: Option @@ -157,7 +157,7 @@ pub mod pipes { } } - pub struct send_packet { + pub struct send_packet { mut p: Option<*packet>, } @@ -185,7 +185,7 @@ pub mod pipes { } } - pub struct recv_packet { + pub struct recv_packet { mut p: Option<*packet>, } diff --git a/src/test/run-pass/issue-3149.rs b/src/test/run-pass/issue-3149.rs index 533106ff93621..c578f1144a785 100644 --- a/src/test/run-pass/issue-3149.rs +++ b/src/test/run-pass/issue-3149.rs @@ -22,7 +22,7 @@ pure fn Matrix4(m11: T, m12: T, m13: T, m14: T, } } -struct Matrix4 { +struct Matrix4 { m11: T, m12: T, m13: T, m14: T, m21: T, m22: T, m23: T, m24: T, m31: T, m32: T, m33: T, m34: T, diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs index d072df4d8e880..cf0a0a07397c0 100644 --- a/src/test/run-pass/reflect-visit-data.rs +++ b/src/test/run-pass/reflect-visit-data.rs @@ -29,7 +29,7 @@ fn align(size: uint, align: uint) -> uint { ((size + align) - 1u) & !(align - 1u) } -enum ptr_visit_adaptor = Inner; +enum ptr_visit_adaptor = Inner; impl ptr_visit_adaptor { diff --git a/src/test/run-pass/resource-generic.rs b/src/test/run-pass/resource-generic.rs index e528cd32974ba..7165d6089e85f 100644 --- a/src/test/run-pass/resource-generic.rs +++ b/src/test/run-pass/resource-generic.rs @@ -13,7 +13,7 @@ struct Arg {val: T, fin: extern fn(T)} -struct finish { +struct finish { arg: Arg } diff --git a/src/test/run-pass/send-type-inference.rs b/src/test/run-pass/send-type-inference.rs index 8476e256cd24c..8cb597a0d792c 100644 --- a/src/test/run-pass/send-type-inference.rs +++ b/src/test/run-pass/send-type-inference.rs @@ -9,7 +9,7 @@ // except according to those terms. // tests that ctrl's type gets inferred properly -type command = {key: K, val: V}; +type command = {key: K, val: V}; fn cache_server(c: oldcomm::Chan>>) { let ctrl = oldcomm::Port(); From c8e9d0694d5d9bdabfb52fd1836a8107abbfb82b Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 28 Jan 2013 18:10:34 -0800 Subject: [PATCH 30/31] librustc: De-implicit-self the visitor --- src/libcargo/cargo.rc | 1 + src/libcore/core.rc | 1 + src/libcore/reflect.rs | 440 +++++++++++++++++- src/libcore/repr.rs | 305 ++++++++++++ src/librustc/front/intrinsic.rs | 132 +++--- src/librustc/middle/lint.rs | 21 +- src/librustc/middle/trans/reflect.rs | 3 +- src/librustc/rustc.rc | 1 + src/librustdoc/rustdoc.rc | 1 + src/libstd/std.rc | 1 + src/libsyntax/syntax.rc | 1 + src/test/compile-fail/lint-default-methods.rs | 2 +- src/test/run-pass/reflect-visit-data.rs | 246 +++++----- 13 files changed, 956 insertions(+), 199 deletions(-) diff --git a/src/libcargo/cargo.rc b/src/libcargo/cargo.rc index efbb9a929d2df..c11e1ec010f3f 100644 --- a/src/libcargo/cargo.rc +++ b/src/libcargo/cargo.rc @@ -35,6 +35,7 @@ #[allow(non_camel_case_types)]; #[allow(deprecated_mode)]; #[allow(deprecated_pattern)]; +#[allow(deprecated_self)]; extern mod core(vers = "0.6"); extern mod std(vers = "0.6"); diff --git a/src/libcore/core.rc b/src/libcore/core.rc index f7a65ed1fe442..1ac0bf4c0c5c0 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -52,6 +52,7 @@ Implicitly, all crates behave as if they included the following prologue: #[warn(deprecated_pattern)]; #[warn(vecs_implicitly_copyable)]; #[deny(non_camel_case_types)]; +#[allow(deprecated_self)]; /* The Prelude. */ diff --git a/src/libcore/reflect.rs b/src/libcore/reflect.rs index 81a36e1ae13ee..94fc9e37a7519 100644 --- a/src/libcore/reflect.rs +++ b/src/libcore/reflect.rs @@ -75,6 +75,7 @@ impl MovePtrAdaptor { } /// Abstract type-directed pointer-movement using the MovePtr trait +#[cfg(stage0)] impl MovePtrAdaptor: TyVisitor { fn visit_bot() -> bool { self.align_to::<()>(); @@ -325,7 +326,8 @@ impl MovePtrAdaptor: TyVisitor { true } - fn visit_enter_class(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_enter_class(n_fields: uint, sz: uint, align: uint) + -> bool { self.align(align); if ! self.inner.visit_enter_class(n_fields, sz, align) { return false; @@ -343,7 +345,8 @@ impl MovePtrAdaptor: TyVisitor { true } - fn visit_leave_class(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_leave_class(n_fields: uint, sz: uint, align: uint) + -> bool { if ! self.inner.visit_leave_class(n_fields, sz, align) { return false; } @@ -394,7 +397,8 @@ impl MovePtrAdaptor: TyVisitor { true } - fn visit_enter_enum(n_variants: uint, sz: uint, align: uint) -> bool { + fn visit_enter_enum(n_variants: uint, sz: uint, align: uint) + -> bool { self.align(align); if ! self.inner.visit_enter_enum(n_variants, sz, align) { return false; @@ -433,7 +437,8 @@ impl MovePtrAdaptor: TyVisitor { true } - fn visit_leave_enum(n_variants: uint, sz: uint, align: uint) -> bool { + fn visit_leave_enum(n_variants: uint, sz: uint, align: uint) + -> bool { if ! self.inner.visit_leave_enum(n_variants, sz, align) { return false; } @@ -494,3 +499,430 @@ impl MovePtrAdaptor: TyVisitor { true } } + +/// Abstract type-directed pointer-movement using the MovePtr trait +#[cfg(stage1)] +#[cfg(stage2)] +impl MovePtrAdaptor: TyVisitor { + fn visit_bot(&self) -> bool { + self.align_to::<()>(); + if ! self.inner.visit_bot() { return false; } + self.bump_past::<()>(); + true + } + + fn visit_nil(&self) -> bool { + self.align_to::<()>(); + if ! self.inner.visit_nil() { return false; } + self.bump_past::<()>(); + true + } + + fn visit_bool(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_bool() { return false; } + self.bump_past::(); + true + } + + fn visit_int(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_int() { return false; } + self.bump_past::(); + true + } + + fn visit_i8(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_i8() { return false; } + self.bump_past::(); + true + } + + fn visit_i16(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_i16() { return false; } + self.bump_past::(); + true + } + + fn visit_i32(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_i32() { return false; } + self.bump_past::(); + true + } + + fn visit_i64(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_i64() { return false; } + self.bump_past::(); + true + } + + fn visit_uint(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_uint() { return false; } + self.bump_past::(); + true + } + + fn visit_u8(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_u8() { return false; } + self.bump_past::(); + true + } + + fn visit_u16(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_u16() { return false; } + self.bump_past::(); + true + } + + fn visit_u32(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_u32() { return false; } + self.bump_past::(); + true + } + + fn visit_u64(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_u64() { return false; } + self.bump_past::(); + true + } + + fn visit_float(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_float() { return false; } + self.bump_past::(); + true + } + + fn visit_f32(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_f32() { return false; } + self.bump_past::(); + true + } + + fn visit_f64(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_f64() { return false; } + self.bump_past::(); + true + } + + fn visit_char(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_char() { return false; } + self.bump_past::(); + true + } + + fn visit_str(&self) -> bool { + self.align_to::<~str>(); + if ! self.inner.visit_str() { return false; } + self.bump_past::<~str>(); + true + } + + fn visit_estr_box(&self) -> bool { + self.align_to::<@str>(); + if ! self.inner.visit_estr_box() { return false; } + self.bump_past::<@str>(); + true + } + + fn visit_estr_uniq(&self) -> bool { + self.align_to::<~str>(); + if ! self.inner.visit_estr_uniq() { return false; } + self.bump_past::<~str>(); + true + } + + fn visit_estr_slice(&self) -> bool { + self.align_to::<&static/str>(); + if ! self.inner.visit_estr_slice() { return false; } + self.bump_past::<&static/str>(); + true + } + + fn visit_estr_fixed(&self, n: uint, + sz: uint, + align: uint) -> bool { + self.align(align); + if ! self.inner.visit_estr_fixed(n, sz, align) { return false; } + self.bump(sz); + true + } + + fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<@u8>(); + if ! self.inner.visit_box(mtbl, inner) { return false; } + self.bump_past::<@u8>(); + true + } + + fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<~u8>(); + if ! self.inner.visit_uniq(mtbl, inner) { return false; } + self.bump_past::<~u8>(); + true + } + + fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<*u8>(); + if ! self.inner.visit_ptr(mtbl, inner) { return false; } + self.bump_past::<*u8>(); + true + } + + fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<&static/u8>(); + if ! self.inner.visit_rptr(mtbl, inner) { return false; } + self.bump_past::<&static/u8>(); + true + } + + fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::(); + if ! self.inner.visit_vec(mtbl, inner) { return false; } + true + } + + fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<~[u8]>(); + if ! self.inner.visit_vec(mtbl, inner) { return false; } + self.bump_past::<~[u8]>(); + true + } + + fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<@[u8]>(); + if ! self.inner.visit_evec_box(mtbl, inner) { return false; } + self.bump_past::<@[u8]>(); + true + } + + fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<~[u8]>(); + if ! self.inner.visit_evec_uniq(mtbl, inner) { return false; } + self.bump_past::<~[u8]>(); + true + } + + fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.align_to::<&static/[u8]>(); + if ! self.inner.visit_evec_slice(mtbl, inner) { return false; } + self.bump_past::<&static/[u8]>(); + true + } + + fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint, + mtbl: uint, inner: *TyDesc) -> bool { + self.align(align); + if ! self.inner.visit_evec_fixed(n, sz, align, mtbl, inner) { + return false; + } + self.bump(sz); + true + } + + fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool { + self.align(align); + if ! self.inner.visit_enter_rec(n_fields, sz, align) { return false; } + true + } + + fn visit_rec_field(&self, i: uint, name: &str, + mtbl: uint, inner: *TyDesc) -> bool { + unsafe { self.align((*inner).align); } + if ! self.inner.visit_rec_field(i, name, mtbl, inner) { + return false; + } + unsafe { self.bump((*inner).size); } + true + } + + fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool { + if ! self.inner.visit_leave_rec(n_fields, sz, align) { return false; } + true + } + + fn visit_enter_class(&self, n_fields: uint, sz: uint, align: uint) + -> bool { + self.align(align); + if ! self.inner.visit_enter_class(n_fields, sz, align) { + return false; + } + true + } + + fn visit_class_field(&self, i: uint, name: &str, + mtbl: uint, inner: *TyDesc) -> bool { + unsafe { self.align((*inner).align); } + if ! self.inner.visit_class_field(i, name, mtbl, inner) { + return false; + } + unsafe { self.bump((*inner).size); } + true + } + + fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint) + -> bool { + if ! self.inner.visit_leave_class(n_fields, sz, align) { + return false; + } + true + } + + fn visit_enter_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool { + self.align(align); + if ! self.inner.visit_enter_tup(n_fields, sz, align) { return false; } + true + } + + fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool { + unsafe { self.align((*inner).align); } + if ! self.inner.visit_tup_field(i, inner) { return false; } + unsafe { self.bump((*inner).size); } + true + } + + fn visit_leave_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool { + if ! self.inner.visit_leave_tup(n_fields, sz, align) { return false; } + true + } + + fn visit_enter_fn(&self, purity: uint, proto: uint, + n_inputs: uint, retstyle: uint) -> bool { + if ! self.inner.visit_enter_fn(purity, proto, n_inputs, retstyle) { + return false + } + true + } + + fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool { + if ! self.inner.visit_fn_input(i, mode, inner) { return false; } + true + } + + fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool { + if ! self.inner.visit_fn_output(retstyle, inner) { return false; } + true + } + + fn visit_leave_fn(&self, purity: uint, proto: uint, + n_inputs: uint, retstyle: uint) -> bool { + if ! self.inner.visit_leave_fn(purity, proto, n_inputs, retstyle) { + return false; + } + true + } + + fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint) + -> bool { + self.align(align); + if ! self.inner.visit_enter_enum(n_variants, sz, align) { + return false; + } + true + } + + fn visit_enter_enum_variant(&self, variant: uint, + disr_val: int, + n_fields: uint, + name: &str) -> bool { + self.inner.push_ptr(); + if ! self.inner.visit_enter_enum_variant(variant, disr_val, + n_fields, name) { + return false; + } + true + } + + fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { + unsafe { self.align((*inner).align); } + if ! self.inner.visit_enum_variant_field(i, inner) { return false; } + unsafe { self.bump((*inner).size); } + true + } + + fn visit_leave_enum_variant(&self, variant: uint, + disr_val: int, + n_fields: uint, + name: &str) -> bool { + if ! self.inner.visit_leave_enum_variant(variant, disr_val, + n_fields, name) { + return false; + } + self.inner.pop_ptr(); + true + } + + fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint) + -> bool { + if ! self.inner.visit_leave_enum(n_variants, sz, align) { + return false; + } + self.bump(sz); + true + } + + fn visit_trait(&self) -> bool { + self.align_to::(); + if ! self.inner.visit_trait() { return false; } + self.bump_past::(); + true + } + + fn visit_var(&self) -> bool { + if ! self.inner.visit_var() { return false; } + true + } + + fn visit_var_integral(&self) -> bool { + if ! self.inner.visit_var_integral() { return false; } + true + } + + fn visit_param(&self, i: uint) -> bool { + if ! self.inner.visit_param(i) { return false; } + true + } + + fn visit_self(&self) -> bool { + self.align_to::<&static/u8>(); + if ! self.inner.visit_self() { return false; } + self.align_to::<&static/u8>(); + true + } + + fn visit_type(&self) -> bool { + if ! self.inner.visit_type() { return false; } + true + } + + fn visit_opaque_box(&self) -> bool { + self.align_to::<@u8>(); + if ! self.inner.visit_opaque_box() { return false; } + self.bump_past::<@u8>(); + true + } + + fn visit_constr(&self, inner: *TyDesc) -> bool { + if ! self.inner.visit_constr(inner) { return false; } + true + } + + fn visit_closure_ptr(&self, ck: uint) -> bool { + self.align_to::(); + if ! self.inner.visit_closure_ptr(ck) { return false; } + self.bump_past::(); + true + } +} diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs index 4d4970eada805..75a572fa46444 100644 --- a/src/libcore/repr.rs +++ b/src/libcore/repr.rs @@ -265,6 +265,7 @@ impl ReprVisitor { } +#[cfg(stage0)] impl ReprVisitor : TyVisitor { fn visit_bot() -> bool { self.writer.write_str("!"); @@ -559,6 +560,310 @@ impl ReprVisitor : TyVisitor { fn visit_closure_ptr(_ck: uint) -> bool { true } } +#[cfg(stage1)] +#[cfg(stage2)] +impl ReprVisitor : TyVisitor { + fn visit_bot(&self) -> bool { + self.writer.write_str("!"); + true + } + fn visit_nil(&self) -> bool { self.write::<()>() } + fn visit_bool(&self) -> bool { self.write::() } + fn visit_int(&self) -> bool { self.write::() } + fn visit_i8(&self) -> bool { self.write::() } + fn visit_i16(&self) -> bool { self.write::() } + fn visit_i32(&self) -> bool { self.write::() } + fn visit_i64(&self) -> bool { self.write::() } + + fn visit_uint(&self) -> bool { self.write::() } + fn visit_u8(&self) -> bool { self.write::() } + fn visit_u16(&self) -> bool { self.write::() } + fn visit_u32(&self) -> bool { self.write::() } + fn visit_u64(&self) -> bool { self.write::() } + + fn visit_float(&self) -> bool { self.write::() } + fn visit_f32(&self) -> bool { self.write::() } + fn visit_f64(&self) -> bool { self.write::() } + + fn visit_char(&self) -> bool { + do self.get:: |&ch| { + self.writer.write_char('\''); + self.writer.write_escaped_char(ch); + self.writer.write_char('\''); + } + } + + // Type no longer exists, vestigial function. + fn visit_str(&self) -> bool { fail; } + + fn visit_estr_box(&self) -> bool { + do self.get::<@str> |s| { + self.writer.write_char('@'); + self.write_escaped_slice(*s); + } + } + fn visit_estr_uniq(&self) -> bool { + do self.get::<~str> |s| { + self.writer.write_char('~'); + self.write_escaped_slice(*s); + } + } + fn visit_estr_slice(&self) -> bool { + do self.get::<&str> |s| { + self.write_escaped_slice(*s); + } + } + + // Type no longer exists, vestigial function. + fn visit_estr_fixed(&self, _n: uint, _sz: uint, + _align: uint) -> bool { fail; } + + fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.writer.write_char('@'); + self.write_mut_qualifier(mtbl); + do self.get::<&managed::raw::BoxRepr> |b| { + let p = ptr::to_unsafe_ptr(&b.data) as *c_void; + self.visit_ptr_inner(p, inner); + } + } + + fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.writer.write_char('~'); + self.write_mut_qualifier(mtbl); + do self.get::<&managed::raw::BoxRepr> |b| { + let p = ptr::to_unsafe_ptr(&b.data) as *c_void; + self.visit_ptr_inner(p, inner); + } + } + + fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { + do self.get::<*c_void> |p| { + self.writer.write_str(fmt!("(0x%x as *())", + *p as uint)); + } + } + + fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool { + self.writer.write_char('&'); + self.write_mut_qualifier(mtbl); + do self.get::<*c_void> |p| { + self.visit_ptr_inner(*p, inner); + } + } + + // Type no longer exists, vestigial function. + fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { fail; } + + + fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { + do self.get:: |b| { + self.write_unboxed_vec_repr(mtbl, b, inner); + } + } + + fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool { + do self.get::<&VecRepr> |b| { + self.writer.write_char('@'); + self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner); + } + } + + fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { + do self.get::<&VecRepr> |b| { + self.writer.write_char('~'); + self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner); + } + } + + fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool { + do self.get:: |s| { + self.writer.write_char('&'); + self.write_vec_range(mtbl, s.data, s.len, inner); + } + } + + fn visit_evec_fixed(&self, _n: uint, sz: uint, _align: uint, + mtbl: uint, inner: *TyDesc) -> bool { + do self.get:: |b| { + self.write_vec_range(mtbl, ptr::to_unsafe_ptr(b), sz, inner); + } + } + + fn visit_enter_rec(&self, _n_fields: uint, + _sz: uint, _align: uint) -> bool { + self.writer.write_char('{'); + true + } + + fn visit_rec_field(&self, i: uint, name: &str, + mtbl: uint, inner: *TyDesc) -> bool { + if i != 0 { + self.writer.write_str(", "); + } + self.write_mut_qualifier(mtbl); + self.writer.write_str(name); + self.writer.write_str(": "); + self.visit_inner(inner); + true + } + + fn visit_leave_rec(&self, _n_fields: uint, + _sz: uint, _align: uint) -> bool { + self.writer.write_char('}'); + true + } + + fn visit_enter_class(&self, _n_fields: uint, + _sz: uint, _align: uint) -> bool { + self.writer.write_char('{'); + true + } + fn visit_class_field(&self, i: uint, name: &str, + mtbl: uint, inner: *TyDesc) -> bool { + if i != 0 { + self.writer.write_str(", "); + } + self.write_mut_qualifier(mtbl); + self.writer.write_str(name); + self.writer.write_str(": "); + self.visit_inner(inner); + true + } + fn visit_leave_class(&self, _n_fields: uint, + _sz: uint, _align: uint) -> bool { + self.writer.write_char('}'); + true + } + + fn visit_enter_tup(&self, _n_fields: uint, + _sz: uint, _align: uint) -> bool { + self.writer.write_char('('); + true + } + fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool { + if i != 0 { + self.writer.write_str(", "); + } + self.visit_inner(inner); + true + } + fn visit_leave_tup(&self, _n_fields: uint, + _sz: uint, _align: uint) -> bool { + self.writer.write_char(')'); + true + } + + fn visit_enter_enum(&self, n_variants: uint, + _sz: uint, _align: uint) -> bool { + if n_variants == 1 { + self.var_stk.push(Degenerate) + } else { + self.var_stk.push(TagMatch) + } + true + } + + fn visit_enter_enum_variant(&self, _variant: uint, + disr_val: int, + n_fields: uint, + name: &str) -> bool { + let mut write = false; + match self.var_stk.pop() { + Degenerate => { + write = true; + self.var_stk.push(Degenerate); + } + TagMatch | TagMismatch => { + do self.get::() |t| { + if disr_val == *t { + write = true; + self.var_stk.push(TagMatch); + } else { + self.var_stk.push(TagMismatch); + } + }; + self.bump_past::(); + } + } + + if write { + self.writer.write_str(name); + if n_fields > 0 { + self.writer.write_char('('); + } + } + true + } + + fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { + match self.var_stk.last() { + Degenerate | TagMatch => { + if i != 0 { + self.writer.write_str(", "); + } + if ! self.visit_inner(inner) { + return false; + } + } + TagMismatch => () + } + true + } + + fn visit_leave_enum_variant(&self, _variant: uint, + _disr_val: int, + n_fields: uint, + _name: &str) -> bool { + match self.var_stk.last() { + Degenerate | TagMatch => { + if n_fields > 0 { + self.writer.write_char(')'); + } + } + TagMismatch => () + } + true + } + + fn visit_leave_enum(&self, _n_variants: uint, + _sz: uint, _align: uint) -> bool { + self.var_stk.pop(); + true + } + + fn visit_enter_fn(&self, _purity: uint, _proto: uint, + _n_inputs: uint, _retstyle: uint) -> bool { true } + fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool { + true + } + fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool { + true + } + fn visit_leave_fn(&self, _purity: uint, _proto: uint, + _n_inputs: uint, _retstyle: uint) -> bool { true } + + + fn visit_trait(&self) -> bool { true } + fn visit_var(&self) -> bool { true } + fn visit_var_integral(&self) -> bool { true } + fn visit_param(&self, _i: uint) -> bool { true } + fn visit_self(&self) -> bool { true } + fn visit_type(&self) -> bool { true } + + fn visit_opaque_box(&self) -> bool { + self.writer.write_char('@'); + do self.get::<&managed::raw::BoxRepr> |b| { + let p = ptr::to_unsafe_ptr(&b.data) as *c_void; + self.visit_ptr_inner(p, b.header.type_desc); + } + } + + // Type no longer exists, vestigial function. + fn visit_constr(&self, _inner: *TyDesc) -> bool { fail; } + + fn visit_closure_ptr(&self, _ck: uint) -> bool { true } +} + pub fn write_repr(writer: @Writer, object: &T) { unsafe { let ptr = ptr::to_unsafe_ptr(object) as *c_void; diff --git a/src/librustc/front/intrinsic.rs b/src/librustc/front/intrinsic.rs index 6657e6fcf0fee..5ccac6f091acc 100644 --- a/src/librustc/front/intrinsic.rs +++ b/src/librustc/front/intrinsic.rs @@ -31,97 +31,97 @@ mod intrinsic { }; trait TyVisitor { - fn visit_bot() -> bool; - fn visit_nil() -> bool; - fn visit_bool() -> bool; - - fn visit_int() -> bool; - fn visit_i8() -> bool; - fn visit_i16() -> bool; - fn visit_i32() -> bool; - fn visit_i64() -> bool; - - fn visit_uint() -> bool; - fn visit_u8() -> bool; - fn visit_u16() -> bool; - fn visit_u32() -> bool; - fn visit_u64() -> bool; - - fn visit_float() -> bool; - fn visit_f32() -> bool; - fn visit_f64() -> bool; - - fn visit_char() -> bool; - fn visit_str() -> bool; - - fn visit_estr_box() -> bool; - fn visit_estr_uniq() -> bool; - fn visit_estr_slice() -> bool; - fn visit_estr_fixed(n: uint, sz: uint, align: uint) -> bool; - - fn visit_box(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_uniq(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_ptr(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_rptr(mtbl: uint, inner: *TyDesc) -> bool; - - fn visit_vec(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_unboxed_vec(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_box(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_uniq(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_slice(mtbl: uint, inner: *TyDesc) -> bool; - fn visit_evec_fixed(n: uint, sz: uint, align: uint, + fn visit_bot(&self) -> bool; + fn visit_nil(&self) -> bool; + fn visit_bool(&self) -> bool; + + fn visit_int(&self) -> bool; + fn visit_i8(&self) -> bool; + fn visit_i16(&self) -> bool; + fn visit_i32(&self) -> bool; + fn visit_i64(&self) -> bool; + + fn visit_uint(&self) -> bool; + fn visit_u8(&self) -> bool; + fn visit_u16(&self) -> bool; + fn visit_u32(&self) -> bool; + fn visit_u64(&self) -> bool; + + fn visit_float(&self) -> bool; + fn visit_f32(&self) -> bool; + fn visit_f64(&self) -> bool; + + fn visit_char(&self) -> bool; + fn visit_str(&self) -> bool; + + fn visit_estr_box(&self) -> bool; + fn visit_estr_uniq(&self) -> bool; + fn visit_estr_slice(&self) -> bool; + fn visit_estr_fixed(&self, n: uint, sz: uint, align: uint) -> bool; + + fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool; + + fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool; + fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_enter_rec(n_fields: uint, + fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool; - fn visit_rec_field(i: uint, name: &str, + fn visit_rec_field(&self, i: uint, name: &str, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_leave_rec(n_fields: uint, + fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool; - fn visit_enter_class(n_fields: uint, + fn visit_enter_class(&self, n_fields: uint, sz: uint, align: uint) -> bool; - fn visit_class_field(i: uint, name: &str, + fn visit_class_field(&self, i: uint, name: &str, mtbl: uint, inner: *TyDesc) -> bool; - fn visit_leave_class(n_fields: uint, + fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint) -> bool; - fn visit_enter_tup(n_fields: uint, + fn visit_enter_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool; - fn visit_tup_field(i: uint, inner: *TyDesc) -> bool; - fn visit_leave_tup(n_fields: uint, + fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool; + fn visit_leave_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool; - fn visit_enter_enum(n_variants: uint, + fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint) -> bool; - fn visit_enter_enum_variant(variant: uint, + fn visit_enter_enum_variant(&self, variant: uint, disr_val: int, n_fields: uint, name: &str) -> bool; - fn visit_enum_variant_field(i: uint, inner: *TyDesc) -> bool; - fn visit_leave_enum_variant(variant: uint, + fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool; + fn visit_leave_enum_variant(&self, variant: uint, disr_val: int, n_fields: uint, name: &str) -> bool; - fn visit_leave_enum(n_variants: uint, + fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint) -> bool; - fn visit_enter_fn(purity: uint, proto: uint, + fn visit_enter_fn(&self, purity: uint, proto: uint, n_inputs: uint, retstyle: uint) -> bool; - fn visit_fn_input(i: uint, mode: uint, inner: *TyDesc) -> bool; - fn visit_fn_output(retstyle: uint, inner: *TyDesc) -> bool; - fn visit_leave_fn(purity: uint, proto: uint, + fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool; + fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool; + fn visit_leave_fn(&self, purity: uint, proto: uint, n_inputs: uint, retstyle: uint) -> bool; - fn visit_trait() -> bool; - fn visit_var() -> bool; - fn visit_var_integral() -> bool; - fn visit_param(i: uint) -> bool; - fn visit_self() -> bool; - fn visit_type() -> bool; - fn visit_opaque_box() -> bool; - fn visit_constr(inner: *TyDesc) -> bool; - fn visit_closure_ptr(ck: uint) -> bool; + fn visit_trait(&self) -> bool; + fn visit_var(&self) -> bool; + fn visit_var_integral(&self) -> bool; + fn visit_param(&self, i: uint) -> bool; + fn visit_self(&self) -> bool; + fn visit_type(&self) -> bool; + fn visit_opaque_box(&self) -> bool; + fn visit_constr(&self, inner: *TyDesc) -> bool; + fn visit_closure_ptr(&self, ck: uint) -> bool; } #[abi = "rust-intrinsic"] diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 515666445e3aa..9b4911d9fbea7 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -233,7 +233,7 @@ fn get_lint_dict() -> lint_dict { (~"deprecated_self", @{lint: deprecated_self, desc: "warn about deprecated uses of `self`", - default: allow}), + default: warn}), /* FIXME(#3266)--make liveness warnings lintable (~"unused_variable", @@ -631,13 +631,18 @@ fn check_item_deprecated_self(cx: ty::ctxt, item: @ast::item) { fn maybe_warn(cx: ty::ctxt, item: @ast::item, self_ty: ast::self_ty) { - cx.sess.span_lint( - deprecated_self, - item.id, - item.id, - self_ty.span, - ~"this method form is deprecated; use an explicit `self` \ - parameter or mark the method as static"); + match self_ty.node { + ast::sty_by_ref => { + cx.sess.span_lint( + deprecated_self, + item.id, + item.id, + self_ty.span, + ~"this method form is deprecated; use an explicit `self` \ + parameter or mark the method as static"); + } + _ => {} + } } match /*bad*/copy item.node { diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 39ab5735dee3f..ba9ff3a4f98bb 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -105,7 +105,8 @@ impl reflector { mth_idx, v, ty::vstore_box, - ast::sty_by_ref), + ast::sty_region( + ast::m_imm)), ArgVals(args), SaveIn(scratch.val), DontAutorefArg); let result = scratch.to_value_llval(bcx); let next_bcx = sub_block(bcx, ~"next"); diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 818c6eb04ea88..4ebd0b33f038a 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -25,6 +25,7 @@ #[allow(non_camel_case_types)]; #[allow(deprecated_mode)]; #[warn(deprecated_pattern)]; +#[allow(deprecated_self)]; #[no_core]; diff --git a/src/librustdoc/rustdoc.rc b/src/librustdoc/rustdoc.rc index 77ed564aab471..c756bbe82492e 100644 --- a/src/librustdoc/rustdoc.rc +++ b/src/librustdoc/rustdoc.rc @@ -26,6 +26,7 @@ #[allow(non_implicitly_copyable_typarams)]; #[allow(deprecated_mode)]; #[allow(deprecated_pattern)]; +#[allow(deprecated_self)]; extern mod core(vers = "0.6"); extern mod std(vers = "0.6"); diff --git a/src/libstd/std.rc b/src/libstd/std.rc index eea9bd0a40f7a..f75715cfd6d90 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -32,6 +32,7 @@ not required in or otherwise suitable for the core library. // that can't be silenced otherwise. Most every module is set to forbid #[allow(deprecated_mode)]; #[forbid(deprecated_pattern)]; +#[allow(deprecated_self)]; #[no_core]; diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc index 0777269f8f7fc..bccff550a435f 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rc @@ -23,6 +23,7 @@ #[allow(non_camel_case_types)]; #[allow(deprecated_mode)]; #[warn(deprecated_pattern)]; +#[allow(deprecated_self)]; #[no_core]; diff --git a/src/test/compile-fail/lint-default-methods.rs b/src/test/compile-fail/lint-default-methods.rs index 6b71f9e972fb2..1350c3e3ad1cd 100644 --- a/src/test/compile-fail/lint-default-methods.rs +++ b/src/test/compile-fail/lint-default-methods.rs @@ -1,7 +1,7 @@ #[forbid(default_methods)]; trait Foo { //~ ERROR default methods are experimental - fn bar() { io::println("hi"); } + fn bar(&self) { io::println("hi"); } } fn main() {} diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs index cf0a0a07397c0..c7c1a6bb33195 100644 --- a/src/test/run-pass/reflect-visit-data.rs +++ b/src/test/run-pass/reflect-visit-data.rs @@ -61,154 +61,154 @@ impl ptr_visit_adaptor { impl ptr_visit_adaptor: TyVisitor { - fn visit_bot() -> bool { + fn visit_bot(&self) -> bool { self.align_to::<()>(); if ! self.inner.visit_bot() { return false; } self.bump_past::<()>(); true } - fn visit_nil() -> bool { + fn visit_nil(&self) -> bool { self.align_to::<()>(); if ! self.inner.visit_nil() { return false; } self.bump_past::<()>(); true } - fn visit_bool() -> bool { + fn visit_bool(&self) -> bool { self.align_to::(); if ! self.inner.visit_bool() { return false; } self.bump_past::(); true } - fn visit_int() -> bool { + fn visit_int(&self) -> bool { self.align_to::(); if ! self.inner.visit_int() { return false; } self.bump_past::(); true } - fn visit_i8() -> bool { + fn visit_i8(&self) -> bool { self.align_to::(); if ! self.inner.visit_i8() { return false; } self.bump_past::(); true } - fn visit_i16() -> bool { + fn visit_i16(&self) -> bool { self.align_to::(); if ! self.inner.visit_i16() { return false; } self.bump_past::(); true } - fn visit_i32() -> bool { + fn visit_i32(&self) -> bool { self.align_to::(); if ! self.inner.visit_i32() { return false; } self.bump_past::(); true } - fn visit_i64() -> bool { + fn visit_i64(&self) -> bool { self.align_to::(); if ! self.inner.visit_i64() { return false; } self.bump_past::(); true } - fn visit_uint() -> bool { + fn visit_uint(&self) -> bool { self.align_to::(); if ! self.inner.visit_uint() { return false; } self.bump_past::(); true } - fn visit_u8() -> bool { + fn visit_u8(&self) -> bool { self.align_to::(); if ! self.inner.visit_u8() { return false; } self.bump_past::(); true } - fn visit_u16() -> bool { + fn visit_u16(&self) -> bool { self.align_to::(); if ! self.inner.visit_u16() { return false; } self.bump_past::(); true } - fn visit_u32() -> bool { + fn visit_u32(&self) -> bool { self.align_to::(); if ! self.inner.visit_u32() { return false; } self.bump_past::(); true } - fn visit_u64() -> bool { + fn visit_u64(&self) -> bool { self.align_to::(); if ! self.inner.visit_u64() { return false; } self.bump_past::(); true } - fn visit_float() -> bool { + fn visit_float(&self) -> bool { self.align_to::(); if ! self.inner.visit_float() { return false; } self.bump_past::(); true } - fn visit_f32() -> bool { + fn visit_f32(&self) -> bool { self.align_to::(); if ! self.inner.visit_f32() { return false; } self.bump_past::(); true } - fn visit_f64() -> bool { + fn visit_f64(&self) -> bool { self.align_to::(); if ! self.inner.visit_f64() { return false; } self.bump_past::(); true } - fn visit_char() -> bool { + fn visit_char(&self) -> bool { self.align_to::(); if ! self.inner.visit_char() { return false; } self.bump_past::(); true } - fn visit_str() -> bool { + fn visit_str(&self) -> bool { self.align_to::<~str>(); if ! self.inner.visit_str() { return false; } self.bump_past::<~str>(); true } - fn visit_estr_box() -> bool { + fn visit_estr_box(&self) -> bool { self.align_to::<@str>(); if ! self.inner.visit_estr_box() { return false; } self.bump_past::<@str>(); true } - fn visit_estr_uniq() -> bool { + fn visit_estr_uniq(&self) -> bool { self.align_to::<~str>(); if ! self.inner.visit_estr_uniq() { return false; } self.bump_past::<~str>(); true } - fn visit_estr_slice() -> bool { + fn visit_estr_slice(&self) -> bool { self.align_to::<&static/str>(); if ! self.inner.visit_estr_slice() { return false; } self.bump_past::<&static/str>(); true } - fn visit_estr_fixed(n: uint, + fn visit_estr_fixed(&self, n: uint, sz: uint, align: uint) -> bool { self.align(align); @@ -217,35 +217,35 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_box(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<@u8>(); if ! self.inner.visit_box(mtbl, inner) { return false; } self.bump_past::<@u8>(); true } - fn visit_uniq(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<~u8>(); if ! self.inner.visit_uniq(mtbl, inner) { return false; } self.bump_past::<~u8>(); true } - fn visit_ptr(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<*u8>(); if ! self.inner.visit_ptr(mtbl, inner) { return false; } self.bump_past::<*u8>(); true } - fn visit_rptr(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<&static/u8>(); if ! self.inner.visit_rptr(mtbl, inner) { return false; } self.bump_past::<&static/u8>(); true } - fn visit_unboxed_vec(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::(); // FIXME (#3732): Inner really has to move its own pointers on this one. // or else possibly we could have some weird interface wherein we @@ -255,35 +255,35 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_vec(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<~[u8]>(); if ! self.inner.visit_vec(mtbl, inner) { return false; } self.bump_past::<~[u8]>(); true } - fn visit_evec_box(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<@[u8]>(); if ! self.inner.visit_evec_box(mtbl, inner) { return false; } self.bump_past::<@[u8]>(); true } - fn visit_evec_uniq(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<~[u8]>(); if ! self.inner.visit_evec_uniq(mtbl, inner) { return false; } self.bump_past::<~[u8]>(); true } - fn visit_evec_slice(mtbl: uint, inner: *TyDesc) -> bool { + fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool { self.align_to::<&static/[u8]>(); if ! self.inner.visit_evec_slice(mtbl, inner) { return false; } self.bump_past::<&static/[u8]>(); true } - fn visit_evec_fixed(n: uint, sz: uint, align: uint, + fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint, mtbl: uint, inner: *TyDesc) -> bool { self.align(align); if ! self.inner.visit_evec_fixed(n, sz, align, mtbl, inner) { @@ -293,24 +293,25 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_enter_rec(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool { self.align(align); if ! self.inner.visit_enter_rec(n_fields, sz, align) { return false; } true } - fn visit_rec_field(i: uint, name: &str, + fn visit_rec_field(&self, i: uint, name: &str, mtbl: uint, inner: *TyDesc) -> bool { if ! self.inner.visit_rec_field(i, name, mtbl, inner) { return false; } true } - fn visit_leave_rec(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool { if ! self.inner.visit_leave_rec(n_fields, sz, align) { return false; } true } - fn visit_enter_class(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_enter_class(&self, n_fields: uint, sz: uint, align: uint) + -> bool { self.align(align); if ! self.inner.visit_enter_class(n_fields, sz, align) { return false; @@ -318,7 +319,7 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_class_field(i: uint, name: &str, + fn visit_class_field(&self, i: uint, name: &str, mtbl: uint, inner: *TyDesc) -> bool { if ! self.inner.visit_class_field(i, name, mtbl, inner) { return false; @@ -326,30 +327,31 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_leave_class(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint) + -> bool { if ! self.inner.visit_leave_class(n_fields, sz, align) { return false; } true } - fn visit_enter_tup(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_enter_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool { self.align(align); if ! self.inner.visit_enter_tup(n_fields, sz, align) { return false; } true } - fn visit_tup_field(i: uint, inner: *TyDesc) -> bool { + fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool { if ! self.inner.visit_tup_field(i, inner) { return false; } true } - fn visit_leave_tup(n_fields: uint, sz: uint, align: uint) -> bool { + fn visit_leave_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool { if ! self.inner.visit_leave_tup(n_fields, sz, align) { return false; } true } - fn visit_enter_fn(purity: uint, proto: uint, + fn visit_enter_fn(&self, purity: uint, proto: uint, n_inputs: uint, retstyle: uint) -> bool { if ! self.inner.visit_enter_fn(purity, proto, n_inputs, retstyle) { return false @@ -357,17 +359,17 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_fn_input(i: uint, mode: uint, inner: *TyDesc) -> bool { + fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool { if ! self.inner.visit_fn_input(i, mode, inner) { return false; } true } - fn visit_fn_output(retstyle: uint, inner: *TyDesc) -> bool { + fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool { if ! self.inner.visit_fn_output(retstyle, inner) { return false; } true } - fn visit_leave_fn(purity: uint, proto: uint, + fn visit_leave_fn(&self, purity: uint, proto: uint, n_inputs: uint, retstyle: uint) -> bool { if ! self.inner.visit_leave_fn(purity, proto, n_inputs, retstyle) { return false; @@ -375,13 +377,14 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_enter_enum(n_variants: uint, sz: uint, align: uint) -> bool { + fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint) + -> bool { self.align(align); if ! self.inner.visit_enter_enum(n_variants, sz, align) { return false; } true } - fn visit_enter_enum_variant(variant: uint, + fn visit_enter_enum_variant(&self, variant: uint, disr_val: int, n_fields: uint, name: &str) -> bool { @@ -392,12 +395,12 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_enum_variant_field(i: uint, inner: *TyDesc) -> bool { + fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { if ! self.inner.visit_enum_variant_field(i, inner) { return false; } true } - fn visit_leave_enum_variant(variant: uint, + fn visit_leave_enum_variant(&self, variant: uint, disr_val: int, n_fields: uint, name: &str) -> bool { @@ -408,58 +411,59 @@ impl ptr_visit_adaptor: TyVisitor { true } - fn visit_leave_enum(n_variants: uint, sz: uint, align: uint) -> bool { + fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint) + -> bool { if ! self.inner.visit_leave_enum(n_variants, sz, align) { return false; } true } - fn visit_trait() -> bool { + fn visit_trait(&self) -> bool { self.align_to::(); if ! self.inner.visit_trait() { return false; } self.bump_past::(); true } - fn visit_var() -> bool { + fn visit_var(&self) -> bool { if ! self.inner.visit_var() { return false; } true } - fn visit_var_integral() -> bool { + fn visit_var_integral(&self) -> bool { if ! self.inner.visit_var_integral() { return false; } true } - fn visit_param(i: uint) -> bool { + fn visit_param(&self, i: uint) -> bool { if ! self.inner.visit_param(i) { return false; } true } - fn visit_self() -> bool { + fn visit_self(&self) -> bool { self.align_to::<&static/u8>(); if ! self.inner.visit_self() { return false; } self.align_to::<&static/u8>(); true } - fn visit_type() -> bool { + fn visit_type(&self) -> bool { if ! self.inner.visit_type() { return false; } true } - fn visit_opaque_box() -> bool { + fn visit_opaque_box(&self) -> bool { self.align_to::<@u8>(); if ! self.inner.visit_opaque_box() { return false; } self.bump_past::<@u8>(); true } - fn visit_constr(inner: *TyDesc) -> bool { + fn visit_constr(&self, inner: *TyDesc) -> bool { if ! self.inner.visit_constr(inner) { return false; } true } - fn visit_closure_ptr(ck: uint) -> bool { + fn visit_closure_ptr(&self, ck: uint) -> bool { self.align_to::(); if ! self.inner.visit_closure_ptr(ck) { return false; } self.bump_past::(); @@ -503,121 +507,125 @@ impl my_visitor: movable_ptr { impl my_visitor: TyVisitor { - fn visit_bot() -> bool { true } - fn visit_nil() -> bool { true } - fn visit_bool() -> bool { + fn visit_bot(&self) -> bool { true } + fn visit_nil(&self) -> bool { true } + fn visit_bool(&self) -> bool { do self.get::() |b| { self.vals += ~[bool::to_str(b)]; }; true } - fn visit_int() -> bool { + fn visit_int(&self) -> bool { do self.get::() |i| { self.vals += ~[int::to_str(i, 10u)]; }; true } - fn visit_i8() -> bool { true } - fn visit_i16() -> bool { true } - fn visit_i32() -> bool { true } - fn visit_i64() -> bool { true } + fn visit_i8(&self) -> bool { true } + fn visit_i16(&self) -> bool { true } + fn visit_i32(&self) -> bool { true } + fn visit_i64(&self) -> bool { true } - fn visit_uint() -> bool { true } - fn visit_u8() -> bool { true } - fn visit_u16() -> bool { true } - fn visit_u32() -> bool { true } - fn visit_u64() -> bool { true } + fn visit_uint(&self) -> bool { true } + fn visit_u8(&self) -> bool { true } + fn visit_u16(&self) -> bool { true } + fn visit_u32(&self) -> bool { true } + fn visit_u64(&self) -> bool { true } - fn visit_float() -> bool { true } - fn visit_f32() -> bool { true } - fn visit_f64() -> bool { true } + fn visit_float(&self) -> bool { true } + fn visit_f32(&self) -> bool { true } + fn visit_f64(&self) -> bool { true } - fn visit_char() -> bool { true } - fn visit_str() -> bool { true } + fn visit_char(&self) -> bool { true } + fn visit_str(&self) -> bool { true } - fn visit_estr_box() -> bool { true } - fn visit_estr_uniq() -> bool { true } - fn visit_estr_slice() -> bool { true } - fn visit_estr_fixed(_n: uint, _sz: uint, + fn visit_estr_box(&self) -> bool { true } + fn visit_estr_uniq(&self) -> bool { true } + fn visit_estr_slice(&self) -> bool { true } + fn visit_estr_fixed(&self, _n: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_box(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_uniq(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_ptr(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_rptr(_mtbl: uint, _inner: *TyDesc) -> bool { true } - - fn visit_vec(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_unboxed_vec(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_evec_box(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_evec_uniq(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_evec_slice(_mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_evec_fixed(_n: uint, _sz: uint, _align: uint, + fn visit_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_uniq(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_rptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + + fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_unboxed_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_evec_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_evec_uniq(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_evec_slice(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true } + fn visit_evec_fixed(&self, _n: uint, _sz: uint, _align: uint, _mtbl: uint, _inner: *TyDesc) -> bool { true } - fn visit_enter_rec(_n_fields: uint, + fn visit_enter_rec(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_rec_field(_i: uint, _name: &str, + fn visit_rec_field(&self, _i: uint, _name: &str, _mtbl: uint, inner: *TyDesc) -> bool { error!("rec field!"); self.visit_inner(inner) } - fn visit_leave_rec(_n_fields: uint, + fn visit_leave_rec(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_enter_class(_n_fields: uint, + fn visit_enter_class(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_class_field(_i: uint, _name: &str, + fn visit_class_field(&self, _i: uint, _name: &str, _mtbl: uint, inner: *TyDesc) -> bool { self.visit_inner(inner) } - fn visit_leave_class(_n_fields: uint, + fn visit_leave_class(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_enter_tup(_n_fields: uint, + fn visit_enter_tup(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_tup_field(_i: uint, inner: *TyDesc) -> bool { + fn visit_tup_field(&self, _i: uint, inner: *TyDesc) -> bool { error!("tup field!"); self.visit_inner(inner) } - fn visit_leave_tup(_n_fields: uint, + fn visit_leave_tup(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_enter_enum(_n_variants: uint, + fn visit_enter_enum(&self, _n_variants: uint, _sz: uint, _align: uint) -> bool { // FIXME (#3732): this needs to rewind between enum variants, or something. true } - fn visit_enter_enum_variant(_variant: uint, + fn visit_enter_enum_variant(&self, _variant: uint, _disr_val: int, _n_fields: uint, _name: &str) -> bool { true } - fn visit_enum_variant_field(_i: uint, inner: *TyDesc) -> bool { + fn visit_enum_variant_field(&self, _i: uint, inner: *TyDesc) -> bool { self.visit_inner(inner) } - fn visit_leave_enum_variant(_variant: uint, + fn visit_leave_enum_variant(&self, _variant: uint, _disr_val: int, _n_fields: uint, _name: &str) -> bool { true } - fn visit_leave_enum(_n_variants: uint, + fn visit_leave_enum(&self, _n_variants: uint, _sz: uint, _align: uint) -> bool { true } - fn visit_enter_fn(_purity: uint, _proto: uint, + fn visit_enter_fn(&self, _purity: uint, _proto: uint, _n_inputs: uint, _retstyle: uint) -> bool { true } - fn visit_fn_input(_i: uint, _mode: uint, _inner: *TyDesc) -> bool { true } - fn visit_fn_output(_retstyle: uint, _inner: *TyDesc) -> bool { true } - fn visit_leave_fn(_purity: uint, _proto: uint, + fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool { + true + } + fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool { + true + } + fn visit_leave_fn(&self, _purity: uint, _proto: uint, _n_inputs: uint, _retstyle: uint) -> bool { true } - fn visit_trait() -> bool { true } - fn visit_var() -> bool { true } - fn visit_var_integral() -> bool { true } - fn visit_param(_i: uint) -> bool { true } - fn visit_self() -> bool { true } - fn visit_type() -> bool { true } - fn visit_opaque_box() -> bool { true } - fn visit_constr(_inner: *TyDesc) -> bool { true } - fn visit_closure_ptr(_ck: uint) -> bool { true } + fn visit_trait(&self) -> bool { true } + fn visit_var(&self) -> bool { true } + fn visit_var_integral(&self) -> bool { true } + fn visit_param(&self, _i: uint) -> bool { true } + fn visit_self(&self) -> bool { true } + fn visit_type(&self) -> bool { true } + fn visit_opaque_box(&self) -> bool { true } + fn visit_constr(&self, _inner: *TyDesc) -> bool { true } + fn visit_closure_ptr(&self, _ck: uint) -> bool { true } } fn get_tydesc_for(&&_t: T) -> *TyDesc { From 2195f75fc2daf37fc554cf4c02c083409bc07022 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 28 Jan 2013 22:44:59 -0800 Subject: [PATCH 31/31] librustc: Speed up byte copy operations --- src/libcore/libc.rs | 13 +++++++++++++ src/libcore/ptr.rs | 26 ++++++++++++++++++++++++- src/libcore/vec.rs | 7 +++++++ src/librustc/middle/trans/base.rs | 10 +++++++++- src/librustc/middle/trans/foreign.rs | 18 +++++++++++++++++ src/librustc/middle/trans/type_use.rs | 2 ++ src/librustc/middle/typeck/check/mod.rs | 22 +++++++++++++++++++++ 7 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs index ecd48fe16bc35..a1107d49c0ec1 100644 --- a/src/libcore/libc.rs +++ b/src/libcore/libc.rs @@ -1123,10 +1123,23 @@ pub mod funcs { unsafe fn strerror(n: c_int) -> *c_char; unsafe fn strtok(s: *c_char, t: *c_char) -> *c_char; unsafe fn strxfrm(s: *c_char, ct: *c_char, n: size_t) -> size_t; + + // These are fine to execute on the Rust stack. They must be, in + // fact, because LLVM generates calls to them! + #[rust_stack] + #[inline(always)] unsafe fn memcpy(s: *c_void, ct: *c_void, n: size_t) -> *c_void; + #[rust_stack] + #[inline(always)] unsafe fn memmove(s: *c_void, ct: *c_void, n: size_t) -> *c_void; + #[rust_stack] + #[inline(always)] unsafe fn memcmp(cx: *c_void, ct: *c_void, n: size_t) -> c_int; + #[rust_stack] + #[inline(always)] unsafe fn memchr(cx: *c_void, c: c_int, n: size_t) -> *c_void; + #[rust_stack] + #[inline(always)] unsafe fn memset(s: *c_void, c: c_int, n: size_t) -> *c_void; } } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index f059c119f4989..dd5c4143b6d7a 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -116,9 +116,16 @@ pub pure fn is_not_null(ptr: *const T) -> bool { !is_null(ptr) } * and destination may overlap. */ #[inline(always)] +#[cfg(target_word_size = "32")] pub unsafe fn copy_memory(dst: *mut T, src: *const T, count: uint) { let n = count * sys::size_of::(); - libc_::memmove(dst as *mut c_void, src as *c_void, n as size_t); + memmove32(dst as *mut u8, src as *u8, n as u32); +} +#[inline(always)] +#[cfg(target_word_size = "64")] +pub unsafe fn copy_memory(dst: *mut T, src: *const T, count: uint) { + let n = count * sys::size_of::(); + memmove64(dst as *mut u8, src as *u8, n as u64); } #[inline(always)] @@ -183,6 +190,23 @@ pub trait Ptr { pure fn offset(count: uint) -> self; } +#[cfg(stage0)] +unsafe fn memmove32(dst: *mut u8, src: *const u8, count: u32) { + libc::memmove(dst as *c_void, src as *c_void, count as size_t); +} +#[cfg(stage0)] +unsafe fn memmove64(dst: *mut u8, src: *const u8, count: u64) { + libc::memmove(dst as *c_void, src as *c_void, count as size_t); +} + +#[abi="rust-intrinsic"] +#[cfg(stage1)] +#[cfg(stage2)] +pub extern { + fn memmove32(dst: *mut u8, src: *u8, size: u32); + fn memmove64(dst: *mut u8, src: *u8, size: u64); +} + /// Extension methods for immutable pointers impl *T: Ptr { /// Returns true if the pointer is equal to the null pointer. diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index e9d60d0f26923..9707ed8459a40 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -266,6 +266,7 @@ pub pure fn slice(v: &[const T], start: uint, end: uint) -> ~[T] { } /// Return a slice that points into another slice. +#[inline(always)] pub pure fn view(v: &r/[T], start: uint, end: uint) -> &r/[T] { assert (start <= end); assert (end <= len(v)); @@ -279,6 +280,7 @@ pub pure fn view(v: &r/[T], start: uint, end: uint) -> &r/[T] { } /// Return a slice that points into another slice. +#[inline(always)] pub pure fn mut_view(v: &r/[mut T], start: uint, end: uint) -> &r/[mut T] { assert (start <= end); assert (end <= len(v)); @@ -292,6 +294,7 @@ pub pure fn mut_view(v: &r/[mut T], start: uint, end: uint) -> &r/[mut T] { } /// Return a slice that points into another slice. +#[inline(always)] pub pure fn const_view(v: &r/[const T], start: uint, end: uint) -> &r/[const T] { assert (start <= end); @@ -305,6 +308,8 @@ pub pure fn const_view(v: &r/[const T], start: uint, } } +/// Copies + /// Split the vector `v` by applying each element against the predicate `f`. pub fn split(v: &[T], f: fn(t: &T) -> bool) -> ~[~[T]] { let ln = len(v); @@ -2127,6 +2132,7 @@ pub mod raw { * Copies `count` bytes from `src` to `dst`. The source and destination * may overlap. */ + #[inline(always)] pub unsafe fn copy_memory(dst: &[mut T], src: &[const T], count: uint) { assert dst.len() >= count; @@ -2193,6 +2199,7 @@ pub mod bytes { * Copies `count` bytes from `src` to `dst`. The source and destination * may overlap. */ + #[inline(always)] pub fn copy_memory(dst: &[mut u8], src: &[const u8], count: uint) { // Bound checks are done at vec::raw::copy_memory. unsafe { vec::raw::copy_memory(dst, src, count) } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index f4814b4657b97..e9f83e25f5590 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2593,9 +2593,15 @@ fn declare_intrinsics(llmod: ModuleRef) -> HashMap<~str, ValueRef> { T_void())); let memcpy32 = decl_cdecl_fn(llmod, ~"llvm.memcpy.p0i8.p0i8.i32", - T_fn(T_memcpy32_args, T_void())); + T_fn(copy T_memcpy32_args, T_void())); let memcpy64 = decl_cdecl_fn(llmod, ~"llvm.memcpy.p0i8.p0i8.i64", + T_fn(copy T_memcpy64_args, T_void())); + let memmove32 = + decl_cdecl_fn(llmod, ~"llvm.memmove.p0i8.p0i8.i32", + T_fn(T_memcpy32_args, T_void())); + let memmove64 = + decl_cdecl_fn(llmod, ~"llvm.memmove.p0i8.p0i8.i64", T_fn(T_memcpy64_args, T_void())); let memset32 = decl_cdecl_fn(llmod, ~"llvm.memset.p0i8.i32", @@ -2704,6 +2710,8 @@ fn declare_intrinsics(llmod: ModuleRef) -> HashMap<~str, ValueRef> { intrinsics.insert(~"llvm.gcread", gcread); intrinsics.insert(~"llvm.memcpy.p0i8.p0i8.i32", memcpy32); intrinsics.insert(~"llvm.memcpy.p0i8.p0i8.i64", memcpy64); + intrinsics.insert(~"llvm.memmove.p0i8.p0i8.i32", memmove32); + intrinsics.insert(~"llvm.memmove.p0i8.p0i8.i64", memmove64); intrinsics.insert(~"llvm.memset.p0i8.i32", memset32); intrinsics.insert(~"llvm.memset.p0i8.i64", memset64); intrinsics.insert(~"llvm.trap", trap); diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 317a64ea52875..46ab560e1b67a 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -568,6 +568,24 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item, T_ptr(T_nil())); Store(bcx, morestack_addr, fcx.llretptr); } + ~"memmove32" => { + let dst_ptr = get_param(decl, first_real_arg); + let src_ptr = get_param(decl, first_real_arg + 1); + let size = get_param(decl, first_real_arg + 2); + let align = C_i32(1); + let volatile = C_bool(false); + let llfn = bcx.ccx().intrinsics.get(~"llvm.memmove.p0i8.p0i8.i32"); + Call(bcx, llfn, ~[dst_ptr, src_ptr, size, align, volatile]); + } + ~"memmove64" => { + let dst_ptr = get_param(decl, first_real_arg); + let src_ptr = get_param(decl, first_real_arg + 1); + let size = get_param(decl, first_real_arg + 2); + let align = C_i32(1); + let volatile = C_bool(false); + let llfn = bcx.ccx().intrinsics.get(~"llvm.memmove.p0i8.p0i8.i64"); + Call(bcx, llfn, ~[dst_ptr, src_ptr, size, align, volatile]); + } ~"sqrtf32" => { let x = get_param(decl, first_real_arg); let sqrtf = ccx.intrinsics.get(~"llvm.sqrt.f32"); diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index ba1901f215c57..1ef5abe8ee683 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -129,6 +129,8 @@ fn type_uses_for(ccx: @crate_ctxt, fn_id: def_id, n_tps: uint) ~"visit_tydesc" | ~"forget" | ~"addr_of" | ~"frame_address" | ~"morestack_addr" => 0, + ~"memmove32" | ~"memmove64" => 0, + ~"sqrtf32" | ~"sqrtf64" | ~"powif32" | ~"powif64" | ~"sinf32" | ~"sinf64" | ~"cosf32" | ~"cosf64" | ~"powf32" | ~"powf64" | ~"expf32" | ~"expf64" | diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 3d5f6e9d303d9..c4440b8941131 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3152,6 +3152,28 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) { ~"morestack_addr" => { (0u, ~[], ty::mk_nil_ptr(tcx)) } + ~"memmove32" => { + (0, ~[arg(ast::by_copy, + ty::mk_ptr(tcx, + ty::mt { ty: ty::mk_u8(tcx), mutbl: ast::m_mutbl })), + arg(ast::by_copy, + ty::mk_ptr(tcx, + ty::mt { ty: ty::mk_u8(tcx), mutbl: ast::m_imm })), + arg(ast::by_copy, + ty::mk_u32(tcx))], + ty::mk_nil(tcx)) + } + ~"memmove64" => { + (0, ~[arg(ast::by_copy, + ty::mk_ptr(tcx, + ty::mt { ty: ty::mk_u8(tcx), mutbl: ast::m_mutbl })), + arg(ast::by_copy, + ty::mk_ptr(tcx, + ty::mt { ty: ty::mk_u8(tcx), mutbl: ast::m_imm })), + arg(ast::by_copy, + ty::mk_u64(tcx))], + ty::mk_nil(tcx)) + } ~"sqrtf32" => { (0u, ~[arg(ast::by_copy, ty::mk_f32(tcx))], ty::mk_f32(tcx))