Skip to content

Instantly share code, notes, and snippets.

@pnkfelix
Created February 8, 2015 22:26
Show Gist options
  • Save pnkfelix/abee2f0cbdca677b6f01 to your computer and use it in GitHub Desktop.
Save pnkfelix/abee2f0cbdca677b6f01 to your computer and use it in GitHub Desktop.
Illustration of type-inference failure when coercing a `box <expr>` to a trait object without using `<expr> as Box<Trait>`
#![feature(box_syntax)]
use std::cell::RefCell;
macro_rules! box_ {
($value:expr) => { {
let mut place = ::uni_protocol::BoxPlace::make_place();
let raw_place = ::uni_protocol::Place::pointer(&mut place);
let value = $value;
unsafe {
::std::ptr::write(raw_place, value);
::uni_protocol::Boxed::finalize(place)
}
} }
}
#[cfg(works)]
pub fn combine_substructure<'a, F>(f: F) -> RefCell<CombineSubstructureFunc<'a>>
where F: FnMut(&mut ExtCtxt, Span, &Substructure) -> P<Expr>, F: 'a
{
RefCell::new(box_!( f ) as CombineSubstructureFunc)
}
#[cfg(not(works))]
pub fn combine_substructure<'a, F>(f: F) -> RefCell<CombineSubstructureFunc<'a>>
where F: FnMut(&mut ExtCtxt, Span, &Substructure) -> P<Expr>, F: 'a
{
RefCell::new(box_!( f ))
}
fn main() { }
pub struct ExtCtxt;
pub struct Span;
pub struct Substructure;
pub struct Expr;
pub struct P<T> { _m: std::marker::InvariantType<T> }
pub type CombineSubstructure<'a> = FnMut(&mut ExtCtxt, Span, &Substructure) -> P<Expr> + 'a;
pub type CombineSubstructureFunc<'a> = Box<CombineSubstructure<'a>>;
pub mod uni_protocol {
/// Both `in (PLACE) EXPR` and `box EXPR` desugar into expressions
/// that allocate an intermediate "place" that holds uninitialized
/// state. The desugaring evaluates EXPR, and writes the result at
/// the address returned by the `pointer` method of this trait.
///
/// If evaluating EXPR fails, then the destructor for the
/// implementation of Place to clean up any intermediate state
/// (e.g. deallocate box storage, pop a stack, etc).
pub trait Place<Data: ?Sized> {
/// Returns the address where the input value will be written.
/// Note that the data at this address is generally
/// uninitialized, and thus one should use `ptr::write` for
/// initializing it.
fn pointer(&mut self) -> *mut Data;
}
/// Core trait for the `in (PLACE) EXPR` form.
///
/// `in (PLACE) EXPR` effectively desugars into:
///
/// ```
/// let p = PLACE;
/// let mut place = Placer::make_place(p);
/// let raw_place = InPlace::pointer(&mut place);
/// let value = EXPR;
/// unsafe {
/// std::ptr::write(raw_place, value);
/// InPlace::finalize(place)
/// }
/// ```
///
/// The type of `in (PLACE) EXPR` is derived from the type of
/// `PLACE`; if the type of `PLACE` is `P`, then the final type of
/// the whole expression is `P::Place::Owner` (see the `InPlace`
/// trait).
///
/// Values for types implementing this trait must either be
/// transient intermediates or `Copy`, since the `make_place`
/// method takes `self` by value.
pub trait Placer<Data: ?Sized> {
/// `Place` is the intermedate agent guarding the
/// uninitialized state for `Data`.
type Place: InPlace<Data>;
/// Creates a fresh place from `self`.
fn make_place(self) -> Self::Place;
}
/// Specialization of `Place` trait supporting `in (PLACE) EXPR`.
pub trait InPlace<Data: ?Sized>: Place<Data> {
/// `Owner` is the type of the end value of `in (PLACE) EXPR`
///
/// Note that when `in (PLACE) EXPR` is solely used for
/// side-effecting an existing data-structure,
/// e.g. `Vec::emplace_back`, then `Owner` need not carry any
/// information at all (e.g. it can be the unit type `()` in
/// that case).
type Owner;
/// Converts self into the final value, shifting
/// deallocation/cleanup responsibilities (if any remain),
/// over to the returned instance of `Owner` and forgetting
/// self.
unsafe fn finalize(self) -> Self::Owner;
}
/// Specialization of `Place` trait supporting `box EXPR`.
pub trait BoxPlace<Data: ?Sized> : Place<Data> {
/// Creates a globally fresh place.
fn make_place() -> Self;
}
/// Core trait for the `box EXPR` form.
///
/// `box EXPR` effectively desugars into:
///
/// ```
/// let mut place = BoxPlace::make_place();
/// let raw_place = BoxPlace::pointer(&mut place);
/// let value = $value;
/// unsafe {
/// ::std::ptr::write(raw_place, value);
/// Boxed::finalize(place)
/// }
/// ```
///
/// The type of `box EXPR` is supplied from its surrounding
/// context; in the above expansion, the result type `T` is used
/// to determine which implementation of `Boxed` to use, and that
/// `<T as Boxed>` in turn dictates determines which
/// implementation of `BoxPlace` to use, namely:
/// `<<T as Boxed>::Place as BoxPlace>`.
pub trait Boxed {
/// The kind of data that is stored in this kind of box.
type Data; /* (`Data` unused b/c cannot yet express below bound.) */
type Place; /* should be bounded by BoxPlace<Self::Data> */
/// Converts filled place into final value, shifting
/// deallocation/cleanup responsibilities (if any remain),
/// over to returned instance of `Owner` and forgetting
/// `filled`.
unsafe fn finalize(filled: Self::Place) -> Self;
}
}
pub struct HEAP;
mod impl_box_for_box {
#[cfg(old)]
use box_protocol as proto;
use uni_protocol as proto;
use std::mem;
use super::HEAP;
struct BoxPlace<T> { fake_box: Option<Box<T>> }
fn make_place<T>() -> BoxPlace<T> {
let t: T = unsafe { mem::zeroed() };
BoxPlace { fake_box: Some(Box::new(t)) }
}
unsafe fn finalize<T>(mut filled: BoxPlace<T>) -> Box<T> {
let mut ret = None;
mem::swap(&mut filled.fake_box, &mut ret);
ret.unwrap()
}
impl<'a, T> proto::Placer<T> for HEAP {
type Place = BoxPlace<T>;
fn make_place(self) -> BoxPlace<T> { make_place() }
}
impl<T> proto::Place<T> for BoxPlace<T> {
fn pointer(&mut self) -> *mut T {
match self.fake_box {
Some(ref mut b) => &mut **b as *mut T,
None => panic!("impossible"),
}
}
}
impl<T> proto::BoxPlace<T> for BoxPlace<T> {
fn make_place() -> BoxPlace<T> { make_place() }
}
impl<T> proto::InPlace<T> for BoxPlace<T> {
type Owner = Box<T>;
unsafe fn finalize(self) -> Box<T> { finalize(self) }
}
impl<T> proto::Boxed for Box<T> {
type Data = T;
type Place = BoxPlace<T>;
unsafe fn finalize(filled: BoxPlace<T>) -> Self { finalize(filled) }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment