@@ -69,6 +69,7 @@ import link::crate_meta_extras_hash;
69
69
import pretty:: ppaux:: ty_to_str;
70
70
import pretty:: ppaux:: ty_to_short_str;
71
71
import pretty:: pprust:: expr_to_str;
72
+ import pretty:: pprust:: path_to_str;
72
73
73
74
obj namegen( mutable int i) {
74
75
fn next ( str prefix ) -> str { i += 1 ; ret prefix + istr ( i) ; }
@@ -6500,23 +6501,38 @@ fn trans_anon_obj(@block_ctxt bcx, &span sp, &ast::anon_obj anon_obj,
6500
6501
6501
6502
assert ( vec:: len( ty_params) == 0 u) ;
6502
6503
auto ccx = bcx. fcx. lcx. ccx;
6504
+
6505
+ let vec[ ast:: anon_obj_field] additional_fields = [ ] ;
6506
+ let vec[ result] additional_field_vals = [ ] ;
6507
+ let vec[ ty:: t] additional_field_tys = [ ] ;
6508
+ alt ( anon_obj. fields) {
6509
+ case ( none) { }
6510
+ case ( some( ?fields) ) {
6511
+ additional_fields = fields;
6512
+ for ( ast:: anon_obj_field f in fields) {
6513
+ additional_field_tys += [ node_ann_type( ccx, f. ann) ] ;
6514
+ additional_field_vals += [ trans_expr( bcx, f. expr) ] ;
6515
+ }
6516
+ }
6517
+ }
6518
+
6503
6519
// If with_obj (the object being extended) exists, translate it, producing
6504
6520
// a result.
6505
-
6506
- let option :: t[ result ] with_obj_val = none [ result ] ;
6521
+ let option :: t [ result ] with_obj_val = none ;
6522
+ let ty :: t with_obj_ty = ty :: mk_type ( ccx . tcx ) ;
6507
6523
alt ( anon_obj. with_obj) {
6508
6524
case ( none) { }
6509
6525
case ( some( ?e) ) {
6510
6526
// Translating with_obj returns a ValueRef (pointer to a 2-word
6511
- // value) wrapped in a result. We want to allocate space for this
6512
- // value in our outer object, then copy it into the outer object.
6513
-
6514
- with_obj_val = some[ result] ( trans_expr( bcx, e) ) ;
6527
+ // value) wrapped in a result.
6528
+ with_obj_val = some[ result] ( trans_expr( bcx, e) ) ;
6529
+ with_obj_ty = node_ann_type( ccx, ty:: expr_ann( e) ) ;
6515
6530
}
6516
6531
}
6517
- // FIXME (part of issue #417): all of the following code is copypasta from
6518
- // trans_obj for translating the anonymous wrapper object. Eventually we
6519
- // should abstract this code out of trans_anon_obj and trans_obj.
6532
+ // FIXME (part of issue #538): much of the following code is copypasta
6533
+ // from trans_obj for translating the anonymous wrapper object.
6534
+ // Eventually we might want to abstract this code out of trans_anon_obj
6535
+ // and trans_obj.
6520
6536
6521
6537
auto self_ty = ty:: node_id_to_type( ccx. tcx, id) ;
6522
6538
auto llself_ty = type_of( ccx, sp, self_ty) ;
@@ -6535,52 +6551,168 @@ fn trans_anon_obj(@block_ctxt bcx, &span sp, &ast::anon_obj anon_obj,
6535
6551
// Make a vtable for the outer object. create_vtbl() wants an ast::_obj
6536
6552
// and all we have is an ast::anon_obj, so we need to roll our own.
6537
6553
6538
- let vec[ ast:: obj_field] addtl_fields = [ ] ;
6539
- alt ( anon_obj. fields) {
6540
- case ( none) { }
6541
- case ( some( ?fields) ) { addtl_fields = fields; }
6542
- }
6543
- let ast:: _obj wrapper_obj =
6544
- rec( fields=addtl_fields,
6545
- methods=anon_obj. methods,
6546
- dtor=none[ @ast:: method] ) ;
6547
- auto vtbl =
6548
- create_vtbl( bcx. fcx. lcx, llself_ty, self_ty, wrapper_obj, ty_params) ;
6554
+ fn anon_obj_field_to_obj_field( & ast:: anon_obj_field f) -> ast:: obj_field {
6555
+ ret rec( mut =f. mut , ty=f. ty, ident=f. ident, id=f. id, ann=f. ann) ;
6556
+ }
6557
+ let ast:: _obj wrapper_obj = rec(
6558
+ fields = vec:: map( anon_obj_field_to_obj_field, additional_fields) ,
6559
+ methods = anon_obj. methods,
6560
+ dtor = none[ @ast:: method] ) ;
6561
+ auto vtbl = create_vtbl( bcx. fcx. lcx, llself_ty, self_ty, wrapper_obj,
6562
+ ty_params) ;
6563
+
6549
6564
bcx. build. Store ( vtbl, pair_vtbl) ;
6550
- // FIXME (part of issue #417): This vtable needs to contain "forwarding
6565
+ // FIXME (part of issue #538): Where do we fill in the field *values* from
6566
+ // the outer object?
6567
+
6568
+ // FIXME (part of issue #539): This vtable needs to contain "forwarding
6551
6569
// slots" for the methods that exist in the with_obj, as well. How do we
6552
6570
// do that?
6553
6571
6554
6572
// Next we have to take care of the other half of the pair we're
6555
6573
// returning: a boxed (reference-counted) tuple containing a tydesc,
6556
- // typarams, and fields.
6557
-
6558
- // FIXME (part of issue #417): Because this is an anonymous object, we
6559
- // also have to fill in the with_obj field of this tuple.
6574
+ // typarams, fields, and a pointer to our with_obj.
6560
6575
6561
6576
let TypeRef llbox_ty = T_opaque_obj_ptr ( ccx. tn) ;
6562
- alt ( anon_obj. fields) {
6563
- case ( none) {
6564
- // If the object we're translating has no fields or type
6565
- // parameters, there's not much to do.
6566
6577
6567
- // Store null into pair, if no args or typarams.
6578
+ if ( vec:: len[ ast:: ty_param] ( ty_params) == 0 u &&
6579
+ vec:: len[ ast:: anon_obj_field] ( additional_fields) == 0 u) {
6580
+ // If the object we're translating has no fields or type parameters,
6581
+ // there's not much to do.
6582
+
6583
+ // Store null into pair, if no args or typarams.
6584
+ bcx. build. Store ( C_null ( llbox_ty) , pair_box) ;
6585
+ } else {
6568
6586
6569
- bcx. build. Store ( C_null ( llbox_ty) , pair_box) ;
6587
+ // Synthesize a tuple type for fields: [field, ...]
6588
+ let ty:: t fields_ty = ty:: mk_imm_tup( ccx. tcx, additional_field_tys) ;
6589
+
6590
+ // Tydescs are run-time instantiations of typarams. We're not
6591
+ // actually supporting typarams for anon objs yet, but let's
6592
+ // create space for them in case we ever want them.
6593
+ let ty:: t tydesc_ty = ty:: mk_type( ccx. tcx) ;
6594
+ let vec[ ty:: t] tps = [ ] ;
6595
+ for ( ast:: ty_param tp in ty_params) {
6596
+ vec:: push[ ty:: t] ( tps, tydesc_ty) ;
6570
6597
}
6571
- case ( some( ?fields) ) {
6572
- // For the moment let's pretend that there are no additional
6573
- // fields.
6598
+ // Synthesize a tuple type for typarams: [typaram, ...]
6599
+ let ty:: t typarams_ty = ty:: mk_imm_tup( ccx. tcx, tps) ;
6600
+
6601
+ // Tuple type for body:
6602
+ // [tydesc_ty, [typaram, ...], [field, ...], with_obj]
6603
+ let ty:: t body_ty =
6604
+ ty:: mk_imm_tup( ccx. tcx, [ tydesc_ty, typarams_ty,
6605
+ fields_ty, with_obj_ty] ) ;
6606
+
6607
+ // Hand this type we've synthesized off to trans_malloc_boxed, which
6608
+ // allocates a box, including space for a refcount.
6609
+ auto box = trans_malloc_boxed( bcx, body_ty) ;
6610
+ bcx = box. bcx;
6611
+
6612
+ // mk_imm_box throws a refcount into the type we're synthesizing,
6613
+ // so that it looks like:
6614
+ // [rc, [tydesc_ty, [typaram, ...], [field, ...], with_obj]]
6615
+ let ty:: t boxed_body_ty = ty:: mk_imm_box( ccx. tcx, body_ty) ;
6616
+
6617
+ // Grab onto the refcount and body parts of the box we allocated.
6618
+ auto rc =
6619
+ GEP_tup_like ( bcx, boxed_body_ty, box. val,
6620
+ [ 0 , abi:: box_rc_field_refcnt] ) ;
6621
+ bcx = rc. bcx;
6622
+ auto body =
6623
+ GEP_tup_like ( bcx, boxed_body_ty, box. val,
6624
+ [ 0 , abi:: box_rc_field_body] ) ;
6625
+ bcx = body. bcx;
6626
+ bcx. build. Store ( C_int ( 1 ) , rc. val) ;
6574
6627
6575
- bcx. fcx. lcx. ccx. sess. unimpl( "anon objs don' t support " +
6576
- "adding fields yet") ;
6577
- // FIXME (issue #417): drop these fields into the newly created
6578
- // object.
6628
+ // Put together a tydesc for the body, so that the object can later be
6629
+ // freed by calling through its tydesc.
6579
6630
6631
+ // Every object (not just those with type parameters) needs to have a
6632
+ // tydesc to describe its body, since all objects have unknown type to
6633
+ // the user of the object. So the tydesc is needed to keep track of
6634
+ // the types of the object's fields, so that the fields can be freed
6635
+ // later.
6636
+
6637
+ auto body_tydesc =
6638
+ GEP_tup_like ( bcx, body_ty, body. val,
6639
+ [ 0 , abi:: obj_body_elt_tydesc] ) ;
6640
+ bcx = body_tydesc. bcx;
6641
+ auto ti = none[ @tydesc_info] ;
6642
+ auto body_td = get_tydesc( bcx, body_ty, true, ti) ;
6643
+ lazily_emit_tydesc_glue( bcx, abi:: tydesc_field_drop_glue, ti) ;
6644
+ lazily_emit_tydesc_glue( bcx, abi:: tydesc_field_free_glue, ti) ;
6645
+ bcx = body_td. bcx;
6646
+ bcx. build. Store ( body_td. val, body_tydesc. val) ;
6647
+
6648
+ // Copy the object's type parameters and fields into the space we
6649
+ // allocated for the object body. (This is something like saving the
6650
+ // lexical environment of a function in its closure: the "captured
6651
+ // typarams" are any type parameters that are passed to the object
6652
+ // constructor and are then available to the object's methods.
6653
+ // Likewise for the object's fields.)
6654
+
6655
+ // Copy typarams into captured typarams.
6656
+ auto body_typarams =
6657
+ GEP_tup_like ( bcx, body_ty, body. val,
6658
+ [ 0 , abi:: obj_body_elt_typarams] ) ;
6659
+ bcx = body_typarams. bcx;
6660
+ let int i = 0 ;
6661
+ for ( ast:: ty_param tp in ty_params) {
6662
+ auto typaram = bcx. fcx. lltydescs. ( i) ;
6663
+ auto capture =
6664
+ GEP_tup_like ( bcx, typarams_ty, body_typarams. val, [ 0 , i] ) ;
6665
+ bcx = capture. bcx;
6666
+ bcx = copy_val( bcx, INIT , capture. val, typaram,
6667
+ tydesc_ty) . bcx;
6668
+ i += 1 ;
6669
+ }
6670
+
6671
+ // Copy additional fields into the object's body.
6672
+ auto body_fields =
6673
+ GEP_tup_like ( bcx, body_ty, body. val,
6674
+ [ 0 , abi:: obj_body_elt_fields] ) ;
6675
+ bcx = body_fields. bcx;
6676
+ i = 0 ;
6677
+ for ( ast:: anon_obj_field f in additional_fields) {
6678
+ // FIXME (part of issue #538): make this work eventually, when we
6679
+ // have additional field exprs in the AST.
6680
+
6681
+ auto field_val = load_if_immediate(
6682
+ bcx,
6683
+ additional_field_vals. ( i) . val,
6684
+ additional_field_tys. ( i) ) ;
6685
+
6686
+ // what was the type of arg_tys.(i)? What's the type of
6687
+ // additional_field_tys.(i) ?
6688
+
6689
+ // arg_tys is a vector of ty::arg, so arg_tys.(i) is a ty::arg,
6690
+ // which is a record of mode and t. Meanwhile,
6691
+ // additional_field_tys is a vec of ty::t. So how about I just
6692
+ // don't index into it?
6693
+
6694
+ auto field =
6695
+ GEP_tup_like ( bcx, fields_ty, body_fields. val, [ 0 , i] ) ;
6696
+ bcx = field. bcx;
6697
+ bcx = copy_val( bcx, INIT , field. val,
6698
+ additional_field_vals. ( i) . val,
6699
+ additional_field_tys. ( i) ) . bcx;
6700
+ i += 1 ;
6580
6701
}
6702
+
6703
+ // Copy a pointer to the with_obj into the object's body. (TODO: Is
6704
+ // it necessary to use GEP_tup_like here?)
6705
+ auto body_with_obj =
6706
+ GEP_tup_like ( bcx, body_ty, body. val,
6707
+ [ 0 , abi:: obj_body_elt_with_obj] ) ;
6708
+ bcx = body_with_obj. bcx;
6709
+
6710
+ // Store box ptr in outer pair.
6711
+ auto p = bcx. build. PointerCast ( box. val, llbox_ty) ;
6712
+ bcx. build. Store ( p, pair_box) ;
6581
6713
}
6582
- // Return the object we built.
6583
6714
6715
+ // Return the object we built.
6584
6716
ret res( bcx, pair) ;
6585
6717
}
6586
6718
@@ -7306,7 +7438,7 @@ fn trans_obj(@local_ctxt cx, &span sp, &ast::_obj ob, ast::node_id ctor_id,
7306
7438
// typarams, and fields.
7307
7439
7308
7440
// FIXME: What about with_obj? Do we have to think about it here?
7309
- // (Pertains to issue #417 .)
7441
+ // (Pertains to issues #538/#539/#540/#543 .)
7310
7442
7311
7443
let TypeRef llbox_ty = T_opaque_obj_ptr ( ccx. tn) ;
7312
7444
// FIXME: we should probably also allocate a box for empty objs that have
@@ -7612,6 +7744,9 @@ fn decl_fn_and_pair(&@crate_ctxt ccx, &span sp, vec[str] path, str flav,
7612
7744
}
7613
7745
}
7614
7746
7747
+ // Create a closure: a pair containing (1) a ValueRef, pointing to where the
7748
+ // fn's definition is in the executable we're creating, and (2) a pointer to
7749
+ // space for the function's environment.
7615
7750
fn create_fn_pair( & @crate_ctxt cx, str ps, TypeRef llfnty, ValueRef llfn,
7616
7751
bool external) -> ValueRef {
7617
7752
auto gvar =
0 commit comments