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::MethodCallee;
24 use middle::typeck::{vtable_res, vtable_origin};
25 use middle::typeck::{vtable_static, vtable_param};
26 use middle::typeck::write_substs_to_tcx;
27 use middle::typeck::write_ty_to_tcx;
29 use util::ppaux::Repr;
32 use syntax::codemap::Span;
33 use syntax::print::pprust::pat_to_str;
35 use syntax::visit::Visitor;
37 fn resolve_type_vars_in_type(fcx: @FnCtxt, sp: Span, typ: ty::t)
39 if !ty::type_needs_infer(typ) { return Some(typ); }
40 match resolve_type(fcx.infcx(), typ, resolve_all | force_all) {
41 Ok(new_type) => return Some(new_type),
43 if !fcx.ccx.tcx.sess.has_errors() {
44 fcx.ccx.tcx.sess.span_err(
46 format!("cannot determine a type \
47 for this expression: {}",
48 infer::fixup_err_to_str(e)))
55 fn resolve_type_vars_in_types(fcx: @FnCtxt, sp: Span, tys: &[ty::t])
58 match resolve_type_vars_in_type(fcx, sp, *t) {
65 fn resolve_method_map_entry(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId) {
67 let tcx = fcx.ccx.tcx;
69 // Resolve any method map entry
70 match fcx.inh.method_map.borrow().get().find(&id) {
72 debug!("writeback::resolve_method_map_entry(id={:?}, entry={:?})",
73 id, method.repr(tcx));
74 let method_ty = match resolve_type_vars_in_type(fcx, sp, method.ty) {
81 let mut new_tps = ~[];
82 for &subst in method.substs.tps.iter() {
83 match resolve_type_vars_in_type(fcx, sp, subst) {
84 Some(t) => new_tps.push(t),
85 None => { wbcx.success = false; return; }
88 let new_method = MethodCallee {
89 origin: method.origin,
93 regions: ty::ErasedRegions,
97 fcx.ccx.method_map.borrow_mut().get().insert(id, new_method);
103 fn resolve_vtable_map_entry(fcx: @FnCtxt, sp: Span, id: ast::NodeId) {
104 // Resolve any vtable map entry
105 match fcx.inh.vtable_map.borrow().get().find_copy(&id) {
107 let r_origins = resolve_origins(fcx, sp, origins);
108 fcx.ccx.vtable_map.borrow_mut().get().insert(id, r_origins);
109 debug!("writeback::resolve_vtable_map_entry(id={}, vtables={:?})",
110 id, r_origins.repr(fcx.tcx()));
115 fn resolve_origins(fcx: @FnCtxt, sp: Span,
116 vtbls: vtable_res) -> vtable_res {
117 @vtbls.map(|os| @os.map(|o| resolve_origin(fcx, sp, o)))
120 fn resolve_origin(fcx: @FnCtxt,
122 origin: &vtable_origin) -> vtable_origin {
124 &vtable_static(def_id, ref tys, origins) => {
125 let r_tys = resolve_type_vars_in_types(fcx, sp, *tys);
126 let r_origins = resolve_origins(fcx, sp, origins);
127 vtable_static(def_id, r_tys, r_origins)
129 &vtable_param(n, b) => {
136 fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId)
139 let tcx = fcx.ccx.tcx;
141 // Resolve any borrowings for the node with id `id`
143 let adjustments = fcx.inh.adjustments.borrow();
144 adjustments.get().find_copy(&id)
149 Some(adjustment) => {
151 ty::AutoAddEnv(r, s) => {
152 match resolve_region(fcx.infcx(),
154 resolve_all | force_all) {
156 // This should not, I think, happen:
159 format!("cannot resolve bound for closure: \
161 infer::fixup_err_to_str(e)));
164 // FIXME(eddyb) #2190 Allow only statically resolved
165 // bare functions to coerce to a closure to avoid
166 // constructing (slower) indirect call wrappers.
168 let def_map = tcx.def_map.borrow();
169 match def_map.get().find(&id) {
170 Some(&ast::DefFn(..)) |
171 Some(&ast::DefStaticMethod(..)) |
172 Some(&ast::DefVariant(..)) |
173 Some(&ast::DefStruct(_)) => {}
174 _ => tcx.sess.span_err(sp,
175 "cannot coerce non-statically resolved bare fn")
179 let resolved_adj = @ty::AutoAddEnv(r1, s);
180 debug!("Adjustments for node {}: {:?}",
183 let mut adjustments = tcx.adjustments
185 adjustments.get().insert(id, resolved_adj);
190 ty::AutoDerefRef(adj) => {
191 let fixup_region = |r| {
192 match resolve_region(fcx.infcx(),
194 resolve_all | force_all) {
197 // This should not, I think, happen.
200 format!("cannot resolve scope of borrow: \
202 infer::fixup_err_to_str(e)));
208 let resolved_autoref = match adj.autoref {
210 Some(ref r) => Some(r.map_region(fixup_region))
213 let resolved_adj = @ty::AutoDerefRef(ty::AutoDerefRef {
214 autoderefs: adj.autoderefs,
215 autoref: resolved_autoref,
217 debug!("Adjustments for node {}: {:?}", id, resolved_adj);
218 let mut adjustments = tcx.adjustments.borrow_mut();
219 adjustments.get().insert(id, resolved_adj);
222 ty::AutoObject(..) => {
223 debug!("Adjustments for node {}: {:?}", id, adjustment);
224 let mut adjustments = tcx.adjustments.borrow_mut();
225 adjustments.get().insert(id, adjustment);
231 // Resolve the type of the node with id `id`
232 let n_ty = fcx.node_ty(id);
233 match resolve_type_vars_in_type(fcx, sp, n_ty) {
235 wbcx.success = false;
240 debug!("resolve_type_vars_for_node(id={}, n_ty={}, t={})",
241 id, ppaux::ty_to_str(tcx, n_ty), ppaux::ty_to_str(tcx, t));
242 write_ty_to_tcx(tcx, id, t);
243 let mut ret = Some(t);
244 fcx.opt_node_ty_substs(id, |substs| {
245 let mut new_tps = ~[];
246 for subst in substs.tps.iter() {
247 match resolve_type_vars_in_type(fcx, sp, *subst) {
248 Some(t) => new_tps.push(t),
249 None => { wbcx.success = false; ret = None; break }
252 write_substs_to_tcx(tcx, id, new_tps);
263 // As soon as we hit an error we have to stop resolving
264 // the entire function.
268 fn visit_stmt(s: &ast::Stmt, wbcx: &mut WbCtxt) {
269 if !wbcx.success { return; }
270 resolve_type_vars_for_node(wbcx, s.span, ty::stmt_node_id(s));
271 visit::walk_stmt(wbcx, s, ());
274 fn visit_expr(e: &ast::Expr, wbcx: &mut WbCtxt) {
279 resolve_type_vars_for_node(wbcx, e.span, e.id);
280 resolve_method_map_entry(wbcx, e.span, e.id);
281 resolve_vtable_map_entry(wbcx.fcx, e.span, e.id);
284 ast::ExprFnBlock(ref decl, _) | ast::ExprProc(ref decl, _) => {
285 for input in decl.inputs.iter() {
286 let _ = resolve_type_vars_for_node(wbcx, e.span, input.id);
292 visit::walk_expr(wbcx, e, ());
295 fn visit_block(b: &ast::Block, wbcx: &mut WbCtxt) {
300 resolve_type_vars_for_node(wbcx, b.span, b.id);
301 visit::walk_block(wbcx, b, ());
304 fn visit_pat(p: &ast::Pat, wbcx: &mut WbCtxt) {
309 resolve_type_vars_for_node(wbcx, p.span, p.id);
310 debug!("Type for pattern binding {} (id {}) resolved to {}",
312 wbcx.fcx.infcx().ty_to_str(
313 ty::node_id_to_type(wbcx.fcx.ccx.tcx,
315 visit::walk_pat(wbcx, p, ());
318 fn visit_local(l: &ast::Local, wbcx: &mut WbCtxt) {
319 if !wbcx.success { return; }
320 let var_ty = wbcx.fcx.local_ty(l.span, l.id);
321 match resolve_type(wbcx.fcx.infcx(), var_ty, resolve_all | force_all) {
323 debug!("Type for local {} (id {}) resolved to {}",
326 wbcx.fcx.infcx().ty_to_str(lty));
327 write_ty_to_tcx(wbcx.fcx.ccx.tcx, l.id, lty);
330 wbcx.fcx.ccx.tcx.sess.span_err(
332 format!("cannot determine a type \
333 for this local variable: {}",
334 infer::fixup_err_to_str(e)));
335 wbcx.success = false;
338 visit::walk_local(wbcx, l, ());
340 fn visit_item(_item: &ast::Item, _wbcx: &mut WbCtxt) {
344 impl Visitor<()> for WbCtxt {
345 fn visit_item(&mut self, i: &ast::Item, _: ()) { visit_item(i, self); }
346 fn visit_stmt(&mut self, s: &ast::Stmt, _: ()) { visit_stmt(s, self); }
347 fn visit_expr(&mut self, ex:&ast::Expr, _: ()) { visit_expr(ex, self); }
348 fn visit_block(&mut self, b: &ast::Block, _: ()) { visit_block(b, self); }
349 fn visit_pat(&mut self, p: &ast::Pat, _: ()) { visit_pat(p, self); }
350 fn visit_local(&mut self, l: &ast::Local, _: ()) { visit_local(l, self); }
351 // FIXME(#10894) should continue recursing
352 fn visit_ty(&mut self, _t: &ast::Ty, _: ()) {}
355 fn resolve_upvar_borrow_map(wbcx: &mut WbCtxt) {
362 let upvar_borrow_map = fcx.inh.upvar_borrow_map.borrow();
363 for (upvar_id, upvar_borrow) in upvar_borrow_map.get().iter() {
364 let r = upvar_borrow.region;
365 match resolve_region(fcx.infcx(), r, resolve_all | force_all) {
367 let new_upvar_borrow = ty::UpvarBorrow {
368 kind: upvar_borrow.kind,
371 debug!("Upvar borrow for {} resolved to {}",
372 upvar_id.repr(tcx), new_upvar_borrow.repr(tcx));
373 let mut tcx_upvar_borrow_map = tcx.upvar_borrow_map.borrow_mut();
374 tcx_upvar_borrow_map.get().insert(*upvar_id, new_upvar_borrow);
377 let span = ty::expr_span(tcx, upvar_id.closure_expr_id);
378 fcx.ccx.tcx.sess.span_err(
379 span, format!("cannot resolve lifetime for \
380 captured variable `{}`: {}",
381 ty::local_var_name_str(tcx, upvar_id.var_id).get().to_str(),
382 infer::fixup_err_to_str(e)));
383 wbcx.success = false;
389 pub fn resolve_type_vars_in_expr(fcx: @FnCtxt, e: &ast::Expr) -> bool {
390 let mut wbcx = WbCtxt { fcx: fcx, success: true };
391 let wbcx = &mut wbcx;
392 wbcx.visit_expr(e, ());
393 resolve_upvar_borrow_map(wbcx);
397 pub fn resolve_type_vars_in_fn(fcx: @FnCtxt, decl: &ast::FnDecl,
398 blk: &ast::Block) -> bool {
399 let mut wbcx = WbCtxt { fcx: fcx, success: true };
400 let wbcx = &mut wbcx;
401 wbcx.visit_block(blk, ());
402 for arg in decl.inputs.iter() {
403 wbcx.visit_pat(arg.pat, ());
404 // Privacy needs the type for the whole pattern, not just each binding
405 if !pat_util::pat_is_binding(fcx.tcx().def_map, arg.pat) {
406 resolve_type_vars_for_node(wbcx, arg.pat.span, arg.pat.id);
409 resolve_upvar_borrow_map(wbcx);