about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2013-03-05 17:49:03 -0500
committerNiko Matsakis <niko@alum.mit.edu>2013-03-06 11:02:19 -0500
commit6267339d6869a27b95f13c578a235204a1562697 (patch)
tree1e2f756ecad93469bb325adc1ed6dde83513d4da
parent959e483fb705e99097a85ce42371bd57b78bd180 (diff)
downloadrust-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.rs238
-rw-r--r--src/librustc/back/link.rs1
-rw-r--r--src/librustc/metadata/encoder.rs2
-rw-r--r--src/librustc/middle/astencode.rs5
-rw-r--r--src/librustc/middle/typeck/coherence.rs8
-rw-r--r--src/librustpkg/rustpkg.rc1
-rw-r--r--src/librustpkg/util.rs1
-rw-r--r--src/libstd/comm.rs21
-rw-r--r--src/test/auxiliary/coherence_inherent_cc_lib.rs21
-rw-r--r--src/test/compile-fail/coherence_inherent.rs45
-rw-r--r--src/test/compile-fail/coherence_inherent_cc.rs38
-rw-r--r--src/test/run-pass/pipe-presentation-examples.rs1
-rw-r--r--src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs4
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;
 }