Skip to content

Commit 7c64f03

Browse files
committed
librustc: Implement the Box<T> type syntax. RFC #14. Issue #13885.
1 parent b5d6b07 commit 7c64f03

File tree

4 files changed

+211
-81
lines changed

4 files changed

+211
-81
lines changed

Diff for: src/librustc/middle/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ lets_do_this! {
262262
ManagedHeapLangItem, "managed_heap", managed_heap;
263263
ExchangeHeapLangItem, "exchange_heap", exchange_heap;
264264
GcLangItem, "gc", gc;
265+
OwnedBoxLangItem, "owned_box", owned_box;
265266

266267
CovariantTypeItem, "covariant_type", covariant_type;
267268
ContravariantTypeItem, "contravariant_type", contravariant_type;

Diff for: src/librustc/middle/typeck/astconv.rs

+161-81
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> {
317317
match ast_ty.node {
318318
ast::TyPath(ref path, _, id) => {
319319
let a_def = match tcx.def_map.borrow().find(&id) {
320-
None => tcx.sess.span_fatal(
320+
None => tcx.sess.span_bug(
321321
ast_ty.span, format!("unbound path {}", path_to_str(path))),
322322
Some(&d) => d
323323
};
@@ -366,95 +366,173 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> {
366366
}
367367
}
368368

369-
// Parses the programmer's textual representation of a type into our
370-
// internal notion of a type.
371-
pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
372-
this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t {
373-
374-
enum PointerTy {
375-
Box,
376-
RPtr(ty::Region),
377-
Uniq
369+
/// Converts the given AST type to a built-in type. A "built-in type" is, at
370+
/// present, either a core numeric type, a string, or `Box`.
371+
pub fn ast_ty_to_builtin_ty<AC:AstConv,
372+
RS:RegionScope>(
373+
this: &AC,
374+
rscope: &RS,
375+
ast_ty: &ast::Ty)
376+
-> Option<ty::t> {
377+
match ast_ty_to_prim_ty(this.tcx(), ast_ty) {
378+
Some(typ) => return Some(typ),
379+
None => {}
378380
}
379381

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

386-
// Handle ~, and & being able to mean strs and vecs.
387-
// If a_seq_ty is a str or a vec, make it a str/vec.
388-
// Also handle first-class trait types.
389-
fn mk_pointer<AC:AstConv,
390-
RS:RegionScope>(
391-
this: &AC,
392-
rscope: &RS,
393-
a_seq_ty: &ast::MutTy,
394-
ptr_ty: PointerTy,
395-
constr: |ty::t| -> ty::t)
396-
-> ty::t {
397-
let tcx = this.tcx();
398-
debug!("mk_pointer(ptr_ty={:?})", ptr_ty);
399-
400-
match a_seq_ty.ty.node {
401-
ast::TyVec(ty) => {
402-
let mut mt = ast_ty_to_mt(this, rscope, ty);
403-
if a_seq_ty.mutbl == ast::MutMutable {
404-
mt.mutbl = ast::MutMutable;
405-
}
406-
return constr(ty::mk_vec(tcx, mt, None));
407-
}
408-
ast::TyPath(ref path, ref bounds, id) => {
409-
// Note that the "bounds must be empty if path is not a trait"
410-
// restriction is enforced in the below case for ty_path, which
411-
// will run after this as long as the path isn't a trait.
412-
match tcx.def_map.borrow().find(&id) {
413-
Some(&ast::DefPrimTy(ast::TyStr)) => {
414-
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
415-
match ptr_ty {
416-
Uniq => {
417-
return ty::mk_uniq(tcx, ty::mk_str(tcx));
418-
}
419-
RPtr(r) => {
420-
return ty::mk_str_slice(tcx, r, ast::MutImmutable);
421-
}
422-
_ => tcx.sess.span_err(path.span,
423-
format!("managed strings are not supported")),
424-
}
390+
// FIXME(#12938): This is a hack until we have full support for
391+
// DST.
392+
match a_def {
393+
ast::DefTy(did) | ast::DefStruct(did)
394+
if Some(did) == this.tcx().lang_items.owned_box() => {
395+
if path.segments
396+
.iter()
397+
.flat_map(|s| s.types.iter())
398+
.len() > 1 {
399+
this.tcx()
400+
.sess
401+
.span_err(path.span,
402+
"`Box` has only one type parameter")
425403
}
426-
Some(&ast::DefTrait(trait_def_id)) => {
427-
let result = ast_path_to_trait_ref(
428-
this, rscope, trait_def_id, None, path);
429-
let trait_store = match ptr_ty {
430-
Uniq => ty::UniqTraitStore,
431-
RPtr(r) => {
432-
ty::RegionTraitStore(r, a_seq_ty.mutbl)
433-
}
434-
_ => {
435-
tcx.sess.span_err(
436-
path.span,
437-
"~trait or &trait are the only supported \
438-
forms of casting-to-trait");
439-
return ty::mk_err();
440-
}
404+
405+
for inner_ast_type in path.segments
406+
.iter()
407+
.flat_map(|s| s.types.iter()) {
408+
let mt = ast::MutTy {
409+
ty: *inner_ast_type,
410+
mutbl: ast::MutImmutable,
441411
};
442-
let bounds = conv_builtin_bounds(this.tcx(), bounds, trait_store);
443-
return ty::mk_trait(tcx,
444-
result.def_id,
445-
result.substs.clone(),
446-
trait_store,
447-
bounds);
412+
return Some(mk_pointer(this,
413+
rscope,
414+
&mt,
415+
Uniq,
416+
|typ| {
417+
match ty::get(typ).sty {
418+
ty::ty_str => {
419+
this.tcx()
420+
.sess
421+
.span_err(path.span,
422+
"`Box<str>` is not a type");
423+
ty::mk_err()
424+
}
425+
ty::ty_vec(_, None) => {
426+
this.tcx()
427+
.sess
428+
.span_err(path.span,
429+
"`Box<[T]>` is not a type");
430+
ty::mk_err()
431+
}
432+
_ => ty::mk_uniq(this.tcx(), typ),
433+
}
434+
}))
448435
}
449-
_ => {}
436+
this.tcx().sess.span_bug(path.span,
437+
"not enough type parameters \
438+
supplied to `Box<T>`")
450439
}
440+
_ => None
451441
}
452-
_ => {}
453442
}
443+
_ => None
444+
}
445+
}
446+
447+
enum PointerTy {
448+
Box,
449+
RPtr(ty::Region),
450+
Uniq
451+
}
452+
453+
fn ast_ty_to_mt<AC:AstConv, RS:RegionScope>(this: &AC,
454+
rscope: &RS,
455+
ty: &ast::Ty) -> ty::mt {
456+
ty::mt {ty: ast_ty_to_ty(this, rscope, ty), mutbl: ast::MutImmutable}
457+
}
458+
459+
// Handle `~`, `Box`, and `&` being able to mean strs and vecs.
460+
// If a_seq_ty is a str or a vec, make it a str/vec.
461+
// Also handle first-class trait types.
462+
fn mk_pointer<AC:AstConv,
463+
RS:RegionScope>(
464+
this: &AC,
465+
rscope: &RS,
466+
a_seq_ty: &ast::MutTy,
467+
ptr_ty: PointerTy,
468+
constr: |ty::t| -> ty::t)
469+
-> ty::t {
470+
let tcx = this.tcx();
471+
debug!("mk_pointer(ptr_ty={:?})", ptr_ty);
454472

455-
constr(ast_ty_to_ty(this, rscope, a_seq_ty.ty))
473+
match a_seq_ty.ty.node {
474+
ast::TyVec(ty) => {
475+
let mut mt = ast_ty_to_mt(this, rscope, ty);
476+
if a_seq_ty.mutbl == ast::MutMutable {
477+
mt.mutbl = ast::MutMutable;
478+
}
479+
return constr(ty::mk_vec(tcx, mt, None));
480+
}
481+
ast::TyPath(ref path, ref bounds, id) => {
482+
// Note that the "bounds must be empty if path is not a trait"
483+
// restriction is enforced in the below case for ty_path, which
484+
// will run after this as long as the path isn't a trait.
485+
match tcx.def_map.borrow().find(&id) {
486+
Some(&ast::DefPrimTy(ast::TyStr)) => {
487+
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
488+
match ptr_ty {
489+
Uniq => {
490+
return constr(ty::mk_str(tcx));
491+
}
492+
RPtr(r) => {
493+
return ty::mk_str_slice(tcx, r, ast::MutImmutable);
494+
}
495+
_ => tcx.sess.span_err(path.span,
496+
format!("managed strings are not supported")),
497+
}
498+
}
499+
Some(&ast::DefTrait(trait_def_id)) => {
500+
let result = ast_path_to_trait_ref(
501+
this, rscope, trait_def_id, None, path);
502+
let trait_store = match ptr_ty {
503+
Uniq => ty::UniqTraitStore,
504+
RPtr(r) => {
505+
ty::RegionTraitStore(r, a_seq_ty.mutbl)
506+
}
507+
_ => {
508+
tcx.sess.span_err(
509+
path.span,
510+
"~trait or &trait are the only supported \
511+
forms of casting-to-trait");
512+
return ty::mk_err();
513+
}
514+
};
515+
let bounds = conv_builtin_bounds(this.tcx(), bounds, trait_store);
516+
return ty::mk_trait(tcx,
517+
result.def_id,
518+
result.substs.clone(),
519+
trait_store,
520+
bounds);
521+
}
522+
_ => {}
523+
}
524+
}
525+
_ => {}
456526
}
457527

528+
constr(ast_ty_to_ty(this, rscope, a_seq_ty.ty))
529+
}
530+
531+
// Parses the programmer's textual representation of a type into our
532+
// internal notion of a type.
533+
pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
534+
this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t {
535+
458536
let tcx = this.tcx();
459537

460538
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>(
471549
ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved);
472550
drop(ast_ty_to_ty_cache);
473551

474-
let typ = ast_ty_to_prim_ty(tcx, ast_ty).unwrap_or_else(|| match ast_ty.node {
552+
let typ = ast_ty_to_builtin_ty(this, rscope, ast_ty).unwrap_or_else(|| {
553+
match ast_ty.node {
475554
ast::TyNil => ty::mk_nil(),
476555
ast::TyBot => ty::mk_bot(),
477556
ast::TyBox(ty) => {
@@ -555,7 +634,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
555634
}
556635
ast::TyPath(ref path, ref bounds, id) => {
557636
let a_def = match tcx.def_map.borrow().find(&id) {
558-
None => tcx.sess.span_fatal(
637+
None => tcx.sess.span_bug(
559638
ast_ty.span, format!("unbound path {}", path_to_str(path))),
560639
Some(&d) => d
561640
};
@@ -639,7 +718,8 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
639718
// and will not descend into this routine.
640719
this.ty_infer(ast_ty.span)
641720
}
642-
});
721+
}
722+
});
643723

644724
tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, ty::atttce_resolved(typ));
645725
return typ;

Diff for: src/libstd/owned.rs

+8
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ pub static HEAP: () = ();
2626
#[cfg(test)]
2727
pub static HEAP: () = ();
2828

29+
/// A type that represents a uniquely-owned value.
30+
#[lang="owned_box"]
31+
#[cfg(not(test))]
32+
pub struct Box<T>(*T);
33+
34+
#[cfg(test)]
35+
pub struct Box<T>(*T);
36+
2937
#[cfg(not(test))]
3038
impl<T:Eq> Eq for ~T {
3139
#[inline]

Diff for: src/test/run-pass/new-box.rs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::owned::Box;
12+
13+
fn f(x: Box<int>) {
14+
let y: &int = x;
15+
println!("{}", *x);
16+
println!("{}", *y);
17+
}
18+
19+
trait Trait {
20+
fn printme(&self);
21+
}
22+
23+
struct Struct;
24+
25+
impl Trait for Struct {
26+
fn printme(&self) {
27+
println!("hello world!");
28+
}
29+
}
30+
31+
fn g(x: Box<Trait>) {
32+
x.printme();
33+
let y: &Trait = x;
34+
y.printme();
35+
}
36+
37+
fn main() {
38+
f(box 1234);
39+
g(box Struct as Box<Trait>);
40+
}
41+

0 commit comments

Comments
 (0)