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.
4 //
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.
10
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
13 // substitutions.
14
15
16 use middle::pat_util;
17 use middle::ty;
18 use middle::ty_fold::TypeFolder;
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_origin, vtable_static, vtable_param};
26 use middle::typeck::write_substs_to_tcx;
27 use middle::typeck::write_ty_to_tcx;
28 use util::ppaux::Repr;
29
30 use syntax::ast;
31 use syntax::codemap::Span;
32 use syntax::print::pprust::pat_to_str;
33 use syntax::visit;
34 use syntax::visit::Visitor;
35
36 ///////////////////////////////////////////////////////////////////////////
37 // Entry point functions
38
39 pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) {
40 assert_eq!(fcx.writeback_errors.get(), false);
41 let mut wbcx = WritebackCx::new(fcx);
42 wbcx.visit_expr(e, ());
43 wbcx.visit_upvar_borrow_map();
44 }
45
46 pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
47 decl: &ast::FnDecl,
48 blk: &ast::Block) {
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_pat(arg.pat, ());
54
55 // Privacy needs the type for the whole pattern, not just each binding
56 if !pat_util::pat_is_binding(&fcx.tcx().def_map, arg.pat) {
57 wbcx.visit_node_id(ResolvingPattern(arg.pat.span),
58 arg.pat.id);
59 }
60 }
61 wbcx.visit_upvar_borrow_map();
62 }
63
64 ///////////////////////////////////////////////////////////////////////////
65 // The Writerback context. This visitor walks the AST, checking the
66 // fn-specific tables to find references to types or regions. It
67 // resolves those regions to remove inference variables and writes the
68 // final result back into the master tables in the tcx. Here and
69 // there, it applies a few ad-hoc checks that were not convenient to
70 // do elsewhere.
71
72 struct WritebackCx<'cx> {
73 fcx: &'cx FnCtxt<'cx>,
74 }
75
76 impl<'cx> WritebackCx<'cx> {
77 fn new(fcx: &'cx FnCtxt) -> WritebackCx<'cx> {
78 WritebackCx { fcx: fcx }
79 }
80
81 fn tcx(&self) -> &'cx ty::ctxt {
82 self.fcx.tcx()
83 }
84 }
85
86 ///////////////////////////////////////////////////////////////////////////
87 // Impl of Visitor for Resolver
88 //
89 // This is the master code which walks the AST. It delegates most of
90 // the heavy lifting to the generic visit and resolve functions
91 // below. In general, a function is made into a `visitor` if it must
92 // traffic in node-ids or update tables in the type context etc.
93
94 impl<'cx> Visitor<()> for WritebackCx<'cx> {
95 fn visit_item(&mut self, _: &ast::Item, _: ()) {
96 // Ignore items
97 }
98
99 fn visit_stmt(&mut self, s: &ast::Stmt, _: ()) {
100 if self.fcx.writeback_errors.get() {
101 return;
102 }
103
104 self.visit_node_id(ResolvingExpr(s.span), ty::stmt_node_id(s));
105 visit::walk_stmt(self, s, ());
106 }
107
108 fn visit_expr(&mut self, e:&ast::Expr, _: ()) {
109 if self.fcx.writeback_errors.get() {
110 return;
111 }
112
113 self.visit_node_id(ResolvingExpr(e.span), e.id);
114 self.visit_method_map_entry(ResolvingExpr(e.span),
115 MethodCall::expr(e.id));
116 self.visit_vtable_map_entry(ResolvingExpr(e.span),
117 MethodCall::expr(e.id));
118
119 match e.node {
120 ast::ExprFnBlock(ref decl, _) | ast::ExprProc(ref decl, _) => {
121 for input in decl.inputs.iter() {
122 let _ = self.visit_node_id(ResolvingExpr(e.span),
123 input.id);
124 }
125 }
126 _ => {}
127 }
128
129 visit::walk_expr(self, e, ());
130 }
131
132 fn visit_block(&mut self, b: &ast::Block, _: ()) {
133 if self.fcx.writeback_errors.get() {
134 return;
135 }
136
137 self.visit_node_id(ResolvingExpr(b.span), b.id);
138 visit::walk_block(self, b, ());
139 }
140
141 fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
142 if self.fcx.writeback_errors.get() {
143 return;
144 }
145
146 self.visit_node_id(ResolvingPattern(p.span), p.id);
147
148 debug!("Type for pattern binding {} (id {}) resolved to {}",
149 pat_to_str(p),
150 p.id,
151 ty::node_id_to_type(self.tcx(), p.id).repr(self.tcx()));
152
153 visit::walk_pat(self, p, ());
154 }
155
156 fn visit_local(&mut self, l: &ast::Local, _: ()) {
157 if self.fcx.writeback_errors.get() {
158 return;
159 }
160
161 let var_ty = self.fcx.local_ty(l.span, l.id);
162 let var_ty = var_ty.resolve(self.fcx, ResolvingLocal(l.span));
163 write_ty_to_tcx(self.tcx(), l.id, var_ty);
164 visit::walk_local(self, l, ());
165 }
166
167 fn visit_ty(&mut self, _t: &ast::Ty, _: ()) {
168 // ignore
169 }
170 }
171
172 impl<'cx> WritebackCx<'cx> {
173 fn visit_upvar_borrow_map(&self) {
174 if self.fcx.writeback_errors.get() {
175 return;
176 }
177
178 for (upvar_id, upvar_borrow) in self.fcx.inh.upvar_borrow_map.borrow().iter() {
179 let r = upvar_borrow.region;
180 let r = r.resolve(self.fcx, ResolvingUpvar(*upvar_id));
181 let new_upvar_borrow = ty::UpvarBorrow { kind: upvar_borrow.kind,
182 region: r };
183 debug!("Upvar borrow for {} resolved to {}",
184 upvar_id.repr(self.tcx()),
185 new_upvar_borrow.repr(self.tcx()));
186 self.fcx.tcx().upvar_borrow_map.borrow_mut().insert(
187 *upvar_id, new_upvar_borrow);
188 }
189 }
190
191 fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
192 // Resolve any borrowings for the node with id `id`
193 self.visit_adjustments(reason, id);
194
195 // Resolve the type of the node with id `id`
196 let n_ty = self.fcx.node_ty(id);
197 let n_ty = n_ty.resolve(self.fcx, reason);
198 write_ty_to_tcx(self.tcx(), id, n_ty);
199 debug!("Node {} has type {}", id, n_ty.repr(self.tcx()));
200
201 // Resolve any substitutions
202 self.fcx.opt_node_ty_substs(id, |node_substs| {
203 let mut new_tps = Vec::new();
204 for subst in node_substs.tps.iter() {
205 new_tps.push(subst.resolve(self.fcx, reason));
206 }
207 write_substs_to_tcx(self.tcx(), id, new_tps);
208 });
209 }
210
211 fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
212 match self.fcx.inh.adjustments.borrow_mut().pop(&id) {
213 None => {
214 debug!("No adjustments for node {}", id);
215 }
216
217 Some(adjustment) => {
218 let resolved_adjustment = match adjustment {
219 ty::AutoAddEnv(store) => {
220 // FIXME(eddyb) #2190 Allow only statically resolved
221 // bare functions to coerce to a closure to avoid
222 // constructing (slower) indirect call wrappers.
223 match self.tcx().def_map.borrow().find(&id) {
224 Some(&ast::DefFn(..)) |
225 Some(&ast::DefStaticMethod(..)) |
226 Some(&ast::DefVariant(..)) |
227 Some(&ast::DefStruct(_)) => {
228 }
229 _ => {
230 self.tcx().sess.span_err(
231 reason.span(self.fcx),
232 "cannot coerce non-statically resolved bare fn")
233 }
234 }
235
236 ty::AutoAddEnv(store.resolve(self.fcx, reason))
237 }
238
239 ty::AutoDerefRef(adj) => {
240 for autoderef in range(0, adj.autoderefs) {
241 let method_call = MethodCall::autoderef(id, autoderef as u32);
242 self.visit_method_map_entry(reason, method_call);
243 self.visit_vtable_map_entry(reason, method_call);
244 }
245
246 ty::AutoDerefRef(ty::AutoDerefRef {
247 autoderefs: adj.autoderefs,
248 autoref: adj.autoref.resolve(self.fcx, reason),
249 })
250 }
251
252 adjustment => adjustment
253 };
254 debug!("Adjustments for node {}: {:?}", id, resolved_adjustment);
255 self.tcx().adjustments.borrow_mut().insert(
256 id, resolved_adjustment);
257 }
258 }
259 }
260
261 fn visit_method_map_entry(&self,
262 reason: ResolveReason,
263 method_call: MethodCall) {
264 // Resolve any method map entry
265 match self.fcx.inh.method_map.borrow_mut().pop(&method_call) {
266 Some(method) => {
267 debug!("writeback::resolve_method_map_entry(call={:?}, entry={})",
268 method_call,
269 method.repr(self.tcx()));
270 let mut new_method = MethodCallee {
271 origin: method.origin,
272 ty: method.ty.resolve(self.fcx, reason),
273 substs: method.substs.resolve(self.fcx, reason),
274 };
275
276 // Wack. For some reason I don't quite know, we always
277 // hard-code the self-ty and regions to these
278 // values. Changing this causes downstream errors I
279 // don't feel like investigating right now (in
280 // particular, self_ty is set to mk_err in some cases,
281 // probably for invocations on objects, and this
282 // causes encoding failures). -nmatsakis
283 new_method.substs.self_ty = None;
284 new_method.substs.regions = ty::ErasedRegions;
285
286 self.tcx().method_map.borrow_mut().insert(
287 method_call,
288 new_method);
289 }
290 None => {}
291 }
292 }
293
294 fn visit_vtable_map_entry(&self,
295 reason: ResolveReason,
296 vtable_key: MethodCall) {
297 // Resolve any vtable map entry
298 match self.fcx.inh.vtable_map.borrow_mut().pop(&vtable_key) {
299 Some(origins) => {
300 let r_origins = origins.resolve(self.fcx, reason);
301 debug!("writeback::resolve_vtable_map_entry(\
302 vtable_key={}, vtables={:?})",
303 vtable_key, r_origins.repr(self.tcx()));
304 self.tcx().vtable_map.borrow_mut().insert(vtable_key, r_origins);
305 }
306 None => {}
307 }
308 }
309 }
310
311 ///////////////////////////////////////////////////////////////////////////
312 // Resolution reason.
313
314 enum ResolveReason {
315 ResolvingExpr(Span),
316 ResolvingLocal(Span),
317 ResolvingPattern(Span),
318 ResolvingUpvar(ty::UpvarId)
319 }
320
321 impl ResolveReason {
322 fn span(&self, fcx: &FnCtxt) -> Span {
323 match *self {
324 ResolvingExpr(s) => s,
325 ResolvingLocal(s) => s,
326 ResolvingPattern(s) => s,
327 ResolvingUpvar(upvar_id) => {
328 ty::expr_span(fcx.tcx(), upvar_id.closure_expr_id)
329 }
330 }
331 }
332 }
333
334 ///////////////////////////////////////////////////////////////////////////
335 // Convenience methods for resolving different kinds of things.
336
337 trait Resolve {
338 fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> Self;
339 }
340
341 impl<T:Resolve> Resolve for Option<T> {
342 fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> Option<T> {
343 self.as_ref().map(|t| t.resolve(fcx, reason))
344 }
345 }
346
347 impl<T:Resolve> Resolve for Vec<T> {
348 fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> Vec<T> {
349 self.iter().map(|t| t.resolve(fcx, reason)).collect()
350 }
351 }
352
353 impl Resolve for ty::TraitStore {
354 fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::TraitStore {
355 Resolver::new(fcx, reason).fold_trait_store(*self)
356 }
357 }
358
359 impl Resolve for ty::t {
360 fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::t {
361 Resolver::new(fcx, reason).fold_ty(*self)
362 }
363 }
364
365 impl Resolve for ty::Region {
366 fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::Region {
367 Resolver::new(fcx, reason).fold_region(*self)
368 }
369 }
370
371 impl Resolve for ty::substs {
372 fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::substs {
373 Resolver::new(fcx, reason).fold_substs(self)
374 }
375 }
376
377 impl Resolve for ty::AutoRef {
378 fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::AutoRef {
379 Resolver::new(fcx, reason).fold_autoref(self)
380 }
381 }
382
383 impl Resolve for vtable_origin {
384 fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> vtable_origin {
385 match *self {
386 vtable_static(def_id, ref tys, ref origins) => {
387 let r_tys = tys.resolve(fcx, reason);
388 let r_origins = origins.resolve(fcx, reason);
389 vtable_static(def_id, r_tys, r_origins)
390 }
391 vtable_param(n, b) => {
392 vtable_param(n, b)
393 }
394 }
395 }
396 }
397
398 ///////////////////////////////////////////////////////////////////////////
399 // The Resolver. This is the type folding engine that detects
400 // unresolved types and so forth.
401
402 struct Resolver<'cx> {
403 fcx: &'cx FnCtxt<'cx>,
404 reason: ResolveReason,
405 }
406
407 impl<'cx> Resolver<'cx> {
408 fn new(fcx: &'cx FnCtxt<'cx>,
409 reason: ResolveReason)
410 -> Resolver<'cx>
411 {
412 Resolver { fcx: fcx, reason: reason }
413 }
414
415 fn report_error(&self, e: infer::fixup_err) {
416 self.fcx.writeback_errors.set(true);
417 if !self.tcx().sess.has_errors() {
418 match self.reason {
419 ResolvingExpr(span) => {
420 self.tcx().sess.span_err(
421 span,
422 format!("cannot determine a type for \
423 this expression: {}",
424 infer::fixup_err_to_str(e)))
425 }
426
427 ResolvingLocal(span) => {
428 self.tcx().sess.span_err(
429 span,
430 format!("cannot determine a type for \
431 this local variable: {}",
432 infer::fixup_err_to_str(e)))
433 }
434
435 ResolvingPattern(span) => {
436 self.tcx().sess.span_err(
437 span,
438 format!("cannot determine a type for \
439 this pattern binding: {}",
440 infer::fixup_err_to_str(e)))
441 }
442
443 ResolvingUpvar(upvar_id) => {
444 let span = self.reason.span(self.fcx);
445 self.tcx().sess.span_err(
446 span,
447 format!("cannot resolve lifetime for \
448 captured variable `{}`: {}",
449 ty::local_var_name_str(
450 self.tcx(),
451 upvar_id.var_id).get().to_str(),
452 infer::fixup_err_to_str(e)));
453 }
454 }
455 }
456 }
457 }
458
459 impl<'cx> TypeFolder for Resolver<'cx> {
460 fn tcx<'a>(&'a self) -> &'a ty::ctxt {
461 self.fcx.tcx()
462 }
463
464 fn fold_ty(&mut self, t: ty::t) -> ty::t {
465 if !ty::type_needs_infer(t) {
466 return t;
467 }
468
469 match resolve_type(self.fcx.infcx(), t, resolve_all | force_all) {
470 Ok(t) => t,
471 Err(e) => {
472 self.report_error(e);
473 ty::mk_err()
474 }
475 }
476 }
477
478 fn fold_region(&mut self, r: ty::Region) -> ty::Region {
479 match resolve_region(self.fcx.infcx(), r, resolve_all | force_all) {
480 Ok(r) => r,
481 Err(e) => {
482 self.report_error(e);
483 ty::ReStatic
484 }
485 }
486 }
487 }
librustc/middle/typeck/check/writeback.rs:71:1-71:1 -struct- definition:
struct WritebackCx<'cx> {
fcx: &'cx FnCtxt<'cx>,
}
references:- 577: fn new(fcx: &'cx FnCtxt) -> WritebackCx<'cx> {
78: WritebackCx { fcx: fcx }
79: }
--
172: impl<'cx> WritebackCx<'cx> {
173: fn visit_upvar_borrow_map(&self) {
librustc/middle/typeck/check/writeback.rs:313:1-313:1 -enum- definition:
enum ResolveReason {
ResolvingExpr(Span),
ResolvingLocal(Span),
references:- 16359: impl Resolve for ty::t {
360: fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::t {
361: Resolver::new(fcx, reason).fold_ty(*self)
--
408: fn new(fcx: &'cx FnCtxt<'cx>,
409: reason: ResolveReason)
410: -> Resolver<'cx>
librustc/middle/typeck/check/writeback.rs:336:1-336:1 -trait- definition:
trait Resolve {
fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> Self;
}
references:- 11359: impl Resolve for ty::t {
360: fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::t {
--
365: impl Resolve for ty::Region {
366: fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::Region {
--
383: impl Resolve for vtable_origin {
384: fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> vtable_origin {
librustc/middle/typeck/check/writeback.rs:401:1-401:1 -struct- definition:
struct Resolver<'cx> {
fcx: &'cx FnCtxt<'cx>,
reason: ResolveReason,
references:- 4411: {
412: Resolver { fcx: fcx, reason: reason }
413: }
--
459: impl<'cx> TypeFolder for Resolver<'cx> {
460: fn tcx<'a>(&'a self) -> &'a ty::ctxt {