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.
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
18 use middle::typeck::astconv::AstConv;
19 use middle::typeck::check::FnCtxt;
20 use middle::typeck::infer::{force_all, resolve_all, resolve_region};
21 use middle::typeck::infer::resolve_type;
22 use middle::typeck::infer;
23 use middle::typeck::{MethodCall, MethodCallee};
24 use middle::typeck::{vtable_res, vtable_static, vtable_param};
25 use middle::typeck::write_substs_to_tcx;
26 use middle::typeck::write_ty_to_tcx;
28 use util::ppaux::Repr;
31 use syntax::codemap::Span;
32 use syntax::print::pprust::pat_to_str;
34 use syntax::visit::Visitor;
36 fn resolve_type_vars_in_type(fcx: &FnCtxt, sp: Span, typ: ty::t)
38 if !ty::type_needs_infer(typ) { return Some(typ); }
39 match resolve_type(fcx.infcx(), typ, resolve_all | force_all) {
40 Ok(new_type) => return Some(new_type),
42 if !fcx.ccx.tcx.sess.has_errors() {
43 fcx.ccx.tcx.sess.span_err(
45 format!("cannot determine a type \
46 for this expression: {}",
47 infer::fixup_err_to_str(e)))
54 fn resolve_type_vars_in_types(fcx: &FnCtxt, sp: Span, tys: &[ty::t])
57 match resolve_type_vars_in_type(fcx, sp, *t) {
64 fn resolve_method_map_entry(wbcx: &mut WbCtxt, sp: Span, method_call: MethodCall) {
66 let tcx = fcx.ccx.tcx;
68 // Resolve any method map entry
69 match fcx.inh.method_map.borrow().find(&method_call) {
71 debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
72 method_call, method.repr(tcx));
73 let method_ty = match resolve_type_vars_in_type(fcx, sp, method.ty) {
80 let mut new_tps = Vec::new();
81 for &subst in method.substs.tps.iter() {
82 match resolve_type_vars_in_type(fcx, sp, subst) {
83 Some(t) => new_tps.push(t),
84 None => { wbcx.success = false; return; }
87 let new_method = MethodCallee {
88 origin: method.origin,
92 regions: ty::ErasedRegions,
96 fcx.ccx.method_map.borrow_mut().insert(method_call, new_method);
102 fn resolve_vtable_map_entry(fcx: &FnCtxt, sp: Span, vtable_key: MethodCall) {
103 // Resolve any vtable map entry
104 match fcx.inh.vtable_map.borrow().find_copy(&vtable_key) {
106 let r_origins = resolve_origins(fcx, sp, origins);
107 fcx.ccx.vtable_map.borrow_mut().insert(vtable_key, r_origins);
108 debug!("writeback::resolve_vtable_map_entry(vtable_key={}, vtables={:?})",
109 vtable_key, r_origins.repr(fcx.tcx()));
114 fn resolve_origins(fcx: &FnCtxt, sp: Span,
115 vtbls: vtable_res) -> vtable_res {
116 @vtbls.map(|os| @os.map(|origin| {
118 &vtable_static(def_id, ref tys, origins) => {
119 let r_tys = resolve_type_vars_in_types(fcx,
122 let r_origins = resolve_origins(fcx, sp, origins);
123 vtable_static(def_id, r_tys, r_origins)
125 &vtable_param(n, b) => {
133 fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId)
136 let tcx = fcx.ccx.tcx;
138 // Resolve any borrowings for the node with id `id`
139 match fcx.inh.adjustments.borrow().find_copy(&id) {
142 Some(adjustment) => {
144 ty::AutoAddEnv(r, s) => {
145 match resolve_region(fcx.infcx(),
147 resolve_all | force_all) {
149 // This should not, I think, happen:
152 format!("cannot resolve bound for closure: \
154 infer::fixup_err_to_str(e)));
157 // FIXME(eddyb) #2190 Allow only statically resolved
158 // bare functions to coerce to a closure to avoid
159 // constructing (slower) indirect call wrappers.
160 match tcx.def_map.borrow().find(&id) {
161 Some(&ast::DefFn(..)) |
162 Some(&ast::DefStaticMethod(..)) |
163 Some(&ast::DefVariant(..)) |
164 Some(&ast::DefStruct(_)) => {}
165 _ => tcx.sess.span_err(sp,
166 "cannot coerce non-statically resolved bare fn")
169 let resolved_adj = @ty::AutoAddEnv(r1, s);
170 debug!("Adjustments for node {}: {:?}",
172 tcx.adjustments.borrow_mut().insert(id, resolved_adj);
177 ty::AutoDerefRef(adj) => {
178 for autoderef in range(0, adj.autoderefs) {
179 let method_call = MethodCall::autoderef(id, autoderef as u32);
180 resolve_method_map_entry(wbcx, sp, method_call);
181 resolve_vtable_map_entry(wbcx.fcx, sp, method_call);
184 let fixup_region = |r| {
185 match resolve_region(fcx.infcx(),
187 resolve_all | force_all) {
190 // This should not, I think, happen.
193 format!("cannot resolve scope of borrow: \
195 infer::fixup_err_to_str(e)));
201 let resolved_autoref = match adj.autoref {
203 Some(ref r) => Some(r.map_region(fixup_region))
206 let resolved_adj = @ty::AutoDerefRef(ty::AutoDerefRef {
207 autoderefs: adj.autoderefs,
208 autoref: resolved_autoref,
210 debug!("Adjustments for node {}: {:?}", id, resolved_adj);
211 tcx.adjustments.borrow_mut().insert(id, resolved_adj);
214 ty::AutoObject(..) => {
215 debug!("Adjustments for node {}: {:?}", id, adjustment);
216 tcx.adjustments.borrow_mut().insert(id, adjustment);
222 // Resolve the type of the node with id `id`
223 let n_ty = fcx.node_ty(id);
224 match resolve_type_vars_in_type(fcx, sp, n_ty) {
226 wbcx.success = false;
231 debug!("resolve_type_vars_for_node(id={}, n_ty={}, t={})",
232 id, ppaux::ty_to_str(tcx, n_ty), ppaux::ty_to_str(tcx, t));
233 write_ty_to_tcx(tcx, id, t);
234 let mut ret = Some(t);
235 fcx.opt_node_ty_substs(id, |substs| {
236 let mut new_tps = Vec::new();
237 for subst in substs.tps.iter() {
238 match resolve_type_vars_in_type(fcx, sp, *subst) {
239 Some(t) => new_tps.push(t),
240 None => { wbcx.success = false; ret = None; break }
243 write_substs_to_tcx(tcx, id, new_tps);
254 // As soon as we hit an error we have to stop resolving
255 // the entire function.
259 fn visit_stmt(s: &ast::Stmt, wbcx: &mut WbCtxt) {
260 if !wbcx.success { return; }
261 resolve_type_vars_for_node(wbcx, s.span, ty::stmt_node_id(s));
262 visit::walk_stmt(wbcx, s, ());
265 fn visit_expr(e: &ast::Expr, wbcx: &mut WbCtxt) {
270 resolve_type_vars_for_node(wbcx, e.span, e.id);
271 resolve_method_map_entry(wbcx, e.span, MethodCall::expr(e.id));
272 resolve_vtable_map_entry(wbcx.fcx, e.span, MethodCall::expr(e.id));
275 ast::ExprFnBlock(ref decl, _) | ast::ExprProc(ref decl, _) => {
276 for input in decl.inputs.iter() {
277 let _ = resolve_type_vars_for_node(wbcx, e.span, input.id);
283 visit::walk_expr(wbcx, e, ());
286 fn visit_block(b: &ast::Block, wbcx: &mut WbCtxt) {
291 resolve_type_vars_for_node(wbcx, b.span, b.id);
292 visit::walk_block(wbcx, b, ());
295 fn visit_pat(p: &ast::Pat, wbcx: &mut WbCtxt) {
300 resolve_type_vars_for_node(wbcx, p.span, p.id);
301 debug!("Type for pattern binding {} (id {}) resolved to {}",
303 wbcx.fcx.infcx().ty_to_str(
304 ty::node_id_to_type(wbcx.fcx.ccx.tcx,
306 visit::walk_pat(wbcx, p, ());
309 fn visit_local(l: &ast::Local, wbcx: &mut WbCtxt) {
310 if !wbcx.success { return; }
311 let var_ty = wbcx.fcx.local_ty(l.span, l.id);
312 match resolve_type(wbcx.fcx.infcx(), var_ty, resolve_all | force_all) {
314 debug!("Type for local {} (id {}) resolved to {}",
317 wbcx.fcx.infcx().ty_to_str(lty));
318 write_ty_to_tcx(wbcx.fcx.ccx.tcx, l.id, lty);
321 wbcx.fcx.ccx.tcx.sess.span_err(
323 format!("cannot determine a type \
324 for this local variable: {}",
325 infer::fixup_err_to_str(e)));
326 wbcx.success = false;
329 visit::walk_local(wbcx, l, ());
331 fn visit_item(_item: &ast::Item, _wbcx: &mut WbCtxt) {
335 impl<'a> Visitor<()> for WbCtxt<'a> {
336 fn visit_item(&mut self, i: &ast::Item, _: ()) { visit_item(i, self); }
337 fn visit_stmt(&mut self, s: &ast::Stmt, _: ()) { visit_stmt(s, self); }
338 fn visit_expr(&mut self, ex:&ast::Expr, _: ()) { visit_expr(ex, self); }
339 fn visit_block(&mut self, b: &ast::Block, _: ()) { visit_block(b, self); }
340 fn visit_pat(&mut self, p: &ast::Pat, _: ()) { visit_pat(p, self); }
341 fn visit_local(&mut self, l: &ast::Local, _: ()) { visit_local(l, self); }
342 // FIXME(#10894) should continue recursing
343 fn visit_ty(&mut self, _t: &ast::Ty, _: ()) {}
346 fn resolve_upvar_borrow_map(wbcx: &mut WbCtxt) {
353 for (upvar_id, upvar_borrow) in fcx.inh.upvar_borrow_map.borrow().iter() {
354 let r = upvar_borrow.region;
355 match resolve_region(fcx.infcx(), r, resolve_all | force_all) {
357 let new_upvar_borrow = ty::UpvarBorrow {
358 kind: upvar_borrow.kind,
361 debug!("Upvar borrow for {} resolved to {}",
362 upvar_id.repr(tcx), new_upvar_borrow.repr(tcx));
363 tcx.upvar_borrow_map.borrow_mut().insert(*upvar_id,
367 let span = ty::expr_span(tcx, upvar_id.closure_expr_id);
368 fcx.ccx.tcx.sess.span_err(
369 span, format!("cannot resolve lifetime for \
370 captured variable `{}`: {}",
371 ty::local_var_name_str(tcx, upvar_id.var_id).get().to_str(),
372 infer::fixup_err_to_str(e)));
373 wbcx.success = false;
379 pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) -> bool {
380 let mut wbcx = WbCtxt { fcx: fcx, success: true };
381 let wbcx = &mut wbcx;
382 wbcx.visit_expr(e, ());
383 resolve_upvar_borrow_map(wbcx);
387 pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, decl: &ast::FnDecl,
388 blk: &ast::Block) -> bool {
389 let mut wbcx = WbCtxt { fcx: fcx, success: true };
390 let wbcx = &mut wbcx;
391 wbcx.visit_block(blk, ());
392 for arg in decl.inputs.iter() {
393 wbcx.visit_pat(arg.pat, ());
394 // Privacy needs the type for the whole pattern, not just each binding
395 if !pat_util::pat_is_binding(fcx.tcx().def_map, arg.pat) {
396 resolve_type_vars_for_node(wbcx, arg.pat.span, arg.pat.id);
399 resolve_upvar_borrow_map(wbcx);