diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2013-03-05 17:49:03 -0500 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2013-03-06 11:02:19 -0500 |
| commit | 6267339d6869a27b95f13c578a235204a1562697 (patch) | |
| tree | 1e2f756ecad93469bb325adc1ed6dde83513d4da | |
| parent | 959e483fb705e99097a85ce42371bd57b78bd180 (diff) | |
| download | rust-6267339d6869a27b95f13c578a235204a1562697.tar.gz rust-6267339d6869a27b95f13c578a235204a1562697.zip | |
Fix bug in coherence that causes all cross-crate impls to be regarded as
inherent impls, not just those of the `impl Type` variety.
| -rw-r--r-- | src/libcore/comm.rs | 238 | ||||
| -rw-r--r-- | src/librustc/back/link.rs | 1 | ||||
| -rw-r--r-- | src/librustc/metadata/encoder.rs | 2 | ||||
| -rw-r--r-- | src/librustc/middle/astencode.rs | 5 | ||||
| -rw-r--r-- | src/librustc/middle/typeck/coherence.rs | 8 | ||||
| -rw-r--r-- | src/librustpkg/rustpkg.rc | 1 | ||||
| -rw-r--r-- | src/librustpkg/util.rs | 1 | ||||
| -rw-r--r-- | src/libstd/comm.rs | 21 | ||||
| -rw-r--r-- | src/test/auxiliary/coherence_inherent_cc_lib.rs | 21 | ||||
| -rw-r--r-- | src/test/compile-fail/coherence_inherent.rs | 45 | ||||
| -rw-r--r-- | src/test/compile-fail/coherence_inherent_cc.rs | 38 | ||||
| -rw-r--r-- | src/test/run-pass/pipe-presentation-examples.rs | 1 | ||||
| -rw-r--r-- | src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs | 4 |
13 files changed, 292 insertions, 94 deletions
diff --git a/src/libcore/comm.rs b/src/libcore/comm.rs index 4f812a5ae76..18e04978944 100644 --- a/src/libcore/comm.rs +++ b/src/libcore/comm.rs @@ -104,64 +104,98 @@ pub fn stream<T:Owned>() -> (Port<T>, Chan<T>) { (Port_(Port_ { endp: Some(s) }), Chan_(Chan_{ endp: Some(c) })) } +// Add an inherent method so that imports of GenericChan are not +// required. +#[cfg(stage1)] +#[cfg(stage2)] +pub impl<T: Owned> Chan<T> { + fn send(&self, x: T) { chan_send(self, x) } + fn try_send(&self, x: T) -> bool { chan_try_send(self, x) } +} + impl<T: Owned> GenericChan<T> for Chan<T> { - fn send(&self, x: T) { - let mut endp = None; - endp <-> self.endp; - self.endp = Some( - streamp::client::data(unwrap(endp), x)) - } + fn send(&self, x: T) { chan_send(self, x) } } -impl<T: Owned> GenericSmartChan<T> for Chan<T> { +#[inline(always)] +fn chan_send<T:Owned>(self: &Chan<T>, x: T) { + let mut endp = None; + endp <-> self.endp; + self.endp = Some( + streamp::client::data(unwrap(endp), x)) +} +impl<T: Owned> GenericSmartChan<T> for Chan<T> { fn try_send(&self, x: T) -> bool { - let mut endp = None; - endp <-> self.endp; - match streamp::client::try_data(unwrap(endp), x) { - Some(next) => { - self.endp = Some(next); - true - } - None => false - } + chan_try_send(self, x) } } -impl<T: Owned> GenericPort<T> for Port<T> { - fn recv(&self) -> T { - let mut endp = None; - endp <-> self.endp; - let streamp::data(x, endp) = recv(unwrap(endp)); - self.endp = Some(endp); - x +#[inline(always)] +fn chan_try_send<T:Owned>(self: &Chan<T>, x: T) -> bool { + let mut endp = None; + endp <-> self.endp; + match streamp::client::try_data(unwrap(endp), x) { + Some(next) => { + self.endp = Some(next); + true + } + None => false } +} - fn try_recv(&self) -> Option<T> { - let mut endp = None; - endp <-> self.endp; - match try_recv(unwrap(endp)) { - Some(streamp::data(x, endp)) => { +// Use an inherent impl so that imports are not required: +#[cfg(stage1)] +#[cfg(stage2)] +pub impl<T: Owned> Port<T> { + fn recv(&self) -> T { port_recv(self) } + fn try_recv(&self) -> Option<T> { port_try_recv(self) } + pure fn peek(&self) -> bool { port_peek(self) } +} + +impl<T: Owned> GenericPort<T> for Port<T> { + // These two calls will prefer the inherent versions above: + fn recv(&self) -> T { port_recv(self) } + fn try_recv(&self) -> Option<T> { port_try_recv(self) } +} + +#[inline(always)] +fn port_recv<T:Owned>(self: &Port<T>) -> T { + let mut endp = None; + endp <-> self.endp; + let streamp::data(x, endp) = recv(unwrap(endp)); + self.endp = Some(endp); + x +} + +#[inline(always)] +fn port_try_recv<T:Owned>(self: &Port<T>) -> Option<T> { + let mut endp = None; + endp <-> self.endp; + match try_recv(unwrap(endp)) { + Some(streamp::data(x, endp)) => { self.endp = Some(endp); Some(x) - } - None => None } + None => None } } impl<T: Owned> Peekable<T> for Port<T> { - pure fn peek(&self) -> bool { - unsafe { - let mut endp = None; - endp <-> self.endp; - let peek = match &endp { - &Some(ref endp) => peek(endp), - &None => fail!(~"peeking empty stream") - }; - self.endp <-> endp; - peek - } + pure fn peek(&self) -> bool { port_peek(self) } +} + +#[inline(always)] +pure fn port_peek<T:Owned>(self: &Port<T>) -> bool { + unsafe { + let mut endp = None; + endp <-> self.endp; + let peek = match &endp { + &Some(ref endp) => peek(endp), + &None => fail!(~"peeking empty stream") + }; + self.endp <-> endp; + peek } } @@ -187,8 +221,16 @@ pub fn PortSet<T: Owned>() -> PortSet<T>{ } } -pub impl<T: Owned> PortSet<T> { +// Use an inherent impl so that imports are not required: +#[cfg(stage1)] +#[cfg(stage2)] +pub impl<T:Owned> PortSet<T> { + fn recv(&self) -> T { port_set_recv(self) } + fn try_recv(&self) -> Option<T> { port_set_try_recv(self) } + pure fn peek(&self) -> bool { port_set_peek(self) } +} +pub impl<T: Owned> PortSet<T> { fn add(&self, port: Port<T>) { self.ports.push(port) } @@ -200,69 +242,89 @@ pub impl<T: Owned> PortSet<T> { } } -impl<T: Owned> GenericPort<T> for PortSet<T> { - - fn try_recv(&self) -> Option<T> { - let mut result = None; - // we have to swap the ports array so we aren't borrowing - // aliasable mutable memory. - let mut ports = ~[]; - ports <-> self.ports; - while result.is_none() && ports.len() > 0 { - let i = wait_many(ports); - match ports[i].try_recv() { - Some(m) => { - result = Some(m); - } - None => { - // Remove this port. - let _ = ports.swap_remove(i); - } +impl<T:Owned> GenericPort<T> for PortSet<T> { + fn try_recv(&self) -> Option<T> { port_set_try_recv(self) } + fn recv(&self) -> T { port_set_recv(self) } +} + +#[inline(always)] +fn port_set_recv<T:Owned>(self: &PortSet<T>) -> T { + port_set_try_recv(self).expect("port_set: endpoints closed") +} + +#[inline(always)] +fn port_set_try_recv<T:Owned>(self: &PortSet<T>) -> Option<T> { + let mut result = None; + // we have to swap the ports array so we aren't borrowing + // aliasable mutable memory. + let mut ports = ~[]; + ports <-> self.ports; + while result.is_none() && ports.len() > 0 { + let i = wait_many(ports); + match ports[i].try_recv() { + Some(m) => { + result = Some(m); + } + None => { + // Remove this port. + let _ = ports.swap_remove(i); } } - ports <-> self.ports; - result } - - fn recv(&self) -> T { - self.try_recv().expect("port_set: endpoints closed") - } - + ports <-> self.ports; + result } impl<T: Owned> Peekable<T> for PortSet<T> { - pure fn peek(&self) -> bool { - // It'd be nice to use self.port.each, but that version isn't - // pure. - for vec::each(self.ports) |p| { - if p.peek() { return true } - } - false + pure fn peek(&self) -> bool { port_set_peek(self) } +} + +#[inline(always)] +pure fn port_set_peek<T:Owned>(self: &PortSet<T>) -> bool { + // It'd be nice to use self.port.each, but that version isn't + // pure. + for vec::each(self.ports) |p| { + if p.peek() { return true } } + false } + /// A channel that can be shared between many senders. pub type SharedChan<T> = unstable::Exclusive<Chan<T>>; +#[cfg(stage1)] +#[cfg(stage2)] +pub impl<T: Owned> SharedChan<T> { + fn send(&self, x: T) { shared_chan_send(self, x) } + fn try_send(&self, x: T) -> bool { shared_chan_try_send(self, x) } +} + impl<T: Owned> GenericChan<T> for SharedChan<T> { - fn send(&self, x: T) { - let mut xx = Some(x); - do self.with_imm |chan| { - let mut x = None; - x <-> xx; - chan.send(option::unwrap(x)) - } + fn send(&self, x: T) { shared_chan_send(self, x) } +} + +#[inline(always)] +fn shared_chan_send<T:Owned>(self: &SharedChan<T>, x: T) { + let mut xx = Some(x); + do self.with_imm |chan| { + let mut x = None; + x <-> xx; + chan.send(option::unwrap(x)) } } impl<T: Owned> GenericSmartChan<T> for SharedChan<T> { - fn try_send(&self, x: T) -> bool { - let mut xx = Some(x); - do self.with_imm |chan| { - let mut x = None; - x <-> xx; - chan.try_send(option::unwrap(x)) - } + fn try_send(&self, x: T) -> bool { shared_chan_try_send(self, x) } +} + +#[inline(always)] +fn shared_chan_try_send<T:Owned>(self: &SharedChan<T>, x: T) -> bool { + let mut xx = Some(x); + do self.with_imm |chan| { + let mut x = None; + x <-> xx; + chan.try_send(option::unwrap(x)) } } diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 30ef73bf670..8e74ec1dc4c 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -23,6 +23,7 @@ use middle::ty; use util::ppaux; use core::char; +use core::hash::Streaming; use core::hash; use core::io::{Writer, WriterUtil}; use core::libc::{c_int, c_uint, c_char}; diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index c5cb6617130..2c9a824471c 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -26,7 +26,7 @@ use core::dvec; use core::flate; use core::hash::{Hash, HashUtil}; use core::int; -use core::io::WriterUtil; +use core::io::{Writer, WriterUtil}; use core::io; use core::str; use core::to_bytes::IterBytes; diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index cf88a0eb902..0fb587dfc9a 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -29,10 +29,11 @@ use core::{dvec, io, option, vec}; use std::ebml::reader; use std::ebml; use std::serialize; -use std::serialize::{Encodable, EncoderHelpers, DecoderHelpers}; -use std::serialize::Decodable; +use std::serialize::{Encoder, Encodable, EncoderHelpers, DecoderHelpers}; +use std::serialize::{Decoder, Decodable}; use syntax::ast; use syntax::ast_map; +use syntax::ast_util::inlined_item_utils; use syntax::ast_util; use syntax::codemap::span; use syntax::codemap; diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 2d2be88de7f..2d1fab5f6a9 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -902,8 +902,12 @@ pub impl CoherenceChecker { // Nothing to do. } Some(base_type_def_id) => { - self.add_inherent_method(base_type_def_id, - *implementation); + // inherent methods apply to `impl Type` but not + // `impl Trait for Type`: + if associated_traits.len() == 0 { + self.add_inherent_method(base_type_def_id, + *implementation); + } self.base_type_def_ids.insert(implementation.did, base_type_def_id); diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc index 603480f907c..0f8463b0b3c 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rc @@ -35,6 +35,7 @@ use std::net::url; use std::{json, semver, getopts}; use syntax::codemap::spanned; use syntax::{ast, attr, codemap, diagnostic, parse, visit}; +use core::container::Map; mod usage; mod util; diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index d7428ae15e7..7238a934c99 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -9,6 +9,7 @@ // except according to those terms. use core::*; +use core::hash::{Hash, HashUtil, Streaming}; use core::hashmap::linear::LinearMap; use rustc::driver::{driver, session}; use rustc::metadata::filesearch; diff --git a/src/libstd/comm.rs b/src/libstd/comm.rs index 14a37ecbf52..e3437fc57aa 100644 --- a/src/libstd/comm.rs +++ b/src/libstd/comm.rs @@ -25,6 +25,27 @@ pub struct DuplexStream<T, U> { priv port: Port<U>, } +// Allow these methods to be used without import: +#[cfg(stage1)] +#[cfg(stage2)] +pub impl<T:Owned,U:Owned> DuplexStream<T, U> { + fn send(x: T) { + self.chan.send(x) + } + fn try_send(x: T) -> bool { + self.chan.try_send(x) + } + fn recv() -> U { + self.port.recv() + } + fn try_recv() -> Option<U> { + self.port.try_recv() + } + pure fn peek() -> bool { + self.port.peek() + } +} + impl<T:Owned,U:Owned> GenericChan<T> for DuplexStream<T, U> { fn send(&self, x: T) { self.chan.send(x) diff --git a/src/test/auxiliary/coherence_inherent_cc_lib.rs b/src/test/auxiliary/coherence_inherent_cc_lib.rs new file mode 100644 index 00000000000..0458636a401 --- /dev/null +++ b/src/test/auxiliary/coherence_inherent_cc_lib.rs @@ -0,0 +1,21 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// See coherence_inherent_cc.rs + +pub trait TheTrait { + fn the_fn(&self); +} + +pub struct TheStruct; + +impl TheTrait for TheStruct { + fn the_fn(&self) {} +} diff --git a/src/test/compile-fail/coherence_inherent.rs b/src/test/compile-fail/coherence_inherent.rs new file mode 100644 index 00000000000..590c12826e4 --- /dev/null +++ b/src/test/compile-fail/coherence_inherent.rs @@ -0,0 +1,45 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that methods that implement a trait cannot be invoked +// unless the trait is imported. + +mod Lib { + pub trait TheTrait { + fn the_fn(&self); + } + + pub struct TheStruct; + + impl TheTrait for TheStruct { + fn the_fn(&self) {} + } +} + +mod Import { + // Trait is in scope here: + use Lib::TheStruct; + use Lib::TheTrait; + + fn call_the_fn(s: &TheStruct) { + s.the_fn(); + } +} + +mod NoImport { + // Trait is not in scope here: + use Lib::TheStruct; + + fn call_the_fn(s: &TheStruct) { + s.the_fn(); //~ ERROR does not implement any method in scope named `the_fn` + } +} + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/coherence_inherent_cc.rs b/src/test/compile-fail/coherence_inherent_cc.rs new file mode 100644 index 00000000000..72c6df57c4f --- /dev/null +++ b/src/test/compile-fail/coherence_inherent_cc.rs @@ -0,0 +1,38 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-fast +// aux-build:coherence_inherent_cc_lib.rs + +// Tests that methods that implement a trait cannot be invoked +// unless the trait is imported. + +extern mod coherence_inherent_cc_lib; + +mod Import { + // Trait is in scope here: + use coherence_inherent_cc_lib::TheStruct; + use coherence_inherent_cc_lib::TheTrait; + + fn call_the_fn(s: &TheStruct) { + s.the_fn(); + } +} + +mod NoImport { + // Trait is not in scope here: + use coherence_inherent_cc_lib::TheStruct; + + fn call_the_fn(s: &TheStruct) { + s.the_fn(); //~ ERROR does not implement any method in scope named `the_fn` + } +} + +fn main() {} \ No newline at end of file diff --git a/src/test/run-pass/pipe-presentation-examples.rs b/src/test/run-pass/pipe-presentation-examples.rs index 8749c1cb113..01f68929b90 100644 --- a/src/test/run-pass/pipe-presentation-examples.rs +++ b/src/test/run-pass/pipe-presentation-examples.rs @@ -17,6 +17,7 @@ use double_buffer::client::*; use double_buffer::give_buffer; +use core::comm::Selectable; macro_rules! select_if ( { diff --git a/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs index f537357d3ce..f344837a22d 100644 --- a/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs +++ b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs @@ -13,7 +13,9 @@ extern mod aux(name = "trait_inheritance_cross_trait_call_xc_aux"); -trait Bar : aux::Foo { +use aux::Foo; + +trait Bar : Foo { fn g() -> int; } |
