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:
Niko Matsakis 2013-03-05 17:49:03 -05:00
parent 959e483fb7
commit 6267339d68
13 changed files with 292 additions and 94 deletions

View File

@ -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))
}
}

View File

@ -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};

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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)

View 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) {}
}

View 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() {}

View 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() {}

View File

@ -17,6 +17,7 @@
use double_buffer::client::*;
use double_buffer::give_buffer;
use core::comm::Selectable;
macro_rules! select_if (
{

View File

@ -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;
}