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.
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.
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
14 use self::ResolveReason
::*;
19 use middle
::ty
::{self, Ty, MethodCall, MethodCallee}
;
20 use middle
::ty_fold
::{TypeFolder,TypeFoldable}
;
22 use write_substs_to_tcx
;
29 use syntax
::codemap
::{DUMMY_SP, Span}
;
30 use syntax
::print
::pprust
::pat_to_string
;
32 use syntax
::visit
::Visitor
;
34 ///////////////////////////////////////////////////////////////////////////
35 // Entry point functions
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
);
41 wbcx
.visit_upvar_borrow_map();
42 wbcx
.visit_closures();
45 pub fn resolve_type_vars_in_fn(fcx
: &FnCtxt
,
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
);
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
),
61 wbcx
.visit_upvar_borrow_map();
62 wbcx
.visit_closures();
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
73 struct WritebackCx
<'cx
, 'tcx
: 'cx
> {
74 fcx
: &'cx FnCtxt
<'cx
, 'tcx
>,
77 impl<'cx
, 'tcx
> WritebackCx
<'cx
, 'tcx
> {
78 fn new(fcx
: &'cx FnCtxt
<'cx
, 'tcx
>) -> WritebackCx
<'cx
, 'tcx
> {
79 WritebackCx { fcx: fcx }
82 fn tcx(&self) -> &'cx ty
::ctxt
<'tcx
> {
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
);
95 let rhs_ty
= self.fcx
.node_ty(rhs
.id
);
96 let rhs_ty
= self.fcx
.infcx().resolve_type_vars_if_possible(&rhs_ty
);
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
));
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
105 if !ast_util
::is_by_value_binop(op
.node
) {
106 self.fcx
.inh
.adjustments
.borrow_mut().remove(&lhs
.id
);
113 ///////////////////////////////////////////////////////////////////////////
114 // Impl of Visitor for Resolver
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.
121 impl<'cx
, 'tcx
, 'v
> Visitor
<'v
> for WritebackCx
<'cx
, 'tcx
> {
122 fn visit_item(&mut self, _
: &ast
::Item
) {
126 fn visit_stmt(&mut self, s
: &ast
::Stmt
) {
127 if self.fcx
.writeback_errors
.get() {
131 self.visit_node_id(ResolvingExpr(s
.span
), ty
::stmt_node_id(s
));
132 visit
::walk_stmt(self, s
);
135 fn visit_expr(&mut self, e
: &ast
::Expr
) {
136 if self.fcx
.writeback_errors
.get() {
140 self.fix_scalar_binary_expr(e
);
142 self.visit_node_id(ResolvingExpr(e
.span
), e
.id
);
143 self.visit_method_map_entry(ResolvingExpr(e
.span
),
144 MethodCall
::expr(e
.id
));
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
);
152 visit
::walk_expr(self, e
);
155 fn visit_block(&mut self, b
: &ast
::Block
) {
156 if self.fcx
.writeback_errors
.get() {
160 self.visit_node_id(ResolvingExpr(b
.span
), b
.id
);
161 visit
::walk_block(self, b
);
164 fn visit_pat(&mut self, p
: &ast
::Pat
) {
165 if self.fcx
.writeback_errors
.get() {
169 self.visit_node_id(ResolvingPattern(p
.span
), p
.id
);
171 debug
!("Type for pattern binding {} (id {}) resolved to {:?}",
174 ty
::node_id_to_type(self.tcx(), p
.id
));
176 visit
::walk_pat(self, p
);
179 fn visit_local(&mut self, l
: &ast
::Local
) {
180 if self.fcx
.writeback_errors
.get() {
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
);
190 fn visit_ty(&mut self, t
: &ast
::Ty
) {
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);
196 _
=> visit
::walk_ty(self, t
)
201 impl<'cx
, 'tcx
> WritebackCx
<'cx
, 'tcx
> {
202 fn visit_upvar_borrow_map(&self) {
203 if self.fcx
.writeback_errors
.get() {
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 }
)
217 debug
!("Upvar capture for {:?} resolved to {:?}",
220 self.fcx
.tcx().upvar_capture_map
.borrow_mut().insert(*upvar_id
, new_upvar_capture
);
224 fn visit_closures(&self) {
225 if self.fcx
.writeback_errors
.get() {
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
);
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
);
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
);
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
);
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
));
256 fn visit_adjustments(&self, reason
: ResolveReason
, id
: ast
::NodeId
) {
257 match self.fcx
.inh
.adjustments
.borrow_mut().remove(&id
) {
259 debug
!("No adjustments for node {}", id
);
262 Some(adjustment
) => {
263 let resolved_adjustment
= match adjustment
{
264 ty
::AdjustReifyFnPointer
=> ty
::AdjustReifyFnPointer
,
266 ty
::AdjustUnsafeFnPointer
=> {
267 ty
::AdjustUnsafeFnPointer
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
);
276 ty
::AdjustDerefRef(ty
::AutoDerefRef
{
277 autoderefs
: adj
.autoderefs
,
278 autoref
: self.resolve(&adj
.autoref
, reason
),
279 unsize
: self.resolve(&adj
.unsize
, reason
),
283 debug
!("Adjustments for node {}: {:?}", id
, resolved_adjustment
);
284 self.tcx().adjustments
.borrow_mut().insert(
285 id
, resolved_adjustment
);
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
) {
296 debug
!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
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
),
305 self.tcx().method_map
.borrow_mut().insert(
313 fn resolve
<T
:TypeFoldable
<'tcx
>>(&self, t
: &T
, reason
: ResolveReason
) -> T
{
314 t
.fold_with(&mut Resolver
::new(self.fcx
, reason
))
318 ///////////////////////////////////////////////////////////////////////////
319 // Resolution reason.
321 #[derive(Copy, Clone)]
324 ResolvingLocal(Span
),
325 ResolvingPattern(Span
),
326 ResolvingUpvar(ty
::UpvarId
),
327 ResolvingClosure(ast
::DefId
),
331 fn span(&self, tcx
: &ty
::ctxt
) -> Span
{
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
)
339 ResolvingClosure(did
) => {
340 if did
.krate
== ast
::LOCAL_CRATE
{
341 ty
::expr_span(tcx
, did
.node
)
350 ///////////////////////////////////////////////////////////////////////////
351 // The Resolver. This is the type folding engine that detects
352 // unresolved types and so forth.
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
,
361 impl<'cx
, 'tcx
> Resolver
<'cx
, 'tcx
> {
362 fn new(fcx
: &'cx FnCtxt
<'cx
, 'tcx
>,
363 reason
: ResolveReason
)
364 -> Resolver
<'cx
, 'tcx
>
366 Resolver
::from_infcx(fcx
.infcx(), &fcx
.writeback_errors
, reason
)
369 fn from_infcx(infcx
: &'cx infer
::InferCtxt
<'cx
, 'tcx
>,
370 writeback_errors
: &'cx Cell
<bool
>,
371 reason
: ResolveReason
)
372 -> Resolver
<'cx
, 'tcx
>
374 Resolver
{ infcx
: infcx
,
376 writeback_errors
: writeback_errors
,
380 fn report_error(&self, e
: infer
::fixup_err
) {
381 self.writeback_errors
.set(true);
382 if !self.tcx
.sess
.has_errors() {
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
));
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
));
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
));
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
));
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")
420 impl<'cx
, 'tcx
> TypeFolder
<'tcx
> for Resolver
<'cx
, 'tcx
> {
421 fn tcx
<'a
>(&'a
self) -> &'a ty
::ctxt
<'tcx
> {
425 fn fold_ty(&mut self, t
: Ty
<'tcx
>) -> Ty
<'tcx
> {
426 match self.infcx
.fully_resolve(&t
) {
429 debug
!("Resolver::fold_ty: input type `{:?}` not fully resolvable",
431 self.report_error(e
);
437 fn fold_region(&mut self, r
: ty
::Region
) -> ty
::Region
{
438 match self.infcx
.fully_resolve(&r
) {
441 self.report_error(e
);
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.