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.
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.
13 # Translation of expressions.
15 ## Recommended entry point
17 If you wish to translate an expression, the preferred way to do
20 expr::trans_into(block, expr, Dest) -> block
22 This will generate code that evaluates `expr`, storing the result into
23 `Dest`, which must either be the special flag ignore (throw the result
24 away) or be a pointer to memory of the same type/size as the
25 expression. It returns the resulting basic block. This form will
26 handle all automatic adjustments for you. The value will be moved if
27 its type is linear and copied otherwise.
29 ## Translation to a datum
31 In some cases, `trans_into()` is too narrow of an interface.
32 Generally this occurs either when you know that the result value is
33 going to be a scalar, or when you need to evaluate the expression into
34 some memory location so you can go and inspect it (e.g., assignments,
35 `match` expressions, the `&` operator).
37 In such cases, you want the following function:
39 trans_to_datum(block, expr) -> DatumBlock
41 This function generates code to evaluate the expression and return a
42 `Datum` describing where the result is to be found. This function
43 tries to return its result in the most efficient way possible, without
44 introducing extra copies or sacrificing information. Therefore, for
45 lvalue expressions, you always get a by-ref `Datum` in return that
46 points at the memory for this lvalue. For rvalue expressions, we will
47 return a by-value `Datum` whenever possible, but it is often necessary
48 to allocate a stack slot, store the result of the rvalue in there, and
49 then return a pointer to the slot (see the discussion later on about
50 the different kinds of rvalues).
52 NB: The `trans_to_datum()` function does perform adjustments, but
53 since it returns a pointer to the value "in place" it does not handle
54 moves. If you wish to copy/move the value returned into a new
55 location, you should use the Datum method `store_to()` (move or copy
56 depending on type). You can also use `move_to()` (force move) or
57 `copy_to()` (force copy) for special situations.
59 ## Translating local variables
61 `trans_local_var()` can be used to trans a ref to a local variable
62 that is not an expression. This is needed for captures.
64 ## Ownership and cleanups
66 The current system for cleanups associates required cleanups with
67 block contexts. Block contexts are structured into a tree that
68 resembles the code itself. Not every block context has cleanups
69 associated with it, only those blocks that have a kind of
70 `block_scope`. See `common::block_kind` for more details.
72 If you invoke `trans_into()`, no cleanup is scheduled for you. The
73 value is written into the given destination and is assumed to be owned
76 When you invoke `trans_to_datum()` on an rvalue, the resulting
77 datum/value will have an appropriate cleanup scheduled for the
78 innermost cleanup scope. If you later use `move_to()` or
79 `drop_val()`, this cleanup will be canceled.
81 During the evaluation of an expression, temporary cleanups are created
82 and later canceled. These represent intermediate or partial results
83 which must be cleaned up in the event of task failure.
85 ## Implementation details
87 We divide expressions into three categories, based on how they are most
88 naturally implemented:
95 Lvalues always refer to user-assignable memory locations.
96 Translating those always results in a by-ref datum; this introduces
97 no inefficiencies into the generated code, because all lvalues are
98 naturally addressable.
100 Datum rvalues are rvalues that always generate datums as a result.
101 These are generally scalar results, such as `a+b` where `a` and `b`
104 DPS rvalues are rvalues that, when translated, must be given a
105 memory location to write into (or the Ignore flag). These are
106 generally expressions that produce structural results that are
107 larger than one word (e.g., a struct literal), but also expressions
108 (like `if`) that involve control flow (otherwise we'd have to
111 Finally, statement rvalues are rvalues that always produce a nil
112 return type, such as `while` loops or assignments (`a = b`).
118 use lib::llvm::{ValueRef, llvm};
120 use metadata::csearch;
121 use middle::trans::_match;
122 use middle::trans::adt;
123 use middle::trans::asm;
124 use middle::trans::base::*;
125 use middle::trans::base;
126 use middle::trans::build::*;
127 use middle::trans::callee::DoAutorefArg;
128 use middle::trans::callee;
129 use middle::trans::closure;
130 use middle::trans::common::*;
131 use middle::trans::consts;
132 use middle::trans::controlflow;
133 use middle::trans::datum::*;
134 use middle::trans::debuginfo;
135 use middle::trans::inline;
136 use middle::trans::machine;
137 use middle::trans::meth;
138 use middle::trans::tvec;
139 use middle::trans::type_of;
140 use middle::ty::struct_fields;
141 use middle::ty::{AutoDerefRef, AutoAddEnv};
142 use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn,
145 use util::common::indenter;
146 use util::ppaux::Repr;
147 use middle::trans::machine::llsize_of;
149 use middle::trans::type_::Type;
151 use std::cast::transmute;
152 use std::hashmap::HashMap;
154 use syntax::print::pprust::{expr_to_str};
160 // These are passed around by the code generating functions to track the
161 // destination of a computation's value.
170 pub fn to_str(&self, ccx: &CrateContext) -> ~str {
172 SaveIn(v) => fmt!("SaveIn(%s)", ccx.tn.val_to_str(v)),
178 fn drop_and_cancel_clean(bcx: block, dat: Datum) -> block {
179 let bcx = dat.drop_val(bcx);
180 dat.cancel_clean(bcx);
184 pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
185 debug!("trans_to_datum(expr=%s)", bcx.expr_to_str(expr));
188 let mut datum = unpack_datum!(bcx, trans_to_datum_unadjusted(bcx, expr));
189 let adjustment = match bcx.tcx().adjustments.find_copy(&expr.id) {
190 None => { return DatumBlock {bcx: bcx, datum: datum}; }
193 debug!("unadjusted datum: %s", datum.to_str(bcx.ccx()));
196 datum = unpack_datum!(bcx, add_env(bcx, expr, datum));
198 AutoDerefRef(ref adj) => {
199 if adj.autoderefs > 0 {
203 datum.autoderef(bcx, expr.span,
204 expr.id, adj.autoderefs));
207 datum = match adj.autoref {
211 Some(AutoUnsafe(*)) | // region + unsafe ptrs have same repr
212 Some(AutoPtr(*)) => {
213 unpack_datum!(bcx, auto_ref(bcx, datum))
215 Some(AutoBorrowVec(*)) => {
216 unpack_datum!(bcx, auto_slice(bcx, adj.autoderefs,
219 Some(AutoBorrowVecRef(*)) => {
220 unpack_datum!(bcx, auto_slice_and_ref(bcx, adj.autoderefs,
223 Some(AutoBorrowFn(*)) => {
224 let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span,
225 datum.ty, Some(adjustment));
226 unpack_datum!(bcx, auto_borrow_fn(bcx, adjusted_ty, datum))
231 debug!("after adjustments, datum=%s", datum.to_str(bcx.ccx()));
232 return DatumBlock {bcx: bcx, datum: datum};
234 fn auto_ref(bcx: block, datum: Datum) -> DatumBlock {
235 DatumBlock {bcx: bcx, datum: datum.to_rptr(bcx)}
238 fn auto_borrow_fn(bcx: block,
240 datum: Datum) -> DatumBlock {
241 // Currently, all closure types are represented precisely the
242 // same, so no runtime adjustment is required, but we still
243 // must patchup the type.
244 DatumBlock {bcx: bcx,
245 datum: Datum {val: datum.val, ty: adjusted_ty,
249 fn auto_slice(bcx: block,
252 datum: Datum) -> DatumBlock {
253 // This is not the most efficient thing possible; since slices
254 // are two words it'd be better if this were compiled in
255 // 'dest' mode, but I can't find a nice way to structure the
256 // code and keep it DRY that accommodates that use case at the
260 let unit_ty = ty::sequence_element_type(tcx, datum.ty);
262 let (bcx, base, len) =
263 datum.get_vec_base_and_len(bcx, expr.span, expr.id, autoderefs+1);
265 // this type may have a different region/mutability than the
266 // real one, but it will have the same runtime representation
267 let slice_ty = ty::mk_evec(tcx,
268 ty::mt { ty: unit_ty, mutbl: ast::m_imm },
269 ty::vstore_slice(ty::re_static));
271 let scratch = scratch_datum(bcx, slice_ty, "__adjust", false);
272 Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
273 Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
274 DatumBlock {bcx: bcx, datum: scratch}
277 fn add_env(bcx: block, expr: &ast::expr, datum: Datum) -> DatumBlock {
278 // This is not the most efficient thing possible; since closures
279 // are two words it'd be better if this were compiled in
280 // 'dest' mode, but I can't find a nice way to structure the
281 // code and keep it DRY that accommodates that use case at the
285 let closure_ty = expr_ty_adjusted(bcx, expr);
286 debug!("add_env(closure_ty=%s)", closure_ty.repr(tcx));
287 let scratch = scratch_datum(bcx, closure_ty, "__adjust", false);
288 let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]);
289 assert_eq!(datum.appropriate_mode(tcx), ByValue);
290 Store(bcx, datum.to_appropriate_llval(bcx), llfn);
291 let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]);
292 Store(bcx, base::null_env_ptr(bcx), llenv);
293 DatumBlock {bcx: bcx, datum: scratch}
296 fn auto_slice_and_ref(bcx: block,
299 datum: Datum) -> DatumBlock {
300 let DatumBlock { bcx, datum } = auto_slice(bcx, autoderefs, expr, datum);
305 pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
306 if bcx.tcx().adjustments.contains_key(&expr.id) {
307 // use trans_to_datum, which is mildly less efficient but
308 // which will perform the adjustments:
309 let datumblock = trans_to_datum(bcx, expr);
311 Ignore => datumblock.bcx,
312 SaveIn(lldest) => datumblock.store_to(INIT, lldest)
316 let ty = expr_ty(bcx, expr);
318 debug!("trans_into_unadjusted(expr=%s, dest=%s)",
319 bcx.expr_to_str(expr),
320 dest.to_str(bcx.ccx()));
321 let _indenter = indenter();
323 debuginfo::update_source_pos(bcx, expr.span);
326 if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
333 let kind = bcx.expr_kind(expr);
334 debug!("expr kind = %?", kind);
337 let datumblock = trans_lvalue_unadjusted(bcx, expr);
339 Ignore => datumblock.bcx,
340 SaveIn(lldest) => datumblock.store_to(INIT, lldest)
343 ty::RvalueDatumExpr => {
344 let datumblock = trans_rvalue_datum_unadjusted(bcx, expr);
346 Ignore => datumblock.drop_val(),
348 // When processing an rvalue, the value will be newly
349 // allocated, so we always `move_to` so as not to
350 // unnecessarily inc ref counts and so forth:
351 SaveIn(lldest) => datumblock.move_to(INIT, lldest)
354 ty::RvalueDpsExpr => {
355 trans_rvalue_dps_unadjusted(bcx, expr, dest)
357 ty::RvalueStmtExpr => {
358 trans_rvalue_stmt_unadjusted(bcx, expr)
363 fn trans_lvalue(bcx: block, expr: @ast::expr) -> DatumBlock {
366 * Translates an lvalue expression, always yielding a by-ref
367 * datum. Generally speaking you should call trans_to_datum()
368 * instead, but sometimes we call trans_lvalue() directly as a
369 * means of asserting that a particular expression is an lvalue. */
371 return match bcx.tcx().adjustments.find(&expr.id) {
372 None => trans_lvalue_unadjusted(bcx, expr),
376 fmt!("trans_lvalue() called on an expression \
382 fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
384 * Translates an expression into a datum. If this expression
385 * is an rvalue, this will result in a temporary value being
386 * created. If you plan to store the value somewhere else,
387 * you should prefer `trans_into()` instead.
392 debug!("trans_to_datum_unadjusted(expr=%s)", bcx.expr_to_str(expr));
393 let _indenter = indenter();
395 debuginfo::update_source_pos(bcx, expr.span);
397 match ty::expr_kind(bcx.tcx(), bcx.ccx().maps.method_map, expr) {
399 return trans_lvalue_unadjusted(bcx, expr);
402 ty::RvalueDatumExpr => {
403 let datum = unpack_datum!(bcx, {
404 trans_rvalue_datum_unadjusted(bcx, expr)
406 datum.add_clean(bcx);
407 return DatumBlock {bcx: bcx, datum: datum};
410 ty::RvalueStmtExpr => {
411 bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
412 return nil(bcx, expr_ty(bcx, expr));
415 ty::RvalueDpsExpr => {
416 let ty = expr_ty(bcx, expr);
417 if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
418 bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
421 let scratch = scratch_datum(bcx, ty, "", false);
422 bcx = trans_rvalue_dps_unadjusted(
423 bcx, expr, SaveIn(scratch.val));
425 // Note: this is not obviously a good idea. It causes
426 // immediate values to be loaded immediately after a
427 // return from a call or other similar expression,
428 // which in turn leads to alloca's having shorter
429 // lifetimes and hence larger stack frames. However,
430 // in turn it can lead to more register pressure.
431 // Still, in practice it seems to increase
432 // performance, since we have fewer problems with
434 let scratch = scratch.to_appropriate_datum(bcx);
436 scratch.add_clean(bcx);
437 return DatumBlock {bcx: bcx, datum: scratch};
442 fn nil(bcx: block, ty: ty::t) -> DatumBlock {
443 let datum = immediate_rvalue(C_nil(), ty);
444 DatumBlock {bcx: bcx, datum: datum}
448 fn trans_rvalue_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
449 let _icx = push_ctxt("trans_rvalue_datum_unadjusted");
451 trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
454 ast::expr_path(_) | ast::expr_self => {
455 return trans_def_datum_unadjusted(bcx, expr, bcx.def(expr.id));
457 ast::expr_vstore(contents, ast::expr_vstore_box) |
458 ast::expr_vstore(contents, ast::expr_vstore_mut_box) => {
459 return tvec::trans_uniq_or_managed_vstore(bcx, heap_managed,
462 ast::expr_vstore(contents, ast::expr_vstore_uniq) => {
463 let heap = heap_for_unique(bcx, expr_ty(bcx, contents));
464 return tvec::trans_uniq_or_managed_vstore(bcx, heap,
467 ast::expr_lit(lit) => {
468 return trans_immediate_lit(bcx, expr, *lit);
470 ast::expr_binary(_, op, lhs, rhs) => {
471 // if overloaded, would be RvalueDpsExpr
472 assert!(!bcx.ccx().maps.method_map.contains_key(&expr.id));
474 return trans_binary(bcx, expr, op, lhs, rhs);
476 ast::expr_unary(_, op, x) => {
477 return trans_unary_datum(bcx, expr, op, x);
479 ast::expr_addr_of(_, x) => {
480 return trans_addr_of(bcx, expr, x);
482 ast::expr_cast(val, _) => {
483 return trans_imm_cast(bcx, val, expr.id);
485 ast::expr_paren(e) => {
486 return trans_rvalue_datum_unadjusted(bcx, e);
489 bcx.tcx().sess.span_bug(
491 fmt!("trans_rvalue_datum_unadjusted reached \
492 fall-through case: %?",
498 fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
500 let _icx = push_ctxt("trans_rvalue_stmt");
506 trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
509 ast::expr_break(label_opt) => {
510 return controlflow::trans_break(bcx, label_opt);
512 ast::expr_again(label_opt) => {
513 return controlflow::trans_cont(bcx, label_opt);
515 ast::expr_ret(ex) => {
516 return controlflow::trans_ret(bcx, ex);
518 ast::expr_log(lvl, a) => {
519 return controlflow::trans_log(expr, lvl, bcx, a);
521 ast::expr_while(cond, ref body) => {
522 return controlflow::trans_while(bcx, cond, body);
524 ast::expr_loop(ref body, opt_label) => {
525 return controlflow::trans_loop(bcx, body, opt_label);
527 ast::expr_assign(dst, src) => {
528 let src_datum = unpack_datum!(
529 bcx, trans_to_datum(bcx, src));
530 let dst_datum = unpack_datum!(
531 bcx, trans_lvalue(bcx, dst));
532 return src_datum.store_to_datum(
533 bcx, DROP_EXISTING, dst_datum);
535 ast::expr_assign_op(callee_id, op, dst, src) => {
536 return trans_assign_op(bcx, expr, callee_id, op, dst, src);
538 ast::expr_paren(a) => {
539 return trans_rvalue_stmt_unadjusted(bcx, a);
541 ast::expr_inline_asm(ref a) => {
542 return asm::trans_inline_asm(bcx, a);
545 bcx.tcx().sess.span_bug(
547 fmt!("trans_rvalue_stmt_unadjusted reached \
548 fall-through case: %?",
554 fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
555 dest: Dest) -> block {
556 let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
559 trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
562 ast::expr_paren(e) => {
563 return trans_rvalue_dps_unadjusted(bcx, e, dest);
565 ast::expr_path(_) | ast::expr_self => {
566 return trans_def_dps_unadjusted(bcx, expr,
567 bcx.def(expr.id), dest);
569 ast::expr_if(cond, ref thn, els) => {
570 return controlflow::trans_if(bcx, cond, thn, els, dest);
572 ast::expr_match(discr, ref arms) => {
573 return _match::trans_match(bcx, expr, discr, *arms, dest);
575 ast::expr_block(ref blk) => {
576 return do base::with_scope(bcx, blk.info(),
577 "block-expr body") |bcx| {
578 controlflow::trans_block(bcx, blk, dest)
581 ast::expr_struct(_, ref fields, base) => {
582 return trans_rec_or_struct(bcx, (*fields), base, expr.span, expr.id, dest);
584 ast::expr_tup(ref args) => {
585 let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr));
586 let numbered_fields: ~[(uint, @ast::expr)] =
587 args.iter().enumerate().transform(|(i, arg)| (i, *arg)).collect();
588 return trans_adt(bcx, repr, 0, numbered_fields, None, dest);
590 ast::expr_lit(@codemap::spanned {node: ast::lit_str(s), _}) => {
591 return tvec::trans_lit_str(bcx, expr, s, dest);
593 ast::expr_vstore(contents, ast::expr_vstore_slice) |
594 ast::expr_vstore(contents, ast::expr_vstore_mut_slice) => {
595 return tvec::trans_slice_vstore(bcx, expr, contents, dest);
597 ast::expr_vec(*) | ast::expr_repeat(*) => {
598 return tvec::trans_fixed_vstore(bcx, expr, expr, dest);
600 ast::expr_fn_block(ref decl, ref body) => {
601 let expr_ty = expr_ty(bcx, expr);
602 let sigil = ty::ty_closure_sigil(expr_ty);
603 debug!("translating fn_block %s with type %s",
604 expr_to_str(expr, tcx.sess.intr()),
606 return closure::trans_expr_fn(bcx, sigil, decl, body,
610 ast::expr_loop_body(blk) => {
611 let expr_ty = expr_ty(bcx, expr);
612 let sigil = ty::ty_closure_sigil(expr_ty);
614 ast::expr_fn_block(ref decl, ref body) => {
615 return closure::trans_expr_fn(bcx,
625 bcx.sess().impossible_case(
627 "loop_body has the wrong kind of contents")
631 ast::expr_do_body(blk) => {
632 return trans_into(bcx, blk, dest);
634 ast::expr_call(f, ref args, _) => {
635 return callee::trans_call(
636 bcx, expr, f, callee::ArgExprs(*args), expr.id, dest);
638 ast::expr_method_call(callee_id, rcvr, _, _, ref args, _) => {
639 return callee::trans_method_call(bcx,
643 callee::ArgExprs(*args),
646 ast::expr_binary(callee_id, _, lhs, rhs) => {
647 // if not overloaded, would be RvalueDatumExpr
648 return trans_overloaded_op(bcx,
656 ast::expr_unary(callee_id, _, subexpr) => {
657 // if not overloaded, would be RvalueDatumExpr
658 return trans_overloaded_op(bcx,
666 ast::expr_index(callee_id, base, idx) => {
667 // if not overloaded, would be RvalueDatumExpr
668 return trans_overloaded_op(bcx,
676 ast::expr_cast(val, _) => {
677 match ty::get(node_id_type(bcx, expr.id)).sty {
678 ty::ty_trait(_, _, store, _, _) => {
679 return meth::trans_trait_cast(bcx, val, expr.id, dest,
683 bcx.tcx().sess.span_bug(expr.span,
684 "expr_cast of non-trait");
688 ast::expr_assign_op(callee_id, op, dst, src) => {
689 return trans_assign_op(bcx, expr, callee_id, op, dst, src);
692 bcx.tcx().sess.span_bug(
694 fmt!("trans_rvalue_dps_unadjusted reached fall-through case: %?",
700 fn trans_def_dps_unadjusted(bcx: block, ref_expr: &ast::expr,
701 def: ast::def, dest: Dest) -> block {
702 let _icx = push_ctxt("trans_def_dps_unadjusted");
705 let lldest = match dest {
706 SaveIn(lldest) => lldest,
707 Ignore => { return bcx; }
711 ast::def_variant(tid, vid) => {
712 let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
713 if variant_info.args.len() > 0u {
715 let fn_data = callee::trans_fn_ref(bcx, vid, ref_expr.id);
716 Store(bcx, fn_data.llfn, lldest);
720 let ty = expr_ty(bcx, ref_expr);
721 let repr = adt::represent_type(ccx, ty);
722 adt::trans_start_init(bcx, repr, lldest,
723 variant_info.disr_val);
727 ast::def_struct(*) => {
728 let ty = expr_ty(bcx, ref_expr);
729 match ty::get(ty).sty {
730 ty::ty_struct(did, _) if ty::has_dtor(ccx.tcx, did) => {
731 let repr = adt::represent_type(ccx, ty);
732 adt::trans_start_init(bcx, repr, lldest, 0);
739 bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
740 "Non-DPS def %? referened by %s",
741 def, bcx.node_id_to_str(ref_expr.id)));
746 fn trans_def_datum_unadjusted(bcx: block,
747 ref_expr: &ast::expr,
748 def: ast::def) -> DatumBlock
750 let _icx = push_ctxt("trans_def_datum_unadjusted");
753 ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
754 let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id);
755 return fn_data_to_datum(bcx, ref_expr, did, fn_data);
757 ast::def_static_method(impl_did, Some(trait_did), _) => {
758 let fn_data = meth::trans_static_method_callee(bcx, impl_did,
761 return fn_data_to_datum(bcx, ref_expr, impl_did, fn_data);
764 bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
765 "Non-DPS def %? referened by %s",
766 def, bcx.node_id_to_str(ref_expr.id)));
770 fn fn_data_to_datum(bcx: block,
771 ref_expr: &ast::expr,
773 fn_data: callee::FnData) -> DatumBlock {
776 * Translates a reference to a top-level fn item into a rust
777 * value. This is just a fn pointer.
781 let fn_tpt = ty::lookup_item_type(bcx.tcx(), def_id);
782 ty::ty_fn_purity(fn_tpt.ty) == ast::extern_fn
784 let (rust_ty, llval) = if is_extern {
785 let rust_ty = ty::mk_ptr(
788 ty: ty::mk_mach_uint(ast::ty_u8),
791 (rust_ty, PointerCast(bcx, fn_data.llfn, Type::i8p()))
793 let fn_ty = expr_ty(bcx, ref_expr);
794 (fn_ty, fn_data.llfn)
798 datum: Datum {val: llval,
805 fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
808 * Translates an lvalue expression, always yielding a by-ref
809 * datum. Does not apply any adjustments. */
811 let _icx = push_ctxt("trans_lval");
814 debug!("trans_lvalue(expr=%s)", bcx.expr_to_str(expr));
815 let _indenter = indenter();
817 trace_span!(bcx, expr.span, shorten(bcx.expr_to_str(expr)));
819 return match expr.node {
820 ast::expr_paren(e) => {
821 trans_lvalue_unadjusted(bcx, e)
823 ast::expr_path(_) | ast::expr_self => {
824 trans_def_lvalue(bcx, expr, bcx.def(expr.id))
826 ast::expr_field(base, ident, _) => {
827 trans_rec_field(bcx, base, ident)
829 ast::expr_index(_, base, idx) => {
830 trans_index(bcx, expr, base, idx)
832 ast::expr_unary(_, ast::deref, base) => {
833 let basedatum = unpack_datum!(bcx, trans_to_datum(bcx, base));
834 basedatum.deref(bcx, expr, 0)
837 bcx.tcx().sess.span_bug(
839 fmt!("trans_lvalue reached fall-through case: %?",
844 fn trans_rec_field(bcx: block,
846 field: ast::ident) -> DatumBlock {
847 //! Translates `base.field`.
850 let _icx = push_ctxt("trans_rec_field");
852 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
853 let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
854 do with_field_tys(bcx.tcx(), base_datum.ty, None) |discr, field_tys| {
855 let ix = ty::field_idx_strict(bcx.tcx(), field, field_tys);
857 datum: do base_datum.get_element(bcx,
860 adt::trans_field_ptr(bcx, repr, srcval, discr, ix)
867 fn trans_index(bcx: block,
868 index_expr: &ast::expr,
870 idx: @ast::expr) -> DatumBlock {
871 //! Translates `base[idx]`.
873 let _icx = push_ctxt("trans_index");
875 let base_ty = expr_ty(bcx, base);
878 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
880 // Translate index expression and cast to a suitable LLVM integer.
881 // Rust is less strict than LLVM in this regard.
882 let Result {bcx, val: ix_val} = trans_to_datum(bcx, idx).to_result();
883 let ix_size = machine::llbitsize_of_real(bcx.ccx(), val_ty(ix_val));
884 let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type);
886 if ix_size < int_size {
887 if ty::type_is_signed(expr_ty(bcx, idx)) {
888 SExt(bcx, ix_val, ccx.int_type)
889 } else { ZExt(bcx, ix_val, ccx.int_type) }
890 } else if ix_size > int_size {
891 Trunc(bcx, ix_val, ccx.int_type)
897 let vt = tvec::vec_types(bcx, base_datum.ty);
898 base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
899 let scaled_ix = Mul(bcx, ix_val, vt.llunit_size);
900 base::maybe_name_value(bcx.ccx(), scaled_ix, "scaled_ix");
902 let (bcx, base, len) =
903 base_datum.get_vec_base_and_len(bcx, index_expr.span,
907 if ty::type_is_str(base_ty) {
908 // acccount for null terminator in the case of string
909 len = Sub(bcx, len, C_uint(bcx.ccx(), 1u));
912 debug!("trans_index: base %s", bcx.val_to_str(base));
913 debug!("trans_index: len %s", bcx.val_to_str(len));
915 let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, len);
916 let bcx = do with_cond(bcx, bounds_check) |bcx| {
917 let unscaled_len = UDiv(bcx, len, vt.llunit_size);
918 controlflow::trans_fail_bounds_check(bcx, index_expr.span,
919 ix_val, unscaled_len)
921 let elt = InBoundsGEP(bcx, base, [ix_val]);
922 let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to());
925 datum: Datum {val: elt,
927 mode: ByRef(ZeroMem)}
931 fn trans_def_lvalue(bcx: block,
932 ref_expr: &ast::expr,
936 //! Translates a reference to a path.
938 let _icx = push_ctxt("trans_def_lvalue");
941 ast::def_static(did, _) => {
942 let const_ty = expr_ty(bcx, ref_expr);
944 fn get_did(ccx: @mut CrateContext, did: ast::def_id)
946 if did.crate != ast::local_crate {
947 inline::maybe_instantiate_inline(ccx, did)
953 fn get_val(bcx: block, did: ast::def_id, const_ty: ty::t)
955 // For external constants, we don't inline.
956 if did.crate == ast::local_crate {
957 // The LLVM global has the type of its initializer,
958 // which may not be equal to the enum's type for
960 let val = base::get_item_val(bcx.ccx(), did.node);
961 let pty = type_of(bcx.ccx(), const_ty).ptr_to();
962 PointerCast(bcx, val, pty)
965 let extern_const_values = &bcx.ccx().extern_const_values;
966 match extern_const_values.find(&did) {
967 None => {} // Continue.
975 let llty = type_of(bcx.ccx(), const_ty);
976 let symbol = csearch::get_symbol(
977 bcx.ccx().sess.cstore,
979 let llval = llvm::LLVMAddGlobal( bcx.ccx().llmod, llty.to_ref(),
980 transmute::<&u8,*i8>(&symbol[0]));
981 let extern_const_values = &mut bcx.ccx().extern_const_values;
982 extern_const_values.insert(did, llval);
988 let did = get_did(ccx, did);
989 let val = get_val(bcx, did, const_ty);
992 datum: Datum {val: val,
994 mode: ByRef(ZeroMem)}
1000 datum: trans_local_var(bcx, def)
1007 pub fn trans_local_var(bcx: block, def: ast::def) -> Datum {
1008 let _icx = push_ctxt("trans_local_var");
1011 ast::def_upvar(nid, _, _, _) => {
1012 // Can't move upvars, so this is never a ZeroMemLastUse.
1013 let local_ty = node_id_type(bcx, nid);
1014 match bcx.fcx.llupvars.find(&nid) {
1019 mode: ByRef(ZeroMem)
1023 bcx.sess().bug(fmt!(
1024 "trans_local_var: no llval for upvar %? found", nid));
1028 ast::def_arg(nid, _) => {
1029 take_local(bcx, bcx.fcx.llargs, nid)
1031 ast::def_local(nid, _) | ast::def_binding(nid, _) => {
1032 take_local(bcx, bcx.fcx.lllocals, nid)
1034 ast::def_self(nid, _) => {
1035 let self_info: ValSelfData = match bcx.fcx.llself {
1036 Some(ref self_info) => *self_info,
1038 bcx.sess().bug(fmt!(
1039 "trans_local_var: reference to self \
1040 out of context with id %?", nid));
1044 debug!("def_self() reference, self_info.t=%s",
1045 self_info.t.repr(bcx.tcx()));
1050 mode: ByRef(ZeroMem)
1054 bcx.sess().unimpl(fmt!(
1055 "unsupported def type in trans_local_var: %?", def));
1059 fn take_local(bcx: block,
1060 table: &HashMap<ast::node_id, ValueRef>,
1061 nid: ast::node_id) -> Datum {
1062 let v = match table.find(&nid) {
1065 bcx.sess().bug(fmt!(
1066 "trans_local_var: no llval for local/arg %? found", nid));
1069 let ty = node_id_type(bcx, nid);
1070 debug!("take_local(nid=%?, v=%s, ty=%s)",
1071 nid, bcx.val_to_str(v), bcx.ty_to_str(ty));
1075 mode: ByRef(ZeroMem)
1080 // The optional node ID here is the node ID of the path identifying the enum
1081 // variant in use. If none, this cannot possibly an enum variant (so, if it
1082 // is and `node_id_opt` is none, this function fails).
1083 pub fn with_field_tys<R>(tcx: ty::ctxt,
1085 node_id_opt: Option<ast::node_id>,
1086 op: &fn(int, (&[ty::field])) -> R) -> R {
1087 match ty::get(ty).sty {
1088 ty::ty_struct(did, ref substs) => {
1089 op(0, struct_fields(tcx, did, substs))
1092 ty::ty_enum(_, ref substs) => {
1093 // We want the *variant* ID here, not the enum ID.
1097 "cannot get field types from the enum type %s \
1102 match tcx.def_map.get_copy(&node_id) {
1103 ast::def_variant(enum_id, variant_id) => {
1104 let variant_info = ty::enum_variant_with_id(
1105 tcx, enum_id, variant_id);
1106 op(variant_info.disr_val,
1107 struct_fields(tcx, variant_id, substs))
1110 tcx.sess.bug("resolve didn't map this expr to a \
1120 "cannot get field types from the type %s",
1126 fn trans_rec_or_struct(bcx: block,
1127 fields: &[ast::Field],
1128 base: Option<@ast::expr>,
1129 expr_span: codemap::span,
1131 dest: Dest) -> block
1133 let _icx = push_ctxt("trans_rec");
1136 let ty = node_id_type(bcx, id);
1137 let tcx = bcx.tcx();
1138 do with_field_tys(tcx, ty, Some(id)) |discr, field_tys| {
1139 let mut need_base = vec::from_elem(field_tys.len(), true);
1141 let numbered_fields = do fields.map |field| {
1142 let opt_pos = field_tys.iter().position(|field_ty| field_ty.ident == field.ident);
1145 need_base[i] = false;
1149 tcx.sess.span_bug(field.span,
1150 "Couldn't find field in struct type")
1154 let optbase = match base {
1155 Some(base_expr) => {
1156 let mut leftovers = ~[];
1157 for need_base.iter().enumerate().advance |(i, b)| {
1159 leftovers.push((i, field_tys[i].mt.ty))
1162 Some(StructBaseInfo {expr: base_expr,
1163 fields: leftovers })
1166 if need_base.iter().any(|b| *b) {
1167 tcx.sess.span_bug(expr_span, "missing fields and no base expr")
1173 let repr = adt::represent_type(bcx.ccx(), ty);
1174 trans_adt(bcx, repr, discr, numbered_fields, optbase, dest)
1179 * Information that `trans_adt` needs in order to fill in the fields
1180 * of a struct copied from a base struct (e.g., from an expression
1181 * like `Foo { a: b, ..base }`.
1183 * Note that `fields` may be empty; the base expression must always be
1184 * evaluated for side-effects.
1186 struct StructBaseInfo {
1187 /// The base expression; will be evaluated after all explicit fields.
1189 /// The indices of fields to copy paired with their types.
1190 fields: ~[(uint, ty::t)]
1194 * Constructs an ADT instance:
1196 * - `fields` should be a list of field indices paired with the
1197 * expression to store into that field. The initializers will be
1198 * evaluated in the order specified by `fields`.
1200 * - `optbase` contains information on the base struct (if any) from
1201 * which remaining fields are copied; see comments on `StructBaseInfo`.
1203 fn trans_adt(bcx: block, repr: &adt::Repr, discr: int,
1204 fields: &[(uint, @ast::expr)],
1205 optbase: Option<StructBaseInfo>,
1206 dest: Dest) -> block {
1207 let _icx = push_ctxt("trans_adt");
1209 let addr = match dest {
1211 for fields.iter().advance |&(_i, e)| {
1212 bcx = trans_into(bcx, e, Ignore);
1214 for optbase.iter().advance |sbi| {
1215 // FIXME #7261: this moves entire base, not just certain fields
1216 bcx = trans_into(bcx, sbi.expr, Ignore);
1222 let mut temp_cleanups = ~[];
1223 adt::trans_start_init(bcx, repr, addr, discr);
1224 for fields.iter().advance |&(i, e)| {
1225 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1226 let e_ty = expr_ty(bcx, e);
1227 bcx = trans_into(bcx, e, SaveIn(dest));
1228 add_clean_temp_mem(bcx, dest, e_ty);
1229 temp_cleanups.push(dest);
1231 for optbase.iter().advance |base| {
1232 // FIXME #6573: is it sound to use the destination's repr on the base?
1233 // And, would it ever be reasonable to be here with discr != 0?
1234 let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base.expr));
1235 for base.fields.iter().advance |&(i, t)| {
1236 let datum = do base_datum.get_element(bcx, t, ZeroMem) |srcval| {
1237 adt::trans_field_ptr(bcx, repr, srcval, discr, i)
1239 let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
1240 bcx = datum.store_to(bcx, INIT, dest);
1244 for temp_cleanups.iter().advance |cleanup| {
1245 revoke_clean(bcx, *cleanup);
1251 fn trans_immediate_lit(bcx: block, expr: @ast::expr,
1252 lit: ast::lit) -> DatumBlock {
1253 // must not be a string constant, that is a RvalueDpsExpr
1254 let _icx = push_ctxt("trans_immediate_lit");
1255 let ty = expr_ty(bcx, expr);
1256 immediate_rvalue_bcx(bcx, consts::const_lit(bcx.ccx(), expr, lit), ty)
1259 fn trans_unary_datum(bcx: block,
1260 un_expr: &ast::expr,
1262 sub_expr: @ast::expr) -> DatumBlock {
1263 let _icx = push_ctxt("trans_unary_datum");
1265 // if deref, would be LvalueExpr
1266 assert!(op != ast::deref);
1268 // if overloaded, would be RvalueDpsExpr
1269 assert!(!bcx.ccx().maps.method_map.contains_key(&un_expr.id));
1271 let un_ty = expr_ty(bcx, un_expr);
1272 let sub_ty = expr_ty(bcx, sub_expr);
1276 let Result {bcx, val} = trans_to_datum(bcx, sub_expr).to_result();
1278 // If this is a boolean type, we must not use the LLVM Not
1279 // instruction, as that is a *bitwise* not and we want *logical*
1280 // not on our 8-bit boolean values.
1281 let llresult = match ty::get(un_ty).sty {
1283 let llcond = ICmp(bcx,
1287 Select(bcx, llcond, C_bool(true), C_bool(false))
1291 immediate_rvalue_bcx(bcx, llresult, un_ty)
1294 let Result {bcx, val} = trans_to_datum(bcx, sub_expr).to_result();
1296 if ty::type_is_fp(un_ty) {
1302 immediate_rvalue_bcx(bcx, llneg, un_ty)
1305 trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty,
1309 let heap = heap_for_unique(bcx, un_ty);
1310 trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty, heap)
1313 bcx.sess().bug("deref expressions should have been \
1314 translated using trans_lvalue(), not \
1315 trans_unary_datum()")
1319 fn trans_boxed_expr(bcx: block,
1321 contents: @ast::expr,
1323 heap: heap) -> DatumBlock {
1324 let _icx = push_ctxt("trans_boxed_expr");
1325 if heap == heap_exchange {
1326 let llty = type_of(bcx.ccx(), contents_ty);
1327 let size = llsize_of(bcx.ccx(), llty);
1328 let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, contents_ty,
1329 heap_exchange, size);
1330 add_clean_free(bcx, val, heap_exchange);
1331 let bcx = trans_into(bcx, contents, SaveIn(val));
1332 revoke_clean(bcx, val);
1333 return immediate_rvalue_bcx(bcx, val, box_ty);
1335 let base::MallocResult { bcx, box: bx, body } =
1336 base::malloc_general(bcx, contents_ty, heap);
1337 add_clean_free(bcx, bx, heap);
1338 let bcx = trans_into(bcx, contents, SaveIn(body));
1339 revoke_clean(bcx, bx);
1340 return immediate_rvalue_bcx(bcx, bx, box_ty);
1345 fn trans_addr_of(bcx: block, expr: &ast::expr,
1346 subexpr: @ast::expr) -> DatumBlock {
1347 let _icx = push_ctxt("trans_addr_of");
1349 let sub_datum = unpack_datum!(bcx, trans_to_datum(bcx, subexpr));
1350 let llval = sub_datum.to_ref_llval(bcx);
1351 return immediate_rvalue_bcx(bcx, llval, expr_ty(bcx, expr));
1354 // Important to get types for both lhs and rhs, because one might be _|_
1355 // and the other not.
1356 fn trans_eager_binop(bcx: block,
1357 binop_expr: &ast::expr,
1363 let _icx = push_ctxt("trans_eager_binop");
1365 let lhs = lhs_datum.to_appropriate_llval(bcx);
1366 let lhs_t = lhs_datum.ty;
1368 let rhs = rhs_datum.to_appropriate_llval(bcx);
1369 let rhs_t = rhs_datum.ty;
1372 if ty::type_is_bot(lhs_t) { rhs_t }
1375 let tcx = bcx.tcx();
1376 if ty::type_is_simd(tcx, intype) {
1377 intype = ty::simd_type(tcx, intype);
1379 let is_float = ty::type_is_fp(intype);
1380 let signed = ty::type_is_signed(intype);
1382 let rhs = base::cast_shift_expr_rhs(bcx, op, lhs, rhs);
1385 let val = match op {
1387 if is_float { FAdd(bcx, lhs, rhs) }
1388 else { Add(bcx, lhs, rhs) }
1391 if is_float { FSub(bcx, lhs, rhs) }
1392 else { Sub(bcx, lhs, rhs) }
1395 if is_float { FMul(bcx, lhs, rhs) }
1396 else { Mul(bcx, lhs, rhs) }
1402 // Only zero-check integers; fp /0 is NaN
1403 bcx = base::fail_if_zero(bcx, binop_expr.span,
1416 // Only zero-check integers; fp %0 is NaN
1417 bcx = base::fail_if_zero(bcx, binop_expr.span,
1426 ast::bitor => Or(bcx, lhs, rhs),
1427 ast::bitand => And(bcx, lhs, rhs),
1428 ast::bitxor => Xor(bcx, lhs, rhs),
1429 ast::shl => Shl(bcx, lhs, rhs),
1433 } else { LShr(bcx, lhs, rhs) }
1435 ast::eq | ast::ne | ast::lt | ast::ge | ast::le | ast::gt => {
1436 if ty::type_is_bot(rhs_t) {
1439 if !ty::type_is_scalar(rhs_t) {
1440 bcx.tcx().sess.span_bug(binop_expr.span,
1441 "non-scalar comparison");
1443 let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op);
1445 ZExt(bcx, cmpr.val, Type::i8())
1449 bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop");
1453 return immediate_rvalue_bcx(bcx, val, binop_ty);
1456 // refinement types would obviate the need for this
1457 enum lazy_binop_ty { lazy_and, lazy_or }
1459 fn trans_lazy_binop(bcx: block,
1460 binop_expr: &ast::expr,
1463 b: @ast::expr) -> DatumBlock {
1464 let _icx = push_ctxt("trans_lazy_binop");
1465 let binop_ty = expr_ty(bcx, binop_expr);
1468 let Result {bcx: past_lhs, val: lhs} = {
1469 do base::with_scope_result(bcx, a.info(), "lhs") |bcx| {
1470 trans_to_datum(bcx, a).to_result()
1474 if past_lhs.unreachable {
1475 return immediate_rvalue_bcx(past_lhs, lhs, binop_ty);
1478 let join = base::sub_block(bcx, "join");
1479 let before_rhs = base::sub_block(bcx, "rhs");
1481 let lhs_i1 = bool_to_i1(past_lhs, lhs);
1483 lazy_and => CondBr(past_lhs, lhs_i1, before_rhs.llbb, join.llbb),
1484 lazy_or => CondBr(past_lhs, lhs_i1, join.llbb, before_rhs.llbb)
1487 let Result {bcx: past_rhs, val: rhs} = {
1488 do base::with_scope_result(before_rhs, b.info(), "rhs") |bcx| {
1489 trans_to_datum(bcx, b).to_result()
1493 if past_rhs.unreachable {
1494 return immediate_rvalue_bcx(join, lhs, binop_ty);
1497 Br(past_rhs, join.llbb);
1498 let phi = Phi(join, Type::bool(), [lhs, rhs], [past_lhs.llbb,
1501 return immediate_rvalue_bcx(join, phi, binop_ty);
1504 fn trans_binary(bcx: block,
1505 binop_expr: &ast::expr,
1508 rhs: @ast::expr) -> DatumBlock
1510 let _icx = push_ctxt("trans_binary");
1514 trans_lazy_binop(bcx, binop_expr, lazy_and, lhs, rhs)
1517 trans_lazy_binop(bcx, binop_expr, lazy_or, lhs, rhs)
1521 let lhs_datum = unpack_datum!(bcx, trans_to_datum(bcx, lhs));
1522 let rhs_datum = unpack_datum!(bcx, trans_to_datum(bcx, rhs));
1523 let binop_ty = expr_ty(bcx, binop_expr);
1524 trans_eager_binop(bcx, binop_expr, binop_ty, op,
1525 &lhs_datum, &rhs_datum)
1530 fn trans_overloaded_op(bcx: block,
1532 callee_id: ast::node_id,
1534 args: ~[@ast::expr],
1538 let origin = bcx.ccx().maps.method_map.get_copy(&expr.id);
1539 let fty = node_id_type(bcx, callee_id);
1540 callee::trans_call_inner(bcx,
1545 meth::trans_method_callee(bcx,
1550 callee::ArgExprs(args),
1555 fn int_cast(bcx: block, lldsttype: Type, llsrctype: Type,
1556 llsrc: ValueRef, signed: bool) -> ValueRef {
1557 let _icx = push_ctxt("int_cast");
1559 let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype.to_ref());
1560 let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype.to_ref());
1561 return if dstsz == srcsz {
1562 BitCast(bcx, llsrc, lldsttype)
1563 } else if srcsz > dstsz {
1564 TruncOrBitCast(bcx, llsrc, lldsttype)
1566 SExtOrBitCast(bcx, llsrc, lldsttype)
1568 ZExtOrBitCast(bcx, llsrc, lldsttype)
1573 fn float_cast(bcx: block, lldsttype: Type, llsrctype: Type,
1574 llsrc: ValueRef) -> ValueRef {
1575 let _icx = push_ctxt("float_cast");
1576 let srcsz = llsrctype.float_width();
1577 let dstsz = lldsttype.float_width();
1578 return if dstsz > srcsz {
1579 FPExt(bcx, llsrc, lldsttype)
1580 } else if srcsz > dstsz {
1581 FPTrunc(bcx, llsrc, lldsttype)
1586 pub enum cast_kind {
1594 pub fn cast_type_kind(t: ty::t) -> cast_kind {
1595 match ty::get(t).sty {
1596 ty::ty_float(*) => cast_float,
1597 ty::ty_ptr(*) => cast_pointer,
1598 ty::ty_rptr(*) => cast_pointer,
1599 ty::ty_int(*) => cast_integral,
1600 ty::ty_uint(*) => cast_integral,
1601 ty::ty_bool => cast_integral,
1602 ty::ty_enum(*) => cast_enum,
1607 fn trans_imm_cast(bcx: block, expr: @ast::expr,
1608 id: ast::node_id) -> DatumBlock {
1609 let _icx = push_ctxt("trans_cast");
1610 let ccx = bcx.ccx();
1612 let t_out = node_id_type(bcx, id);
1615 let llexpr = unpack_result!(bcx, trans_to_datum(bcx, expr).to_result());
1616 let ll_t_in = val_ty(llexpr);
1617 let t_in = expr_ty(bcx, expr);
1618 let ll_t_out = type_of::type_of(ccx, t_out);
1620 let k_in = cast_type_kind(t_in);
1621 let k_out = cast_type_kind(t_out);
1622 let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
1625 match (k_in, k_out) {
1626 (cast_integral, cast_integral) => {
1627 int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
1629 (cast_float, cast_float) => {
1630 float_cast(bcx, ll_t_out, ll_t_in, llexpr)
1632 (cast_integral, cast_float) => {
1634 SIToFP(bcx, llexpr, ll_t_out)
1635 } else { UIToFP(bcx, llexpr, ll_t_out) }
1637 (cast_float, cast_integral) => {
1638 if ty::type_is_signed(t_out) {
1639 FPToSI(bcx, llexpr, ll_t_out)
1640 } else { FPToUI(bcx, llexpr, ll_t_out) }
1642 (cast_integral, cast_pointer) => {
1643 IntToPtr(bcx, llexpr, ll_t_out)
1645 (cast_pointer, cast_integral) => {
1646 PtrToInt(bcx, llexpr, ll_t_out)
1648 (cast_pointer, cast_pointer) => {
1649 PointerCast(bcx, llexpr, ll_t_out)
1651 (cast_enum, cast_integral) |
1652 (cast_enum, cast_float) => {
1654 let repr = adt::represent_type(ccx, t_in);
1655 let lldiscrim_a = adt::trans_get_discr(bcx, repr, llexpr);
1657 cast_integral => int_cast(bcx, ll_t_out,
1658 val_ty(lldiscrim_a),
1660 cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
1661 _ => ccx.sess.bug("translating unsupported cast.")
1664 _ => ccx.sess.bug("translating unsupported cast.")
1666 return immediate_rvalue_bcx(bcx, newval, t_out);
1669 fn trans_assign_op(bcx: block,
1671 callee_id: ast::node_id,
1674 src: @ast::expr) -> block
1676 let _icx = push_ctxt("trans_assign_op");
1679 debug!("trans_assign_op(expr=%s)", bcx.expr_to_str(expr));
1681 // Evaluate LHS (destination), which should be an lvalue
1682 let dst_datum = unpack_datum!(bcx, trans_lvalue_unadjusted(bcx, dst));
1684 // A user-defined operator method
1685 if bcx.ccx().maps.method_map.find(&expr.id).is_some() {
1686 // FIXME(#2528) evaluates the receiver twice!!
1687 let scratch = scratch_datum(bcx, dst_datum.ty, "__assign_op", false);
1688 let bcx = trans_overloaded_op(bcx,
1694 SaveIn(scratch.val));
1695 return scratch.move_to_datum(bcx, DROP_EXISTING, dst_datum);
1698 // Evaluate RHS (source)
1699 let src_datum = unpack_datum!(bcx, trans_to_datum(bcx, src));
1701 // Perform computation and store the result
1705 bcx, expr, dst_datum.ty, op,
1706 &dst_datum, &src_datum));
1707 return result_datum.copy_to_datum(bcx, DROP_EXISTING, dst_datum);
1710 fn shorten(x: &str) -> @str {
1711 (if x.char_len() > 60 {x.slice_chars(0, 60)} else {x}).to_managed()