1 // Copyright 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 // Type resolution: the phase that finds all the types in the AST with
12 // unresolved type variables and replaces "ty_var" types with their
14 use self::ResolveReason::*;
18 use middle::def_id::DefId;
20 use middle::ty::{self, Ty, MethodCall, MethodCallee, HasTypeFlags};
21 use middle::ty::adjustment;
22 use middle::ty::fold::{TypeFolder,TypeFoldable};
24 use write_substs_to_tcx;
30 use syntax::codemap::{DUMMY_SP, Span};
31 use rustc_front::print::pprust::pat_to_string;
32 use rustc_front::intravisit::{self, Visitor};
33 use rustc_front::util as hir_util;
36 ///////////////////////////////////////////////////////////////////////////
37 // Entry point functions
39 pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &hir::Expr) {
40 assert_eq!(fcx.writeback_errors.get(), false);
41 let mut wbcx = WritebackCx::new(fcx);
43 wbcx.visit_upvar_borrow_map();
44 wbcx.visit_closures();
45 wbcx.visit_liberated_fn_sigs();
48 pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
51 assert_eq!(fcx.writeback_errors.get(), false);
52 let mut wbcx = WritebackCx::new(fcx);
53 wbcx.visit_block(blk);
54 for arg in &decl.inputs {
55 wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
56 wbcx.visit_pat(&*arg.pat);
58 // Privacy needs the type for the whole pattern, not just each binding
59 if !pat_util::pat_is_binding(&fcx.tcx().def_map.borrow(), &*arg.pat) {
60 wbcx.visit_node_id(ResolvingPattern(arg.pat.span),
64 wbcx.visit_upvar_borrow_map();
65 wbcx.visit_closures();
66 wbcx.visit_liberated_fn_sigs();
69 ///////////////////////////////////////////////////////////////////////////
70 // The Writerback context. This visitor walks the AST, checking the
71 // fn-specific tables to find references to types or regions. It
72 // resolves those regions to remove inference variables and writes the
73 // final result back into the master tables in the tcx. Here and
74 // there, it applies a few ad-hoc checks that were not convenient to
77 struct WritebackCx<'cx, 'tcx: 'cx> {
78 fcx: &'cx FnCtxt<'cx, 'tcx>,
81 impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
82 fn new(fcx: &'cx FnCtxt<'cx, 'tcx>) -> WritebackCx<'cx, 'tcx> {
83 WritebackCx { fcx: fcx }
86 fn tcx(&self) -> &'cx ty::ctxt<'tcx> {
90 // Hacky hack: During type-checking, we treat *all* operators
91 // as potentially overloaded. But then, during writeback, if
92 // we observe that something like `a+b` is (known to be)
93 // operating on scalars, we clear the overload.
94 fn fix_scalar_binary_expr(&mut self, e: &hir::Expr) {
96 hir::ExprBinary(ref op, ref lhs, ref rhs) |
97 hir::ExprAssignOp(ref op, ref lhs, ref rhs) => {
98 let lhs_ty = self.fcx.node_ty(lhs.id);
99 let lhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&lhs_ty);
101 let rhs_ty = self.fcx.node_ty(rhs.id);
102 let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty);
104 if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
105 self.fcx.inh.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
107 // weird but true: the by-ref binops put an
108 // adjustment on the lhs but not the rhs; the
109 // adjustment for rhs is kind of baked into the
112 hir::ExprBinary(..) => {
113 if !hir_util::is_by_value_binop(op.node) {
114 self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id);
117 hir::ExprAssignOp(..) => {
118 self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id);
123 let tcx = self.tcx();
125 if let hir::ExprAssignOp(..) = e.node {
127 !tcx.sess.features.borrow().augmented_assignments &&
128 !self.fcx.expr_ty(e).references_error()
132 "overloaded augmented assignments are not stable");
135 "add #![feature(augmented_assignments)] to the crate root \
146 ///////////////////////////////////////////////////////////////////////////
147 // Impl of Visitor for Resolver
149 // This is the master code which walks the AST. It delegates most of
150 // the heavy lifting to the generic visit and resolve functions
151 // below. In general, a function is made into a `visitor` if it must
152 // traffic in node-ids or update tables in the type context etc.
154 impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
155 fn visit_stmt(&mut self, s: &hir::Stmt) {
156 if self.fcx.writeback_errors.get() {
160 self.visit_node_id(ResolvingExpr(s.span), hir_util::stmt_id(s));
161 intravisit::walk_stmt(self, s);
164 fn visit_expr(&mut self, e: &hir::Expr) {
165 if self.fcx.writeback_errors.get() {
169 self.fix_scalar_binary_expr(e);
171 self.visit_node_id(ResolvingExpr(e.span), e.id);
172 self.visit_method_map_entry(ResolvingExpr(e.span),
173 MethodCall::expr(e.id));
175 if let hir::ExprClosure(_, ref decl, _) = e.node {
176 for input in &decl.inputs {
177 self.visit_node_id(ResolvingExpr(e.span), input.id);
181 intravisit::walk_expr(self, e);
184 fn visit_block(&mut self, b: &hir::Block) {
185 if self.fcx.writeback_errors.get() {
189 self.visit_node_id(ResolvingExpr(b.span), b.id);
190 intravisit::walk_block(self, b);
193 fn visit_pat(&mut self, p: &hir::Pat) {
194 if self.fcx.writeback_errors.get() {
198 self.visit_node_id(ResolvingPattern(p.span), p.id);
200 debug!("Type for pattern binding {} (id {}) resolved to {:?}",
203 self.tcx().node_id_to_type(p.id));
205 intravisit::walk_pat(self, p);
208 fn visit_local(&mut self, l: &hir::Local) {
209 if self.fcx.writeback_errors.get() {
213 let var_ty = self.fcx.local_ty(l.span, l.id);
214 let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
215 write_ty_to_tcx(self.tcx(), l.id, var_ty);
216 intravisit::walk_local(self, l);
219 fn visit_ty(&mut self, t: &hir::Ty) {
221 hir::TyFixedLengthVec(ref ty, ref count_expr) => {
222 self.visit_ty(&**ty);
223 write_ty_to_tcx(self.tcx(), count_expr.id, self.tcx().types.usize);
225 hir::TyBareFn(ref function_declaration) => {
226 intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
227 walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
229 _ => intravisit::walk_ty(self, t)
234 impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
235 fn visit_upvar_borrow_map(&self) {
236 if self.fcx.writeback_errors.get() {
240 for (upvar_id, upvar_capture) in self.fcx.inh.tables.borrow().upvar_capture_map.iter() {
241 let new_upvar_capture = match *upvar_capture {
242 ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
243 ty::UpvarCapture::ByRef(ref upvar_borrow) => {
244 let r = upvar_borrow.region;
245 let r = self.resolve(&r, ResolvingUpvar(*upvar_id));
246 ty::UpvarCapture::ByRef(
247 ty::UpvarBorrow { kind: upvar_borrow.kind, region: r })
250 debug!("Upvar capture for {:?} resolved to {:?}",
257 .insert(*upvar_id, new_upvar_capture);
261 fn visit_closures(&self) {
262 if self.fcx.writeback_errors.get() {
266 for (def_id, closure_ty) in self.fcx.inh.tables.borrow().closure_tys.iter() {
267 let closure_ty = self.resolve(closure_ty, ResolvingClosure(*def_id));
268 self.fcx.tcx().tables.borrow_mut().closure_tys.insert(*def_id, closure_ty);
271 for (def_id, &closure_kind) in self.fcx.inh.tables.borrow().closure_kinds.iter() {
272 self.fcx.tcx().tables.borrow_mut().closure_kinds.insert(*def_id, closure_kind);
276 fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
277 // Resolve any borrowings for the node with id `id`
278 self.visit_adjustments(reason, id);
280 // Resolve the type of the node with id `id`
281 let n_ty = self.fcx.node_ty(id);
282 let n_ty = self.resolve(&n_ty, reason);
283 write_ty_to_tcx(self.tcx(), id, n_ty);
284 debug!("Node {} has type {:?}", id, n_ty);
286 // Resolve any substitutions
287 self.fcx.opt_node_ty_substs(id, |item_substs| {
288 write_substs_to_tcx(self.tcx(), id,
289 self.resolve(item_substs, reason));
293 fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
294 let adjustments = self.fcx.inh.tables.borrow_mut().adjustments.remove(&id);
297 debug!("No adjustments for node {}", id);
300 Some(adjustment) => {
301 let resolved_adjustment = match adjustment {
302 adjustment::AdjustReifyFnPointer => {
303 adjustment::AdjustReifyFnPointer
306 adjustment::AdjustUnsafeFnPointer => {
307 adjustment::AdjustUnsafeFnPointer
310 adjustment::AdjustDerefRef(adj) => {
311 for autoderef in 0..adj.autoderefs {
312 let method_call = MethodCall::autoderef(id, autoderef as u32);
313 self.visit_method_map_entry(reason, method_call);
316 adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
317 autoderefs: adj.autoderefs,
318 autoref: self.resolve(&adj.autoref, reason),
319 unsize: self.resolve(&adj.unsize, reason),
323 debug!("Adjustments for node {}: {:?}", id, resolved_adjustment);
324 self.tcx().tables.borrow_mut().adjustments.insert(
325 id, resolved_adjustment);
330 fn visit_method_map_entry(&self,
331 reason: ResolveReason,
332 method_call: MethodCall) {
333 // Resolve any method map entry
334 let new_method = match self.fcx.inh.tables.borrow_mut().method_map.remove(&method_call) {
336 debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
339 let new_method = MethodCallee {
340 def_id: method.def_id,
341 ty: self.resolve(&method.ty, reason),
342 substs: self.tcx().mk_substs(self.resolve(method.substs, reason)),
350 //NB(jroesch): We need to match twice to avoid a double borrow which would cause an ICE
353 self.tcx().tables.borrow_mut().method_map.insert(
361 fn visit_liberated_fn_sigs(&self) {
362 for (&node_id, fn_sig) in self.fcx.inh.tables.borrow().liberated_fn_sigs.iter() {
363 let fn_sig = self.resolve(fn_sig, ResolvingFnSig(node_id));
364 self.tcx().tables.borrow_mut().liberated_fn_sigs.insert(node_id, fn_sig.clone());
368 fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
369 t.fold_with(&mut Resolver::new(self.fcx, reason))
373 ///////////////////////////////////////////////////////////////////////////
374 // Resolution reason.
376 #[derive(Copy, Clone)]
379 ResolvingLocal(Span),
380 ResolvingPattern(Span),
381 ResolvingUpvar(ty::UpvarId),
382 ResolvingClosure(DefId),
383 ResolvingFnSig(ast::NodeId),
387 fn span(&self, tcx: &ty::ctxt) -> Span {
389 ResolvingExpr(s) => s,
390 ResolvingLocal(s) => s,
391 ResolvingPattern(s) => s,
392 ResolvingUpvar(upvar_id) => {
393 tcx.expr_span(upvar_id.closure_expr_id)
395 ResolvingFnSig(id) => {
398 ResolvingClosure(did) => {
399 if let Some(node_id) = tcx.map.as_local_node_id(did) {
400 tcx.expr_span(node_id)
409 ///////////////////////////////////////////////////////////////////////////
410 // The Resolver. This is the type folding engine that detects
411 // unresolved types and so forth.
413 struct Resolver<'cx, 'tcx: 'cx> {
414 tcx: &'cx ty::ctxt<'tcx>,
415 infcx: &'cx infer::InferCtxt<'cx, 'tcx>,
416 writeback_errors: &'cx Cell<bool>,
417 reason: ResolveReason,
420 impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
421 fn new(fcx: &'cx FnCtxt<'cx, 'tcx>,
422 reason: ResolveReason)
423 -> Resolver<'cx, 'tcx>
425 Resolver::from_infcx(fcx.infcx(), &fcx.writeback_errors, reason)
428 fn from_infcx(infcx: &'cx infer::InferCtxt<'cx, 'tcx>,
429 writeback_errors: &'cx Cell<bool>,
430 reason: ResolveReason)
431 -> Resolver<'cx, 'tcx>
433 Resolver { infcx: infcx,
435 writeback_errors: writeback_errors,
439 fn report_error(&self, e: infer::FixupError) {
440 self.writeback_errors.set(true);
441 if !self.tcx.sess.has_errors() {
443 ResolvingExpr(span) => {
444 span_err!(self.tcx.sess, span, E0101,
445 "cannot determine a type for this expression: {}",
446 infer::fixup_err_to_string(e));
449 ResolvingLocal(span) => {
450 span_err!(self.tcx.sess, span, E0102,
451 "cannot determine a type for this local variable: {}",
452 infer::fixup_err_to_string(e));
455 ResolvingPattern(span) => {
456 span_err!(self.tcx.sess, span, E0103,
457 "cannot determine a type for this pattern binding: {}",
458 infer::fixup_err_to_string(e));
461 ResolvingUpvar(upvar_id) => {
462 let span = self.reason.span(self.tcx);
463 span_err!(self.tcx.sess, span, E0104,
464 "cannot resolve lifetime for captured variable `{}`: {}",
465 self.tcx.local_var_name_str(upvar_id.var_id).to_string(),
466 infer::fixup_err_to_string(e));
469 ResolvingClosure(_) => {
470 let span = self.reason.span(self.tcx);
471 span_err!(self.tcx.sess, span, E0196,
472 "cannot determine a type for this closure")
475 ResolvingFnSig(id) => {
476 // any failures here should also fail when
477 // resolving the patterns, closure types, or
479 let span = self.reason.span(self.tcx);
480 self.tcx.sess.delay_span_bug(
482 &format!("cannot resolve some aspect of fn sig for {:?}", id));
489 impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
490 fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
494 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
495 match self.infcx.fully_resolve(&t) {
498 debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable",
500 self.report_error(e);
506 fn fold_region(&mut self, r: ty::Region) -> ty::Region {
507 match self.infcx.fully_resolve(&r) {
510 self.report_error(e);
517 ///////////////////////////////////////////////////////////////////////////
518 // During type check, we store promises with the result of trait
519 // lookup rather than the actual results (because the results are not
520 // necessarily available immediately). These routines unwind the
521 // promises. It is expected that we will have already reported any
522 // errors that may be encountered, so if the promises store an error,
523 // a dummy result is returned.