diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 4b0153b67fff4..86291a7d6cb3e 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -71,6 +71,10 @@ pub trait TypeFolder { fn fold_trait_store(&mut self, s: ty::TraitStore) -> ty::TraitStore { super_fold_trait_store(self, s) } + + fn fold_autoref(&mut self, ar: &ty::AutoRef) -> ty::AutoRef { + super_fold_autoref(self, ar) + } } pub fn fold_opt_ty(this: &mut T, @@ -200,6 +204,19 @@ pub fn super_fold_trait_store(this: &mut T, } } +pub fn super_fold_autoref(this: &mut T, + autoref: &ty::AutoRef) + -> ty::AutoRef +{ + match *autoref { + ty::AutoPtr(r, m) => ty::AutoPtr(this.fold_region(r), m), + ty::AutoBorrowVec(r, m) => ty::AutoBorrowVec(this.fold_region(r), m), + ty::AutoBorrowVecRef(r, m) => ty::AutoBorrowVecRef(this.fold_region(r), m), + ty::AutoUnsafe(m) => ty::AutoUnsafe(m), + ty::AutoBorrowObj(r, m) => ty::AutoBorrowObj(this.fold_region(r), m), + } +} + /////////////////////////////////////////////////////////////////////////// // Some sample folders diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index c352ba7e3a5c8..bf5874e133661 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -221,6 +221,10 @@ enum IsBinopAssignment{ #[deriving(Clone)] pub struct FnCtxt<'a> { + // This flag is set to true if, during the writeback phase, we encounter + // a type error in this function. + writeback_errors: Cell, + // Number of errors that had been reported when we started // checking this function. On exit, if we find that *more* errors // have been reported, we will skip regionck and other work that @@ -280,6 +284,7 @@ fn blank_fn_ctxt<'a>(ccx: &'a CrateCtxt<'a>, region_bnd: ast::NodeId) -> FnCtxt<'a> { FnCtxt { + writeback_errors: Cell::new(false), err_count_on_creation: ccx.tcx.sess.err_count(), ret_ty: rty, ps: RefCell::new(FnStyleState::function(ast::NormalFn, 0)), @@ -469,6 +474,7 @@ fn check_fn<'a>(ccx: &'a CrateCtxt<'a>, // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. let fcx = FnCtxt { + writeback_errors: Cell::new(false), err_count_on_creation: err_count_on_creation, ret_ty: ret_ty, ps: RefCell::new(FnStyleState::function(fn_style, id)), @@ -1198,11 +1204,10 @@ impl<'a> FnCtxt<'a> { pub fn opt_node_ty_substs(&self, id: ast::NodeId, - f: |&ty::substs| -> bool) - -> bool { + f: |&ty::substs|) { match self.inh.node_type_substs.borrow().find(&id) { - Some(s) => f(s), - None => true + Some(s) => { f(s) } + None => { } } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 192c67eb8d1d9..f2d6171cc6392 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -644,7 +644,6 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { insert_vtables(fcx, MethodCall::expr(ex.id), vtbls); } } - true }); } diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 3843c38fd1800..77429118a2c45 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -15,16 +15,16 @@ use middle::pat_util; use middle::ty; +use middle::ty_fold::TypeFolder; use middle::typeck::astconv::AstConv; use middle::typeck::check::FnCtxt; use middle::typeck::infer::{force_all, resolve_all, resolve_region}; use middle::typeck::infer::resolve_type; use middle::typeck::infer; use middle::typeck::{MethodCall, MethodCallee}; -use middle::typeck::{vtable_res, vtable_static, vtable_param}; +use middle::typeck::{vtable_origin, vtable_static, vtable_param}; use middle::typeck::write_substs_to_tcx; use middle::typeck::write_ty_to_tcx; -use util::ppaux; use util::ppaux::Repr; use syntax::ast; @@ -33,357 +33,455 @@ use syntax::print::pprust::pat_to_str; use syntax::visit; use syntax::visit::Visitor; -fn resolve_type_vars_in_type(fcx: &FnCtxt, sp: Span, typ: ty::t) - -> Option { - if !ty::type_needs_infer(typ) { return Some(typ); } - match resolve_type(fcx.infcx(), typ, resolve_all | force_all) { - Ok(new_type) => return Some(new_type), - Err(e) => { - if !fcx.ccx.tcx.sess.has_errors() { - fcx.ccx.tcx.sess.span_err( - sp, - format!("cannot determine a type \ - for this expression: {}", - infer::fixup_err_to_str(e))) - } - return None; +/////////////////////////////////////////////////////////////////////////// +// Entry point functions + +pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) { + assert_eq!(fcx.writeback_errors.get(), false); + let mut wbcx = WritebackCx::new(fcx); + wbcx.visit_expr(e, ()); + wbcx.visit_upvar_borrow_map(); +} + +pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, + decl: &ast::FnDecl, + blk: &ast::Block) { + assert_eq!(fcx.writeback_errors.get(), false); + let mut wbcx = WritebackCx::new(fcx); + wbcx.visit_block(blk, ()); + for arg in decl.inputs.iter() { + wbcx.visit_pat(arg.pat, ()); + + // Privacy needs the type for the whole pattern, not just each binding + if !pat_util::pat_is_binding(&fcx.tcx().def_map, arg.pat) { + wbcx.visit_node_id(ResolvingPattern(arg.pat.span), + arg.pat.id); } } + wbcx.visit_upvar_borrow_map(); } -fn resolve_method_map_entry(wbcx: &mut WbCtxt, sp: Span, method_call: MethodCall) { - let fcx = wbcx.fcx; - let tcx = fcx.ccx.tcx; - - // Resolve any method map entry - match fcx.inh.method_map.borrow_mut().pop(&method_call) { - Some(method) => { - debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})", - method_call, method.repr(tcx)); - let new_method = MethodCallee { - origin: method.origin, - ty: match resolve_type_vars_in_type(fcx, sp, method.ty) { - Some(t) => t, - None => { - wbcx.success = false; - return; - } - }, - substs: ty::substs { - tps: method.substs.tps.move_iter().map(|subst| { - match resolve_type_vars_in_type(fcx, sp, subst) { - Some(t) => t, - None => { wbcx.success = false; ty::mk_err() } - } - }).collect(), - regions: ty::ErasedRegions, - self_ty: None - } - }; - tcx.method_map.borrow_mut().insert(method_call, new_method); - } - None => {} +/////////////////////////////////////////////////////////////////////////// +// The Writerback context. This visitor walks the AST, checking the +// fn-specific tables to find references to types or regions. It +// resolves those regions to remove inference variables and writes the +// final result back into the master tables in the tcx. Here and +// there, it applies a few ad-hoc checks that were not convenient to +// do elsewhere. + +struct WritebackCx<'cx> { + fcx: &'cx FnCtxt<'cx>, +} + +impl<'cx> WritebackCx<'cx> { + fn new(fcx: &'cx FnCtxt) -> WritebackCx<'cx> { + WritebackCx { fcx: fcx } + } + + fn tcx(&self) -> &'cx ty::ctxt { + self.fcx.tcx() } } -fn resolve_vtable_map_entry(fcx: &FnCtxt, sp: Span, vtable_key: MethodCall) { - // Resolve any vtable map entry - match fcx.inh.vtable_map.borrow_mut().pop(&vtable_key) { - Some(origins) => { - let r_origins = resolve_origins(fcx, sp, origins); - debug!("writeback::resolve_vtable_map_entry(vtable_key={}, vtables={:?})", - vtable_key, r_origins.repr(fcx.tcx())); - fcx.tcx().vtable_map.borrow_mut().insert(vtable_key, r_origins); +/////////////////////////////////////////////////////////////////////////// +// Impl of Visitor for Resolver +// +// This is the master code which walks the AST. It delegates most of +// the heavy lifting to the generic visit and resolve functions +// below. In general, a function is made into a `visitor` if it must +// traffic in node-ids or update tables in the type context etc. + +impl<'cx> Visitor<()> for WritebackCx<'cx> { + fn visit_item(&mut self, _: &ast::Item, _: ()) { + // Ignore items + } + + fn visit_stmt(&mut self, s: &ast::Stmt, _: ()) { + if self.fcx.writeback_errors.get() { + return; } - None => {} + + self.visit_node_id(ResolvingExpr(s.span), ty::stmt_node_id(s)); + visit::walk_stmt(self, s, ()); } - fn resolve_origins(fcx: &FnCtxt, sp: Span, - vtbls: vtable_res) -> vtable_res { - vtbls.move_iter().map(|os| os.move_iter().map(|origin| { - match origin { - vtable_static(def_id, tys, origins) => { - let r_tys = tys.move_iter().map(|t| { - match resolve_type_vars_in_type(fcx, sp, t) { - Some(t1) => t1, - None => ty::mk_err() - } - }).collect(); - let r_origins = resolve_origins(fcx, sp, origins); - vtable_static(def_id, r_tys, r_origins) + fn visit_expr(&mut self, e:&ast::Expr, _: ()) { + if self.fcx.writeback_errors.get() { + return; + } + + self.visit_node_id(ResolvingExpr(e.span), e.id); + self.visit_method_map_entry(ResolvingExpr(e.span), + MethodCall::expr(e.id)); + self.visit_vtable_map_entry(ResolvingExpr(e.span), + MethodCall::expr(e.id)); + + match e.node { + ast::ExprFnBlock(ref decl, _) | ast::ExprProc(ref decl, _) => { + for input in decl.inputs.iter() { + let _ = self.visit_node_id(ResolvingExpr(e.span), + input.id); } - vtable_param(n, b) => vtable_param(n, b) } - }).collect()).collect() + _ => {} + } + + visit::walk_expr(self, e, ()); } -} -fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId) { - let fcx = wbcx.fcx; - let tcx = fcx.ccx.tcx; - - // Resolve any borrowings for the node with id `id` - let resolved_adj = match fcx.inh.adjustments.borrow_mut().pop(&id) { - None => None, - - Some(adjustment) => { - Some(match adjustment { - ty::AutoAddEnv(store) => { - let r = match store { - ty::RegionTraitStore(r, _) => r, - ty::UniqTraitStore => ty::ReStatic - }; - match resolve_region(fcx.infcx(), - r, - resolve_all | force_all) { - Err(e) => { - // This should not, I think, happen: - tcx.sess.span_err( - sp, - format!("cannot resolve bound for closure: \ - {}", - infer::fixup_err_to_str(e))); - wbcx.success = false; - return; - } - Ok(r1) => { - // FIXME(eddyb) #2190 Allow only statically resolved - // bare functions to coerce to a closure to avoid - // constructing (slower) indirect call wrappers. - match tcx.def_map.borrow().find(&id) { - Some(&ast::DefFn(..)) | - Some(&ast::DefStaticMethod(..)) | - Some(&ast::DefVariant(..)) | - Some(&ast::DefStruct(_)) => {} - _ => tcx.sess.span_err(sp, - "cannot coerce non-statically resolved bare fn") - } + fn visit_block(&mut self, b: &ast::Block, _: ()) { + if self.fcx.writeback_errors.get() { + return; + } - ty::AutoAddEnv(match store { - ty::RegionTraitStore(..) => { - ty::RegionTraitStore(r1, ast::MutMutable) - } - ty::UniqTraitStore => ty::UniqTraitStore - }) - } - } - } + self.visit_node_id(ResolvingExpr(b.span), b.id); + visit::walk_block(self, b, ()); + } - ty::AutoDerefRef(adj) => { - for autoderef in range(0, adj.autoderefs) { - let method_call = MethodCall::autoderef(id, autoderef as u32); - resolve_method_map_entry(wbcx, sp, method_call); - resolve_vtable_map_entry(wbcx.fcx, sp, method_call); - } + fn visit_pat(&mut self, p: &ast::Pat, _: ()) { + if self.fcx.writeback_errors.get() { + return; + } - ty::AutoDerefRef(ty::AutoDerefRef { - autoderefs: adj.autoderefs, - autoref: adj.autoref.map(|r| r.map_region(|r| { - match resolve_region(fcx.infcx(), r, - resolve_all | force_all) { - Ok(r1) => r1, - Err(e) => { - // This should not, I think, happen. - tcx.sess.span_err( - sp, - format!("cannot resolve scope of borrow: \ - {}", - infer::fixup_err_to_str(e))); - r - } - } - })), - }) - } + self.visit_node_id(ResolvingPattern(p.span), p.id); + + debug!("Type for pattern binding {} (id {}) resolved to {}", + pat_to_str(p), + p.id, + ty::node_id_to_type(self.tcx(), p.id).repr(self.tcx())); + + visit::walk_pat(self, p, ()); + } - adjustment => adjustment - }) + fn visit_local(&mut self, l: &ast::Local, _: ()) { + if self.fcx.writeback_errors.get() { + return; } - }; - debug!("Adjustments for node {}: {:?}", - id, resolved_adj); - match resolved_adj { - Some(adj) => { - tcx.adjustments.borrow_mut().insert(id, adj); + let var_ty = self.fcx.local_ty(l.span, l.id); + let var_ty = var_ty.resolve(self.fcx, ResolvingLocal(l.span)); + write_ty_to_tcx(self.tcx(), l.id, var_ty); + visit::walk_local(self, l, ()); + } + + fn visit_ty(&mut self, _t: &ast::Ty, _: ()) { + // ignore + } +} + +impl<'cx> WritebackCx<'cx> { + fn visit_upvar_borrow_map(&self) { + if self.fcx.writeback_errors.get() { + return; + } + + for (upvar_id, upvar_borrow) in self.fcx.inh.upvar_borrow_map.borrow().iter() { + let r = upvar_borrow.region; + let r = r.resolve(self.fcx, ResolvingUpvar(*upvar_id)); + let new_upvar_borrow = ty::UpvarBorrow { kind: upvar_borrow.kind, + region: r }; + debug!("Upvar borrow for {} resolved to {}", + upvar_id.repr(self.tcx()), + new_upvar_borrow.repr(self.tcx())); + self.fcx.tcx().upvar_borrow_map.borrow_mut().insert( + *upvar_id, new_upvar_borrow); } - None => {} } - // Resolve the type of the node with id `id` - let n_ty = fcx.node_ty(id); - match resolve_type_vars_in_type(fcx, sp, n_ty) { - None => { - wbcx.success = false; - } - - Some(t) => { - debug!("resolve_type_vars_for_node(id={}, n_ty={}, t={})", - id, ppaux::ty_to_str(tcx, n_ty), ppaux::ty_to_str(tcx, t)); - write_ty_to_tcx(tcx, id, t); - fcx.opt_node_ty_substs(id, |substs| { - let mut new_tps = Vec::new(); - for subst in substs.tps.iter() { - match resolve_type_vars_in_type(fcx, sp, *subst) { - Some(t) => new_tps.push(t), - None => { wbcx.success = false; break } - } - } - write_substs_to_tcx(tcx, id, new_tps); - wbcx.success + fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) { + // Resolve any borrowings for the node with id `id` + self.visit_adjustments(reason, id); + + // Resolve the type of the node with id `id` + let n_ty = self.fcx.node_ty(id); + let n_ty = n_ty.resolve(self.fcx, reason); + write_ty_to_tcx(self.tcx(), id, n_ty); + debug!("Node {} has type {}", id, n_ty.repr(self.tcx())); + + // Resolve any substitutions + self.fcx.opt_node_ty_substs(id, |node_substs| { + let mut new_tps = Vec::new(); + for subst in node_substs.tps.iter() { + new_tps.push(subst.resolve(self.fcx, reason)); + } + write_substs_to_tcx(self.tcx(), id, new_tps); }); - } } -} -struct WbCtxt<'a> { - fcx: &'a FnCtxt<'a>, + fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) { + match self.fcx.inh.adjustments.borrow_mut().pop(&id) { + None => { + debug!("No adjustments for node {}", id); + } - // As soon as we hit an error we have to stop resolving - // the entire function. - success: bool, -} + Some(adjustment) => { + let resolved_adjustment = match adjustment { + ty::AutoAddEnv(store) => { + // FIXME(eddyb) #2190 Allow only statically resolved + // bare functions to coerce to a closure to avoid + // constructing (slower) indirect call wrappers. + match self.tcx().def_map.borrow().find(&id) { + Some(&ast::DefFn(..)) | + Some(&ast::DefStaticMethod(..)) | + Some(&ast::DefVariant(..)) | + Some(&ast::DefStruct(_)) => { + } + _ => { + self.tcx().sess.span_err( + reason.span(self.fcx), + "cannot coerce non-statically resolved bare fn") + } + } -fn visit_stmt(s: &ast::Stmt, wbcx: &mut WbCtxt) { - if !wbcx.success { return; } - resolve_type_vars_for_node(wbcx, s.span, ty::stmt_node_id(s)); - visit::walk_stmt(wbcx, s, ()); -} + ty::AutoAddEnv(store.resolve(self.fcx, reason)) + } + + ty::AutoDerefRef(adj) => { + for autoderef in range(0, adj.autoderefs) { + let method_call = MethodCall::autoderef(id, autoderef as u32); + self.visit_method_map_entry(reason, method_call); + self.visit_vtable_map_entry(reason, method_call); + } -fn visit_expr(e: &ast::Expr, wbcx: &mut WbCtxt) { - if !wbcx.success { - return; + ty::AutoDerefRef(ty::AutoDerefRef { + autoderefs: adj.autoderefs, + autoref: adj.autoref.resolve(self.fcx, reason), + }) + } + + adjustment => adjustment + }; + debug!("Adjustments for node {}: {:?}", id, resolved_adjustment); + self.tcx().adjustments.borrow_mut().insert( + id, resolved_adjustment); + } + } } - resolve_type_vars_for_node(wbcx, e.span, e.id); - resolve_method_map_entry(wbcx, e.span, MethodCall::expr(e.id)); - resolve_vtable_map_entry(wbcx.fcx, e.span, MethodCall::expr(e.id)); + fn visit_method_map_entry(&self, + reason: ResolveReason, + method_call: MethodCall) { + // Resolve any method map entry + match self.fcx.inh.method_map.borrow_mut().pop(&method_call) { + Some(method) => { + debug!("writeback::resolve_method_map_entry(call={:?}, entry={})", + method_call, + method.repr(self.tcx())); + let mut new_method = MethodCallee { + origin: method.origin, + ty: method.ty.resolve(self.fcx, reason), + substs: method.substs.resolve(self.fcx, reason), + }; + + // Wack. For some reason I don't quite know, we always + // hard-code the self-ty and regions to these + // values. Changing this causes downstream errors I + // don't feel like investigating right now (in + // particular, self_ty is set to mk_err in some cases, + // probably for invocations on objects, and this + // causes encoding failures). -nmatsakis + new_method.substs.self_ty = None; + new_method.substs.regions = ty::ErasedRegions; + + self.tcx().method_map.borrow_mut().insert( + method_call, + new_method); + } + None => {} + } + } - match e.node { - ast::ExprFnBlock(ref decl, _) | ast::ExprProc(ref decl, _) => { - for input in decl.inputs.iter() { - let _ = resolve_type_vars_for_node(wbcx, e.span, input.id); + fn visit_vtable_map_entry(&self, + reason: ResolveReason, + vtable_key: MethodCall) { + // Resolve any vtable map entry + match self.fcx.inh.vtable_map.borrow_mut().pop(&vtable_key) { + Some(origins) => { + let r_origins = origins.resolve(self.fcx, reason); + debug!("writeback::resolve_vtable_map_entry(\ + vtable_key={}, vtables={:?})", + vtable_key, r_origins.repr(self.tcx())); + self.tcx().vtable_map.borrow_mut().insert(vtable_key, r_origins); } + None => {} } - _ => {} } +} + +/////////////////////////////////////////////////////////////////////////// +// Resolution reason. - visit::walk_expr(wbcx, e, ()); +enum ResolveReason { + ResolvingExpr(Span), + ResolvingLocal(Span), + ResolvingPattern(Span), + ResolvingUpvar(ty::UpvarId) } -fn visit_block(b: &ast::Block, wbcx: &mut WbCtxt) { - if !wbcx.success { - return; +impl ResolveReason { + fn span(&self, fcx: &FnCtxt) -> Span { + match *self { + ResolvingExpr(s) => s, + ResolvingLocal(s) => s, + ResolvingPattern(s) => s, + ResolvingUpvar(upvar_id) => { + ty::expr_span(fcx.tcx(), upvar_id.closure_expr_id) + } + } } +} + +/////////////////////////////////////////////////////////////////////////// +// Convenience methods for resolving different kinds of things. - resolve_type_vars_for_node(wbcx, b.span, b.id); - visit::walk_block(wbcx, b, ()); +trait Resolve { + fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> Self; } -fn visit_pat(p: &ast::Pat, wbcx: &mut WbCtxt) { - if !wbcx.success { - return; +impl Resolve for Option { + fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> Option { + self.as_ref().map(|t| t.resolve(fcx, reason)) } +} - resolve_type_vars_for_node(wbcx, p.span, p.id); - debug!("Type for pattern binding {} (id {}) resolved to {}", - pat_to_str(p), p.id, - wbcx.fcx.infcx().ty_to_str( - ty::node_id_to_type(wbcx.fcx.ccx.tcx, - p.id))); - visit::walk_pat(wbcx, p, ()); +impl Resolve for Vec { + fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> Vec { + self.iter().map(|t| t.resolve(fcx, reason)).collect() + } } -fn visit_local(l: &ast::Local, wbcx: &mut WbCtxt) { - if !wbcx.success { return; } - let var_ty = wbcx.fcx.local_ty(l.span, l.id); - match resolve_type(wbcx.fcx.infcx(), var_ty, resolve_all | force_all) { - Ok(lty) => { - debug!("Type for local {} (id {}) resolved to {}", - pat_to_str(l.pat), - l.id, - wbcx.fcx.infcx().ty_to_str(lty)); - write_ty_to_tcx(wbcx.fcx.ccx.tcx, l.id, lty); - } - Err(e) => { - wbcx.fcx.ccx.tcx.sess.span_err( - l.span, - format!("cannot determine a type \ - for this local variable: {}", - infer::fixup_err_to_str(e))); - wbcx.success = false; - } +impl Resolve for ty::TraitStore { + fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::TraitStore { + Resolver::new(fcx, reason).fold_trait_store(*self) } - visit::walk_local(wbcx, l, ()); } -fn visit_item(_item: &ast::Item, _wbcx: &mut WbCtxt) { - // Ignore items + +impl Resolve for ty::t { + fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::t { + Resolver::new(fcx, reason).fold_ty(*self) + } } -impl<'a> Visitor<()> for WbCtxt<'a> { - fn visit_item(&mut self, i: &ast::Item, _: ()) { visit_item(i, self); } - fn visit_stmt(&mut self, s: &ast::Stmt, _: ()) { visit_stmt(s, self); } - fn visit_expr(&mut self, ex:&ast::Expr, _: ()) { visit_expr(ex, self); } - fn visit_block(&mut self, b: &ast::Block, _: ()) { visit_block(b, self); } - fn visit_pat(&mut self, p: &ast::Pat, _: ()) { visit_pat(p, self); } - fn visit_local(&mut self, l: &ast::Local, _: ()) { visit_local(l, self); } - // FIXME(#10894) should continue recursing - fn visit_ty(&mut self, _t: &ast::Ty, _: ()) {} +impl Resolve for ty::Region { + fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::Region { + Resolver::new(fcx, reason).fold_region(*self) + } } -fn resolve_upvar_borrow_map(wbcx: &mut WbCtxt) { - if !wbcx.success { - return; +impl Resolve for ty::substs { + fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::substs { + Resolver::new(fcx, reason).fold_substs(self) } +} - let fcx = wbcx.fcx; - let tcx = fcx.tcx(); - for (upvar_id, upvar_borrow) in fcx.inh.upvar_borrow_map.borrow().iter() { - let r = upvar_borrow.region; - match resolve_region(fcx.infcx(), r, resolve_all | force_all) { - Ok(r) => { - let new_upvar_borrow = ty::UpvarBorrow { - kind: upvar_borrow.kind, - region: r - }; - debug!("Upvar borrow for {} resolved to {}", - upvar_id.repr(tcx), new_upvar_borrow.repr(tcx)); - tcx.upvar_borrow_map.borrow_mut().insert(*upvar_id, - new_upvar_borrow); +impl Resolve for ty::AutoRef { + fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::AutoRef { + Resolver::new(fcx, reason).fold_autoref(self) + } +} + +impl Resolve for vtable_origin { + fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> vtable_origin { + match *self { + vtable_static(def_id, ref tys, ref origins) => { + let r_tys = tys.resolve(fcx, reason); + let r_origins = origins.resolve(fcx, reason); + vtable_static(def_id, r_tys, r_origins) } - Err(e) => { - let span = ty::expr_span(tcx, upvar_id.closure_expr_id); - fcx.ccx.tcx.sess.span_err( - span, format!("cannot resolve lifetime for \ - captured variable `{}`: {}", - ty::local_var_name_str(tcx, upvar_id.var_id).get().to_str(), - infer::fixup_err_to_str(e))); - wbcx.success = false; + vtable_param(n, b) => { + vtable_param(n, b) } - }; + } } } -pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) -> bool { - let mut wbcx = WbCtxt { fcx: fcx, success: true }; - let wbcx = &mut wbcx; - wbcx.visit_expr(e, ()); - resolve_upvar_borrow_map(wbcx); - return wbcx.success; +/////////////////////////////////////////////////////////////////////////// +// The Resolver. This is the type folding engine that detects +// unresolved types and so forth. + +struct Resolver<'cx> { + fcx: &'cx FnCtxt<'cx>, + reason: ResolveReason, } -pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, decl: &ast::FnDecl, - blk: &ast::Block) -> bool { - let mut wbcx = WbCtxt { fcx: fcx, success: true }; - let wbcx = &mut wbcx; - wbcx.visit_block(blk, ()); - for arg in decl.inputs.iter() { - wbcx.visit_pat(arg.pat, ()); - // Privacy needs the type for the whole pattern, not just each binding - if !pat_util::pat_is_binding(&fcx.tcx().def_map, arg.pat) { - resolve_type_vars_for_node(wbcx, arg.pat.span, arg.pat.id); +impl<'cx> Resolver<'cx> { + fn new(fcx: &'cx FnCtxt<'cx>, + reason: ResolveReason) + -> Resolver<'cx> + { + Resolver { fcx: fcx, reason: reason } + } + + fn report_error(&self, e: infer::fixup_err) { + self.fcx.writeback_errors.set(true); + if !self.tcx().sess.has_errors() { + match self.reason { + ResolvingExpr(span) => { + self.tcx().sess.span_err( + span, + format!("cannot determine a type for \ + this expression: {}", + infer::fixup_err_to_str(e))) + } + + ResolvingLocal(span) => { + self.tcx().sess.span_err( + span, + format!("cannot determine a type for \ + this local variable: {}", + infer::fixup_err_to_str(e))) + } + + ResolvingPattern(span) => { + self.tcx().sess.span_err( + span, + format!("cannot determine a type for \ + this pattern binding: {}", + infer::fixup_err_to_str(e))) + } + + ResolvingUpvar(upvar_id) => { + let span = self.reason.span(self.fcx); + self.tcx().sess.span_err( + span, + format!("cannot resolve lifetime for \ + captured variable `{}`: {}", + ty::local_var_name_str( + self.tcx(), + upvar_id.var_id).get().to_str(), + infer::fixup_err_to_str(e))); + } + } + } + } +} + +impl<'cx> TypeFolder for Resolver<'cx> { + fn tcx<'a>(&'a self) -> &'a ty::ctxt { + self.fcx.tcx() + } + + fn fold_ty(&mut self, t: ty::t) -> ty::t { + if !ty::type_needs_infer(t) { + return t; + } + + match resolve_type(self.fcx.infcx(), t, resolve_all | force_all) { + Ok(t) => t, + Err(e) => { + self.report_error(e); + ty::mk_err() + } + } + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match resolve_region(self.fcx.infcx(), r, resolve_all | force_all) { + Ok(r) => r, + Err(e) => { + self.report_error(e); + ty::ReStatic + } } } - resolve_upvar_borrow_map(wbcx); - return wbcx.success; } diff --git a/src/test/compile-fail/typeck_type_placeholder_mismatch.rs b/src/test/compile-fail/typeck_type_placeholder_mismatch.rs index 492a0afff3003..f7e5964fa2450 100644 --- a/src/test/compile-fail/typeck_type_placeholder_mismatch.rs +++ b/src/test/compile-fail/typeck_type_placeholder_mismatch.rs @@ -26,5 +26,4 @@ fn test1() { fn test2() { let x: Foo<_> = Bar::; //~^ ERROR mismatched types: expected `Foo<>` but found `Bar` - //~^^ ERROR cannot determine a type for this local variable: unconstrained type }