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