]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/writeback.rs
Merge pull request #20510 from tshepang/patch-6
[rust.git] / src / librustc_typeck / check / writeback.rs
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.
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 use self::ResolveReason::*;
15
16 use astconv::AstConv;
17 use check::FnCtxt;
18 use middle::pat_util;
19 use middle::ty::{self, Ty, MethodCall, MethodCallee};
20 use middle::ty_fold::{TypeFolder,TypeFoldable};
21 use middle::infer;
22 use write_substs_to_tcx;
23 use write_ty_to_tcx;
24 use util::ppaux::Repr;
25
26 use std::cell::Cell;
27
28 use syntax::ast;
29 use syntax::codemap::{DUMMY_SP, Span};
30 use syntax::print::pprust::pat_to_string;
31 use syntax::visit;
32 use syntax::visit::Visitor;
33
34 ///////////////////////////////////////////////////////////////////////////
35 // Entry point functions
36
37 pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) {
38     assert_eq!(fcx.writeback_errors.get(), false);
39     let mut wbcx = WritebackCx::new(fcx);
40     wbcx.visit_expr(e);
41     wbcx.visit_upvar_borrow_map();
42     wbcx.visit_unboxed_closures();
43     wbcx.visit_object_cast_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_node_id(ResolvingPattern(arg.pat.span), arg.id);
54         wbcx.visit_pat(&*arg.pat);
55
56         // Privacy needs the type for the whole pattern, not just each binding
57         if !pat_util::pat_is_binding(&fcx.tcx().def_map, &*arg.pat) {
58             wbcx.visit_node_id(ResolvingPattern(arg.pat.span),
59                                arg.pat.id);
60         }
61     }
62     wbcx.visit_upvar_borrow_map();
63     wbcx.visit_unboxed_closures();
64     wbcx.visit_object_cast_map();
65 }
66
67 ///////////////////////////////////////////////////////////////////////////
68 // The Writerback context. This visitor walks the AST, checking the
69 // fn-specific tables to find references to types or regions. It
70 // resolves those regions to remove inference variables and writes the
71 // final result back into the master tables in the tcx. Here and
72 // there, it applies a few ad-hoc checks that were not convenient to
73 // do elsewhere.
74
75 struct WritebackCx<'cx, 'tcx: 'cx> {
76     fcx: &'cx FnCtxt<'cx, 'tcx>,
77 }
78
79 impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
80     fn new(fcx: &'cx FnCtxt<'cx, 'tcx>) -> WritebackCx<'cx, 'tcx> {
81         WritebackCx { fcx: fcx }
82     }
83
84     fn tcx(&self) -> &'cx ty::ctxt<'tcx> {
85         self.fcx.tcx()
86     }
87 }
88
89 ///////////////////////////////////////////////////////////////////////////
90 // Impl of Visitor for Resolver
91 //
92 // This is the master code which walks the AST. It delegates most of
93 // the heavy lifting to the generic visit and resolve functions
94 // below. In general, a function is made into a `visitor` if it must
95 // traffic in node-ids or update tables in the type context etc.
96
97 impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
98     fn visit_item(&mut self, _: &ast::Item) {
99         // Ignore items
100     }
101
102     fn visit_stmt(&mut self, s: &ast::Stmt) {
103         if self.fcx.writeback_errors.get() {
104             return;
105         }
106
107         self.visit_node_id(ResolvingExpr(s.span), ty::stmt_node_id(s));
108         visit::walk_stmt(self, s);
109     }
110
111     fn visit_expr(&mut self, e: &ast::Expr) {
112         if self.fcx.writeback_errors.get() {
113             return;
114         }
115
116         self.visit_node_id(ResolvingExpr(e.span), e.id);
117         self.visit_method_map_entry(ResolvingExpr(e.span),
118                                     MethodCall::expr(e.id));
119
120         match e.node {
121             ast::ExprClosure(_, _, ref decl, _) => {
122                 for input in decl.inputs.iter() {
123                     let _ = self.visit_node_id(ResolvingExpr(e.span),
124                                                input.id);
125                 }
126             }
127             _ => {}
128         }
129
130         visit::walk_expr(self, e);
131     }
132
133     fn visit_block(&mut self, b: &ast::Block) {
134         if self.fcx.writeback_errors.get() {
135             return;
136         }
137
138         self.visit_node_id(ResolvingExpr(b.span), b.id);
139         visit::walk_block(self, b);
140     }
141
142     fn visit_pat(&mut self, p: &ast::Pat) {
143         if self.fcx.writeback_errors.get() {
144             return;
145         }
146
147         self.visit_node_id(ResolvingPattern(p.span), p.id);
148
149         debug!("Type for pattern binding {} (id {}) resolved to {}",
150                pat_to_string(p),
151                p.id,
152                ty::node_id_to_type(self.tcx(), p.id).repr(self.tcx()));
153
154         visit::walk_pat(self, p);
155     }
156
157     fn visit_local(&mut self, l: &ast::Local) {
158         if self.fcx.writeback_errors.get() {
159             return;
160         }
161
162         let var_ty = self.fcx.local_ty(l.span, l.id);
163         let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
164         write_ty_to_tcx(self.tcx(), l.id, var_ty);
165         visit::walk_local(self, l);
166     }
167
168     fn visit_ty(&mut self, t: &ast::Ty) {
169         match t.node {
170             ast::TyFixedLengthVec(ref ty, ref count_expr) => {
171                 self.visit_ty(&**ty);
172                 write_ty_to_tcx(self.tcx(), count_expr.id, self.tcx().types.uint);
173             }
174             _ => visit::walk_ty(self, t)
175         }
176     }
177 }
178
179 impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
180     fn visit_upvar_borrow_map(&self) {
181         if self.fcx.writeback_errors.get() {
182             return;
183         }
184
185         for (upvar_id, upvar_borrow) in self.fcx.inh.upvar_borrow_map.borrow().iter() {
186             let r = upvar_borrow.region;
187             let r = self.resolve(&r, ResolvingUpvar(*upvar_id));
188             let new_upvar_borrow = ty::UpvarBorrow { kind: upvar_borrow.kind,
189                                                      region: r };
190             debug!("Upvar borrow for {} resolved to {}",
191                    upvar_id.repr(self.tcx()),
192                    new_upvar_borrow.repr(self.tcx()));
193             self.fcx.tcx().upvar_borrow_map.borrow_mut().insert(
194                 *upvar_id, new_upvar_borrow);
195         }
196     }
197
198     fn visit_unboxed_closures(&self) {
199         if self.fcx.writeback_errors.get() {
200             return
201         }
202
203         for (def_id, unboxed_closure) in self.fcx
204                                              .inh
205                                              .unboxed_closures
206                                              .borrow()
207                                              .iter() {
208             let closure_ty = self.resolve(&unboxed_closure.closure_type,
209                                           ResolvingUnboxedClosure(*def_id));
210             let unboxed_closure = ty::UnboxedClosure {
211                 closure_type: closure_ty,
212                 kind: unboxed_closure.kind,
213             };
214             self.fcx
215                 .tcx()
216                 .unboxed_closures
217                 .borrow_mut()
218                 .insert(*def_id, unboxed_closure);
219         }
220     }
221
222     fn visit_object_cast_map(&self) {
223         if self.fcx.writeback_errors.get() {
224             return
225         }
226
227         for (&node_id, trait_ref) in self.fcx
228                                             .inh
229                                             .object_cast_map
230                                             .borrow()
231                                             .iter()
232         {
233             let span = ty::expr_span(self.tcx(), node_id);
234             let reason = ResolvingExpr(span);
235             let closure_ty = self.resolve(trait_ref, reason);
236             self.tcx()
237                 .object_cast_map
238                 .borrow_mut()
239                 .insert(node_id, closure_ty);
240         }
241     }
242
243     fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
244         // Resolve any borrowings for the node with id `id`
245         self.visit_adjustments(reason, id);
246
247         // Resolve the type of the node with id `id`
248         let n_ty = self.fcx.node_ty(id);
249         let n_ty = self.resolve(&n_ty, reason);
250         write_ty_to_tcx(self.tcx(), id, n_ty);
251         debug!("Node {} has type {}", id, n_ty.repr(self.tcx()));
252
253         // Resolve any substitutions
254         self.fcx.opt_node_ty_substs(id, |item_substs| {
255             write_substs_to_tcx(self.tcx(), id,
256                                 self.resolve(item_substs, reason));
257         });
258     }
259
260     fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
261         match self.fcx.inh.adjustments.borrow_mut().remove(&id) {
262             None => {
263                 debug!("No adjustments for node {}", id);
264             }
265
266             Some(adjustment) => {
267                 let adj_object = ty::adjust_is_object(&adjustment);
268                 let resolved_adjustment = match adjustment {
269                     ty::AdjustAddEnv(def_id, store) => {
270                         ty::AdjustAddEnv(def_id, self.resolve(&store, reason))
271                     }
272
273                     ty::AdjustReifyFnPointer(def_id) => {
274                         ty::AdjustReifyFnPointer(def_id)
275                     }
276
277                     ty::AdjustDerefRef(adj) => {
278                         for autoderef in range(0, adj.autoderefs) {
279                             let method_call = MethodCall::autoderef(id, autoderef);
280                             self.visit_method_map_entry(reason, method_call);
281                         }
282
283                         if adj_object {
284                             let method_call = MethodCall::autoobject(id);
285                             self.visit_method_map_entry(reason, method_call);
286                         }
287
288                         ty::AdjustDerefRef(ty::AutoDerefRef {
289                             autoderefs: adj.autoderefs,
290                             autoref: self.resolve(&adj.autoref, reason),
291                         })
292                     }
293                 };
294                 debug!("Adjustments for node {}: {}", id, resolved_adjustment);
295                 self.tcx().adjustments.borrow_mut().insert(
296                     id, resolved_adjustment);
297             }
298         }
299     }
300
301     fn visit_method_map_entry(&self,
302                               reason: ResolveReason,
303                               method_call: MethodCall) {
304         // Resolve any method map entry
305         match self.fcx.inh.method_map.borrow_mut().remove(&method_call) {
306             Some(method) => {
307                 debug!("writeback::resolve_method_map_entry(call={}, entry={})",
308                        method_call,
309                        method.repr(self.tcx()));
310                 let new_method = MethodCallee {
311                     origin: self.resolve(&method.origin, reason),
312                     ty: self.resolve(&method.ty, reason),
313                     substs: self.resolve(&method.substs, reason),
314                 };
315
316                 self.tcx().method_map.borrow_mut().insert(
317                     method_call,
318                     new_method);
319             }
320             None => {}
321         }
322     }
323
324     fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
325         t.fold_with(&mut Resolver::new(self.fcx, reason))
326     }
327 }
328
329 ///////////////////////////////////////////////////////////////////////////
330 // Resolution reason.
331
332 #[derive(Copy)]
333 enum ResolveReason {
334     ResolvingExpr(Span),
335     ResolvingLocal(Span),
336     ResolvingPattern(Span),
337     ResolvingUpvar(ty::UpvarId),
338     ResolvingUnboxedClosure(ast::DefId),
339 }
340
341 impl ResolveReason {
342     fn span(&self, tcx: &ty::ctxt) -> Span {
343         match *self {
344             ResolvingExpr(s) => s,
345             ResolvingLocal(s) => s,
346             ResolvingPattern(s) => s,
347             ResolvingUpvar(upvar_id) => {
348                 ty::expr_span(tcx, upvar_id.closure_expr_id)
349             }
350             ResolvingUnboxedClosure(did) => {
351                 if did.krate == ast::LOCAL_CRATE {
352                     ty::expr_span(tcx, did.node)
353                 } else {
354                     DUMMY_SP
355                 }
356             }
357         }
358     }
359 }
360
361 ///////////////////////////////////////////////////////////////////////////
362 // The Resolver. This is the type folding engine that detects
363 // unresolved types and so forth.
364
365 struct Resolver<'cx, 'tcx: 'cx> {
366     tcx: &'cx ty::ctxt<'tcx>,
367     infcx: &'cx infer::InferCtxt<'cx, 'tcx>,
368     writeback_errors: &'cx Cell<bool>,
369     reason: ResolveReason,
370 }
371
372 impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
373     fn new(fcx: &'cx FnCtxt<'cx, 'tcx>,
374            reason: ResolveReason)
375            -> Resolver<'cx, 'tcx>
376     {
377         Resolver::from_infcx(fcx.infcx(), &fcx.writeback_errors, reason)
378     }
379
380     fn from_infcx(infcx: &'cx infer::InferCtxt<'cx, 'tcx>,
381                   writeback_errors: &'cx Cell<bool>,
382                   reason: ResolveReason)
383                   -> Resolver<'cx, 'tcx>
384     {
385         Resolver { infcx: infcx,
386                    tcx: infcx.tcx,
387                    writeback_errors: writeback_errors,
388                    reason: reason }
389     }
390
391     fn report_error(&self, e: infer::fixup_err) {
392         self.writeback_errors.set(true);
393         if !self.tcx.sess.has_errors() {
394             match self.reason {
395                 ResolvingExpr(span) => {
396                     span_err!(self.tcx.sess, span, E0101,
397                         "cannot determine a type for this expression: {}",
398                         infer::fixup_err_to_string(e));
399                 }
400
401                 ResolvingLocal(span) => {
402                     span_err!(self.tcx.sess, span, E0102,
403                         "cannot determine a type for this local variable: {}",
404                         infer::fixup_err_to_string(e));
405                 }
406
407                 ResolvingPattern(span) => {
408                     span_err!(self.tcx.sess, span, E0103,
409                         "cannot determine a type for this pattern binding: {}",
410                         infer::fixup_err_to_string(e));
411                 }
412
413                 ResolvingUpvar(upvar_id) => {
414                     let span = self.reason.span(self.tcx);
415                     span_err!(self.tcx.sess, span, E0104,
416                         "cannot resolve lifetime for captured variable `{}`: {}",
417                         ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_string(),
418                         infer::fixup_err_to_string(e));
419                 }
420
421                 ResolvingUnboxedClosure(_) => {
422                     let span = self.reason.span(self.tcx);
423                     self.tcx.sess.span_err(span,
424                                            "cannot determine a type for this \
425                                             unboxed closure")
426                 }
427             }
428         }
429     }
430 }
431
432 impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
433     fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
434         self.tcx
435     }
436
437     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
438         match self.infcx.fully_resolve(&t) {
439             Ok(t) => t,
440             Err(e) => {
441                 debug!("Resolver::fold_ty: input type `{}` not fully resolvable",
442                        t.repr(self.tcx));
443                 self.report_error(e);
444                 self.tcx().types.err
445             }
446         }
447     }
448
449     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
450         match self.infcx.fully_resolve(&r) {
451             Ok(r) => r,
452             Err(e) => {
453                 self.report_error(e);
454                 ty::ReStatic
455             }
456         }
457     }
458 }
459
460 ///////////////////////////////////////////////////////////////////////////
461 // During type check, we store promises with the result of trait
462 // lookup rather than the actual results (because the results are not
463 // necessarily available immediately). These routines unwind the
464 // promises. It is expected that we will have already reported any
465 // errors that may be encountered, so if the promises store an error,
466 // a dummy result is returned.