rustc: Update how Gc<T> is recognized

This commit uses the same trick as ~/Box to map Gc<T> to @T internally inside
the compiler. This moves a number of implementations of traits to the `gc`
module in the standard library.

This removes functions such as `Gc::new`, `Gc::borrow`, and `Gc::ptr_eq` in
favor of the more modern equivalents, `box(GC)`, `Deref`, and pointer equality.

The Gc pointer itself should be much more useful now, and subsequent commits
will move the compiler away from @T towards Gc<T>

[breaking-change]
This commit is contained in:
Alex Crichton 2014-05-15 18:18:00 -07:00
parent ea41101b35
commit 531ed3d599
16 changed files with 155 additions and 173 deletions

View File

@ -320,8 +320,8 @@ mod tests {
#[test]
fn gc_inside() {
// see issue #11532
use std::gc::Gc;
let a = Rc::new(RefCell::new(Gc::new(1)));
use realstd::gc::Gc;
let a = Rc::new(RefCell::new(box(GC) 1));
assert!(a.try_borrow_mut().is_some());
}

View File

@ -248,13 +248,6 @@ impl<S: Writer, T: Hash<S>> Hash<S> for Box<T> {
}
}
impl<S: Writer, T: Hash<S>> Hash<S> for @T {
#[inline]
fn hash(&self, state: &mut S) {
(**self).hash(state);
}
}
impl<S: Writer, T: Hash<S>> Hash<S> for Rc<T> {
#[inline]
fn hash(&self, state: &mut S) {

View File

@ -39,12 +39,6 @@ pub trait Clone {
}
}
impl<T> Clone for @T {
/// Return a shallow copy of the managed box.
#[inline]
fn clone(&self) -> @T { *self }
}
impl<'a, T> Clone for &'a T {
/// Return a shallow copy of the reference.
#[inline]

View File

@ -326,29 +326,6 @@ mod impls {
fn cmp(&self, other: &&'a mut T) -> Ordering { (**self).cmp(*other) }
}
impl<'a, T: Eq> Eq for &'a mut T {}
// @ pointers
impl<T:PartialEq> PartialEq for @T {
#[inline]
fn eq(&self, other: &@T) -> bool { *(*self) == *(*other) }
#[inline]
fn ne(&self, other: &@T) -> bool { *(*self) != *(*other) }
}
impl<T:PartialOrd> PartialOrd for @T {
#[inline]
fn lt(&self, other: &@T) -> bool { *(*self) < *(*other) }
#[inline]
fn le(&self, other: &@T) -> bool { *(*self) <= *(*other) }
#[inline]
fn ge(&self, other: &@T) -> bool { *(*self) >= *(*other) }
#[inline]
fn gt(&self, other: &@T) -> bool { *(*self) > *(*other) }
}
impl<T: Ord> Ord for @T {
#[inline]
fn cmp(&self, other: &@T) -> Ordering { (**self).cmp(*other) }
}
impl<T: Eq> Eq for @T {}
}
#[cfg(test)]

View File

@ -43,7 +43,3 @@ default_impl!(i64, 0i64)
default_impl!(f32, 0.0f32)
default_impl!(f64, 0.0f64)
impl<T: Default + 'static> Default for @T {
fn default() -> @T { @Default::default() }
}

View File

@ -628,9 +628,6 @@ pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> {
// Implementations of the core formatting traits
impl<T: Show> Show for @T {
fn fmt(&self, f: &mut Formatter) -> Result { secret_show(&**self, f) }
}
impl<'a, T: Show> Show for &'a T {
fn fmt(&self, f: &mut Formatter) -> Result { secret_show(*self, f) }
}

View File

@ -79,7 +79,6 @@ pub trait Repr<T> {
impl<'a, T> Repr<Slice<T>> for &'a [T] {}
impl<'a> Repr<Slice<u8>> for &'a str {}
impl<T> Repr<*Box<T>> for @T {}
impl<T> Repr<*Vec<T>> for ~[T] {}
#[cfg(test)]

View File

@ -399,12 +399,20 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,
bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id);
DatumBlock::new(bcx, datum)
}
ast::ExprBox(_, contents) => {
// Special case for `box T`. (The other case, for GC, is handled
// in `trans_rvalue_dps_unadjusted`.)
ast::ExprBox(_, ref contents) => {
// Special case for `Box<T>` and `Gc<T>`
let box_ty = expr_ty(bcx, expr);
let contents_ty = expr_ty(bcx, contents);
trans_uniq_expr(bcx, box_ty, contents, contents_ty)
let contents_ty = expr_ty(bcx, &**contents);
match ty::get(box_ty).sty {
ty::ty_uniq(..) => {
trans_uniq_expr(bcx, box_ty, &**contents, contents_ty)
}
ty::ty_box(..) => {
trans_managed_expr(bcx, box_ty, &**contents, contents_ty)
}
_ => bcx.sess().span_bug(expr.span,
"expected unique or managed box")
}
}
ast::ExprLit(lit) => trans_immediate_lit(bcx, expr, (*lit).clone()),
ast::ExprBinary(op, lhs, rhs) => {
@ -773,11 +781,6 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
ast::ExprAssignOp(op, dst, src) => {
trans_assign_op(bcx, expr, op, dst, src)
}
ast::ExprBox(_, contents) => {
// Special case for `Gc<T>` for now. The other case, for unique
// pointers, is handled in `trans_rvalue_datum_unadjusted`.
trans_gc(bcx, expr, contents, dest)
}
_ => {
bcx.tcx().sess.span_bug(
expr.span,
@ -1242,31 +1245,6 @@ fn trans_addr_of<'a>(bcx: &'a Block<'a>,
return immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock();
}
fn trans_gc<'a>(mut bcx: &'a Block<'a>,
expr: &ast::Expr,
contents: &ast::Expr,
dest: Dest)
-> &'a Block<'a> {
let contents_ty = expr_ty(bcx, contents);
let box_ty = ty::mk_box(bcx.tcx(), contents_ty);
let contents_datum = unpack_datum!(bcx, trans_managed_expr(bcx,
box_ty,
contents,
contents_ty));
match dest {
Ignore => bcx,
SaveIn(addr) => {
let expr_ty = expr_ty(bcx, expr);
let repr = adt::represent_type(bcx.ccx(), expr_ty);
adt::trans_start_init(bcx, &*repr, addr, 0);
let field_dest = adt::trans_field_ptr(bcx, &*repr, addr, 0, 0);
contents_datum.store_to(bcx, field_dest)
}
}
}
// Important to get types for both lhs and rhs, because one might be _|_
// and the other not.
fn trans_eager_binop<'a>(

View File

@ -18,7 +18,7 @@ use middle::lint;
use middle::const_eval;
use middle::def;
use middle::dependency_format;
use middle::lang_items::{ExchangeHeapLangItem, OpaqueStructLangItem};
use middle::lang_items::OpaqueStructLangItem;
use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem};
use middle::freevars;
use middle::resolve;
@ -3108,17 +3108,17 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
}
ast::ExprBox(place, _) => {
// Special case `Box<T>` for now:
// Special case `Box<T>`/`Gc<T>` for now:
let definition = match tcx.def_map.borrow().find(&place.id) {
Some(&def) => def,
None => fail!("no def for place"),
};
let def_id = definition.def_id();
match tcx.lang_items.items.get(ExchangeHeapLangItem as uint) {
&Some(item_def_id) if def_id == item_def_id => {
RvalueDatumExpr
}
&Some(_) | &None => RvalueDpsExpr,
if tcx.lang_items.exchange_heap() == Some(def_id) ||
tcx.lang_items.managed_heap() == Some(def_id) {
RvalueDatumExpr
} else {
RvalueDpsExpr
}
}

View File

@ -451,6 +451,53 @@ pub fn ast_ty_to_builtin_ty<AC:AstConv,
supplied to `Box<T>`");
Some(ty::mk_err())
}
ast::DefTy(did) | ast::DefStruct(did)
if Some(did) == this.tcx().lang_items.gc() => {
if path.segments
.iter()
.flat_map(|s| s.types.iter())
.len() > 1 {
this.tcx()
.sess
.span_err(path.span,
"`Gc` has only one type parameter")
}
for inner_ast_type in path.segments
.iter()
.flat_map(|s| s.types.iter()) {
let mt = ast::MutTy {
ty: *inner_ast_type,
mutbl: ast::MutImmutable,
};
return Some(mk_pointer(this,
rscope,
&mt,
Box,
|typ| {
match ty::get(typ).sty {
ty::ty_str => {
this.tcx()
.sess
.span_err(path.span,
"`Gc<str>` is not a type");
ty::mk_err()
}
ty::ty_vec(_, None) => {
this.tcx()
.sess
.span_err(path.span,
"`Gc<[T]>` is not a type");
ty::mk_err()
}
_ => ty::mk_box(this.tcx(), typ),
}
}))
}
this.tcx().sess.span_bug(path.span,
"not enough type parameters \
supplied to `Gc<T>`")
}
_ => None
}
}

View File

@ -2862,52 +2862,14 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
// places: the exchange heap and the managed heap.
let definition = lookup_def(fcx, path.span, place.id);
let def_id = definition.def_id();
match tcx.lang_items
.items
.get(ExchangeHeapLangItem as uint) {
&Some(item_def_id) if def_id == item_def_id => {
fcx.write_ty(id, ty::mk_uniq(tcx,
fcx.expr_ty(subexpr)));
checked = true
}
&Some(_) | &None => {}
}
if !checked {
match tcx.lang_items
.items
.get(ManagedHeapLangItem as uint) {
&Some(item_def_id) if def_id == item_def_id => {
// Assign the magic `Gc<T>` struct.
let gc_struct_id =
match tcx.lang_items
.require(GcLangItem) {
Ok(id) => id,
Err(msg) => {
tcx.sess.span_err(expr.span,
msg.as_slice());
ast::DefId {
krate: ast::CRATE_NODE_ID,
node: ast::DUMMY_NODE_ID,
}
}
};
let regions =
subst::NonerasedRegions(Vec::new());
let sty = ty::mk_struct(tcx,
gc_struct_id,
subst::Substs {
self_ty: None,
tps: vec!(
fcx.expr_ty(
subexpr)
),
regions: regions,
});
fcx.write_ty(id, sty);
checked = true
}
&Some(_) | &None => {}
}
if tcx.lang_items.exchange_heap() == Some(def_id) {
fcx.write_ty(id, ty::mk_uniq(tcx,
fcx.expr_ty(&**subexpr)));
checked = true
} else if tcx.lang_items.managed_heap() == Some(def_id) {
fcx.write_ty(id, ty::mk_box(tcx,
fcx.expr_ty(&**subexpr)));
checked = true
}
}
_ => {}

View File

@ -129,6 +129,14 @@ fn type_is_defined_in_local_crate(tcx: &ty::ctxt, original_type: t) -> bool {
_ => {}
}
}
ty_box(..) => {
match tcx.lang_items.gc() {
Some(did) if did.krate == ast::LOCAL_CRATE => {
found_nominal = true;
}
_ => {}
}
}
_ => { }
}

View File

@ -510,7 +510,7 @@ impl<T:Repr> Repr for Rc<T> {
}
}
impl<T:Repr> Repr for @T {
impl<T:Repr + 'static> Repr for Gc<T> {
fn repr(&self, tcx: &ctxt) -> String {
(&**self).repr(tcx)
}

View File

@ -16,6 +16,7 @@ Core encoding and decoding interfaces.
use std::path;
use std::rc::Rc;
use std::gc::Gc;
pub trait Encoder<E> {
// Primitive types:
@ -387,7 +388,7 @@ impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for Box<T> {
}
}
impl<E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for @T {
impl<E, S:Encoder<E>,T:'static + Encodable<S, E>> Encodable<S, E> for Gc<T> {
fn encode(&self, s: &mut S) -> Result<(), E> {
(**self).encode(s)
}
@ -407,9 +408,9 @@ impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for Rc<T> {
}
}
impl<E, D:Decoder<E>,T:Decodable<D, E> + 'static> Decodable<D, E> for @T {
fn decode(d: &mut D) -> Result<@T, E> {
Ok(@try!(Decodable::decode(d)))
impl<E, D:Decoder<E>,T:Decodable<D, E> + 'static> Decodable<D, E> for Gc<T> {
fn decode(d: &mut D) -> Result<Gc<T>, E> {
Ok(box(GC) try!(Decodable::decode(d)))
}
}

View File

@ -18,52 +18,33 @@ collector is task-local so `Gc<T>` is not sendable.
#![allow(experimental)]
use kinds::marker;
use clone::Clone;
use cmp::{TotalOrd, Ord, Ordering, TotalEq, Eq};
use default::Default;
use fmt;
use hash::Hash;
use io::Writer;
use kinds::marker;
use ops::Deref;
use raw;
/// Immutable garbage-collected pointer type
#[lang="gc"]
#[cfg(not(test))]
#[experimental = "Gc is currently based on reference-counting and will not collect cycles until \
task annihilation. For now, cycles need to be broken manually by using `Rc<T>` \
with a non-owning `Weak<T>` pointer. A tracing garbage collector is planned."]
pub struct Gc<T> {
#[cfg(stage0)]
ptr: @T,
#[cfg(not(stage0))]
ptr: *T,
marker: marker::NoSend,
}
#[cfg(test)]
pub struct Gc<T> {
ptr: @T,
marker: marker::NoSend,
}
impl<T: 'static> Gc<T> {
/// Construct a new garbage-collected box
#[inline]
pub fn new(value: T) -> Gc<T> {
Gc { ptr: @value, marker: marker::NoSend }
}
/// Borrow the value contained in the garbage-collected box
#[inline]
pub fn borrow<'r>(&'r self) -> &'r T {
&*self.ptr
}
/// Determine if two garbage-collected boxes point to the same object
#[inline]
pub fn ptr_eq(&self, other: &Gc<T>) -> bool {
self.borrow() as *T == other.borrow() as *T
}
}
impl<T> Clone for Gc<T> {
impl<T: 'static> Clone for Gc<T> {
/// Clone the pointer only
#[inline]
fn clone(&self) -> Gc<T> {
Gc{ ptr: self.ptr, marker: marker::NoSend }
}
fn clone(&self) -> Gc<T> { *self }
}
/// An value that represents the task-local managed heap.
@ -73,8 +54,54 @@ impl<T> Clone for Gc<T> {
#[cfg(not(test))]
pub static GC: () = ();
#[cfg(test)]
pub static GC: () = ();
impl<T: Eq + 'static> Eq for Gc<T> {
#[inline]
fn eq(&self, other: &Gc<T>) -> bool { *(*self) == *(*other) }
#[inline]
fn ne(&self, other: &Gc<T>) -> bool { *(*self) != *(*other) }
}
impl<T: Ord + 'static> Ord for Gc<T> {
#[inline]
fn lt(&self, other: &Gc<T>) -> bool { *(*self) < *(*other) }
#[inline]
fn le(&self, other: &Gc<T>) -> bool { *(*self) <= *(*other) }
#[inline]
fn ge(&self, other: &Gc<T>) -> bool { *(*self) >= *(*other) }
#[inline]
fn gt(&self, other: &Gc<T>) -> bool { *(*self) > *(*other) }
}
impl<T: TotalOrd + 'static> TotalOrd for Gc<T> {
#[inline]
fn cmp(&self, other: &Gc<T>) -> Ordering { (**self).cmp(&**other) }
}
impl<T: TotalEq + 'static> TotalEq for Gc<T> {}
impl<T: 'static> Deref<T> for Gc<T> {
#[cfg(stage0)]
fn deref<'a>(&'a self) -> &'a T { &*self.ptr }
#[cfg(not(stage0))]
fn deref<'a>(&'a self) -> &'a T { &**self }
}
impl<T: Default + 'static> Default for Gc<T> {
fn default() -> Gc<T> {
box(GC) Default::default()
}
}
impl<T: 'static> raw::Repr<*raw::Box<T>> for Gc<T> {}
impl<S: Writer, T: Hash<S> + 'static> Hash<S> for Gc<T> {
fn hash(&self, s: &mut S) {
(**self).hash(s)
}
}
impl<T: 'static + fmt::Show> fmt::Show for Gc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt(f)
}
}
#[cfg(test)]
mod tests {

View File

@ -135,6 +135,8 @@ extern crate rustrt;
#[cfg(test)] pub use realstd::ops;
#[cfg(test)] pub use realstd::cmp;
#[cfg(test)] pub use realstd::ty;
#[cfg(test)] pub use realstd::owned;
#[cfg(test)] pub use realstd::gc;
// NB: These reexports are in the order they should be listed in rustdoc
@ -219,6 +221,7 @@ pub mod rand;
pub mod ascii;
#[cfg(not(test))]
pub mod gc;
/* Common traits */