]> git.proxmox.com Git - rustc.git/blame - src/librustc_typeck/check/writeback.rs
Imported Upstream version 1.7.0+dfsg1
[rustc.git] / src / librustc_typeck / check / writeback.rs
CommitLineData
1a4d82fc
JJ
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.
14use self::ResolveReason::*;
15
16use astconv::AstConv;
17use check::FnCtxt;
e9174d1e 18use middle::def_id::DefId;
1a4d82fc 19use middle::pat_util;
9cc50fc6 20use middle::ty::{self, Ty, MethodCall, MethodCallee};
e9174d1e
SL
21use middle::ty::adjustment;
22use middle::ty::fold::{TypeFolder,TypeFoldable};
1a4d82fc
JJ
23use middle::infer;
24use write_substs_to_tcx;
25use write_ty_to_tcx;
1a4d82fc
JJ
26
27use std::cell::Cell;
28
29use syntax::ast;
30use syntax::codemap::{DUMMY_SP, Span};
e9174d1e 31use rustc_front::print::pprust::pat_to_string;
92a42be0 32use rustc_front::intravisit::{self, Visitor};
e9174d1e
SL
33use rustc_front::util as hir_util;
34use rustc_front::hir;
1a4d82fc
JJ
35
36///////////////////////////////////////////////////////////////////////////
37// Entry point functions
38
e9174d1e 39pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &hir::Expr) {
1a4d82fc
JJ
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();
85aaf69f 44 wbcx.visit_closures();
92a42be0 45 wbcx.visit_liberated_fn_sigs();
1a4d82fc
JJ
46}
47
48pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
e9174d1e
SL
49 decl: &hir::FnDecl,
50 blk: &hir::Block) {
1a4d82fc
JJ
51 assert_eq!(fcx.writeback_errors.get(), false);
52 let mut wbcx = WritebackCx::new(fcx);
53 wbcx.visit_block(blk);
85aaf69f 54 for arg in &decl.inputs {
1a4d82fc
JJ
55 wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
56 wbcx.visit_pat(&*arg.pat);
57
58 // Privacy needs the type for the whole pattern, not just each binding
92a42be0 59 if !pat_util::pat_is_binding(&fcx.tcx().def_map.borrow(), &*arg.pat) {
1a4d82fc
JJ
60 wbcx.visit_node_id(ResolvingPattern(arg.pat.span),
61 arg.pat.id);
62 }
63 }
64 wbcx.visit_upvar_borrow_map();
85aaf69f 65 wbcx.visit_closures();
92a42be0 66 wbcx.visit_liberated_fn_sigs();
1a4d82fc
JJ
67}
68
69///////////////////////////////////////////////////////////////////////////
70// The Writerback context. This visitor walks the AST, checking the
71// fn-specific tables to find references to types or regions. It
72// resolves those regions to remove inference variables and writes the
73// final result back into the master tables in the tcx. Here and
74// there, it applies a few ad-hoc checks that were not convenient to
75// do elsewhere.
76
77struct WritebackCx<'cx, 'tcx: 'cx> {
78 fcx: &'cx FnCtxt<'cx, 'tcx>,
79}
80
81impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
82 fn new(fcx: &'cx FnCtxt<'cx, 'tcx>) -> WritebackCx<'cx, 'tcx> {
83 WritebackCx { fcx: fcx }
84 }
85
86 fn tcx(&self) -> &'cx ty::ctxt<'tcx> {
87 self.fcx.tcx()
88 }
d9579d0f
AL
89
90 // Hacky hack: During type-checking, we treat *all* operators
91 // as potentially overloaded. But then, during writeback, if
92 // we observe that something like `a+b` is (known to be)
93 // operating on scalars, we clear the overload.
e9174d1e 94 fn fix_scalar_binary_expr(&mut self, e: &hir::Expr) {
b039eaaf
SL
95 match e.node {
96 hir::ExprBinary(ref op, ref lhs, ref rhs) |
97 hir::ExprAssignOp(ref op, ref lhs, ref rhs) => {
98 let lhs_ty = self.fcx.node_ty(lhs.id);
99 let lhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&lhs_ty);
100
101 let rhs_ty = self.fcx.node_ty(rhs.id);
102 let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty);
103
104 if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
105 self.fcx.inh.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
106
107 // weird but true: the by-ref binops put an
108 // adjustment on the lhs but not the rhs; the
109 // adjustment for rhs is kind of baked into the
110 // system.
111 match e.node {
112 hir::ExprBinary(..) => {
113 if !hir_util::is_by_value_binop(op.node) {
114 self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id);
115 }
116 },
117 hir::ExprAssignOp(..) => {
118 self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id);
119 },
120 _ => {},
121 }
122 } else {
123 let tcx = self.tcx();
124
9cc50fc6 125 if let hir::ExprAssignOp(_, ref lhs, ref rhs) = e.node {
b039eaaf
SL
126 if
127 !tcx.sess.features.borrow().augmented_assignments &&
9cc50fc6
SL
128 !self.fcx.expr_ty(e).references_error() &&
129 !self.fcx.expr_ty(lhs).references_error() &&
130 !self.fcx.expr_ty(rhs).references_error()
b039eaaf 131 {
9cc50fc6
SL
132 tcx.sess.struct_span_err(e.span,
133 "overloaded augmented assignments \
134 are not stable")
135 .fileline_help(e.span,
136 "add #![feature(augmented_assignments)] to the \
137 crate root to enable")
138 .emit()
b039eaaf
SL
139 }
140 }
d9579d0f
AL
141 }
142 }
b039eaaf 143 _ => {},
d9579d0f
AL
144 }
145 }
1a4d82fc
JJ
146}
147
148///////////////////////////////////////////////////////////////////////////
149// Impl of Visitor for Resolver
150//
151// This is the master code which walks the AST. It delegates most of
152// the heavy lifting to the generic visit and resolve functions
153// below. In general, a function is made into a `visitor` if it must
154// traffic in node-ids or update tables in the type context etc.
155
156impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
e9174d1e 157 fn visit_stmt(&mut self, s: &hir::Stmt) {
1a4d82fc
JJ
158 if self.fcx.writeback_errors.get() {
159 return;
160 }
161
e9174d1e 162 self.visit_node_id(ResolvingExpr(s.span), hir_util::stmt_id(s));
92a42be0 163 intravisit::walk_stmt(self, s);
1a4d82fc
JJ
164 }
165
e9174d1e 166 fn visit_expr(&mut self, e: &hir::Expr) {
1a4d82fc
JJ
167 if self.fcx.writeback_errors.get() {
168 return;
169 }
170
d9579d0f 171 self.fix_scalar_binary_expr(e);
c34b1796 172
1a4d82fc
JJ
173 self.visit_node_id(ResolvingExpr(e.span), e.id);
174 self.visit_method_map_entry(ResolvingExpr(e.span),
175 MethodCall::expr(e.id));
176
e9174d1e 177 if let hir::ExprClosure(_, ref decl, _) = e.node {
d9579d0f
AL
178 for input in &decl.inputs {
179 self.visit_node_id(ResolvingExpr(e.span), input.id);
1a4d82fc 180 }
1a4d82fc
JJ
181 }
182
92a42be0 183 intravisit::walk_expr(self, e);
1a4d82fc
JJ
184 }
185
e9174d1e 186 fn visit_block(&mut self, b: &hir::Block) {
1a4d82fc
JJ
187 if self.fcx.writeback_errors.get() {
188 return;
189 }
190
191 self.visit_node_id(ResolvingExpr(b.span), b.id);
92a42be0 192 intravisit::walk_block(self, b);
1a4d82fc
JJ
193 }
194
e9174d1e 195 fn visit_pat(&mut self, p: &hir::Pat) {
1a4d82fc
JJ
196 if self.fcx.writeback_errors.get() {
197 return;
198 }
199
200 self.visit_node_id(ResolvingPattern(p.span), p.id);
201
62682a34 202 debug!("Type for pattern binding {} (id {}) resolved to {:?}",
1a4d82fc
JJ
203 pat_to_string(p),
204 p.id,
c1a9b12d 205 self.tcx().node_id_to_type(p.id));
1a4d82fc 206
92a42be0 207 intravisit::walk_pat(self, p);
1a4d82fc
JJ
208 }
209
e9174d1e 210 fn visit_local(&mut self, l: &hir::Local) {
1a4d82fc
JJ
211 if self.fcx.writeback_errors.get() {
212 return;
213 }
214
215 let var_ty = self.fcx.local_ty(l.span, l.id);
216 let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
217 write_ty_to_tcx(self.tcx(), l.id, var_ty);
92a42be0 218 intravisit::walk_local(self, l);
1a4d82fc
JJ
219 }
220
e9174d1e 221 fn visit_ty(&mut self, t: &hir::Ty) {
1a4d82fc 222 match t.node {
e9174d1e 223 hir::TyFixedLengthVec(ref ty, ref count_expr) => {
1a4d82fc 224 self.visit_ty(&**ty);
c34b1796 225 write_ty_to_tcx(self.tcx(), count_expr.id, self.tcx().types.usize);
1a4d82fc 226 }
b039eaaf 227 hir::TyBareFn(ref function_declaration) => {
92a42be0 228 intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
b039eaaf
SL
229 walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
230 }
92a42be0 231 _ => intravisit::walk_ty(self, t)
1a4d82fc
JJ
232 }
233 }
234}
235
236impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
237 fn visit_upvar_borrow_map(&self) {
238 if self.fcx.writeback_errors.get() {
239 return;
240 }
241
c1a9b12d 242 for (upvar_id, upvar_capture) in self.fcx.inh.tables.borrow().upvar_capture_map.iter() {
85aaf69f
SL
243 let new_upvar_capture = match *upvar_capture {
244 ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
245 ty::UpvarCapture::ByRef(ref upvar_borrow) => {
246 let r = upvar_borrow.region;
247 let r = self.resolve(&r, ResolvingUpvar(*upvar_id));
248 ty::UpvarCapture::ByRef(
249 ty::UpvarBorrow { kind: upvar_borrow.kind, region: r })
250 }
251 };
62682a34
SL
252 debug!("Upvar capture for {:?} resolved to {:?}",
253 upvar_id,
254 new_upvar_capture);
c1a9b12d
SL
255 self.fcx.tcx()
256 .tables
257 .borrow_mut()
258 .upvar_capture_map
259 .insert(*upvar_id, new_upvar_capture);
1a4d82fc
JJ
260 }
261 }
262
85aaf69f 263 fn visit_closures(&self) {
1a4d82fc
JJ
264 if self.fcx.writeback_errors.get() {
265 return
266 }
267
c1a9b12d 268 for (def_id, closure_ty) in self.fcx.inh.tables.borrow().closure_tys.iter() {
85aaf69f 269 let closure_ty = self.resolve(closure_ty, ResolvingClosure(*def_id));
c1a9b12d 270 self.fcx.tcx().tables.borrow_mut().closure_tys.insert(*def_id, closure_ty);
85aaf69f
SL
271 }
272
c1a9b12d
SL
273 for (def_id, &closure_kind) in self.fcx.inh.tables.borrow().closure_kinds.iter() {
274 self.fcx.tcx().tables.borrow_mut().closure_kinds.insert(*def_id, closure_kind);
1a4d82fc
JJ
275 }
276 }
277
1a4d82fc
JJ
278 fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
279 // Resolve any borrowings for the node with id `id`
280 self.visit_adjustments(reason, id);
281
282 // Resolve the type of the node with id `id`
283 let n_ty = self.fcx.node_ty(id);
284 let n_ty = self.resolve(&n_ty, reason);
285 write_ty_to_tcx(self.tcx(), id, n_ty);
62682a34 286 debug!("Node {} has type {:?}", id, n_ty);
1a4d82fc
JJ
287
288 // Resolve any substitutions
289 self.fcx.opt_node_ty_substs(id, |item_substs| {
290 write_substs_to_tcx(self.tcx(), id,
291 self.resolve(item_substs, reason));
292 });
293 }
294
295 fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
c1a9b12d
SL
296 let adjustments = self.fcx.inh.tables.borrow_mut().adjustments.remove(&id);
297 match adjustments {
1a4d82fc
JJ
298 None => {
299 debug!("No adjustments for node {}", id);
300 }
301
302 Some(adjustment) => {
1a4d82fc 303 let resolved_adjustment = match adjustment {
e9174d1e
SL
304 adjustment::AdjustReifyFnPointer => {
305 adjustment::AdjustReifyFnPointer
306 }
1a4d82fc 307
e9174d1e
SL
308 adjustment::AdjustUnsafeFnPointer => {
309 adjustment::AdjustUnsafeFnPointer
c34b1796
AL
310 }
311
e9174d1e 312 adjustment::AdjustDerefRef(adj) => {
85aaf69f 313 for autoderef in 0..adj.autoderefs {
9346a6ac 314 let method_call = MethodCall::autoderef(id, autoderef as u32);
1a4d82fc
JJ
315 self.visit_method_map_entry(reason, method_call);
316 }
317
e9174d1e 318 adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
1a4d82fc
JJ
319 autoderefs: adj.autoderefs,
320 autoref: self.resolve(&adj.autoref, reason),
9346a6ac 321 unsize: self.resolve(&adj.unsize, reason),
1a4d82fc
JJ
322 })
323 }
324 };
325 debug!("Adjustments for node {}: {:?}", id, resolved_adjustment);
c1a9b12d 326 self.tcx().tables.borrow_mut().adjustments.insert(
1a4d82fc
JJ
327 id, resolved_adjustment);
328 }
329 }
330 }
331
332 fn visit_method_map_entry(&self,
333 reason: ResolveReason,
334 method_call: MethodCall) {
335 // Resolve any method map entry
c1a9b12d 336 let new_method = match self.fcx.inh.tables.borrow_mut().method_map.remove(&method_call) {
1a4d82fc 337 Some(method) => {
62682a34 338 debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
1a4d82fc 339 method_call,
62682a34 340 method);
1a4d82fc 341 let new_method = MethodCallee {
c1a9b12d 342 def_id: method.def_id,
1a4d82fc 343 ty: self.resolve(&method.ty, reason),
c1a9b12d 344 substs: self.tcx().mk_substs(self.resolve(method.substs, reason)),
1a4d82fc
JJ
345 };
346
c1a9b12d
SL
347 Some(new_method)
348 }
349 None => None
350 };
351
352 //NB(jroesch): We need to match twice to avoid a double borrow which would cause an ICE
353 match new_method {
354 Some(method) => {
355 self.tcx().tables.borrow_mut().method_map.insert(
1a4d82fc 356 method_call,
c1a9b12d 357 method);
1a4d82fc
JJ
358 }
359 None => {}
360 }
361 }
362
92a42be0
SL
363 fn visit_liberated_fn_sigs(&self) {
364 for (&node_id, fn_sig) in self.fcx.inh.tables.borrow().liberated_fn_sigs.iter() {
365 let fn_sig = self.resolve(fn_sig, ResolvingFnSig(node_id));
366 self.tcx().tables.borrow_mut().liberated_fn_sigs.insert(node_id, fn_sig.clone());
367 }
368 }
369
1a4d82fc
JJ
370 fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
371 t.fold_with(&mut Resolver::new(self.fcx, reason))
372 }
373}
374
375///////////////////////////////////////////////////////////////////////////
376// Resolution reason.
377
c34b1796 378#[derive(Copy, Clone)]
1a4d82fc
JJ
379enum ResolveReason {
380 ResolvingExpr(Span),
381 ResolvingLocal(Span),
382 ResolvingPattern(Span),
383 ResolvingUpvar(ty::UpvarId),
e9174d1e 384 ResolvingClosure(DefId),
92a42be0 385 ResolvingFnSig(ast::NodeId),
1a4d82fc
JJ
386}
387
388impl ResolveReason {
389 fn span(&self, tcx: &ty::ctxt) -> Span {
390 match *self {
391 ResolvingExpr(s) => s,
392 ResolvingLocal(s) => s,
393 ResolvingPattern(s) => s,
394 ResolvingUpvar(upvar_id) => {
c1a9b12d 395 tcx.expr_span(upvar_id.closure_expr_id)
1a4d82fc 396 }
92a42be0
SL
397 ResolvingFnSig(id) => {
398 tcx.map.span(id)
399 }
85aaf69f 400 ResolvingClosure(did) => {
b039eaaf
SL
401 if let Some(node_id) = tcx.map.as_local_node_id(did) {
402 tcx.expr_span(node_id)
1a4d82fc
JJ
403 } else {
404 DUMMY_SP
405 }
406 }
407 }
408 }
409}
410
411///////////////////////////////////////////////////////////////////////////
412// The Resolver. This is the type folding engine that detects
413// unresolved types and so forth.
414
415struct Resolver<'cx, 'tcx: 'cx> {
416 tcx: &'cx ty::ctxt<'tcx>,
417 infcx: &'cx infer::InferCtxt<'cx, 'tcx>,
418 writeback_errors: &'cx Cell<bool>,
419 reason: ResolveReason,
420}
421
422impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
423 fn new(fcx: &'cx FnCtxt<'cx, 'tcx>,
424 reason: ResolveReason)
425 -> Resolver<'cx, 'tcx>
426 {
427 Resolver::from_infcx(fcx.infcx(), &fcx.writeback_errors, reason)
428 }
429
430 fn from_infcx(infcx: &'cx infer::InferCtxt<'cx, 'tcx>,
431 writeback_errors: &'cx Cell<bool>,
432 reason: ResolveReason)
433 -> Resolver<'cx, 'tcx>
434 {
435 Resolver { infcx: infcx,
436 tcx: infcx.tcx,
437 writeback_errors: writeback_errors,
438 reason: reason }
439 }
440
c1a9b12d 441 fn report_error(&self, e: infer::FixupError) {
1a4d82fc
JJ
442 self.writeback_errors.set(true);
443 if !self.tcx.sess.has_errors() {
444 match self.reason {
445 ResolvingExpr(span) => {
446 span_err!(self.tcx.sess, span, E0101,
447 "cannot determine a type for this expression: {}",
448 infer::fixup_err_to_string(e));
449 }
450
451 ResolvingLocal(span) => {
452 span_err!(self.tcx.sess, span, E0102,
453 "cannot determine a type for this local variable: {}",
454 infer::fixup_err_to_string(e));
455 }
456
457 ResolvingPattern(span) => {
458 span_err!(self.tcx.sess, span, E0103,
459 "cannot determine a type for this pattern binding: {}",
460 infer::fixup_err_to_string(e));
461 }
462
463 ResolvingUpvar(upvar_id) => {
464 let span = self.reason.span(self.tcx);
465 span_err!(self.tcx.sess, span, E0104,
466 "cannot resolve lifetime for captured variable `{}`: {}",
c1a9b12d 467 self.tcx.local_var_name_str(upvar_id.var_id).to_string(),
1a4d82fc
JJ
468 infer::fixup_err_to_string(e));
469 }
470
85aaf69f 471 ResolvingClosure(_) => {
1a4d82fc 472 let span = self.reason.span(self.tcx);
85aaf69f
SL
473 span_err!(self.tcx.sess, span, E0196,
474 "cannot determine a type for this closure")
1a4d82fc 475 }
92a42be0
SL
476
477 ResolvingFnSig(id) => {
478 // any failures here should also fail when
479 // resolving the patterns, closure types, or
480 // something else.
481 let span = self.reason.span(self.tcx);
482 self.tcx.sess.delay_span_bug(
483 span,
484 &format!("cannot resolve some aspect of fn sig for {:?}", id));
485 }
1a4d82fc
JJ
486 }
487 }
488 }
489}
490
491impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
492 fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
493 self.tcx
494 }
495
496 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
497 match self.infcx.fully_resolve(&t) {
498 Ok(t) => t,
499 Err(e) => {
62682a34
SL
500 debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable",
501 t);
1a4d82fc
JJ
502 self.report_error(e);
503 self.tcx().types.err
504 }
505 }
506 }
507
508 fn fold_region(&mut self, r: ty::Region) -> ty::Region {
509 match self.infcx.fully_resolve(&r) {
510 Ok(r) => r,
511 Err(e) => {
512 self.report_error(e);
513 ty::ReStatic
514 }
515 }
516 }
517}
518
519///////////////////////////////////////////////////////////////////////////
520// During type check, we store promises with the result of trait
521// lookup rather than the actual results (because the results are not
522// necessarily available immediately). These routines unwind the
523// promises. It is expected that we will have already reported any
524// errors that may be encountered, so if the promises store an error,
525// a dummy result is returned.