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