Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

librustc: Implement the Box<T> type syntax #13904

Merged
merged 1 commit into from
May 3, 2014
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
@@ -262,6 +262,7 @@ lets_do_this! {
ManagedHeapLangItem, "managed_heap", managed_heap;
ExchangeHeapLangItem, "exchange_heap", exchange_heap;
GcLangItem, "gc", gc;
OwnedBoxLangItem, "owned_box", owned_box;

CovariantTypeItem, "covariant_type", covariant_type;
ContravariantTypeItem, "contravariant_type", contravariant_type;
242 changes: 161 additions & 81 deletions src/librustc/middle/typeck/astconv.rs
Original file line number Diff line number Diff line change
@@ -317,7 +317,7 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> {
match ast_ty.node {
ast::TyPath(ref path, _, id) => {
let a_def = match tcx.def_map.borrow().find(&id) {
None => tcx.sess.span_fatal(
None => tcx.sess.span_bug(
ast_ty.span, format!("unbound path {}", path_to_str(path))),
Some(&d) => d
};
@@ -366,95 +366,173 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> {
}
}

// Parses the programmer's textual representation of a type into our
// internal notion of a type.
pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t {

enum PointerTy {
Box,
RPtr(ty::Region),
Uniq
/// Converts the given AST type to a built-in type. A "built-in type" is, at
/// present, either a core numeric type, a string, or `Box`.
pub fn ast_ty_to_builtin_ty<AC:AstConv,
RS:RegionScope>(
this: &AC,
rscope: &RS,
ast_ty: &ast::Ty)
-> Option<ty::t> {
match ast_ty_to_prim_ty(this.tcx(), ast_ty) {
Some(typ) => return Some(typ),
None => {}
}

fn ast_ty_to_mt<AC:AstConv, RS:RegionScope>(this: &AC,
rscope: &RS,
ty: &ast::Ty) -> ty::mt {
ty::mt {ty: ast_ty_to_ty(this, rscope, ty), mutbl: ast::MutImmutable}
}
match ast_ty.node {
ast::TyPath(ref path, _, id) => {
let a_def = match this.tcx().def_map.borrow().find(&id) {
None => this.tcx().sess.span_bug(
ast_ty.span, format!("unbound path {}", path_to_str(path))),
Some(&d) => d
};

// Handle ~, and & being able to mean strs and vecs.
// If a_seq_ty is a str or a vec, make it a str/vec.
// Also handle first-class trait types.
fn mk_pointer<AC:AstConv,
RS:RegionScope>(
this: &AC,
rscope: &RS,
a_seq_ty: &ast::MutTy,
ptr_ty: PointerTy,
constr: |ty::t| -> ty::t)
-> ty::t {
let tcx = this.tcx();
debug!("mk_pointer(ptr_ty={:?})", ptr_ty);

match a_seq_ty.ty.node {
ast::TyVec(ty) => {
let mut mt = ast_ty_to_mt(this, rscope, ty);
if a_seq_ty.mutbl == ast::MutMutable {
mt.mutbl = ast::MutMutable;
}
return constr(ty::mk_vec(tcx, mt, None));
}
ast::TyPath(ref path, ref bounds, id) => {
// Note that the "bounds must be empty if path is not a trait"
// restriction is enforced in the below case for ty_path, which
// will run after this as long as the path isn't a trait.
match tcx.def_map.borrow().find(&id) {
Some(&ast::DefPrimTy(ast::TyStr)) => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
match ptr_ty {
Uniq => {
return ty::mk_uniq(tcx, ty::mk_str(tcx));
}
RPtr(r) => {
return ty::mk_str_slice(tcx, r, ast::MutImmutable);
}
_ => tcx.sess.span_err(path.span,
format!("managed strings are not supported")),
}
// FIXME(#12938): This is a hack until we have full support for
// DST.
match a_def {
ast::DefTy(did) | ast::DefStruct(did)
if Some(did) == this.tcx().lang_items.owned_box() => {
if path.segments
.iter()
.flat_map(|s| s.types.iter())
.len() > 1 {
this.tcx()
.sess
.span_err(path.span,
"`Box` has only one type parameter")
}
Some(&ast::DefTrait(trait_def_id)) => {
let result = ast_path_to_trait_ref(
this, rscope, trait_def_id, None, path);
let trait_store = match ptr_ty {
Uniq => ty::UniqTraitStore,
RPtr(r) => {
ty::RegionTraitStore(r, a_seq_ty.mutbl)
}
_ => {
tcx.sess.span_err(
path.span,
"~trait or &trait are the only supported \
forms of casting-to-trait");
return ty::mk_err();
}

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,
};
let bounds = conv_builtin_bounds(this.tcx(), bounds, trait_store);
return ty::mk_trait(tcx,
result.def_id,
result.substs.clone(),
trait_store,
bounds);
return Some(mk_pointer(this,
rscope,
&mt,
Uniq,
|typ| {
match ty::get(typ).sty {
ty::ty_str => {
this.tcx()
.sess
.span_err(path.span,
"`Box<str>` is not a type");
ty::mk_err()
}
ty::ty_vec(_, None) => {
this.tcx()
.sess
.span_err(path.span,
"`Box<[T]>` is not a type");
ty::mk_err()
}
_ => ty::mk_uniq(this.tcx(), typ),
}
}))
}
_ => {}
this.tcx().sess.span_bug(path.span,
"not enough type parameters \
supplied to `Box<T>`")
}
_ => None
}
_ => {}
}
_ => None
}
}

enum PointerTy {
Box,
RPtr(ty::Region),
Uniq
}

fn ast_ty_to_mt<AC:AstConv, RS:RegionScope>(this: &AC,
rscope: &RS,
ty: &ast::Ty) -> ty::mt {
ty::mt {ty: ast_ty_to_ty(this, rscope, ty), mutbl: ast::MutImmutable}
}

// Handle `~`, `Box`, and `&` being able to mean strs and vecs.
// If a_seq_ty is a str or a vec, make it a str/vec.
// Also handle first-class trait types.
fn mk_pointer<AC:AstConv,
RS:RegionScope>(
this: &AC,
rscope: &RS,
a_seq_ty: &ast::MutTy,
ptr_ty: PointerTy,
constr: |ty::t| -> ty::t)
-> ty::t {
let tcx = this.tcx();
debug!("mk_pointer(ptr_ty={:?})", ptr_ty);

constr(ast_ty_to_ty(this, rscope, a_seq_ty.ty))
match a_seq_ty.ty.node {
ast::TyVec(ty) => {
let mut mt = ast_ty_to_mt(this, rscope, ty);
if a_seq_ty.mutbl == ast::MutMutable {
mt.mutbl = ast::MutMutable;
}
return constr(ty::mk_vec(tcx, mt, None));
}
ast::TyPath(ref path, ref bounds, id) => {
// Note that the "bounds must be empty if path is not a trait"
// restriction is enforced in the below case for ty_path, which
// will run after this as long as the path isn't a trait.
match tcx.def_map.borrow().find(&id) {
Some(&ast::DefPrimTy(ast::TyStr)) => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
match ptr_ty {
Uniq => {
return constr(ty::mk_str(tcx));
}
RPtr(r) => {
return ty::mk_str_slice(tcx, r, ast::MutImmutable);
}
_ => tcx.sess.span_err(path.span,
format!("managed strings are not supported")),
}
}
Some(&ast::DefTrait(trait_def_id)) => {
let result = ast_path_to_trait_ref(
this, rscope, trait_def_id, None, path);
let trait_store = match ptr_ty {
Uniq => ty::UniqTraitStore,
RPtr(r) => {
ty::RegionTraitStore(r, a_seq_ty.mutbl)
}
_ => {
tcx.sess.span_err(
path.span,
"~trait or &trait are the only supported \
forms of casting-to-trait");
return ty::mk_err();
}
};
let bounds = conv_builtin_bounds(this.tcx(), bounds, trait_store);
return ty::mk_trait(tcx,
result.def_id,
result.substs.clone(),
trait_store,
bounds);
}
_ => {}
}
}
_ => {}
}

constr(ast_ty_to_ty(this, rscope, a_seq_ty.ty))
}

// Parses the programmer's textual representation of a type into our
// internal notion of a type.
pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t {

let tcx = this.tcx();

let mut ast_ty_to_ty_cache = tcx.ast_ty_to_ty_cache.borrow_mut();
@@ -471,7 +549,8 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved);
drop(ast_ty_to_ty_cache);

let typ = ast_ty_to_prim_ty(tcx, ast_ty).unwrap_or_else(|| match ast_ty.node {
let typ = ast_ty_to_builtin_ty(this, rscope, ast_ty).unwrap_or_else(|| {
match ast_ty.node {
ast::TyNil => ty::mk_nil(),
ast::TyBot => ty::mk_bot(),
ast::TyBox(ty) => {
@@ -555,7 +634,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
}
ast::TyPath(ref path, ref bounds, id) => {
let a_def = match tcx.def_map.borrow().find(&id) {
None => tcx.sess.span_fatal(
None => tcx.sess.span_bug(
ast_ty.span, format!("unbound path {}", path_to_str(path))),
Some(&d) => d
};
@@ -639,7 +718,8 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
// and will not descend into this routine.
this.ty_infer(ast_ty.span)
}
});
}
});

tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, ty::atttce_resolved(typ));
return typ;
8 changes: 8 additions & 0 deletions src/libstd/owned.rs
Original file line number Diff line number Diff line change
@@ -26,6 +26,14 @@ pub static HEAP: () = ();
#[cfg(test)]
pub static HEAP: () = ();

/// A type that represents a uniquely-owned value.
#[lang="owned_box"]
#[cfg(not(test))]
pub struct Box<T>(*T);

#[cfg(test)]
pub struct Box<T>(*T);

#[cfg(not(test))]
impl<T:Eq> Eq for ~T {
#[inline]
41 changes: 41 additions & 0 deletions src/test/run-pass/new-box.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// 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.

use std::owned::Box;

fn f(x: Box<int>) {
let y: &int = x;
println!("{}", *x);
println!("{}", *y);
}

trait Trait {
fn printme(&self);
}

struct Struct;

impl Trait for Struct {
fn printme(&self) {
println!("hello world!");
}
}

fn g(x: Box<Trait>) {
x.printme();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let y: &Trait = x;

let y: &Trait = x;
y.printme();
}

fn main() {
f(box 1234);
g(box Struct as Box<Trait>);
}