Fix bug in coherence that causes all cross-crate impls to be regarded as
inherent impls, not just those of the `impl Type` variety.
This commit is contained in:
parent
959e483fb7
commit
6267339d68
@ -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) }
|
||||
}
|
||||
|
||||
#[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> {
|
||||
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) }
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
#[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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
21
src/test/auxiliary/coherence_inherent_cc_lib.rs
Normal file
21
src/test/auxiliary/coherence_inherent_cc_lib.rs
Normal file
@ -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) {}
|
||||
}
|
45
src/test/compile-fail/coherence_inherent.rs
Normal file
45
src/test/compile-fail/coherence_inherent.rs
Normal file
@ -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() {}
|
38
src/test/compile-fail/coherence_inherent_cc.rs
Normal file
38
src/test/compile-fail/coherence_inherent_cc.rs
Normal file
@ -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() {}
|
@ -17,6 +17,7 @@
|
||||
|
||||
use double_buffer::client::*;
|
||||
use double_buffer::give_buffer;
|
||||
use core::comm::Selectable;
|
||||
|
||||
macro_rules! select_if (
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user