librustc: Forbid type implementations on typedefs.

This commit is contained in:
Patrick Walton 2013-04-26 18:52:15 -07:00
parent 670ab8ac36
commit 37abf4bad0
8 changed files with 192 additions and 83 deletions

View File

@ -395,24 +395,55 @@ pub mod server {
}
/// The send end of a oneshot pipe.
pub type ChanOne<T> = oneshot::client::Oneshot<T>;
pub struct ChanOne<T> {
contents: oneshot::client::Oneshot<T>
}
impl<T> ChanOne<T> {
pub fn new(contents: oneshot::client::Oneshot<T>) -> ChanOne<T> {
ChanOne {
contents: contents
}
}
}
/// The receive end of a oneshot pipe.
pub type PortOne<T> = oneshot::server::Oneshot<T>;
pub struct PortOne<T> {
contents: oneshot::server::Oneshot<T>
}
impl<T> PortOne<T> {
pub fn new(contents: oneshot::server::Oneshot<T>) -> PortOne<T> {
PortOne {
contents: contents
}
}
}
/// Initialiase a (send-endpoint, recv-endpoint) oneshot pipe pair.
pub fn oneshot<T: Owned>() -> (PortOne<T>, ChanOne<T>) {
let (chan, port) = oneshot::init();
(port, chan)
(PortOne::new(port), ChanOne::new(chan))
}
pub impl<T: Owned> PortOne<T> {
fn recv(self) -> T { recv_one(self) }
fn try_recv(self) -> Option<T> { try_recv_one(self) }
fn unwrap(self) -> oneshot::server::Oneshot<T> {
match self {
PortOne { contents: s } => s
}
}
}
pub impl<T: Owned> ChanOne<T> {
fn send(self, data: T) { send_one(self, data) }
fn try_send(self, data: T) -> bool { try_send_one(self, data) }
fn unwrap(self) -> oneshot::client::Oneshot<T> {
match self {
ChanOne { contents: s } => s
}
}
}
/**
@ -420,33 +451,47 @@ fn try_send(self, data: T) -> bool { try_send_one(self, data) }
* closed.
*/
pub fn recv_one<T: Owned>(port: PortOne<T>) -> T {
let oneshot::send(message) = recv(port);
message
match port {
PortOne { contents: port } => {
let oneshot::send(message) = recv(port);
message
}
}
}
/// Receive a message from a oneshot pipe unless the connection was closed.
pub fn try_recv_one<T: Owned> (port: PortOne<T>) -> Option<T> {
let message = try_recv(port);
match port {
PortOne { contents: port } => {
let message = try_recv(port);
if message.is_none() { None }
else {
let oneshot::send(message) = message.unwrap();
Some(message)
if message.is_none() {
None
} else {
let oneshot::send(message) = message.unwrap();
Some(message)
}
}
}
}
/// Send a message on a oneshot pipe, failing if the connection was closed.
pub fn send_one<T: Owned>(chan: ChanOne<T>, data: T) {
oneshot::client::send(chan, data);
match chan {
ChanOne { contents: chan } => oneshot::client::send(chan, data),
}
}
/**
* Send a message on a oneshot pipe, or return false if the connection was
* closed.
*/
pub fn try_send_one<T: Owned>(chan: ChanOne<T>, data: T)
-> bool {
oneshot::client::try_send(chan, data).is_some()
pub fn try_send_one<T: Owned>(chan: ChanOne<T>, data: T) -> bool {
match chan {
ChanOne { contents: chan } => {
oneshot::client::try_send(chan, data).is_some()
}
}
}

View File

@ -21,6 +21,11 @@
use to_str::ToStr;
use ascii::{AsciiCast, AsciiStr};
#[cfg(windows)]
pub use Path = self::WindowsPath;
#[cfg(unix)]
pub use Path = self::PosixPath;
#[deriving(Clone, Eq)]
pub struct WindowsPath {
host: Option<~str>,
@ -72,22 +77,6 @@ pub trait GenericPath {
fn is_absolute(&self) -> bool;
}
#[cfg(windows)]
pub type Path = WindowsPath;
#[cfg(windows)]
pub fn Path(s: &str) -> Path {
WindowsPath(s)
}
#[cfg(unix)]
pub type Path = PosixPath;
#[cfg(unix)]
pub fn Path(s: &str) -> Path {
PosixPath(s)
}
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
mod stat {

View File

@ -38,8 +38,9 @@
use middle::typeck::infer::InferCtxt;
use middle::typeck::infer::{new_infer_ctxt, resolve_ivar};
use middle::typeck::infer::{resolve_nested_tvar, resolve_type};
use syntax::ast::{crate, def_id, def_mod, def_trait};
use syntax::ast::{item, item_impl, item_mod, local_crate, method, trait_ref};
use syntax::ast::{crate, def_id, def_mod, def_struct, def_trait, def_ty};
use syntax::ast::{item, item_enum, item_impl, item_mod, item_struct};
use syntax::ast::{local_crate, method, trait_ref, ty_path};
use syntax::ast;
use syntax::ast_map::node_item;
use syntax::ast_map;
@ -661,7 +662,19 @@ fn check_privileged_scopes(self, crate: @crate) {
// Then visit the module items.
visit_mod(module_, item.span, item.id, (), visitor);
}
item_impl(_, opt_trait, _, _) => {
item_impl(_, None, ast_ty, _) => {
if !self.ast_type_is_defined_in_local_crate(ast_ty) {
// This is an error.
let session = self.crate_context.tcx.sess;
session.span_err(item.span,
~"cannot associate methods with \
a type outside the crate the \
type is defined in; define \
and implement a trait or new \
type instead");
}
}
item_impl(_, Some(trait_ref), _, _) => {
// `for_ty` is `Type` in `impl Trait for Type`
let for_ty =
ty::node_id_to_type(self.crate_context.tcx,
@ -671,40 +684,16 @@ fn check_privileged_scopes(self, crate: @crate) {
// 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 trait_def_id =
self.trait_ref_to_trait_def_id(trait_ref);
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");
}
Some(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");
}
}
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");
}
}
@ -754,6 +743,46 @@ fn please_check_that_trait_methods_are_implemented(&self,
}
}
/// For coherence, when we have `impl Type`, we need to guarantee that
/// `Type` is "local" to the crate. For our purposes, this means that it
/// must precisely name some nominal type defined in this crate.
pub fn ast_type_is_defined_in_local_crate(&self, original_type: @ast::Ty)
-> bool {
match original_type.node {
ty_path(_, path_id) => {
match *self.crate_context.tcx.def_map.get(&path_id) {
def_ty(def_id) | def_struct(def_id) => {
if def_id.crate != local_crate {
return false;
}
// Make sure that this type precisely names a nominal
// type.
match self.crate_context
.tcx
.items
.find(&def_id.node) {
None => {
self.crate_context.tcx.sess.span_bug(
original_type.span,
~"resolve didn't resolve this type?!");
}
Some(&node_item(item, _)) => {
match item.node {
item_struct(*) | item_enum(*) => true,
_ => false,
}
}
Some(_) => false,
}
}
_ => false
}
}
_ => false
}
}
// Converts an implementation in the AST to an Impl structure.
fn create_impl_from_item(&self, item: @item) -> @Impl {
fn add_provided_methods(all_methods: &mut ~[@MethodInfo],

View File

@ -23,7 +23,7 @@
use core::cast;
use core::cell::Cell;
use core::comm::{oneshot, PortOne, send_one};
use core::comm::{ChanOne, PortOne, oneshot, send_one};
use core::pipes::recv;
use core::task;
@ -120,8 +120,7 @@ pub fn from_value<A>(val: A) -> Future<A> {
Future {state: Forced(val)}
}
pub fn from_port<A:Owned>(port: PortOne<A>) ->
Future<A> {
pub fn from_port<A:Owned>(port: PortOne<A>) -> Future<A> {
/*!
* Create a future from a port
*
@ -131,7 +130,7 @@ pub fn from_port<A:Owned>(port: PortOne<A>) ->
let port = Cell(port);
do from_fn || {
let port = port.take();
let port = port.take().unwrap();
match recv(port) {
oneshot::send(data) => data
}
@ -158,10 +157,10 @@ pub fn spawn<A:Owned>(blk: ~fn() -> A) -> Future<A> {
* value of the future.
*/
let (chan, port) = oneshot::init();
let (port, chan) = oneshot();
let chan = Cell(chan);
do task::spawn || {
do task::spawn {
let chan = chan.take();
send_one(chan, blk());
}
@ -186,7 +185,7 @@ fn test_from_value() {
#[test]
fn test_from_port() {
let (ch, po) = oneshot::init();
let (ch, po) = oneshot();
send_one(ch, ~"whale");
let f = from_port(po);
assert!(f.get() == ~"whale");

View File

@ -16,10 +16,13 @@
use sort;
use core::cell::Cell;
use core::comm::{oneshot, PortOne, send_one};
use core::cmp;
use core::comm::{ChanOne, PortOne, oneshot, send_one};
use core::either::{Either, Left, Right};
use core::hashmap::HashMap;
use core::io;
use core::pipes::recv;
use core::run;
use core::hashmap::HashMap;
use core::to_bytes;
/**
@ -340,13 +343,13 @@ fn exec<T:Owned +
}
_ => {
let (chan, port) = oneshot::init();
let (port, chan) = oneshot();
let mut blk = None;
blk <-> bo;
let blk = blk.unwrap();
let chan = Cell(chan);
do task::spawn || {
do task::spawn {
let exe = Exec {
discovered_inputs: WorkMap::new(),
discovered_outputs: WorkMap::new(),
@ -383,7 +386,7 @@ fn unwrap<T:Owned +
None => fail!(),
Some(Left(v)) => v,
Some(Right(port)) => {
let (exe, v) = match recv(port) {
let (exe, v) = match recv(port.unwrap()) {
oneshot::send(data) => data
};

View File

@ -215,7 +215,50 @@ fn filter_attrs(item: @ast::item) -> @ast::item {
}
}
priv impl @ext_ctxt {
trait ExtCtxtMethods {
fn bind_path(&self,
span: span,
ident: ast::ident,
path: @ast::Path,
bounds: @OptVec<ast::TyParamBound>)
-> ast::TyParam;
fn expr(&self, span: span, node: ast::expr_) -> @ast::expr;
fn path(&self, span: span, strs: ~[ast::ident]) -> @ast::Path;
fn path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::Path;
fn path_tps(&self, span: span, strs: ~[ast::ident], tps: ~[@ast::Ty])
-> @ast::Path;
fn path_tps_global(&self,
span: span,
strs: ~[ast::ident],
tps: ~[@ast::Ty])
-> @ast::Path;
fn ty_path(&self, span: span, strs: ~[ast::ident], tps: ~[@ast::Ty])
-> @ast::Ty;
fn binder_pat(&self, span: span, nm: ast::ident) -> @ast::pat;
fn stmt(&self, expr: @ast::expr) -> @ast::stmt;
fn lit_str(&self, span: span, s: @~str) -> @ast::expr;
fn lit_uint(&self, span: span, i: uint) -> @ast::expr;
fn lambda(&self, blk: ast::blk) -> @ast::expr;
fn blk(&self, span: span, stmts: ~[@ast::stmt]) -> ast::blk;
fn expr_blk(&self, expr: @ast::expr) -> ast::blk;
fn expr_path(&self, span: span, strs: ~[ast::ident]) -> @ast::expr;
fn expr_path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::expr;
fn expr_var(&self, span: span, var: ~str) -> @ast::expr;
fn expr_field(&self, span: span, expr: @ast::expr, ident: ast::ident)
-> @ast::expr;
fn expr_call(&self, span: span, expr: @ast::expr, args: ~[@ast::expr])
-> @ast::expr;
fn expr_method_call(&self,
span: span,
expr: @ast::expr,
ident: ast::ident,
args: ~[@ast::expr])
-> @ast::expr;
fn lambda_expr(&self, expr: @ast::expr) -> @ast::expr;
fn lambda_stmts(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr;
}
impl ExtCtxtMethods for @ext_ctxt {
fn bind_path(
&self,
_span: span,

View File

@ -867,7 +867,11 @@ fn new_span(@self, span: span) -> span {
}
}
pub impl @ast_fold {
pub trait AstFoldExtensions {
fn fold_attributes(&self, attrs: ~[attribute]) -> ~[attribute];
}
impl AstFoldExtensions for @ast_fold {
fn fold_attributes(&self, attrs: ~[attribute]) -> ~[attribute] {
attrs.map(|x| fold_attribute_(*x, *self))
}

View File

@ -56,6 +56,3 @@ fn context_res() -> context_res {
pub type context = arc_destruct<context_res>;
pub impl context {
fn socket(&self) { }
}