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::*;
20 use middle::ty::{mod, Ty, MethodCall, MethodCallee};
21 use middle::ty_fold::{TypeFolder,TypeFoldable};
22 use middle::infer::{force_all, resolve_all, resolve_region};
23 use middle::infer::resolve_type;
25 use write_substs_to_tcx;
27 use util::ppaux::Repr;
32 use syntax::codemap::{DUMMY_SP, Span};
33 use syntax::print::pprust::pat_to_string;
35 use syntax::visit::Visitor;
37 ///////////////////////////////////////////////////////////////////////////
38 // Entry point functions
40 pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) {
41 assert_eq!(fcx.writeback_errors.get(), false);
42 let mut wbcx = WritebackCx::new(fcx);
44 wbcx.visit_upvar_borrow_map();
45 wbcx.visit_unboxed_closures();
46 wbcx.visit_object_cast_map();
49 pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
52 assert_eq!(fcx.writeback_errors.get(), false);
53 let mut wbcx = WritebackCx::new(fcx);
54 wbcx.visit_block(blk);
55 for arg in decl.inputs.iter() {
56 wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
57 wbcx.visit_pat(&*arg.pat);
59 // Privacy needs the type for the whole pattern, not just each binding
60 if !pat_util::pat_is_binding(&fcx.tcx().def_map, &*arg.pat) {
61 wbcx.visit_node_id(ResolvingPattern(arg.pat.span),
65 wbcx.visit_upvar_borrow_map();
66 wbcx.visit_unboxed_closures();
67 wbcx.visit_object_cast_map();
70 ///////////////////////////////////////////////////////////////////////////
71 // The Writerback context. This visitor walks the AST, checking the
72 // fn-specific tables to find references to types or regions. It
73 // resolves those regions to remove inference variables and writes the
74 // final result back into the master tables in the tcx. Here and
75 // there, it applies a few ad-hoc checks that were not convenient to
78 struct WritebackCx<'cx, 'tcx: 'cx> {
79 fcx: &'cx FnCtxt<'cx, 'tcx>,
82 impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
83 fn new(fcx: &'cx FnCtxt<'cx, 'tcx>) -> WritebackCx<'cx, 'tcx> {
84 WritebackCx { fcx: fcx }
87 fn tcx(&self) -> &'cx ty::ctxt<'tcx> {
92 ///////////////////////////////////////////////////////////////////////////
93 // Impl of Visitor for Resolver
95 // This is the master code which walks the AST. It delegates most of
96 // the heavy lifting to the generic visit and resolve functions
97 // below. In general, a function is made into a `visitor` if it must
98 // traffic in node-ids or update tables in the type context etc.
100 impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
101 fn visit_item(&mut self, _: &ast::Item) {
105 fn visit_stmt(&mut self, s: &ast::Stmt) {
106 if self.fcx.writeback_errors.get() {
110 self.visit_node_id(ResolvingExpr(s.span), ty::stmt_node_id(s));
111 visit::walk_stmt(self, s);
114 fn visit_expr(&mut self, e: &ast::Expr) {
115 if self.fcx.writeback_errors.get() {
119 self.visit_node_id(ResolvingExpr(e.span), e.id);
120 self.visit_method_map_entry(ResolvingExpr(e.span),
121 MethodCall::expr(e.id));
124 ast::ExprClosure(_, _, ref decl, _) |
125 ast::ExprProc(ref decl, _) => {
126 for input in decl.inputs.iter() {
127 let _ = self.visit_node_id(ResolvingExpr(e.span),
134 visit::walk_expr(self, e);
137 fn visit_block(&mut self, b: &ast::Block) {
138 if self.fcx.writeback_errors.get() {
142 self.visit_node_id(ResolvingExpr(b.span), b.id);
143 visit::walk_block(self, b);
146 fn visit_pat(&mut self, p: &ast::Pat) {
147 if self.fcx.writeback_errors.get() {
151 self.visit_node_id(ResolvingPattern(p.span), p.id);
153 debug!("Type for pattern binding {} (id {}) resolved to {}",
156 ty::node_id_to_type(self.tcx(), p.id).repr(self.tcx()));
158 visit::walk_pat(self, p);
161 fn visit_local(&mut self, l: &ast::Local) {
162 if self.fcx.writeback_errors.get() {
166 let var_ty = self.fcx.local_ty(l.span, l.id);
167 let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
168 write_ty_to_tcx(self.tcx(), l.id, var_ty);
169 visit::walk_local(self, l);
172 fn visit_ty(&mut self, t: &ast::Ty) {
174 ast::TyFixedLengthVec(ref ty, ref count_expr) => {
175 self.visit_ty(&**ty);
176 write_ty_to_tcx(self.tcx(), count_expr.id, ty::mk_uint());
178 _ => visit::walk_ty(self, t)
183 impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
184 fn visit_upvar_borrow_map(&self) {
185 if self.fcx.writeback_errors.get() {
189 for (upvar_id, upvar_borrow) in self.fcx.inh.upvar_borrow_map.borrow().iter() {
190 let r = upvar_borrow.region;
191 let r = self.resolve(&r, ResolvingUpvar(*upvar_id));
192 let new_upvar_borrow = ty::UpvarBorrow { kind: upvar_borrow.kind,
194 debug!("Upvar borrow for {} resolved to {}",
195 upvar_id.repr(self.tcx()),
196 new_upvar_borrow.repr(self.tcx()));
197 self.fcx.tcx().upvar_borrow_map.borrow_mut().insert(
198 *upvar_id, new_upvar_borrow);
202 fn visit_unboxed_closures(&self) {
203 if self.fcx.writeback_errors.get() {
207 for (def_id, unboxed_closure) in self.fcx
212 let closure_ty = self.resolve(&unboxed_closure.closure_type,
213 ResolvingUnboxedClosure(*def_id));
214 let unboxed_closure = ty::UnboxedClosure {
215 closure_type: closure_ty,
216 kind: unboxed_closure.kind,
222 .insert(*def_id, unboxed_closure);
226 fn visit_object_cast_map(&self) {
227 if self.fcx.writeback_errors.get() {
231 for (&node_id, trait_ref) in self.fcx
237 let span = ty::expr_span(self.tcx(), node_id);
238 let reason = ResolvingExpr(span);
239 let closure_ty = self.resolve(trait_ref, reason);
243 .insert(node_id, closure_ty);
247 fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
248 // Resolve any borrowings for the node with id `id`
249 self.visit_adjustments(reason, id);
251 // Resolve the type of the node with id `id`
252 let n_ty = self.fcx.node_ty(id);
253 let n_ty = self.resolve(&n_ty, reason);
254 write_ty_to_tcx(self.tcx(), id, n_ty);
255 debug!("Node {} has type {}", id, n_ty.repr(self.tcx()));
257 // Resolve any substitutions
258 self.fcx.opt_node_ty_substs(id, |item_substs| {
259 write_substs_to_tcx(self.tcx(), id,
260 self.resolve(item_substs, reason));
264 fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
265 match self.fcx.inh.adjustments.borrow_mut().remove(&id) {
267 debug!("No adjustments for node {}", id);
270 Some(adjustment) => {
271 let adj_object = ty::adjust_is_object(&adjustment);
272 let resolved_adjustment = match adjustment {
273 ty::AdjustAddEnv(store) => {
274 // FIXME(eddyb) #2190 Allow only statically resolved
275 // bare functions to coerce to a closure to avoid
276 // constructing (slower) indirect call wrappers.
277 match self.tcx().def_map.borrow().get(&id) {
278 Some(&def::DefFn(..)) |
279 Some(&def::DefStaticMethod(..)) |
280 Some(&def::DefVariant(..)) |
281 Some(&def::DefStruct(_)) => {
284 span_err!(self.tcx().sess, reason.span(self.tcx()), E0100,
285 "cannot coerce non-statically resolved bare fn to closure");
286 span_help!(self.tcx().sess, reason.span(self.tcx()),
287 "consider embedding the function in a closure");
291 ty::AdjustAddEnv(self.resolve(&store, reason))
294 ty::AdjustDerefRef(adj) => {
295 for autoderef in range(0, adj.autoderefs) {
296 let method_call = MethodCall::autoderef(id, autoderef);
297 self.visit_method_map_entry(reason, method_call);
301 let method_call = MethodCall::autoobject(id);
302 self.visit_method_map_entry(reason, method_call);
305 ty::AdjustDerefRef(ty::AutoDerefRef {
306 autoderefs: adj.autoderefs,
307 autoref: self.resolve(&adj.autoref, reason),
311 debug!("Adjustments for node {}: {}", id, resolved_adjustment);
312 self.tcx().adjustments.borrow_mut().insert(
313 id, resolved_adjustment);
318 fn visit_method_map_entry(&self,
319 reason: ResolveReason,
320 method_call: MethodCall) {
321 // Resolve any method map entry
322 match self.fcx.inh.method_map.borrow_mut().remove(&method_call) {
324 debug!("writeback::resolve_method_map_entry(call={}, entry={})",
326 method.repr(self.tcx()));
327 let new_method = MethodCallee {
328 origin: self.resolve(&method.origin, reason),
329 ty: self.resolve(&method.ty, reason),
330 substs: self.resolve(&method.substs, reason),
333 self.tcx().method_map.borrow_mut().insert(
341 fn resolve<T:ResolveIn<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
342 t.resolve_in(&mut Resolver::new(self.fcx, reason))
346 ///////////////////////////////////////////////////////////////////////////
347 // Resolution reason.
351 ResolvingLocal(Span),
352 ResolvingPattern(Span),
353 ResolvingUpvar(ty::UpvarId),
354 ResolvingUnboxedClosure(ast::DefId),
358 fn span(&self, tcx: &ty::ctxt) -> Span {
360 ResolvingExpr(s) => s,
361 ResolvingLocal(s) => s,
362 ResolvingPattern(s) => s,
363 ResolvingUpvar(upvar_id) => {
364 ty::expr_span(tcx, upvar_id.closure_expr_id)
366 ResolvingUnboxedClosure(did) => {
367 if did.krate == ast::LOCAL_CRATE {
368 ty::expr_span(tcx, did.node)
377 ///////////////////////////////////////////////////////////////////////////
378 // Convenience methods for resolving different kinds of things.
380 trait ResolveIn<'tcx> {
381 fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> Self;
384 impl<'tcx, T: TypeFoldable<'tcx>> ResolveIn<'tcx> for T {
385 fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> T {
386 self.fold_with(resolver)
390 ///////////////////////////////////////////////////////////////////////////
391 // The Resolver. This is the type folding engine that detects
392 // unresolved types and so forth.
394 struct Resolver<'cx, 'tcx: 'cx> {
395 tcx: &'cx ty::ctxt<'tcx>,
396 infcx: &'cx infer::InferCtxt<'cx, 'tcx>,
397 writeback_errors: &'cx Cell<bool>,
398 reason: ResolveReason,
401 impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
402 fn new(fcx: &'cx FnCtxt<'cx, 'tcx>,
403 reason: ResolveReason)
404 -> Resolver<'cx, 'tcx>
406 Resolver::from_infcx(fcx.infcx(), &fcx.writeback_errors, reason)
409 fn from_infcx(infcx: &'cx infer::InferCtxt<'cx, 'tcx>,
410 writeback_errors: &'cx Cell<bool>,
411 reason: ResolveReason)
412 -> Resolver<'cx, 'tcx>
414 Resolver { infcx: infcx,
416 writeback_errors: writeback_errors,
420 fn report_error(&self, e: infer::fixup_err) {
421 self.writeback_errors.set(true);
422 if !self.tcx.sess.has_errors() {
424 ResolvingExpr(span) => {
425 span_err!(self.tcx.sess, span, E0101,
426 "cannot determine a type for this expression: {}",
427 infer::fixup_err_to_string(e));
430 ResolvingLocal(span) => {
431 span_err!(self.tcx.sess, span, E0102,
432 "cannot determine a type for this local variable: {}",
433 infer::fixup_err_to_string(e));
436 ResolvingPattern(span) => {
437 span_err!(self.tcx.sess, span, E0103,
438 "cannot determine a type for this pattern binding: {}",
439 infer::fixup_err_to_string(e));
442 ResolvingUpvar(upvar_id) => {
443 let span = self.reason.span(self.tcx);
444 span_err!(self.tcx.sess, span, E0104,
445 "cannot resolve lifetime for captured variable `{}`: {}",
446 ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_string(),
447 infer::fixup_err_to_string(e));
450 ResolvingUnboxedClosure(_) => {
451 let span = self.reason.span(self.tcx);
452 self.tcx.sess.span_err(span,
453 "cannot determine a type for this \
461 impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
462 fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
466 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
467 if !ty::type_needs_infer(t) {
471 match resolve_type(self.infcx, None, t, resolve_all | force_all) {
474 self.report_error(e);
480 fn fold_region(&mut self, r: ty::Region) -> ty::Region {
481 match resolve_region(self.infcx, r, resolve_all | force_all) {
484 self.report_error(e);
491 ///////////////////////////////////////////////////////////////////////////
492 // During type check, we store promises with the result of trait
493 // lookup rather than the actual results (because the results are not
494 // necessarily available immediately). These routines unwind the
495 // promises. It is expected that we will have already reported any
496 // errors that may be encountered, so if the promises store an error,
497 // a dummy result is returned.