提交 7c64f036 编写于 作者: P Patrick Walton

librustc: Implement the `Box<T>` type syntax. RFC #14. Issue #13885.

上级 b5d6b073
...@@ -262,6 +262,7 @@ pub fn collect_language_items(krate: &ast::Crate, ...@@ -262,6 +262,7 @@ pub fn collect_language_items(krate: &ast::Crate,
ManagedHeapLangItem, "managed_heap", managed_heap; ManagedHeapLangItem, "managed_heap", managed_heap;
ExchangeHeapLangItem, "exchange_heap", exchange_heap; ExchangeHeapLangItem, "exchange_heap", exchange_heap;
GcLangItem, "gc", gc; GcLangItem, "gc", gc;
OwnedBoxLangItem, "owned_box", owned_box;
CovariantTypeItem, "covariant_type", covariant_type; CovariantTypeItem, "covariant_type", covariant_type;
ContravariantTypeItem, "contravariant_type", contravariant_type; ContravariantTypeItem, "contravariant_type", contravariant_type;
......
...@@ -317,7 +317,7 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> { ...@@ -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 { match ast_ty.node {
ast::TyPath(ref path, _, id) => { ast::TyPath(ref path, _, id) => {
let a_def = match tcx.def_map.borrow().find(&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))), ast_ty.span, format!("unbound path {}", path_to_str(path))),
Some(&d) => d Some(&d) => d
}; };
...@@ -366,95 +366,173 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> { ...@@ -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 /// Converts the given AST type to a built-in type. A "built-in type" is, at
// internal notion of a type. /// present, either a core numeric type, a string, or `Box`.
pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>( pub fn ast_ty_to_builtin_ty<AC:AstConv,
this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t { RS:RegionScope>(
this: &AC,
enum PointerTy { rscope: &RS,
Box, ast_ty: &ast::Ty)
RPtr(ty::Region), -> Option<ty::t> {
Uniq 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, match ast_ty.node {
rscope: &RS, ast::TyPath(ref path, _, id) => {
ty: &ast::Ty) -> ty::mt { let a_def = match this.tcx().def_map.borrow().find(&id) {
ty::mt {ty: ast_ty_to_ty(this, rscope, ty), mutbl: ast::MutImmutable} 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. // FIXME(#12938): This is a hack until we have full support for
// If a_seq_ty is a str or a vec, make it a str/vec. // DST.
// Also handle first-class trait types. match a_def {
fn mk_pointer<AC:AstConv, ast::DefTy(did) | ast::DefStruct(did)
RS:RegionScope>( if Some(did) == this.tcx().lang_items.owned_box() => {
this: &AC, if path.segments
rscope: &RS, .iter()
a_seq_ty: &ast::MutTy, .flat_map(|s| s.types.iter())
ptr_ty: PointerTy, .len() > 1 {
constr: |ty::t| -> ty::t) this.tcx()
-> ty::t { .sess
let tcx = this.tcx(); .span_err(path.span,
debug!("mk_pointer(ptr_ty={:?})", ptr_ty); "`Box` has only one type parameter")
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")),
}
} }
Some(&ast::DefTrait(trait_def_id)) => {
let result = ast_path_to_trait_ref( for inner_ast_type in path.segments
this, rscope, trait_def_id, None, path); .iter()
let trait_store = match ptr_ty { .flat_map(|s| s.types.iter()) {
Uniq => ty::UniqTraitStore, let mt = ast::MutTy {
RPtr(r) => { ty: *inner_ast_type,
ty::RegionTraitStore(r, a_seq_ty.mutbl) mutbl: ast::MutImmutable,
}
_ => {
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 Some(mk_pointer(this,
return ty::mk_trait(tcx, rscope,
result.def_id, &mt,
result.substs.clone(), Uniq,
trait_store, |typ| {
bounds); 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 tcx = this.tcx();
let mut ast_ty_to_ty_cache = tcx.ast_ty_to_ty_cache.borrow_mut(); let mut ast_ty_to_ty_cache = tcx.ast_ty_to_ty_cache.borrow_mut();
...@@ -471,7 +549,8 @@ fn mk_pointer<AC:AstConv, ...@@ -471,7 +549,8 @@ fn mk_pointer<AC:AstConv,
ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved); ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved);
drop(ast_ty_to_ty_cache); 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::TyNil => ty::mk_nil(),
ast::TyBot => ty::mk_bot(), ast::TyBot => ty::mk_bot(),
ast::TyBox(ty) => { ast::TyBox(ty) => {
...@@ -555,7 +634,7 @@ fn mk_pointer<AC:AstConv, ...@@ -555,7 +634,7 @@ fn mk_pointer<AC:AstConv,
} }
ast::TyPath(ref path, ref bounds, id) => { ast::TyPath(ref path, ref bounds, id) => {
let a_def = match tcx.def_map.borrow().find(&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))), ast_ty.span, format!("unbound path {}", path_to_str(path))),
Some(&d) => d Some(&d) => d
}; };
...@@ -639,7 +718,8 @@ fn mk_pointer<AC:AstConv, ...@@ -639,7 +718,8 @@ fn mk_pointer<AC:AstConv,
// and will not descend into this routine. // and will not descend into this routine.
this.ty_infer(ast_ty.span) this.ty_infer(ast_ty.span)
} }
}); }
});
tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, ty::atttce_resolved(typ)); tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, ty::atttce_resolved(typ));
return typ; return typ;
......
...@@ -26,6 +26,14 @@ ...@@ -26,6 +26,14 @@
#[cfg(test)] #[cfg(test)]
pub static HEAP: () = (); 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))] #[cfg(not(test))]
impl<T:Eq> Eq for ~T { impl<T:Eq> Eq for ~T {
#[inline] #[inline]
......
// 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();
let y: &Trait = x;
y.printme();
}
fn main() {
f(box 1234);
g(box Struct as Box<Trait>);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册