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::ty_fold::{TypeFolder,TypeFoldable};
19 use middle::typeck::astconv::AstConv;
20 use middle::typeck::check::FnCtxt;
21 use middle::typeck::infer::{force_all, resolve_all, resolve_region};
22 use middle::typeck::infer::resolve_type;
23 use middle::typeck::infer;
24 use middle::typeck::{MethodCall, MethodCallee};
25 use middle::typeck::vtable_res;
26 use middle::typeck::write_substs_to_tcx;
27 use middle::typeck::write_ty_to_tcx;
28 use util::ppaux::Repr;
33 use syntax::codemap::{DUMMY_SP, Span};
34 use syntax::print::pprust::pat_to_string;
36 use syntax::visit::Visitor;
38 ///////////////////////////////////////////////////////////////////////////
39 // Entry point functions
41 pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) {
42 assert_eq!(fcx.writeback_errors.get(), false);
43 let mut wbcx = WritebackCx::new(fcx);
44 wbcx.visit_expr(e, ());
45 wbcx.visit_upvar_borrow_map();
46 wbcx.visit_unboxed_closure_types();
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_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, &*arg.pat) {
60 wbcx.visit_node_id(ResolvingPattern(arg.pat.span),
64 wbcx.visit_upvar_borrow_map();
65 wbcx.visit_unboxed_closure_types();
68 pub fn resolve_impl_res(infcx: &infer::InferCtxt,
70 vtable_res: &vtable_res)
72 let errors = Cell::new(false); // nobody cares
73 let mut resolver = Resolver::from_infcx(infcx,
75 ResolvingImplRes(span));
76 vtable_res.resolve_in(&mut resolver)
79 ///////////////////////////////////////////////////////////////////////////
80 // The Writerback context. This visitor walks the AST, checking the
81 // fn-specific tables to find references to types or regions. It
82 // resolves those regions to remove inference variables and writes the
83 // final result back into the master tables in the tcx. Here and
84 // there, it applies a few ad-hoc checks that were not convenient to
87 struct WritebackCx<'cx> {
88 fcx: &'cx FnCtxt<'cx>,
91 impl<'cx> WritebackCx<'cx> {
92 fn new(fcx: &'cx FnCtxt) -> WritebackCx<'cx> {
93 WritebackCx { fcx: fcx }
96 fn tcx(&self) -> &'cx ty::ctxt {
101 ///////////////////////////////////////////////////////////////////////////
102 // Impl of Visitor for Resolver
104 // This is the master code which walks the AST. It delegates most of
105 // the heavy lifting to the generic visit and resolve functions
106 // below. In general, a function is made into a `visitor` if it must
107 // traffic in node-ids or update tables in the type context etc.
109 impl<'cx> Visitor<()> for WritebackCx<'cx> {
110 fn visit_item(&mut self, _: &ast::Item, _: ()) {
114 fn visit_stmt(&mut self, s: &ast::Stmt, _: ()) {
115 if self.fcx.writeback_errors.get() {
119 self.visit_node_id(ResolvingExpr(s.span), ty::stmt_node_id(s));
120 visit::walk_stmt(self, s, ());
123 fn visit_expr(&mut self, e:&ast::Expr, _: ()) {
124 if self.fcx.writeback_errors.get() {
128 self.visit_node_id(ResolvingExpr(e.span), e.id);
129 self.visit_method_map_entry(ResolvingExpr(e.span),
130 MethodCall::expr(e.id));
131 self.visit_vtable_map_entry(ResolvingExpr(e.span),
132 MethodCall::expr(e.id));
135 ast::ExprFnBlock(ref decl, _) |
136 ast::ExprProc(ref decl, _) |
137 ast::ExprUnboxedFn(ref decl, _) => {
138 for input in decl.inputs.iter() {
139 let _ = self.visit_node_id(ResolvingExpr(e.span),
146 visit::walk_expr(self, e, ());
149 fn visit_block(&mut self, b: &ast::Block, _: ()) {
150 if self.fcx.writeback_errors.get() {
154 self.visit_node_id(ResolvingExpr(b.span), b.id);
155 visit::walk_block(self, b, ());
158 fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
159 if self.fcx.writeback_errors.get() {
163 self.visit_node_id(ResolvingPattern(p.span), p.id);
165 debug!("Type for pattern binding {} (id {}) resolved to {}",
168 ty::node_id_to_type(self.tcx(), p.id).repr(self.tcx()));
170 visit::walk_pat(self, p, ());
173 fn visit_local(&mut self, l: &ast::Local, _: ()) {
174 if self.fcx.writeback_errors.get() {
178 let var_ty = self.fcx.local_ty(l.span, l.id);
179 let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
180 write_ty_to_tcx(self.tcx(), l.id, var_ty);
181 visit::walk_local(self, l, ());
184 fn visit_ty(&mut self, t: &ast::Ty, _: ()) {
186 ast::TyFixedLengthVec(ref ty, ref count_expr) => {
187 self.visit_ty(&**ty, ());
188 write_ty_to_tcx(self.tcx(), count_expr.id, ty::mk_uint());
190 _ => visit::walk_ty(self, t, ())
195 impl<'cx> WritebackCx<'cx> {
196 fn visit_upvar_borrow_map(&self) {
197 if self.fcx.writeback_errors.get() {
201 for (upvar_id, upvar_borrow) in self.fcx.inh.upvar_borrow_map.borrow().iter() {
202 let r = upvar_borrow.region;
203 let r = self.resolve(&r, ResolvingUpvar(*upvar_id));
204 let new_upvar_borrow = ty::UpvarBorrow { kind: upvar_borrow.kind,
206 debug!("Upvar borrow for {} resolved to {}",
207 upvar_id.repr(self.tcx()),
208 new_upvar_borrow.repr(self.tcx()));
209 self.fcx.tcx().upvar_borrow_map.borrow_mut().insert(
210 *upvar_id, new_upvar_borrow);
214 fn visit_unboxed_closure_types(&self) {
215 if self.fcx.writeback_errors.get() {
219 for (def_id, closure_ty) in self.fcx
221 .unboxed_closure_types
224 let closure_ty = self.resolve(closure_ty,
225 ResolvingUnboxedClosure(*def_id));
228 .unboxed_closure_types
230 .insert(*def_id, closure_ty);
234 fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
235 // Resolve any borrowings for the node with id `id`
236 self.visit_adjustments(reason, id);
238 // Resolve the type of the node with id `id`
239 let n_ty = self.fcx.node_ty(id);
240 let n_ty = self.resolve(&n_ty, reason);
241 write_ty_to_tcx(self.tcx(), id, n_ty);
242 debug!("Node {} has type {}", id, n_ty.repr(self.tcx()));
244 // Resolve any substitutions
245 self.fcx.opt_node_ty_substs(id, |item_substs| {
246 write_substs_to_tcx(self.tcx(), id,
247 self.resolve(item_substs, reason));
251 fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
252 match self.fcx.inh.adjustments.borrow_mut().pop(&id) {
254 debug!("No adjustments for node {}", id);
257 Some(adjustment) => {
258 let resolved_adjustment = match adjustment {
259 ty::AutoAddEnv(store) => {
260 // FIXME(eddyb) #2190 Allow only statically resolved
261 // bare functions to coerce to a closure to avoid
262 // constructing (slower) indirect call wrappers.
263 match self.tcx().def_map.borrow().find(&id) {
264 Some(&def::DefFn(..)) |
265 Some(&def::DefStaticMethod(..)) |
266 Some(&def::DefVariant(..)) |
267 Some(&def::DefStruct(_)) => {
270 span_err!(self.tcx().sess, reason.span(self.tcx()), E0100,
271 "cannot coerce non-statically resolved bare fn");
275 ty::AutoAddEnv(self.resolve(&store, reason))
278 ty::AutoDerefRef(adj) => {
279 for autoderef in range(0, adj.autoderefs) {
280 let method_call = MethodCall::autoderef(id, autoderef);
281 self.visit_method_map_entry(reason, method_call);
282 self.visit_vtable_map_entry(reason, method_call);
285 ty::AutoDerefRef(ty::AutoDerefRef {
286 autoderefs: adj.autoderefs,
287 autoref: self.resolve(&adj.autoref, reason),
291 ty::AutoObject(trait_store, bb, def_id, substs) => {
292 let method_call = MethodCall::autoobject(id);
293 self.visit_method_map_entry(reason, method_call);
294 self.visit_vtable_map_entry(reason, method_call);
297 self.resolve(&trait_store, reason),
298 self.resolve(&bb, reason),
300 self.resolve(&substs, reason)
304 debug!("Adjustments for node {}: {:?}", id, resolved_adjustment);
305 self.tcx().adjustments.borrow_mut().insert(
306 id, resolved_adjustment);
311 fn visit_method_map_entry(&self,
312 reason: ResolveReason,
313 method_call: MethodCall) {
314 // Resolve any method map entry
315 match self.fcx.inh.method_map.borrow_mut().pop(&method_call) {
317 debug!("writeback::resolve_method_map_entry(call={:?}, entry={})",
319 method.repr(self.tcx()));
320 let new_method = MethodCallee {
321 origin: method.origin,
322 ty: self.resolve(&method.ty, reason),
323 substs: self.resolve(&method.substs, reason),
326 self.tcx().method_map.borrow_mut().insert(
334 fn visit_vtable_map_entry(&self,
335 reason: ResolveReason,
336 vtable_key: MethodCall) {
337 // Resolve any vtable map entry
338 match self.fcx.inh.vtable_map.borrow_mut().pop(&vtable_key) {
340 let r_origins = self.resolve(&origins, reason);
341 debug!("writeback::resolve_vtable_map_entry(\
342 vtable_key={}, vtables={:?})",
343 vtable_key, r_origins.repr(self.tcx()));
344 self.tcx().vtable_map.borrow_mut().insert(vtable_key, r_origins);
350 fn resolve<T:ResolveIn>(&self, t: &T, reason: ResolveReason) -> T {
351 t.resolve_in(&mut Resolver::new(self.fcx, reason))
355 ///////////////////////////////////////////////////////////////////////////
356 // Resolution reason.
360 ResolvingLocal(Span),
361 ResolvingPattern(Span),
362 ResolvingUpvar(ty::UpvarId),
363 ResolvingImplRes(Span),
364 ResolvingUnboxedClosure(ast::DefId),
368 fn span(&self, tcx: &ty::ctxt) -> Span {
370 ResolvingExpr(s) => s,
371 ResolvingLocal(s) => s,
372 ResolvingPattern(s) => s,
373 ResolvingUpvar(upvar_id) => {
374 ty::expr_span(tcx, upvar_id.closure_expr_id)
376 ResolvingImplRes(s) => s,
377 ResolvingUnboxedClosure(did) => {
378 if did.krate == ast::LOCAL_CRATE {
379 ty::expr_span(tcx, did.node)
388 ///////////////////////////////////////////////////////////////////////////
389 // Convenience methods for resolving different kinds of things.
392 fn resolve_in(&self, resolver: &mut Resolver) -> Self;
395 impl<T:TypeFoldable> ResolveIn for T {
396 fn resolve_in(&self, resolver: &mut Resolver) -> T {
397 self.fold_with(resolver)
401 ///////////////////////////////////////////////////////////////////////////
402 // The Resolver. This is the type folding engine that detects
403 // unresolved types and so forth.
405 struct Resolver<'cx> {
407 infcx: &'cx infer::InferCtxt<'cx>,
408 writeback_errors: &'cx Cell<bool>,
409 reason: ResolveReason,
412 impl<'cx> Resolver<'cx> {
413 fn new(fcx: &'cx FnCtxt<'cx>,
414 reason: ResolveReason)
417 Resolver { infcx: fcx.infcx(),
419 writeback_errors: &fcx.writeback_errors,
423 fn from_infcx(infcx: &'cx infer::InferCtxt<'cx>,
424 writeback_errors: &'cx Cell<bool>,
425 reason: ResolveReason)
428 Resolver { infcx: infcx,
430 writeback_errors: writeback_errors,
434 fn report_error(&self, e: infer::fixup_err) {
435 self.writeback_errors.set(true);
436 if !self.tcx.sess.has_errors() {
438 ResolvingExpr(span) => {
439 span_err!(self.tcx.sess, span, E0101,
440 "cannot determine a type for this expression: {}",
441 infer::fixup_err_to_string(e));
444 ResolvingLocal(span) => {
445 span_err!(self.tcx.sess, span, E0102,
446 "cannot determine a type for this local variable: {}",
447 infer::fixup_err_to_string(e));
450 ResolvingPattern(span) => {
451 span_err!(self.tcx.sess, span, E0103,
452 "cannot determine a type for this pattern binding: {}",
453 infer::fixup_err_to_string(e));
456 ResolvingUpvar(upvar_id) => {
457 let span = self.reason.span(self.tcx);
458 span_err!(self.tcx.sess, span, E0104,
459 "cannot resolve lifetime for captured variable `{}`: {}",
460 ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_string(),
461 infer::fixup_err_to_string(e));
464 ResolvingImplRes(span) => {
465 span_err!(self.tcx.sess, span, E0105,
466 "cannot determine a type for impl supertrait");
469 ResolvingUnboxedClosure(_) => {
470 let span = self.reason.span(self.tcx);
471 self.tcx.sess.span_err(span,
472 "cannot determine a type for this \
480 impl<'cx> TypeFolder for Resolver<'cx> {
481 fn tcx<'a>(&'a self) -> &'a ty::ctxt {
485 fn fold_ty(&mut self, t: ty::t) -> ty::t {
486 if !ty::type_needs_infer(t) {
490 match resolve_type(self.infcx, None, t, resolve_all | force_all) {
493 self.report_error(e);
499 fn fold_region(&mut self, r: ty::Region) -> ty::Region {
500 match resolve_region(self.infcx, r, resolve_all | force_all) {
503 self.report_error(e);