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::*;
19 use middle::ty::{mod, Ty, MethodCall, MethodCallee};
20 use middle::ty_fold::{TypeFolder,TypeFoldable};
22 use write_substs_to_tcx;
24 use util::ppaux::Repr;
29 use syntax::codemap::{DUMMY_SP, Span};
30 use syntax::print::pprust::pat_to_string;
32 use syntax::visit::Visitor;
34 ///////////////////////////////////////////////////////////////////////////
35 // Entry point functions
37 pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) {
38 assert_eq!(fcx.writeback_errors.get(), false);
39 let mut wbcx = WritebackCx::new(fcx);
41 wbcx.visit_upvar_borrow_map();
42 wbcx.visit_unboxed_closures();
43 wbcx.visit_object_cast_map();
46 pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
49 assert_eq!(fcx.writeback_errors.get(), false);
50 let mut wbcx = WritebackCx::new(fcx);
51 wbcx.visit_block(blk);
52 for arg in decl.inputs.iter() {
53 wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
54 wbcx.visit_pat(&*arg.pat);
56 // Privacy needs the type for the whole pattern, not just each binding
57 if !pat_util::pat_is_binding(&fcx.tcx().def_map, &*arg.pat) {
58 wbcx.visit_node_id(ResolvingPattern(arg.pat.span),
62 wbcx.visit_upvar_borrow_map();
63 wbcx.visit_unboxed_closures();
64 wbcx.visit_object_cast_map();
67 ///////////////////////////////////////////////////////////////////////////
68 // The Writerback context. This visitor walks the AST, checking the
69 // fn-specific tables to find references to types or regions. It
70 // resolves those regions to remove inference variables and writes the
71 // final result back into the master tables in the tcx. Here and
72 // there, it applies a few ad-hoc checks that were not convenient to
75 struct WritebackCx<'cx, 'tcx: 'cx> {
76 fcx: &'cx FnCtxt<'cx, 'tcx>,
79 impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
80 fn new(fcx: &'cx FnCtxt<'cx, 'tcx>) -> WritebackCx<'cx, 'tcx> {
81 WritebackCx { fcx: fcx }
84 fn tcx(&self) -> &'cx ty::ctxt<'tcx> {
89 ///////////////////////////////////////////////////////////////////////////
90 // Impl of Visitor for Resolver
92 // This is the master code which walks the AST. It delegates most of
93 // the heavy lifting to the generic visit and resolve functions
94 // below. In general, a function is made into a `visitor` if it must
95 // traffic in node-ids or update tables in the type context etc.
97 impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
98 fn visit_item(&mut self, _: &ast::Item) {
102 fn visit_stmt(&mut self, s: &ast::Stmt) {
103 if self.fcx.writeback_errors.get() {
107 self.visit_node_id(ResolvingExpr(s.span), ty::stmt_node_id(s));
108 visit::walk_stmt(self, s);
111 fn visit_expr(&mut self, e: &ast::Expr) {
112 if self.fcx.writeback_errors.get() {
116 self.visit_node_id(ResolvingExpr(e.span), e.id);
117 self.visit_method_map_entry(ResolvingExpr(e.span),
118 MethodCall::expr(e.id));
121 ast::ExprClosure(_, _, ref decl, _) => {
122 for input in decl.inputs.iter() {
123 let _ = self.visit_node_id(ResolvingExpr(e.span),
130 visit::walk_expr(self, e);
133 fn visit_block(&mut self, b: &ast::Block) {
134 if self.fcx.writeback_errors.get() {
138 self.visit_node_id(ResolvingExpr(b.span), b.id);
139 visit::walk_block(self, b);
142 fn visit_pat(&mut self, p: &ast::Pat) {
143 if self.fcx.writeback_errors.get() {
147 self.visit_node_id(ResolvingPattern(p.span), p.id);
149 debug!("Type for pattern binding {} (id {}) resolved to {}",
152 ty::node_id_to_type(self.tcx(), p.id).repr(self.tcx()));
154 visit::walk_pat(self, p);
157 fn visit_local(&mut self, l: &ast::Local) {
158 if self.fcx.writeback_errors.get() {
162 let var_ty = self.fcx.local_ty(l.span, l.id);
163 let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
164 write_ty_to_tcx(self.tcx(), l.id, var_ty);
165 visit::walk_local(self, l);
168 fn visit_ty(&mut self, t: &ast::Ty) {
170 ast::TyFixedLengthVec(ref ty, ref count_expr) => {
171 self.visit_ty(&**ty);
172 write_ty_to_tcx(self.tcx(), count_expr.id, self.tcx().types.uint);
174 _ => visit::walk_ty(self, t)
179 impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
180 fn visit_upvar_borrow_map(&self) {
181 if self.fcx.writeback_errors.get() {
185 for (upvar_id, upvar_borrow) in self.fcx.inh.upvar_borrow_map.borrow().iter() {
186 let r = upvar_borrow.region;
187 let r = self.resolve(&r, ResolvingUpvar(*upvar_id));
188 let new_upvar_borrow = ty::UpvarBorrow { kind: upvar_borrow.kind,
190 debug!("Upvar borrow for {} resolved to {}",
191 upvar_id.repr(self.tcx()),
192 new_upvar_borrow.repr(self.tcx()));
193 self.fcx.tcx().upvar_borrow_map.borrow_mut().insert(
194 *upvar_id, new_upvar_borrow);
198 fn visit_unboxed_closures(&self) {
199 if self.fcx.writeback_errors.get() {
203 for (def_id, unboxed_closure) in self.fcx
208 let closure_ty = self.resolve(&unboxed_closure.closure_type,
209 ResolvingUnboxedClosure(*def_id));
210 let unboxed_closure = ty::UnboxedClosure {
211 closure_type: closure_ty,
212 kind: unboxed_closure.kind,
218 .insert(*def_id, unboxed_closure);
222 fn visit_object_cast_map(&self) {
223 if self.fcx.writeback_errors.get() {
227 for (&node_id, trait_ref) in self.fcx
233 let span = ty::expr_span(self.tcx(), node_id);
234 let reason = ResolvingExpr(span);
235 let closure_ty = self.resolve(trait_ref, reason);
239 .insert(node_id, closure_ty);
243 fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
244 // Resolve any borrowings for the node with id `id`
245 self.visit_adjustments(reason, id);
247 // Resolve the type of the node with id `id`
248 let n_ty = self.fcx.node_ty(id);
249 let n_ty = self.resolve(&n_ty, reason);
250 write_ty_to_tcx(self.tcx(), id, n_ty);
251 debug!("Node {} has type {}", id, n_ty.repr(self.tcx()));
253 // Resolve any substitutions
254 self.fcx.opt_node_ty_substs(id, |item_substs| {
255 write_substs_to_tcx(self.tcx(), id,
256 self.resolve(item_substs, reason));
260 fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
261 match self.fcx.inh.adjustments.borrow_mut().remove(&id) {
263 debug!("No adjustments for node {}", id);
266 Some(adjustment) => {
267 let adj_object = ty::adjust_is_object(&adjustment);
268 let resolved_adjustment = match adjustment {
269 ty::AdjustAddEnv(def_id, store) => {
270 ty::AdjustAddEnv(def_id, self.resolve(&store, reason))
273 ty::AdjustReifyFnPointer(def_id) => {
274 ty::AdjustReifyFnPointer(def_id)
277 ty::AdjustDerefRef(adj) => {
278 for autoderef in range(0, adj.autoderefs) {
279 let method_call = MethodCall::autoderef(id, autoderef);
280 self.visit_method_map_entry(reason, method_call);
284 let method_call = MethodCall::autoobject(id);
285 self.visit_method_map_entry(reason, method_call);
288 ty::AdjustDerefRef(ty::AutoDerefRef {
289 autoderefs: adj.autoderefs,
290 autoref: self.resolve(&adj.autoref, reason),
294 debug!("Adjustments for node {}: {}", id, resolved_adjustment);
295 self.tcx().adjustments.borrow_mut().insert(
296 id, resolved_adjustment);
301 fn visit_method_map_entry(&self,
302 reason: ResolveReason,
303 method_call: MethodCall) {
304 // Resolve any method map entry
305 match self.fcx.inh.method_map.borrow_mut().remove(&method_call) {
307 debug!("writeback::resolve_method_map_entry(call={}, entry={})",
309 method.repr(self.tcx()));
310 let new_method = MethodCallee {
311 origin: self.resolve(&method.origin, reason),
312 ty: self.resolve(&method.ty, reason),
313 substs: self.resolve(&method.substs, reason),
316 self.tcx().method_map.borrow_mut().insert(
324 fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
325 t.fold_with(&mut Resolver::new(self.fcx, reason))
329 ///////////////////////////////////////////////////////////////////////////
330 // Resolution reason.
335 ResolvingLocal(Span),
336 ResolvingPattern(Span),
337 ResolvingUpvar(ty::UpvarId),
338 ResolvingUnboxedClosure(ast::DefId),
342 fn span(&self, tcx: &ty::ctxt) -> Span {
344 ResolvingExpr(s) => s,
345 ResolvingLocal(s) => s,
346 ResolvingPattern(s) => s,
347 ResolvingUpvar(upvar_id) => {
348 ty::expr_span(tcx, upvar_id.closure_expr_id)
350 ResolvingUnboxedClosure(did) => {
351 if did.krate == ast::LOCAL_CRATE {
352 ty::expr_span(tcx, did.node)
361 ///////////////////////////////////////////////////////////////////////////
362 // The Resolver. This is the type folding engine that detects
363 // unresolved types and so forth.
365 struct Resolver<'cx, 'tcx: 'cx> {
366 tcx: &'cx ty::ctxt<'tcx>,
367 infcx: &'cx infer::InferCtxt<'cx, 'tcx>,
368 writeback_errors: &'cx Cell<bool>,
369 reason: ResolveReason,
372 impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
373 fn new(fcx: &'cx FnCtxt<'cx, 'tcx>,
374 reason: ResolveReason)
375 -> Resolver<'cx, 'tcx>
377 Resolver::from_infcx(fcx.infcx(), &fcx.writeback_errors, reason)
380 fn from_infcx(infcx: &'cx infer::InferCtxt<'cx, 'tcx>,
381 writeback_errors: &'cx Cell<bool>,
382 reason: ResolveReason)
383 -> Resolver<'cx, 'tcx>
385 Resolver { infcx: infcx,
387 writeback_errors: writeback_errors,
391 fn report_error(&self, e: infer::fixup_err) {
392 self.writeback_errors.set(true);
393 if !self.tcx.sess.has_errors() {
395 ResolvingExpr(span) => {
396 span_err!(self.tcx.sess, span, E0101,
397 "cannot determine a type for this expression: {}",
398 infer::fixup_err_to_string(e));
401 ResolvingLocal(span) => {
402 span_err!(self.tcx.sess, span, E0102,
403 "cannot determine a type for this local variable: {}",
404 infer::fixup_err_to_string(e));
407 ResolvingPattern(span) => {
408 span_err!(self.tcx.sess, span, E0103,
409 "cannot determine a type for this pattern binding: {}",
410 infer::fixup_err_to_string(e));
413 ResolvingUpvar(upvar_id) => {
414 let span = self.reason.span(self.tcx);
415 span_err!(self.tcx.sess, span, E0104,
416 "cannot resolve lifetime for captured variable `{}`: {}",
417 ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_string(),
418 infer::fixup_err_to_string(e));
421 ResolvingUnboxedClosure(_) => {
422 let span = self.reason.span(self.tcx);
423 self.tcx.sess.span_err(span,
424 "cannot determine a type for this \
432 impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
433 fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
437 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
438 match self.infcx.fully_resolve(&t) {
441 debug!("Resolver::fold_ty: input type `{}` not fully resolvable",
443 self.report_error(e);
449 fn fold_region(&mut self, r: ty::Region) -> ty::Region {
450 match self.infcx.fully_resolve(&r) {
453 self.report_error(e);
460 ///////////////////////////////////////////////////////////////////////////
461 // During type check, we store promises with the result of trait
462 // lookup rather than the actual results (because the results are not
463 // necessarily available immediately). These routines unwind the
464 // promises. It is expected that we will have already reported any
465 // errors that may be encountered, so if the promises store an error,
466 // a dummy result is returned.