1 // Copyright 2012-2014 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.
11 /*! See doc.rs for a thorough explanation of the borrow checker */
13 #![allow(non_camel_case_types)]
15 use mc = middle::mem_categorization;
19 use middle::dataflow::DataFlowContext;
20 use middle::dataflow::DataFlowOperator;
21 use util::nodemap::NodeSet;
22 use util::ppaux::{note_and_explain_region, Repr, UserString};
24 use std::cell::{Cell, RefCell};
25 use collections::HashMap;
26 use std::ops::{BitOr, BitAnd};
27 use std::result::Result;
28 use std::strbuf::StrBuf;
32 use syntax::codemap::Span;
33 use syntax::parse::token;
35 use syntax::visit::{Visitor, FnKind};
36 use syntax::ast::{FnDecl, Block, NodeId};
42 Err(e) => { return Err(e); }
55 pub struct LoanDataFlowOperator;
57 /// FIXME(pcwalton): Should just be #[deriving(Clone)], but that doesn't work
58 /// yet on unit structs.
59 impl Clone for LoanDataFlowOperator {
60 fn clone(&self) -> LoanDataFlowOperator {
65 pub type LoanDataFlow<'a> = DataFlowContext<'a, LoanDataFlowOperator>;
67 impl<'a> Visitor<()> for BorrowckCtxt<'a> {
68 fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl,
69 b: &Block, s: Span, n: NodeId, _: ()) {
70 borrowck_fn(self, fk, fd, b, s, n);
73 fn visit_item(&mut self, item: &ast::Item, _: ()) {
74 borrowck_item(self, item);
78 pub fn check_crate(tcx: &ty::ctxt,
79 method_map: typeck::MethodMap,
81 moved_variables_set: &NodeSet,
82 capture_map: &moves::CaptureMap,
85 let mut bccx = BorrowckCtxt {
87 method_map: method_map,
89 moved_variables_set: moved_variables_set,
90 capture_map: capture_map,
93 loaned_paths_same: Cell::new(0),
94 loaned_paths_imm: Cell::new(0),
95 stable_paths: Cell::new(0),
96 guaranteed_paths: Cell::new(0),
101 visit::walk_crate(bccx, krate, ());
103 if tcx.sess.borrowck_stats() {
104 println!("--- borrowck stats ---");
105 println!("paths requiring guarantees: {}",
106 bccx.stats.guaranteed_paths.get());
107 println!("paths requiring loans : {}",
108 make_stat(bccx, bccx.stats.loaned_paths_same.get()));
109 println!("paths requiring imm loans : {}",
110 make_stat(bccx, bccx.stats.loaned_paths_imm.get()));
111 println!("stable paths : {}",
112 make_stat(bccx, bccx.stats.stable_paths.get()));
115 return bccx.root_map;
117 fn make_stat(bccx: &mut BorrowckCtxt, stat: uint) -> ~str {
118 let stat_f = stat as f64;
119 let total = bccx.stats.guaranteed_paths.get() as f64;
120 format!("{} ({:.0f}%)", stat , stat_f * 100.0 / total)
124 fn borrowck_item(this: &mut BorrowckCtxt, item: &ast::Item) {
125 // Gather loans for items. Note that we don't need
126 // to check loans for single expressions. The check
127 // loan step is intended for things that have a data
128 // flow dependent conditions.
130 ast::ItemStatic(_, _, ex) => {
131 gather_loans::gather_loans_in_static_initializer(this, ex);
134 visit::walk_item(this, item, ());
139 fn borrowck_fn(this: &mut BorrowckCtxt,
145 debug!("borrowck_fn(id={})", id);
147 // Check the body of fn items.
148 let (id_range, all_loans, move_data) =
149 gather_loans::gather_loans_in_fn(this, decl, body);
151 DataFlowContext::new(this.tcx,
153 LoanDataFlowOperator,
156 for (loan_idx, loan) in all_loans.iter().enumerate() {
157 loan_dfcx.add_gen(loan.gen_scope, loan_idx);
158 loan_dfcx.add_kill(loan.kill_scope, loan_idx);
160 loan_dfcx.propagate(body);
162 let flowed_moves = move_data::FlowedMoveData::new(move_data,
168 check_loans::check_loans(this, &loan_dfcx, flowed_moves,
169 all_loans.as_slice(), body);
171 visit::walk_fn(this, fk, decl, body, sp, id, ());
174 // ----------------------------------------------------------------------
177 pub struct BorrowckCtxt<'a> {
179 method_map: typeck::MethodMap,
180 moves_map: &'a NodeSet,
181 moved_variables_set: &'a NodeSet,
182 capture_map: &'a moves::CaptureMap,
189 pub struct BorrowStats {
190 loaned_paths_same: Cell<uint>,
191 loaned_paths_imm: Cell<uint>,
192 stable_paths: Cell<uint>,
193 guaranteed_paths: Cell<uint>,
196 // The keys to the root map combine the `id` of the deref expression
197 // with the number of types that it is *autodereferenced*. So, for
198 // example, imagine I have a variable `x: @@@T` and an expression
199 // `(*x).f`. This will have 3 derefs, one explicit and then two
200 // autoderefs. These are the relevant `root_map_key` values that could
203 // {id:*x, derefs:0} --> roots `x` (type: @@@T, due to explicit deref)
204 // {id:*x, derefs:1} --> roots `*x` (type: @@T, due to autoderef #1)
205 // {id:*x, derefs:2} --> roots `**x` (type: @T, due to autoderef #2)
207 // Note that there is no entry with derefs:3---the type of that expression
208 // is T, which is not a box.
209 #[deriving(Eq, TotalEq, Hash)]
210 pub struct root_map_key {
215 pub type BckResult<T> = Result<T, BckError>;
218 pub enum PartialTotal {
219 Partial, // Loan affects some portion
220 Total // Loan affects entire path
223 ///////////////////////////////////////////////////////////////////////////
224 // Loans and loan paths
226 /// Record of a loan that was issued.
229 loan_path: @LoanPath,
231 kind: ty::BorrowKind,
232 restrictions: Vec<Restriction> ,
233 gen_scope: ast::NodeId,
234 kill_scope: ast::NodeId,
241 ClosureCapture(Span),
247 #[deriving(Eq, TotalEq, Hash)]
249 LpVar(ast::NodeId), // `x` in doc.rs
250 LpExtend(@LoanPath, mc::MutabilityCategory, LoanPathElem)
253 #[deriving(Eq, TotalEq, Hash)]
254 pub enum LoanPathElem {
255 LpDeref(mc::PointerKind), // `*LV` in doc.rs
256 LpInterior(mc::InteriorKind) // `LV.f` in doc.rs
260 pub fn node_id(&self) -> ast::NodeId {
262 LpVar(local_id) => local_id,
263 LpExtend(base, _, _) => base.node_id()
268 pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> {
269 //! Computes the `LoanPath` (if any) for a `cmt`.
270 //! Note that this logic is somewhat duplicated in
271 //! the method `compute()` found in `gather_loans::restrictions`,
272 //! which allows it to share common loan path pieces as it
273 //! traverses the CMT.
277 mc::cat_static_item |
278 mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {
284 mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id: id, .. }) |
285 mc::cat_upvar(ty::UpvarId {var_id: id, ..}, _) => {
289 mc::cat_deref(cmt_base, _, pk) => {
290 opt_loan_path(cmt_base).map(|lp| {
291 @LpExtend(lp, cmt.mutbl, LpDeref(pk))
295 mc::cat_interior(cmt_base, ik) => {
296 opt_loan_path(cmt_base).map(|lp| {
297 @LpExtend(lp, cmt.mutbl, LpInterior(ik))
301 mc::cat_downcast(cmt_base) |
302 mc::cat_discr(cmt_base, _) => {
303 opt_loan_path(cmt_base)
308 ///////////////////////////////////////////////////////////////////////////
311 // Borrowing an lvalue often results in *restrictions* that limit what
312 // can be done with this lvalue during the scope of the loan:
314 // - `RESTR_MUTATE`: The lvalue may not be modified or `&mut` borrowed.
315 // - `RESTR_FREEZE`: `&` borrows of the lvalue are forbidden.
317 // In addition, no value which is restricted may be moved. Therefore,
318 // restrictions are meaningful even if the RestrictionSet is empty,
319 // because the restriction against moves is implied.
321 pub struct Restriction {
322 loan_path: @LoanPath,
327 pub struct RestrictionSet {
331 #[allow(dead_code)] // potentially useful
332 pub static RESTR_EMPTY: RestrictionSet = RestrictionSet {bits: 0b0000};
333 pub static RESTR_MUTATE: RestrictionSet = RestrictionSet {bits: 0b0001};
334 pub static RESTR_FREEZE: RestrictionSet = RestrictionSet {bits: 0b0010};
336 impl RestrictionSet {
337 pub fn intersects(&self, restr: RestrictionSet) -> bool {
338 (self.bits & restr.bits) != 0
342 impl BitOr<RestrictionSet,RestrictionSet> for RestrictionSet {
343 fn bitor(&self, rhs: &RestrictionSet) -> RestrictionSet {
344 RestrictionSet {bits: self.bits | rhs.bits}
348 impl BitAnd<RestrictionSet,RestrictionSet> for RestrictionSet {
349 fn bitand(&self, rhs: &RestrictionSet) -> RestrictionSet {
350 RestrictionSet {bits: self.bits & rhs.bits}
354 impl Repr for RestrictionSet {
355 fn repr(&self, _tcx: &ty::ctxt) -> ~str {
356 format!("RestrictionSet(0x{:x})", self.bits as uint)
360 ///////////////////////////////////////////////////////////////////////////
361 // Rooting of managed boxes
363 // When we borrow the interior of a managed box, it is sometimes
364 // necessary to *root* the box, meaning to stash a copy of the box
365 // somewhere that the garbage collector will find it. This ensures
366 // that the box is not collected for the lifetime of the borrow.
368 // As part of this rooting, we sometimes also freeze the box at
369 // runtime, meaning that we dynamically detect when the box is
370 // borrowed in incompatible ways.
372 // Both of these actions are driven through the `root_map`, which maps
373 // from a node to the dynamic rooting action that should be taken when
374 // that node executes. The node is identified through a
375 // `root_map_key`, which pairs a node-id and a deref count---the
376 // problem is that sometimes the box that needs to be rooted is only
377 // uncovered after a certain number of auto-derefs.
379 pub struct RootInfo {
380 pub scope: ast::NodeId,
383 pub type root_map = @RefCell<HashMap<root_map_key, RootInfo>>;
385 pub fn root_map() -> root_map {
386 return @RefCell::new(HashMap::new());
389 ///////////////////////////////////////////////////////////////////////////
392 // Errors that can occur
394 pub enum bckerr_code {
396 err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope
397 err_out_of_scope(ty::Region, ty::Region), // superscope, subscope
398 err_borrowed_pointer_too_short(
399 ty::Region, ty::Region, RestrictionSet), // loan, ptr
402 // Combination of an error code and the categorization of the expression
405 pub struct BckError {
412 pub enum AliasableViolationKind {
414 BorrowViolation(LoanCause)
417 pub enum MovedValueUseKind {
422 ///////////////////////////////////////////////////////////////////////////
425 impl<'a> BorrowckCtxt<'a> {
426 pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region)
428 self.tcx.region_maps.is_subregion_of(r_sub, r_sup)
431 pub fn is_subscope_of(&self, r_sub: ast::NodeId, r_sup: ast::NodeId)
433 self.tcx.region_maps.is_subscope_of(r_sub, r_sup)
436 pub fn is_move(&self, id: ast::NodeId) -> bool {
437 self.moves_map.contains(&id)
440 pub fn mc(&self) -> mc::MemCategorizationContext<TcxTyper<'a>> {
441 mc::MemCategorizationContext {
444 method_map: self.method_map
449 pub fn cat_expr(&self, expr: &ast::Expr) -> mc::cmt {
450 match self.mc().cat_expr(expr) {
453 self.tcx.sess.span_bug(expr.span, "error in mem categorization");
458 pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> mc::cmt {
459 match self.mc().cat_expr_unadjusted(expr) {
462 self.tcx.sess.span_bug(expr.span, "error in mem categorization");
467 pub fn cat_expr_autoderefd(&self,
469 adj: &ty::AutoAdjustment)
472 ty::AutoAddEnv(..) | ty::AutoObject(..) => {
474 self.mc().cat_expr_unadjusted(expr)
479 autoderefs: autoderefs, ..}) => {
480 self.mc().cat_expr_autoderefd(expr, autoderefs)
487 self.tcx.sess.span_bug(expr.span,
488 "error in mem categorization");
493 pub fn cat_def(&self,
499 match self.mc().cat_def(id, span, ty, def) {
502 self.tcx.sess.span_bug(span, "error in mem categorization");
507 pub fn cat_captured_var(&self,
510 captured_var: &moves::CaptureVar) -> mc::cmt {
511 // Create the cmt for the variable being borrowed, from the
512 // caller's perspective
513 let var_id = ast_util::def_id_of_def(captured_var.def).node;
514 let var_ty = ty::node_id_to_type(self.tcx, var_id);
515 self.cat_def(id, span, var_ty, captured_var.def)
518 pub fn cat_discr(&self, cmt: mc::cmt, match_id: ast::NodeId) -> mc::cmt {
519 @mc::cmt_ {cat:mc::cat_discr(cmt, match_id),
520 mutbl:cmt.mutbl.inherit(),
524 pub fn cat_pattern(&self,
527 op: |mc::cmt, &ast::Pat|) {
528 let r = self.mc().cat_pattern(cmt, pat, |_,x,y| op(x,y));
532 pub fn report(&self, err: BckError) {
535 self.bckerr_to_str(err));
536 self.note_and_explain_bckerr(err);
539 pub fn report_use_of_moved_value(&self,
541 use_kind: MovedValueUseKind,
543 move: &move_data::Move,
544 moved_lp: @LoanPath) {
545 let verb = match use_kind {
547 MovedInCapture => "capture",
551 move_data::Declared => {
552 self.tcx.sess.span_err(
554 format!("{} of possibly uninitialized variable: `{}`",
556 self.loan_path_to_str(lp)));
559 let partially = if lp == moved_lp {""} else {"partially "};
560 self.tcx.sess.span_err(
562 format!("{} of {}moved value: `{}`",
565 self.loan_path_to_str(lp)));
570 move_data::Declared => {}
572 move_data::MoveExpr => {
573 let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
574 Some(ast_map::NodeExpr(expr)) => {
575 (ty::expr_ty_adjusted(self.tcx, expr,
576 &*self.method_map.borrow()), expr.span)
578 r => self.tcx.sess.bug(format!("MoveExpr({:?}) maps to {:?}, not Expr",
581 let suggestion = move_suggestion(self.tcx, expr_ty,
582 "moved by default (use `copy` to override)");
583 self.tcx.sess.span_note(
585 format!("`{}` moved here because it has type `{}`, which is {}",
586 self.loan_path_to_str(moved_lp),
587 expr_ty.user_string(self.tcx), suggestion));
590 move_data::MovePat => {
591 let pat_ty = ty::node_id_to_type(self.tcx, move.id);
592 self.tcx.sess.span_note(self.tcx.map.span(move.id),
593 format!("`{}` moved here because it has type `{}`, \
594 which is moved by default (use `ref` to override)",
595 self.loan_path_to_str(moved_lp),
596 pat_ty.user_string(self.tcx)));
599 move_data::Captured => {
600 let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
601 Some(ast_map::NodeExpr(expr)) => {
602 (ty::expr_ty_adjusted(self.tcx, expr,
603 &*self.method_map.borrow()), expr.span)
605 r => self.tcx.sess.bug(format!("Captured({:?}) maps to {:?}, not Expr",
608 let suggestion = move_suggestion(self.tcx, expr_ty,
609 "moved by default (make a copy and \
610 capture that instead to override)");
611 self.tcx.sess.span_note(
613 format!("`{}` moved into closure environment here because it \
614 has type `{}`, which is {}",
615 self.loan_path_to_str(moved_lp),
616 expr_ty.user_string(self.tcx), suggestion));
620 fn move_suggestion(tcx: &ty::ctxt, ty: ty::t, default_msg: &'static str)
622 match ty::get(ty).sty {
623 ty::ty_closure(ref cty) if cty.sigil == ast::BorrowedSigil =>
624 "a non-copyable stack closure (capture it in a new closure, \
625 e.g. `|x| f(x)`, to override)",
626 _ if ty::type_moves_by_default(tcx, ty) =>
627 "non-copyable (perhaps you meant to use clone()?)",
633 pub fn report_reassigned_immutable_variable(&self,
637 &move_data::Assignment) {
638 self.tcx.sess.span_err(
640 format!("re-assignment of immutable variable `{}`",
641 self.loan_path_to_str(lp)));
642 self.tcx.sess.span_note(
644 format!("prior assignment occurs here"));
647 pub fn span_err(&self, s: Span, m: &str) {
648 self.tcx.sess.span_err(s, m);
651 pub fn span_note(&self, s: Span, m: &str) {
652 self.tcx.sess.span_note(s, m);
655 pub fn span_end_note(&self, s: Span, m: &str) {
656 self.tcx.sess.span_end_note(s, m);
659 pub fn bckerr_to_str(&self, err: BckError) -> ~str {
662 let descr = match opt_loan_path(err.cmt) {
663 None => format!("{} {}",
664 err.cmt.mutbl.to_user_str(),
665 self.cmt_to_str(err.cmt)),
666 Some(lp) => format!("{} {} `{}`",
667 err.cmt.mutbl.to_user_str(),
668 self.cmt_to_str(err.cmt),
669 self.loan_path_to_str(lp)),
673 ClosureCapture(_) => {
674 format!("closure cannot assign to {}", descr)
676 AddrOf | RefBinding | AutoRef => {
677 format!("cannot borrow {} as mutable", descr)
681 err_out_of_root_scope(..) => {
682 format!("cannot root managed value long enough")
684 err_out_of_scope(..) => {
685 let msg = match opt_loan_path(err.cmt) {
686 None => format!("borrowed value"),
687 Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
689 format!("{} does not live long enough", msg)
691 err_borrowed_pointer_too_short(..) => {
692 let descr = match opt_loan_path(err.cmt) {
693 Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
694 None => self.cmt_to_str(err.cmt),
697 format!("lifetime of {} is too short to guarantee \
698 its contents can be safely reborrowed",
704 pub fn report_aliasability_violation(&self,
706 kind: AliasableViolationKind,
707 cause: mc::AliasableReason) {
708 let prefix = match kind {
709 MutabilityViolation => {
710 "cannot assign to data"
712 BorrowViolation(ClosureCapture(_)) => {
713 // I don't think we can get aliasability violations
714 // with closure captures, so no need to come up with a
715 // good error message. The reason this cannot happen
716 // is because we only capture local variables in
717 // closures, and those are never aliasable.
718 self.tcx.sess.span_bug(
720 "aliasability violation with closure");
722 BorrowViolation(AddrOf) |
723 BorrowViolation(AutoRef) |
724 BorrowViolation(RefBinding) => {
725 "cannot borrow data mutably"
730 mc::AliasableOther => {
731 self.tcx.sess.span_err(
733 format!("{} in an aliasable location", prefix));
735 mc::AliasableStatic(..) |
736 mc::AliasableStaticMut(..) => {
737 self.tcx.sess.span_err(
739 format!("{} in a static location", prefix));
741 mc::AliasableManaged => {
742 self.tcx.sess.span_err(
744 format!("{} in a `@` pointer", prefix));
746 mc::AliasableBorrowed => {
747 self.tcx.sess.span_err(
749 format!("{} in a `&` reference", prefix));
754 pub fn note_and_explain_bckerr(&self, err: BckError) {
759 err_out_of_root_scope(super_scope, sub_scope) => {
760 note_and_explain_region(
762 "managed value would have to be rooted for ",
765 note_and_explain_region(
767 "...but can only be rooted for ",
772 err_out_of_scope(super_scope, sub_scope) => {
773 note_and_explain_region(
775 "reference must be valid for ",
778 note_and_explain_region(
780 "...but borrowed value is only valid for ",
785 err_borrowed_pointer_too_short(loan_scope, ptr_scope, _) => {
786 let descr = match opt_loan_path(err.cmt) {
787 Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
788 None => self.cmt_to_str(err.cmt),
790 note_and_explain_region(
792 format!("{} would have to be valid for ", descr),
795 note_and_explain_region(
797 format!("...but {} is only valid for ", descr),
804 pub fn append_loan_path_to_str(&self,
805 loan_path: &LoanPath,
809 out.push_str(ty::local_var_name_str(self.tcx, id).get());
812 LpExtend(lp_base, _, LpInterior(mc::InteriorField(fname))) => {
813 self.append_autoderefd_loan_path_to_str(lp_base, out);
815 mc::NamedField(fname) => {
817 out.push_str(token::get_name(fname).get());
819 mc::PositionalField(idx) => {
820 out.push_char('#'); // invent a notation here
821 out.push_str(idx.to_str());
826 LpExtend(lp_base, _, LpInterior(mc::InteriorElement(_))) => {
827 self.append_autoderefd_loan_path_to_str(lp_base, out);
828 out.push_str("[..]");
831 LpExtend(lp_base, _, LpDeref(_)) => {
833 self.append_loan_path_to_str(lp_base, out);
838 pub fn append_autoderefd_loan_path_to_str(&self,
839 loan_path: &LoanPath,
842 LpExtend(lp_base, _, LpDeref(_)) => {
843 // For a path like `(*x).f` or `(*x)[3]`, autoderef
844 // rules would normally allow users to omit the `*x`.
845 // So just serialize such paths to `x.f` or x[3]` respectively.
846 self.append_autoderefd_loan_path_to_str(lp_base, out)
849 LpVar(..) | LpExtend(_, _, LpInterior(..)) => {
850 self.append_loan_path_to_str(loan_path, out)
855 pub fn loan_path_to_str(&self, loan_path: &LoanPath) -> ~str {
856 let mut result = StrBuf::new();
857 self.append_loan_path_to_str(loan_path, &mut result);
861 pub fn cmt_to_str(&self, cmt: mc::cmt) -> ~str {
862 self.mc().cmt_to_str(cmt)
866 impl DataFlowOperator for LoanDataFlowOperator {
868 fn initial_value(&self) -> bool {
869 false // no loans in scope by default
873 fn join(&self, succ: uint, pred: uint) -> uint {
874 succ | pred // loans from both preds are in scope
879 fn repr(&self, tcx: &ty::ctxt) -> ~str {
880 format!("Loan_{:?}({}, {:?}, {:?}-{:?}, {})",
882 self.loan_path.repr(tcx),
886 self.restrictions.repr(tcx))
890 impl Repr for Restriction {
891 fn repr(&self, tcx: &ty::ctxt) -> ~str {
892 format!("Restriction({}, {:x})",
893 self.loan_path.repr(tcx),
894 self.set.bits as uint)
898 impl Repr for LoanPath {
899 fn repr(&self, tcx: &ty::ctxt) -> ~str {
902 format!("$({})", tcx.map.node_to_str(id))
905 &LpExtend(lp, _, LpDeref(_)) => {
906 format!("{}.*", lp.repr(tcx))
909 &LpExtend(lp, _, LpInterior(ref interior)) => {
910 format!("{}.{}", lp.repr(tcx), interior.repr(tcx))
916 ///////////////////////////////////////////////////////////////////////////
918 pub struct TcxTyper<'a> {
920 method_map: typeck::MethodMap,
923 impl<'a> mc::Typer for TcxTyper<'a> {
924 fn tcx<'a>(&'a self) -> &'a ty::ctxt {
928 fn node_ty(&mut self, id: ast::NodeId) -> mc::McResult<ty::t> {
929 Ok(ty::node_id_to_type(self.tcx, id))
932 fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option<ty::t> {
933 self.method_map.borrow().find(&method_call).map(|method| method.ty)
936 fn adjustment(&mut self, id: ast::NodeId) -> Option<@ty::AutoAdjustment> {
937 self.tcx.adjustments.borrow().find_copy(&id)
940 fn is_method_call(&mut self, id: ast::NodeId) -> bool {
941 self.method_map.borrow().contains_key(&typeck::MethodCall::expr(id))
944 fn temporary_scope(&mut self, id: ast::NodeId) -> Option<ast::NodeId> {
945 self.tcx.region_maps.temporary_scope(id)
948 fn upvar_borrow(&mut self, id: ty::UpvarId) -> ty::UpvarBorrow {
949 self.tcx.upvar_borrow_map.borrow().get_copy(&id)