about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2014-05-02 14:53:33 -0700
committerPatrick Walton <pcwalton@mimiga.net>2014-05-02 18:27:50 -0700
commit7c64f0360774c05dfc819270f8f53266b23b1ced (patch)
tree91602a626fe8c86f0728228ac85cbbedd9858ee6
parentb5d6b07370b665df6b54fa20e971e61041a233b0 (diff)
downloadrust-7c64f0360774c05dfc819270f8f53266b23b1ced.tar.gz
rust-7c64f0360774c05dfc819270f8f53266b23b1ced.zip
librustc: Implement the `Box<T>` type syntax. RFC #14. Issue #13885.
-rw-r--r--src/librustc/middle/lang_items.rs1
-rw-r--r--src/librustc/middle/typeck/astconv.rs242
-rw-r--r--src/libstd/owned.rs8
-rw-r--r--src/test/run-pass/new-box.rs41
4 files changed, 211 insertions, 81 deletions
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 42ef8b9d51b..48465309f1e 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -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;
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index 77f339ec10e..bd26e2e0c4d 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -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;
diff --git a/src/libstd/owned.rs b/src/libstd/owned.rs
index 1fa86c53117..826ada8f252 100644
--- a/src/libstd/owned.rs
+++ b/src/libstd/owned.rs
@@ -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]
diff --git a/src/test/run-pass/new-box.rs b/src/test/run-pass/new-box.rs
new file mode 100644
index 00000000000..0202695841e
--- /dev/null
+++ b/src/test/run-pass/new-box.rs
@@ -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();
+    let y: &Trait = x;
+    y.printme();
+}
+
+fn main() {
+    f(box 1234);
+    g(box Struct as Box<Trait>);
+}
+