]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/writeback.rs
Merge pull request #20675 from jbcrail/fix-test-comments
[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::AdjustReifyFnPointer(def_id) => {
270                         ty::AdjustReifyFnPointer(def_id)
271                     }
272
273                     ty::AdjustDerefRef(adj) => {
274                         for autoderef in range(0, adj.autoderefs) {
275                             let method_call = MethodCall::autoderef(id, autoderef);
276                             self.visit_method_map_entry(reason, method_call);
277                         }
278
279                         if adj_object {
280                             let method_call = MethodCall::autoobject(id);
281                             self.visit_method_map_entry(reason, method_call);
282                         }
283
284                         ty::AdjustDerefRef(ty::AutoDerefRef {
285                             autoderefs: adj.autoderefs,
286                             autoref: self.resolve(&adj.autoref, reason),
287                         })
288                     }
289                 };
290                 debug!("Adjustments for node {}: {:?}", id, resolved_adjustment);
291                 self.tcx().adjustments.borrow_mut().insert(
292                     id, resolved_adjustment);
293             }
294         }
295     }
296
297     fn visit_method_map_entry(&self,
298                               reason: ResolveReason,
299                               method_call: MethodCall) {
300         // Resolve any method map entry
301         match self.fcx.inh.method_map.borrow_mut().remove(&method_call) {
302             Some(method) => {
303                 debug!("writeback::resolve_method_map_entry(call={:?}, entry={})",
304                        method_call,
305                        method.repr(self.tcx()));
306                 let new_method = MethodCallee {
307                     origin: self.resolve(&method.origin, reason),
308                     ty: self.resolve(&method.ty, reason),
309                     substs: self.resolve(&method.substs, reason),
310                 };
311
312                 self.tcx().method_map.borrow_mut().insert(
313                     method_call,
314                     new_method);
315             }
316             None => {}
317         }
318     }
319
320     fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
321         t.fold_with(&mut Resolver::new(self.fcx, reason))
322     }
323 }
324
325 ///////////////////////////////////////////////////////////////////////////
326 // Resolution reason.
327
328 #[derive(Copy)]
329 enum ResolveReason {
330     ResolvingExpr(Span),
331     ResolvingLocal(Span),
332     ResolvingPattern(Span),
333     ResolvingUpvar(ty::UpvarId),
334     ResolvingUnboxedClosure(ast::DefId),
335 }
336
337 impl ResolveReason {
338     fn span(&self, tcx: &ty::ctxt) -> Span {
339         match *self {
340             ResolvingExpr(s) => s,
341             ResolvingLocal(s) => s,
342             ResolvingPattern(s) => s,
343             ResolvingUpvar(upvar_id) => {
344                 ty::expr_span(tcx, upvar_id.closure_expr_id)
345             }
346             ResolvingUnboxedClosure(did) => {
347                 if did.krate == ast::LOCAL_CRATE {
348                     ty::expr_span(tcx, did.node)
349                 } else {
350                     DUMMY_SP
351                 }
352             }
353         }
354     }
355 }
356
357 ///////////////////////////////////////////////////////////////////////////
358 // The Resolver. This is the type folding engine that detects
359 // unresolved types and so forth.
360
361 struct Resolver<'cx, 'tcx: 'cx> {
362     tcx: &'cx ty::ctxt<'tcx>,
363     infcx: &'cx infer::InferCtxt<'cx, 'tcx>,
364     writeback_errors: &'cx Cell<bool>,
365     reason: ResolveReason,
366 }
367
368 impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
369     fn new(fcx: &'cx FnCtxt<'cx, 'tcx>,
370            reason: ResolveReason)
371            -> Resolver<'cx, 'tcx>
372     {
373         Resolver::from_infcx(fcx.infcx(), &fcx.writeback_errors, reason)
374     }
375
376     fn from_infcx(infcx: &'cx infer::InferCtxt<'cx, 'tcx>,
377                   writeback_errors: &'cx Cell<bool>,
378                   reason: ResolveReason)
379                   -> Resolver<'cx, 'tcx>
380     {
381         Resolver { infcx: infcx,
382                    tcx: infcx.tcx,
383                    writeback_errors: writeback_errors,
384                    reason: reason }
385     }
386
387     fn report_error(&self, e: infer::fixup_err) {
388         self.writeback_errors.set(true);
389         if !self.tcx.sess.has_errors() {
390             match self.reason {
391                 ResolvingExpr(span) => {
392                     span_err!(self.tcx.sess, span, E0101,
393                         "cannot determine a type for this expression: {}",
394                         infer::fixup_err_to_string(e));
395                 }
396
397                 ResolvingLocal(span) => {
398                     span_err!(self.tcx.sess, span, E0102,
399                         "cannot determine a type for this local variable: {}",
400                         infer::fixup_err_to_string(e));
401                 }
402
403                 ResolvingPattern(span) => {
404                     span_err!(self.tcx.sess, span, E0103,
405                         "cannot determine a type for this pattern binding: {}",
406                         infer::fixup_err_to_string(e));
407                 }
408
409                 ResolvingUpvar(upvar_id) => {
410                     let span = self.reason.span(self.tcx);
411                     span_err!(self.tcx.sess, span, E0104,
412                         "cannot resolve lifetime for captured variable `{}`: {}",
413                         ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_string(),
414                         infer::fixup_err_to_string(e));
415                 }
416
417                 ResolvingUnboxedClosure(_) => {
418                     let span = self.reason.span(self.tcx);
419                     self.tcx.sess.span_err(span,
420                                            "cannot determine a type for this \
421                                             unboxed closure")
422                 }
423             }
424         }
425     }
426 }
427
428 impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
429     fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
430         self.tcx
431     }
432
433     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
434         match self.infcx.fully_resolve(&t) {
435             Ok(t) => t,
436             Err(e) => {
437                 debug!("Resolver::fold_ty: input type `{}` not fully resolvable",
438                        t.repr(self.tcx));
439                 self.report_error(e);
440                 self.tcx().types.err
441             }
442         }
443     }
444
445     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
446         match self.infcx.fully_resolve(&r) {
447             Ok(r) => r,
448             Err(e) => {
449                 self.report_error(e);
450                 ty::ReStatic
451             }
452         }
453     }
454 }
455
456 ///////////////////////////////////////////////////////////////////////////
457 // During type check, we store promises with the result of trait
458 // lookup rather than the actual results (because the results are not
459 // necessarily available immediately). These routines unwind the
460 // promises. It is expected that we will have already reported any
461 // errors that may be encountered, so if the promises store an error,
462 // a dummy result is returned.