diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 0458bd70346c1..bdf58fd7caaaa 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -787,7 +787,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // process. fn walk_adjustment(&mut self, expr: &ast::Expr) { let typer = self.typer; - if let Some(adjustment) = typer.adjustments().borrow().get(&expr.id) { + typer.adjustments( |adjustments| if let Some(adjustment) = adjustments.get(&expr.id) { match *adjustment { ty::AdjustReifyFnPointer | ty::AdjustUnsafeFnPointer => { @@ -802,7 +802,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { self.walk_autoderefref(expr, adj); } } - } + }) } /// Autoderefs for overloaded Deref calls in fact reference their receiver. That is, if we have @@ -1283,10 +1283,11 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } } -fn copy_or_move<'tcx>(typer: &mc::Typer<'tcx>, - cmt: &mc::cmt<'tcx>, - move_reason: MoveReason) - -> ConsumeMode +fn copy_or_move<'tcx,T>(typer: &T, + cmt: &mc::cmt<'tcx>, + move_reason: MoveReason) + -> ConsumeMode + where T: mc::Typer<'tcx> { if typer.type_moves_by_default(cmt.span, cmt.ty) { Move(move_reason) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3fff15049930b..7d5aeb337637e 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -87,7 +87,6 @@ use syntax::codemap::Span; use syntax::print::pprust; use syntax::parse::token; -use std::cell::RefCell; use std::rc::Rc; #[derive(Clone, PartialEq, Debug)] @@ -292,7 +291,8 @@ pub trait Typer<'tcx> : ty::ClosureTyper<'tcx> { fn node_method_ty(&self, method_call: ty::MethodCall) -> Option>; fn node_method_origin(&self, method_call: ty::MethodCall) -> Option>; - fn adjustments<'a>(&'a self) -> &'a RefCell>>; + fn adjustments(&self, closure: F) -> T + where F: FnOnce(&NodeMap>) -> T; fn is_method_call(&self, id: ast::NodeId) -> bool; fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option; fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option; @@ -409,9 +409,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult> { let unadjusted_ty = try!(self.expr_ty(expr)); - Ok(ty::adjust_ty(self.tcx(), expr.span, expr.id, unadjusted_ty, - self.typer.adjustments().borrow().get(&expr.id), - |method_call| self.typer.node_method_ty(method_call))) + self.typer.adjustments( |adjustments| + Ok(ty::adjust_ty(self.tcx(), expr.span, expr.id, unadjusted_ty, + adjustments.get(&expr.id), + |method_call| self.typer.node_method_ty(method_call)))) } fn node_ty(&self, id: ast::NodeId) -> McResult> { @@ -443,7 +444,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } pub fn cat_expr(&self, expr: &ast::Expr) -> McResult> { - match self.typer.adjustments().borrow().get(&expr.id) { + self.typer.adjustments( |adjustments| match adjustments.get(&expr.id) { None => { // No adjustments. self.cat_expr_unadjusted(expr) @@ -470,7 +471,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } } } - } + } ) } pub fn cat_expr_autoderefd(&self, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index cb069acdfd2f0..7976a9e2e53fd 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -6127,10 +6127,11 @@ pub struct ClosureUpvar<'tcx> { } // Returns a list of `ClosureUpvar`s for each upvar. -pub fn closure_upvars<'tcx>(typer: &mc::Typer<'tcx>, - closure_id: ast::DefId, - substs: &Substs<'tcx>) - -> Option>> +pub fn closure_upvars<'tcx,T>(typer: &T, + closure_id: ast::DefId, + substs: &Substs<'tcx>) + -> Option>> + where T: mc::Typer<'tcx> { // Presently an unboxed closure type cannot "escape" out of a // function, so we will only encounter ones that originated in the @@ -6831,8 +6832,9 @@ impl<'a,'tcx> mc::Typer<'tcx> for ParameterEnvironment<'a,'tcx> { self.tcx.method_map.borrow().get(&method_call).map(|method| method.origin.clone()) } - fn adjustments(&self) -> &RefCell>> { - &self.tcx.adjustments + fn adjustments(&self, closure: F) -> T + where F: FnOnce(&NodeMap>) -> T { + closure(&self.tcx.adjustments.borrow()) } fn is_method_call(&self, id: ast::NodeId) -> bool { diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 03dda57e5689f..198ee29f1525a 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -669,8 +669,9 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> { .map(|method| method.origin.clone()) } - fn adjustments<'a>(&'a self) -> &'a RefCell>> { - &self.tcx().adjustments + fn adjustments(&self, closure: F) -> T + where F: FnOnce(&NodeMap>) -> T { + closure(&self.tcx().adjustments.borrow()) } fn is_method_call(&self, id: ast::NodeId) -> bool { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 54ec1aace9211..7ac831d6a5955 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -92,7 +92,7 @@ pub trait AstConv<'tcx> { /// Returns the set of bounds in scope for the type parameter with /// the given id. - fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId) + fn get_type_parameter_bounds(&mut self, span: Span, def_id: ast::NodeId) -> Result>, ErrorReported>; /// Returns true if the trait with id `trait_def_id` defines an @@ -118,7 +118,7 @@ pub trait AstConv<'tcx> { /// signatures for that reason. In a function body, we can always /// handle it because we can use inference variables to remove the /// late-bound regions. - fn projected_ty_from_poly_trait_ref(&self, + fn projected_ty_from_poly_trait_ref(&mut self, span: Span, poly_trait_ref: ty::PolyTraitRef<'tcx>, item_name: ast::Name) @@ -137,7 +137,7 @@ pub trait AstConv<'tcx> { /// Project an associated type from a non-higher-ranked trait reference. /// This is fairly straightforward and can be accommodated in any context. - fn projected_ty(&self, + fn projected_ty(&mut self, span: Span, _trait_ref: ty::TraitRef<'tcx>, _item_name: ast::Name) @@ -187,7 +187,7 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) } pub fn opt_ast_region_to_region<'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, rscope: &RegionScope, default_span: Span, opt_lifetime: &Option) -> ty::Region @@ -266,7 +266,7 @@ pub fn opt_ast_region_to_region<'tcx>( /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, /// returns an appropriate set of substitutions for this particular reference to `I`. pub fn ast_path_substs_for_ty<'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, param_mode: PathParamMode, @@ -274,8 +274,6 @@ pub fn ast_path_substs_for_ty<'tcx>( item_segment: &ast::PathSegment) -> Substs<'tcx> { - let tcx = this.tcx(); - // ast_path_substs() is only called to convert paths that are // known to refer to traits, types, or structs. In these cases, // all type parameters defined for the item being referenced will @@ -292,7 +290,7 @@ pub fn ast_path_substs_for_ty<'tcx>( convert_angle_bracketed_parameters(this, rscope, span, decl_generics, data) } ast::ParenthesizedParameters(ref data) => { - span_err!(tcx.sess, span, E0214, + span_err!(this.tcx().sess, span, E0214, "parenthesized parameters may only be used with a trait"); convert_parenthesized_parameters(this, rscope, span, decl_generics, data) } @@ -318,7 +316,7 @@ pub enum PathParamMode { } fn create_region_substs<'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, decl_generics: &ty::Generics<'tcx>, @@ -362,7 +360,7 @@ fn create_region_substs<'tcx>( /// -- that is, a substitution with no types but the correct number of /// regions. fn create_substs_for_ast_path<'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, span: Span, param_mode: PathParamMode, decl_generics: &ty::Generics<'tcx>, @@ -466,7 +464,7 @@ struct ConvertedBinding<'tcx> { span: Span, } -fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>, +fn convert_angle_bracketed_parameters<'tcx>(this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, decl_generics: &ty::Generics<'tcx>, @@ -533,7 +531,7 @@ fn find_implied_output_region(input_tys: &[Ty], input_pats: Vec) (implied_output_region, lifetimes_for_params) } -fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>, +fn convert_ty_with_lifetime_elision<'tcx>(this: &mut AstConv<'tcx>, implied_output_region: Option, param_lifetimes: Vec<(String, usize)>, ty: &ast::Ty) @@ -554,7 +552,7 @@ fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>, } } -fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>, +fn convert_parenthesized_parameters<'tcx>(this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, decl_generics: &ty::Generics<'tcx>, @@ -602,7 +600,7 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>, } pub fn instantiate_poly_trait_ref<'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, rscope: &RegionScope, ast_trait_ref: &ast::PolyTraitRef, self_ty: Option>, @@ -628,7 +626,7 @@ pub fn instantiate_poly_trait_ref<'tcx>( /// If the `projections` argument is `None`, then assoc type bindings like `Foo` /// are disallowed. Otherwise, they are pushed onto the vector given. pub fn instantiate_mono_trait_ref<'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, rscope: &RegionScope, trait_ref: &ast::TraitRef, self_ty: Option>) @@ -644,7 +642,7 @@ pub fn instantiate_mono_trait_ref<'tcx>( trait_ref.path.segments.last().unwrap()) } -fn trait_def_id<'tcx>(this: &AstConv<'tcx>, trait_ref: &ast::TraitRef) -> ast::DefId { +fn trait_def_id<'tcx>(this: &mut AstConv<'tcx>, trait_ref: &ast::TraitRef) -> ast::DefId { let path = &trait_ref.path; match ::lookup_full_def(this.tcx(), path.span, trait_ref.ref_id) { def::DefTrait(trait_def_id) => trait_def_id, @@ -656,7 +654,7 @@ fn trait_def_id<'tcx>(this: &AstConv<'tcx>, trait_ref: &ast::TraitRef) -> ast::D } fn object_path_to_poly_trait_ref<'a,'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, param_mode: PathParamMode, @@ -676,7 +674,7 @@ fn object_path_to_poly_trait_ref<'a,'tcx>( } fn ast_path_to_poly_trait_ref<'a,'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, param_mode: PathParamMode, @@ -722,7 +720,7 @@ fn ast_path_to_poly_trait_ref<'a,'tcx>( poly_trait_ref } -fn ast_path_to_mono_trait_ref<'a,'tcx>(this: &AstConv<'tcx>, +fn ast_path_to_mono_trait_ref<'a,'tcx>(this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, param_mode: PathParamMode, @@ -743,7 +741,7 @@ fn ast_path_to_mono_trait_ref<'a,'tcx>(this: &AstConv<'tcx>, ty::TraitRef::new(trait_def_id, substs) } -fn create_substs_for_ast_trait_ref<'a,'tcx>(this: &AstConv<'tcx>, +fn create_substs_for_ast_trait_ref<'a,'tcx>(this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, param_mode: PathParamMode, @@ -807,14 +805,12 @@ fn create_substs_for_ast_trait_ref<'a,'tcx>(this: &AstConv<'tcx>, } fn ast_type_binding_to_poly_projection_predicate<'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, mut trait_ref: ty::PolyTraitRef<'tcx>, self_ty: Option>, binding: &ConvertedBinding<'tcx>) -> Result, ErrorReported> { - let tcx = this.tcx(); - // Given something like `U : SomeTrait`, we want to produce a // predicate like `::T = X`. This is somewhat // subtle in the event that `T` is defined in a supertrait of @@ -850,19 +846,19 @@ fn ast_type_binding_to_poly_projection_predicate<'tcx>( // this, we currently insert a dummy type and then remove it // later. Yuck. - let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0)); + let dummy_self_ty = ty::mk_infer(this.tcx(), ty::FreshTy(0)); if self_ty.is_none() { // if converting for an object type let mut dummy_substs = trait_ref.skip_binder().substs.clone(); // binder moved here -+ assert!(dummy_substs.self_ty().is_none()); // | dummy_substs.types.push(SelfSpace, dummy_self_ty); // | trait_ref = ty::Binder(ty::TraitRef::new(trait_ref.def_id(), // <------------+ - tcx.mk_substs(dummy_substs))); + this.tcx().mk_substs(dummy_substs))); } try!(this.ensure_super_predicates(binding.span, trait_ref.def_id())); let mut candidates: Vec = - traits::supertraits(tcx, trait_ref.clone()) + traits::supertraits(this.tcx(), trait_ref.clone()) .filter(|r| this.trait_defines_associated_type_named(r.def_id(), binding.item_name)) .collect(); @@ -874,13 +870,13 @@ fn ast_type_binding_to_poly_projection_predicate<'tcx>( assert!(dummy_substs.self_ty() == Some(dummy_self_ty)); dummy_substs.types.pop(SelfSpace); *candidate = ty::Binder(ty::TraitRef::new(candidate.def_id(), - tcx.mk_substs(dummy_substs))); + this.tcx().mk_substs(dummy_substs))); } } - let candidate = try!(one_bound_for_assoc_type(tcx, + let candidate = try!(one_bound_for_assoc_type(this.tcx(), candidates, - &trait_ref.user_string(tcx), + &trait_ref.user_string(this.tcx()), &token::get_name(binding.item_name), binding.span)); @@ -894,7 +890,7 @@ fn ast_type_binding_to_poly_projection_predicate<'tcx>( } fn ast_path_to_ty<'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, param_mode: PathParamMode, @@ -902,13 +898,12 @@ fn ast_path_to_ty<'tcx>( item_segment: &ast::PathSegment) -> Ty<'tcx> { - let tcx = this.tcx(); let (generics, decl_ty) = match this.get_item_type_scheme(span, did) { Ok(ty::TypeScheme { generics, ty: decl_ty }) => { (generics, decl_ty) } Err(ErrorReported) => { - return tcx.types.err; + return this.tcx().types.err; } }; @@ -930,7 +925,7 @@ fn ast_path_to_ty<'tcx>( type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec>); -fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, +fn ast_ty_to_trait_ref<'tcx>(this: &mut AstConv<'tcx>, rscope: &RegionScope, ty: &ast::Ty, bounds: &[ast::TyParamBound]) @@ -1013,7 +1008,7 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, } } -fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>, +fn trait_ref_to_object_type<'tcx>(this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, trait_ref: ty::PolyTraitRef<'tcx>, @@ -1035,7 +1030,7 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>, result } -fn make_object_type<'tcx>(this: &AstConv<'tcx>, +fn make_object_type<'tcx>(this: &mut AstConv<'tcx>, span: Span, principal: ty::PolyTraitRef<'tcx>, bounds: ty::ExistentialBounds<'tcx>) @@ -1096,14 +1091,12 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt, // (which might be `Self`, but only if it is the `Self` of a trait, not an // impl). This function will fail if there are no suitable bounds or there is // any ambiguity. -fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, +fn find_bound_for_assoc_item<'tcx>(this: &mut AstConv<'tcx>, ty_param_node_id: ast::NodeId, assoc_name: ast::Name, span: Span) -> Result, ErrorReported> { - let tcx = this.tcx(); - let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) { Ok(v) => v, Err(ErrorReported) => { @@ -1119,12 +1112,12 @@ fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, // Check that there is exactly one way to find an associated type with the // correct name. let suitable_bounds: Vec<_> = - traits::transitive_bounds(tcx, &bounds) + traits::transitive_bounds(this.tcx(), &bounds) .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) .collect(); - let ty_param_name = tcx.type_parameter_def(ty_param_node_id).name; - one_bound_for_assoc_type(tcx, + let ty_param_name = this.tcx().type_parameter_def(ty_param_node_id).name; + one_bound_for_assoc_type(this.tcx(), suitable_bounds, &token::get_name(ty_param_name), &token::get_name(assoc_name), @@ -1172,19 +1165,18 @@ fn one_bound_for_assoc_type<'tcx>(tcx: &ty::ctxt<'tcx>, // the whole path. // Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type // parameter or Self. -fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, +fn associated_path_def_to_ty<'tcx>(this: &mut AstConv<'tcx>, span: Span, ty: Ty<'tcx>, ty_path_def: def::Def, item_segment: &ast::PathSegment) -> (Ty<'tcx>, def::Def) { - let tcx = this.tcx(); let assoc_name = item_segment.identifier.name; - debug!("associated_path_def_to_ty: {}::{}", ty.repr(tcx), token::get_name(assoc_name)); + debug!("associated_path_def_to_ty: {}::{}", ty.repr(this.tcx()), token::get_name(assoc_name)); - check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); + check_path_args(this.tcx(), slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); // Find the type of the associated item, and the trait where the associated // item is declared. @@ -1192,10 +1184,10 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, (_, def::DefSelfTy(Some(trait_did), Some((impl_id, _)))) => { // `Self` in an impl of a trait - we have a concrete self type and a // trait reference. - match tcx.map.expect_item(impl_id).node { + match this.tcx().map.expect_item(impl_id).node { ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) => { if this.ensure_super_predicates(span, trait_did).is_err() { - return (tcx.types.err, ty_path_def); + return (this.tcx().types.err, ty_path_def); } let trait_segment = &trait_ref.path.segments.last().unwrap(); @@ -1208,18 +1200,18 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, trait_segment); let candidates: Vec = - traits::supertraits(tcx, ty::Binder(trait_ref.clone())) + traits::supertraits(this.tcx(), ty::Binder(trait_ref.clone())) .filter(|r| this.trait_defines_associated_type_named(r.def_id(), assoc_name)) .collect(); - match one_bound_for_assoc_type(tcx, + match one_bound_for_assoc_type(this.tcx(), candidates, "Self", &token::get_name(assoc_name), span) { Ok(bound) => bound, - Err(ErrorReported) => return (tcx.types.err, ty_path_def), + Err(ErrorReported) => return (this.tcx().types.err, ty_path_def), } } _ => unreachable!() @@ -1232,16 +1224,16 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, let ty_param_node_id = ty_path_def.local_node_id(); match find_bound_for_assoc_item(this, ty_param_node_id, assoc_name, span) { Ok(bound) => bound, - Err(ErrorReported) => return (tcx.types.err, ty_path_def), + Err(ErrorReported) => return (this.tcx().types.err, ty_path_def), } } _ => { - report_ambiguous_associated_type(tcx, + report_ambiguous_associated_type(this.tcx(), span, - &ty.user_string(tcx), + &ty.user_string(this.tcx()), "Trait", &token::get_name(assoc_name)); - return (tcx.types.err, ty_path_def); + return (this.tcx().types.err, ty_path_def); } }; @@ -1251,7 +1243,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, let item_did = if trait_did.krate == ast::LOCAL_CRATE { // `ty::trait_items` used below requires information generated // by type collection, which may be in progress at this point. - match tcx.map.expect_item(trait_did.node).node { + match this.tcx().map.expect_item(trait_did.node).node { ast::ItemTrait(_, _, _, ref trait_items) => { let item = trait_items.iter() .find(|i| i.ident.name == assoc_name) @@ -1261,7 +1253,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, _ => unreachable!() } } else { - let trait_items = ty::trait_items(tcx, trait_did); + let trait_items = ty::trait_items(this.tcx(), trait_did); let item = trait_items.iter().find(|i| i.name() == assoc_name); item.expect("missing associated type").def_id() }; @@ -1269,7 +1261,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, (ty, def::DefAssociatedTy(trait_did, item_did)) } -fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, +fn qpath_to_ty<'tcx>(this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, param_mode: PathParamMode, @@ -1279,23 +1271,21 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, item_segment: &ast::PathSegment) -> Ty<'tcx> { - let tcx = this.tcx(); - - check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); + check_path_args(this.tcx(), slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); let self_ty = if let Some(ty) = opt_self_ty { ty } else { - let path_str = ty::item_path_str(tcx, trait_def_id); - report_ambiguous_associated_type(tcx, + let path_str = ty::item_path_str(this.tcx(), trait_def_id); + report_ambiguous_associated_type(this.tcx(), span, "Type", &path_str, &token::get_ident(item_segment.identifier)); - return tcx.types.err; + return this.tcx().types.err; }; - debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx)); + debug!("qpath_to_ty: self_type={}", self_ty.repr(this.tcx())); let trait_ref = ast_path_to_mono_trait_ref(this, rscope, @@ -1305,7 +1295,7 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, Some(self_ty), trait_segment); - debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx)); + debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx())); this.projected_ty(span, trait_ref, item_segment.identifier.name) } @@ -1324,7 +1314,7 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, /// * `region_substs`: a partial substitution consisting of /// only the region type parameters being supplied to this type. /// * `ast_ty`: the ast representation of the type being supplied -pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>, +pub fn ast_ty_arg_to_ty<'tcx>(this: &mut AstConv<'tcx>, rscope: &RegionScope, decl_generics: &ty::Generics<'tcx>, index: usize, @@ -1332,10 +1322,8 @@ pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>, ast_ty: &ast::Ty) -> Ty<'tcx> { - let tcx = this.tcx(); - if let Some(def) = decl_generics.types.opt_get(TypeSpace, index) { - let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs); + let object_lifetime_default = def.object_lifetime_default.subst(this.tcx(), region_substs); let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default); ast_ty_to_ty(this, rscope1, ast_ty) } else { @@ -1346,7 +1334,7 @@ pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>, // Check the base def in a PathResolution and convert it to a Ty. If there are // associated types in the PathResolution, these will need to be separately // resolved. -fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, +fn base_def_to_ty<'tcx>(this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, param_mode: PathParamMode, @@ -1354,8 +1342,6 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, opt_self_ty: Option>, base_segments: &[ast::PathSegment]) -> Ty<'tcx> { - let tcx = this.tcx(); - match *def { def::DefTrait(trait_def_id) => { // N.B. this case overlaps somewhat with @@ -1370,7 +1356,7 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, base_segments.last().unwrap(), &mut projection_bounds); - check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS); + check_path_args(this.tcx(), base_segments.init(), NO_TPS | NO_REGIONS); trait_ref_to_object_type(this, rscope, span, @@ -1379,7 +1365,7 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, &[]) } def::DefTy(did, _) | def::DefStruct(did) => { - check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS); + check_path_args(this.tcx(), base_segments.init(), NO_TPS | NO_REGIONS); ast_path_to_ty(this, rscope, span, @@ -1388,25 +1374,26 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, base_segments.last().unwrap()) } def::DefTyParam(space, index, _, name) => { - check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); - ty::mk_param(tcx, space, index, name) + check_path_args(this.tcx(), base_segments, NO_TPS | NO_REGIONS); + ty::mk_param(this.tcx(), space, index, name) } def::DefSelfTy(_, Some((_, self_ty_id))) => { // Self in impl (we know the concrete type). - check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); - if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&self_ty_id) { + check_path_args(this.tcx(), base_segments, NO_TPS | NO_REGIONS); + if let Some(&ty) = this.tcx().ast_ty_to_ty_cache.borrow().get(&self_ty_id) { ty } else { - tcx.sess.span_bug(span, "self type has not been fully resolved") + this.tcx().sess.span_bug(span, "self type has not been fully resolved") } } def::DefSelfTy(Some(_), None) => { // Self in trait. - check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); - ty::mk_self_type(tcx) + check_path_args(this.tcx(), base_segments, NO_TPS | NO_REGIONS); + ty::mk_self_type(this.tcx()) } def::DefAssociatedTy(trait_did, _) => { - check_path_args(tcx, &base_segments[..base_segments.len()-2], NO_TPS | NO_REGIONS); + check_path_args(this.tcx(), + &base_segments[..base_segments.len()-2], NO_TPS | NO_REGIONS); qpath_to_ty(this, rscope, span, @@ -1426,21 +1413,21 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, // we don't have the trait information around, which is just sad. if !base_segments.is_empty() { - span_err!(tcx.sess, + span_err!(this.tcx().sess, span, E0247, "found module name used as a type: {}", - tcx.map.node_to_string(id.node)); + this.tcx().map.node_to_string(id.node)); return this.tcx().types.err; } opt_self_ty.expect("missing T in ::a::b::c") } def::DefPrimTy(prim_ty) => { - prim_ty_to_ty(tcx, base_segments, prim_ty) + prim_ty_to_ty(this.tcx(), base_segments, prim_ty) } _ => { - span_err!(tcx.sess, span, E0248, + span_err!(this.tcx().sess, span, E0248, "found value name used as a type: {:?}", *def); return this.tcx().types.err; } @@ -1449,7 +1436,7 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, // Note that both base_segments and assoc_segments may be empty, although not at // the same time. -pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, +pub fn finish_resolving_def_to_ty<'tcx>(this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, param_mode: PathParamMode, @@ -1485,7 +1472,7 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, /// Parses the programmer's textual representation of a type into our /// internal notion of a type. -pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, +pub fn ast_ty_to_ty<'tcx>(this: &mut AstConv<'tcx>, rscope: &RegionScope, ast_ty: &ast::Ty) -> Ty<'tcx> @@ -1493,15 +1480,14 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, debug!("ast_ty_to_ty(ast_ty={})", ast_ty.repr(this.tcx())); - let tcx = this.tcx(); - - if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { + if let Some(&ty) = this.tcx().ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { return ty; } let typ = match ast_ty.node { ast::TyVec(ref ty) => { - ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), None) + let ast_ty = ast_ty_to_ty(this, rscope, &**ty); + ty::mk_vec(this.tcx(), ast_ty, None) } ast::TyObjectSum(ref ty, ref bounds) => { match ast_ty_to_trait_ref(this, rscope, &**ty, bounds) { @@ -1519,8 +1505,9 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, } } ast::TyPtr(ref mt) => { - ty::mk_ptr(tcx, ty::mt { - ty: ast_ty_to_ty(this, rscope, &*mt.ty), + let ast_ty = ast_ty_to_ty(this, rscope, &*mt.ty); + ty::mk_ptr(this.tcx(), ty::mt { + ty: ast_ty, mutbl: mt.mutbl }) } @@ -1532,28 +1519,28 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, rscope, Some(ty::ObjectLifetimeDefault::Specific(r))); let t = ast_ty_to_ty(this, rscope1, &*mt.ty); - ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl}) + ty::mk_rptr(this.tcx(), this.tcx().mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl}) } ast::TyTup(ref fields) => { let flds = fields.iter() .map(|t| ast_ty_to_ty(this, rscope, &**t)) .collect(); - ty::mk_tup(tcx, flds) + ty::mk_tup(this.tcx(), flds) } ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ), ast::TyBareFn(ref bf) => { if bf.decl.variadic && bf.abi != abi::C { - span_err!(tcx.sess, ast_ty.span, E0222, + span_err!(this.tcx().sess, ast_ty.span, E0222, "variadic function must have C calling convention"); } let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl); - ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(bare_fn)) + ty::mk_bare_fn(this.tcx(), None, this.tcx().mk_bare_fn(bare_fn)) } ast::TyPolyTraitRef(ref bounds) => { conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds) } ast::TyPath(ref maybe_qself, ref path) => { - let path_res = if let Some(&d) = tcx.def_map.borrow().get(&ast_ty.id) { + let path_res = if let Some(&d) = this.tcx().def_map.borrow().get(&ast_ty.id) { d } else if let Some(ast::QSelf { position: 0, .. }) = *maybe_qself { // Create some fake resolution that can't possibly be a type. @@ -1563,8 +1550,8 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, depth: path.segments.len() } } else { - tcx.sess.span_bug(ast_ty.span, - &format!("unbound path {}", ast_ty.repr(tcx))) + this.tcx().sess.span_bug(ast_ty.span, + &format!("unbound path {}", ast_ty.repr(this.tcx()))) }; let def = path_res.base_def; let base_ty_end = path.segments.len() - path_res.depth; @@ -1582,7 +1569,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, if path_res.depth != 0 && ty.sty != ty::ty_err { // Write back the new resolution. - tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution { + this.tcx().def_map.borrow_mut().insert(ast_ty.id, def::PathResolution { base_def: def, last_private: path_res.last_private, depth: 0 @@ -1592,17 +1579,22 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, ty } ast::TyFixedLengthVec(ref ty, ref e) => { - match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.usize)) { + match const_eval::eval_const_expr_partial(this.tcx(), &**e, + Some(this.tcx().types.usize)) { Ok(r) => { match r { - const_eval::const_int(i) => - ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), - Some(i as usize)), - const_eval::const_uint(i) => - ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty), - Some(i as usize)), + const_eval::const_int(i) => { + let ast_ty = ast_ty_to_ty(this, rscope, &**ty); + ty::mk_vec(this.tcx(), ast_ty, + Some(i as usize)) + }, + const_eval::const_uint(i) => { + let ast_ty = ast_ty_to_ty(this, rscope, &**ty); + ty::mk_vec(this.tcx(), ast_ty, + Some(i as usize)) + }, _ => { - span_err!(tcx.sess, ast_ty.span, E0249, + span_err!(this.tcx().sess, ast_ty.span, E0249, "expected constant integer expression \ for array length"); this.tcx().types.err @@ -1612,18 +1604,18 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, Err(ref r) => { let subspan = ast_ty.span.lo <= r.span.lo && r.span.hi <= ast_ty.span.hi; - span_err!(tcx.sess, r.span, E0250, + span_err!(this.tcx().sess, r.span, E0250, "array length constant evaluation error: {}", r.description()); if !subspan { - span_note!(tcx.sess, ast_ty.span, "for array length here") + span_note!(this.tcx().sess, ast_ty.span, "for array length here") } this.tcx().types.err } } } ast::TyTypeof(ref _e) => { - tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented"); + this.tcx().sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented"); } ast::TyInfer => { // TyInfer also appears as the type of arguments or return @@ -1634,11 +1626,11 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, } }; - tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, typ); + this.tcx().ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, typ); return typ; } -pub fn ty_of_arg<'tcx>(this: &AstConv<'tcx>, +pub fn ty_of_arg<'tcx>(this: &mut AstConv<'tcx>, rscope: &RegionScope, a: &ast::Arg, expected_ty: Option>) @@ -1656,7 +1648,7 @@ struct SelfInfo<'a, 'tcx> { explicit_self: &'a ast::ExplicitSelf, } -pub fn ty_of_method<'tcx>(this: &AstConv<'tcx>, +pub fn ty_of_method<'tcx>(this: &mut AstConv<'tcx>, sig: &ast::MethodSig, untransformed_self_ty: Ty<'tcx>) -> (ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) { @@ -1673,13 +1665,13 @@ pub fn ty_of_method<'tcx>(this: &AstConv<'tcx>, (bare_fn_ty, optional_explicit_self_category.unwrap()) } -pub fn ty_of_bare_fn<'tcx>(this: &AstConv<'tcx>, unsafety: ast::Unsafety, abi: abi::Abi, +pub fn ty_of_bare_fn<'tcx>(this: &mut AstConv<'tcx>, unsafety: ast::Unsafety, abi: abi::Abi, decl: &ast::FnDecl) -> ty::BareFnTy<'tcx> { let (bare_fn_ty, _) = ty_of_method_or_bare_fn(this, unsafety, abi, None, decl); bare_fn_ty } -fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, +fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &mut AstConv<'tcx>, unsafety: ast::Unsafety, abi: abi::Abi, opt_self_info: Option>, @@ -1738,12 +1730,13 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, } else { &decl.inputs[..] }; - let input_tys = input_params.iter().map(|a| ty_of_arg(this, &rb, a, None)); let input_pats: Vec = input_params.iter() .map(|a| pprust::pat_to_string(&*a.pat)) .collect(); - let self_and_input_tys: Vec = - self_ty.into_iter().chain(input_tys).collect(); + let self_and_input_tys: Vec = { + let input_tys = input_params.iter().map(|a| ty_of_arg(this, &rb, a, None)); + self_ty.into_iter().chain(input_tys).collect() + }; // Second, if there was exactly one lifetime (either a substitution or a @@ -1787,7 +1780,7 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>, }, explicit_self_category_result) } -fn determine_explicit_self_category<'a, 'tcx>(this: &AstConv<'tcx>, +fn determine_explicit_self_category<'a, 'tcx>(this: &mut AstConv<'tcx>, rscope: &RegionScope, self_info: &SelfInfo<'a, 'tcx>) -> ty::ExplicitSelfCategory @@ -1868,7 +1861,7 @@ fn determine_explicit_self_category<'a, 'tcx>(this: &AstConv<'tcx>, } pub fn ty_of_closure<'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, unsafety: ast::Unsafety, decl: &ast::FnDecl, abi: abi::Abi, @@ -1931,7 +1924,7 @@ pub fn ty_of_closure<'tcx>( /// for closures. Eventually this should all be normalized, I think, so that there is no "main /// trait ref" and instead we just have a flat list of bounds as the existential type. fn conv_existential_bounds<'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, principal_trait_ref: ty::PolyTraitRef<'tcx>, @@ -1947,7 +1940,7 @@ fn conv_existential_bounds<'tcx>( } fn conv_ty_poly_trait_ref<'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, ast_bounds: &[ast::TyParamBound]) @@ -1981,7 +1974,7 @@ fn conv_ty_poly_trait_ref<'tcx>( } pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, principal_trait_ref: ty::PolyTraitRef<'tcx>, @@ -2021,7 +2014,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>( /// user provided, if they provided one, and otherwise search the supertypes of trait bounds for /// region bounds. It may be that we can derive no bound at all, in which case we return `None`. fn compute_object_lifetime_bound<'tcx>( - this: &AstConv<'tcx>, + this: &mut AstConv<'tcx>, rscope: &RegionScope, span: Span, explicit_region_bounds: &[&ast::Lifetime], diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 1f4d6cc2fd471..03b3b1935b7d5 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -16,9 +16,9 @@ use middle::pat_util::pat_is_resolved_const; use middle::privacy::{AllPublic, LastMod}; use middle::subst::Substs; use middle::ty::{self, Ty}; -use check::{check_expr, check_expr_has_type, check_expr_with_expectation}; -use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation}; -use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type}; +use super::{check_expr, check_expr_has_type, check_expr_with_expectation}; +use super::{check_expr_coercable_to_type, demand, CheckEnv, FnCtxt, FnCtxtJoined, Expectation}; +use super::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type}; use require_same_types; use util::nodemap::FnvHashMap; use util::ppaux::Repr; @@ -32,7 +32,8 @@ use syntax::parse::token; use syntax::print::pprust; use syntax::ptr::P; -pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, +pub fn check_pat<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, expected: Ty<'tcx>) { @@ -45,18 +46,19 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, match pat.node { ast::PatWild(_) => { - fcx.write_ty(pat.id, expected); + fcx.write_ty(check_env, pat.id, expected); } ast::PatLit(ref lt) => { - check_expr(fcx, &**lt); - let expr_ty = fcx.expr_ty(&**lt); + check_expr(check_env, fcx, &**lt); + let expr_ty = fcx.expr_ty(&check_env.tt.node_types, &**lt); // Byte string patterns behave the same way as array patterns // They can denote both statically and dynamically sized byte arrays let mut pat_ty = expr_ty; if let ast::ExprLit(ref lt) = lt.node { if let ast::LitBinary(_) = lt.node { - let expected_ty = structurally_resolved_type(fcx, pat.span, expected); + let expected_ty = structurally_resolved_type(check_env, fcx, + pat.span, expected); if let ty::ty_rptr(_, mt) = expected_ty.sty { if let ty::ty_vec(_, None) = mt.ty.sty { pat_ty = ty::mk_slice(tcx, tcx.mk_region(ty::ReStatic), @@ -66,7 +68,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } } - fcx.write_ty(pat.id, pat_ty); + fcx.write_ty(check_env, pat.id, pat_ty); // somewhat surprising: in this case, the subtyping // relation goes the opposite way as the other @@ -83,11 +85,11 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, demand::suptype(fcx, pat.span, expected, pat_ty); } ast::PatRange(ref begin, ref end) => { - check_expr(fcx, &**begin); - check_expr(fcx, &**end); + check_expr(check_env, fcx, &**begin); + check_expr(check_env, fcx, &**end); - let lhs_ty = fcx.expr_ty(&**begin); - let rhs_ty = fcx.expr_ty(&**end); + let lhs_ty = fcx.expr_ty(&check_env.tt.node_types, &**begin); + let rhs_ty = fcx.expr_ty(&check_env.tt.node_types, &**end); let lhs_eq_rhs = require_same_types( @@ -115,7 +117,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, "only char and numeric types are allowed in range"); } - fcx.write_ty(pat.id, lhs_ty); + fcx.write_ty(check_env, pat.id, lhs_ty); // subtyping doesn't matter here, as the value is some kind of scalar demand::eqtype(fcx, pat.span, expected, lhs_ty); @@ -124,10 +126,13 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id(); let const_scheme = ty::lookup_item_type(tcx, const_did); assert!(const_scheme.generics.is_empty()); - let const_ty = pcx.fcx.instantiate_type_scheme(pat.span, - &Substs::empty(), - &const_scheme.ty); - fcx.write_ty(pat.id, const_ty); + let const_ty = { + let mut joined = FnCtxtJoined::new(check_env, fcx); + joined.instantiate_type_scheme(pat.span, + &Substs::empty(), + &const_scheme.ty) + }; + fcx.write_ty(check_env, pat.id, const_ty); // FIXME(#20489) -- we should limit the types here to scalars or something! @@ -137,7 +142,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, demand::suptype(fcx, pat.span, expected, const_ty); } ast::PatIdent(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map, pat) => { - let typ = fcx.local_ty(pat.span, pat.id); + let typ = fcx.local_ty(check_env, pat.span, pat.id); match bm { ast::BindByRef(mutbl) => { // if the binding is like @@ -161,30 +166,33 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } } - fcx.write_ty(pat.id, typ); + fcx.write_ty(check_env, pat.id, typ); // if there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be let canon_id = *pcx.map.get(&path.node).unwrap(); if canon_id != pat.id { - let ct = fcx.local_ty(pat.span, canon_id); + let ct = fcx.local_ty(check_env, pat.span, canon_id); demand::eqtype(fcx, pat.span, ct, typ); } if let Some(ref p) = *sub { - check_pat(pcx, &**p, expected); + check_pat(check_env, pcx, &**p, expected); } } ast::PatIdent(_, ref path, _) => { let path = ast_util::ident_to_path(path.span, path.node); - check_pat_enum(pcx, pat, &path, Some(&[]), expected); + check_pat_enum(check_env, pcx, pat, &path, Some(&[]), expected); } ast::PatEnum(ref path, ref subpats) => { let subpats = subpats.as_ref().map(|v| &v[..]); - check_pat_enum(pcx, pat, path, subpats, expected); + check_pat_enum(check_env, pcx, pat, path, subpats, expected); } ast::PatQPath(ref qself, ref path) => { - let self_ty = fcx.to_ty(&qself.ty); + let self_ty = { + let mut joined = FnCtxtJoined::new(check_env, fcx); + joined.to_ty(&qself.ty) + }; let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) { d } else if qself.position == 0 { @@ -199,33 +207,33 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, &format!("unbound path {}", pat.repr(tcx))) }; if let Some((opt_ty, segments, def)) = - resolve_ty_and_def_ufcs(fcx, path_res, Some(self_ty), + resolve_ty_and_def_ufcs(check_env, fcx, path_res, Some(self_ty), path, pat.span, pat.id) { if check_assoc_item_is_const(pcx, def, pat.span) { let scheme = ty::lookup_item_type(tcx, def.def_id()); let predicates = ty::lookup_predicates(tcx, def.def_id()); - instantiate_path(fcx, segments, + instantiate_path(check_env, fcx, segments, scheme, &predicates, opt_ty, def, pat.span, pat.id); - let const_ty = fcx.node_ty(pat.id); + let const_ty = fcx.node_ty(&check_env.tt.node_types, pat.id); demand::suptype(fcx, pat.span, expected, const_ty); } else { - fcx.write_error(pat.id) + fcx.write_error(check_env, pat.id) } } } ast::PatStruct(ref path, ref fields, etc) => { - check_pat_struct(pcx, pat, path, fields, etc, expected); + check_pat_struct(check_env, pcx, pat, path, fields, etc, expected); } ast::PatTup(ref elements) => { let element_tys: Vec<_> = (0..elements.len()).map(|_| fcx.infcx().next_ty_var()) .collect(); let pat_ty = ty::mk_tup(tcx, element_tys.clone()); - fcx.write_ty(pat.id, pat_ty); + fcx.write_ty(check_env, pat.id, pat_ty); demand::eqtype(fcx, pat.span, expected, pat_ty); for (element_pat, element_ty) in elements.iter().zip(element_tys.into_iter()) { - check_pat(pcx, &**element_pat, element_ty); + check_pat(check_env, pcx, &**element_pat, element_ty); } } ast::PatBox(ref inner) => { @@ -237,11 +245,11 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // think any errors can be introduced by using // `demand::eqtype`. demand::eqtype(fcx, pat.span, expected, uniq_ty); - fcx.write_ty(pat.id, uniq_ty); - check_pat(pcx, &**inner, inner_ty); + fcx.write_ty(check_env, pat.id, uniq_ty); + check_pat(check_env, pcx, &**inner, inner_ty); } else { - fcx.write_error(pat.id); - check_pat(pcx, &**inner, tcx.types.err); + fcx.write_error(check_env, pat.id); + check_pat(check_env, pcx, &**inner, tcx.types.err); } } ast::PatRegion(ref inner, mutbl) => { @@ -256,15 +264,15 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // `eqtype` turns out to be equally general. See (*) // below for details. demand::eqtype(fcx, pat.span, expected, rptr_ty); - fcx.write_ty(pat.id, rptr_ty); - check_pat(pcx, &**inner, inner_ty); + fcx.write_ty(check_env, pat.id, rptr_ty); + check_pat(check_env, pcx, &**inner, inner_ty); } else { - fcx.write_error(pat.id); - check_pat(pcx, &**inner, tcx.types.err); + fcx.write_error(check_env, pat.id); + check_pat(check_env, pcx, &**inner, tcx.types.err); } } ast::PatVec(ref before, ref slice, ref after) => { - let expected_ty = structurally_resolved_type(fcx, pat.span, expected); + let expected_ty = structurally_resolved_type(check_env, fcx, pat.span, expected); let inner_ty = fcx.infcx().next_ty_var(); let pat_ty = match expected_ty.sty { ty::ty_vec(_, Some(size)) => ty::mk_vec(tcx, inner_ty, Some({ @@ -284,7 +292,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } }; - fcx.write_ty(pat.id, pat_ty); + fcx.write_ty(check_env, pat.id, pat_ty); // `demand::subtype` would be good enough, but using // `eqtype` turns out to be equally general. See (*) @@ -292,7 +300,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, demand::eqtype(fcx, pat.span, expected, pat_ty); for elt in before { - check_pat(pcx, &**elt, inner_ty); + check_pat(check_env, pcx, &**elt, inner_ty); } if let Some(ref slice) = *slice { let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); @@ -303,10 +311,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, ty: inner_ty, mutbl: mutbl }); - check_pat(pcx, &**slice, slice_ty); + check_pat(check_env, pcx, &**slice, slice_ty); } for elt in after { - check_pat(pcx, &**elt, inner_ty); + check_pat(check_env, pcx, &**elt, inner_ty); } } ast::PatMac(_) => tcx.sess.bug("unexpanded macro") @@ -402,7 +410,8 @@ pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } } -pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn check_match<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx ast::Expr, discrim: &'tcx ast::Expr, arms: &'tcx [ast::Arm], @@ -416,14 +425,14 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let contains_ref_bindings = arms.iter().any(|a| tcx.arm_contains_ref_binding(a)); let discrim_ty; if contains_ref_bindings { - check_expr(fcx, discrim); - discrim_ty = fcx.expr_ty(discrim); + check_expr(check_env, fcx, discrim); + discrim_ty = fcx.expr_ty(&check_env.tt.node_types, discrim); } else { // ...but otherwise we want to use any supertype of the // discriminant. This is sort of a workaround, see note (*) in // `check_pat` for some details. discrim_ty = fcx.infcx().next_ty_var(); - check_expr_has_type(fcx, discrim, discrim_ty); + check_expr_has_type(check_env, fcx, discrim, discrim_ty); }; // Typecheck the patterns first, so that we get types for all the @@ -434,7 +443,7 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, map: pat_id_map(&tcx.def_map, &*arm.pats[0]), }; for p in &arm.pats { - check_pat(&mut pcx, &**p, discrim_ty); + check_pat(check_env, &mut pcx, &**p, discrim_ty); } } @@ -456,17 +465,17 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // arm for inconsistent arms or to the whole match when a `()` type // is required). Expectation::ExpectHasType(ety) if ety != ty::mk_nil(fcx.tcx()) => { - check_expr_coercable_to_type(fcx, &*arm.body, ety); + check_expr_coercable_to_type(check_env, fcx, &*arm.body, ety); ety } _ => { - check_expr_with_expectation(fcx, &*arm.body, expected); - fcx.node_ty(arm.body.id) + check_expr_with_expectation(check_env, fcx, &*arm.body, expected); + fcx.node_ty(&check_env.tt.node_types, arm.body.id) } }; if let Some(ref e) = arm.guard { - check_expr_has_type(fcx, &**e, tcx.types.bool); + check_expr_has_type(check_env, fcx, &**e, tcx.types.bool); } if ty::type_is_error(result_ty) || ty::type_is_error(bty) { @@ -497,7 +506,7 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } }); - fcx.write_ty(expr.id, result_ty); + fcx.write_ty(check_env, expr.id, result_ty); } pub struct pat_ctxt<'a, 'tcx: 'a> { @@ -505,9 +514,10 @@ pub struct pat_ctxt<'a, 'tcx: 'a> { pub map: PatIdMap, } -pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, - path: &ast::Path, fields: &'tcx [Spanned], - etc: bool, expected: Ty<'tcx>) { +fn check_pat_struct<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, + path: &ast::Path, fields: &'tcx [Spanned], + etc: bool, expected: Ty<'tcx>) { let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; @@ -517,10 +527,10 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, let name = pprust::path_to_string(path); span_err!(tcx.sess, pat.span, E0168, "use of trait `{}` in a struct pattern", name); - fcx.write_error(pat.id); + fcx.write_error(check_env, pat.id); for field in fields { - check_pat(pcx, &*field.node.pat, tcx.types.err); + check_pat(check_env, pcx, &*field.node.pat, tcx.types.err); } return; }, @@ -536,10 +546,10 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, let name = pprust::path_to_string(path); span_err!(tcx.sess, pat.span, E0163, "`{}` does not name a struct or a struct variant", name); - fcx.write_error(pat.id); + fcx.write_error(check_env, pat.id); for field in fields { - check_pat(pcx, &*field.node.pat, tcx.types.err); + check_pat(check_env, pcx, &*field.node.pat, tcx.types.err); } return; } @@ -547,7 +557,8 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, } }; - instantiate_path(pcx.fcx, + instantiate_path(check_env, + pcx.fcx, &path.segments, ty::lookup_item_type(tcx, enum_def_id), &ty::lookup_predicates(tcx, enum_def_id), @@ -556,25 +567,26 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, pat.span, pat.id); - let pat_ty = fcx.node_ty(pat.id); + let pat_ty = fcx.node_ty(&check_env.tt.node_types, pat.id); demand::eqtype(fcx, pat.span, expected, pat_ty); let item_substs = fcx - .item_substs() + .item_substs(check_env) .get(&pat.id) .map(|substs| substs.substs.clone()) .unwrap_or_else(|| Substs::empty()); let struct_fields = ty::struct_fields(tcx, variant_def_id, &item_substs); - check_struct_pat_fields(pcx, pat.span, fields, &struct_fields, + check_struct_pat_fields(check_env, pcx, pat.span, fields, &struct_fields, variant_def_id, etc); } -pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, - pat: &ast::Pat, - path: &ast::Path, - subpats: Option<&'tcx [P]>, - expected: Ty<'tcx>) +fn check_pat_enum<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + pcx: &pat_ctxt<'a, 'tcx>, + pat: &ast::Pat, + path: &ast::Path, + subpats: Option<&'tcx [P]>, + expected: Ty<'tcx>) { // Typecheck the path. let fcx = pcx.fcx; @@ -582,7 +594,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let path_res = *tcx.def_map.borrow().get(&pat.id).unwrap(); - let (opt_ty, segments, def) = match resolve_ty_and_def_ufcs(fcx, path_res, + let (opt_ty, segments, def) = match resolve_ty_and_def_ufcs(check_env, fcx, path_res, None, path, pat.span, pat.id) { Some(resolution) => resolution, @@ -594,7 +606,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // Items that were partially resolved before should have been resolved to // associated constants (i.e. not methods). if path_res.depth != 0 && !check_assoc_item_is_const(pcx, def, pat.span) { - fcx.write_error(pat.id); + fcx.write_error(check_env, pat.id); return; } @@ -612,7 +624,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } else { ctor_scheme }; - instantiate_path(pcx.fcx, segments, + instantiate_path(check_env, pcx.fcx, segments, path_scheme, &ctor_predicates, opt_ty, def, pat.span, pat.id); @@ -620,30 +632,32 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // associated const, and we should quit now, since the rest of this // function uses checks specific to structs and enums. if path_res.depth != 0 { - let pat_ty = fcx.node_ty(pat.id); + let pat_ty = fcx.node_ty(&check_env.tt.node_types, pat.id); demand::suptype(fcx, pat.span, expected, pat_ty); return; } - let pat_ty = fcx.node_ty(pat.id); + let pat_ty = fcx.node_ty(&check_env.tt.node_types, pat.id); demand::eqtype(fcx, pat.span, expected, pat_ty); - let real_path_ty = fcx.node_ty(pat.id); + let real_path_ty = fcx.node_ty(&check_env.tt.node_types, pat.id); let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty { ty::ty_enum(enum_def_id, expected_substs) if def == def::DefVariant(enum_def_id, def.def_id(), false) => { let variant = ty::enum_variant_with_id(tcx, enum_def_id, def.def_id()); + let mut joined = FnCtxtJoined::new(check_env, fcx); (variant.args.iter() - .map(|t| fcx.instantiate_type_scheme(pat.span, expected_substs, t)) + .map(|t| joined.instantiate_type_scheme(pat.span, expected_substs, t)) .collect(), "variant") } ty::ty_struct(struct_def_id, expected_substs) => { let struct_fields = ty::struct_fields(tcx, struct_def_id, expected_substs); + let mut joined = FnCtxtJoined::new(check_env, fcx); (struct_fields.iter() - .map(|field| fcx.instantiate_type_scheme(pat.span, + .map(|field| joined.instantiate_type_scheme(pat.span, expected_substs, &field.mt.ty)) .collect(), @@ -653,11 +667,11 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let name = pprust::path_to_string(path); span_err!(tcx.sess, pat.span, E0164, "`{}` does not name a non-struct variant or a tuple struct", name); - fcx.write_error(pat.id); + fcx.write_error(check_env, pat.id); if let Some(subpats) = subpats { for pat in subpats { - check_pat(pcx, &**pat, tcx.types.err); + check_pat(check_env, pcx, &**pat, tcx.types.err); } } return; @@ -667,7 +681,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, if let Some(subpats) = subpats { if subpats.len() == arg_tys.len() { for (subpat, arg_ty) in subpats.iter().zip(arg_tys.iter()) { - check_pat(pcx, &**subpat, *arg_ty); + check_pat(check_env, pcx, &**subpat, *arg_ty); } } else if arg_tys.is_empty() { span_err!(tcx.sess, pat.span, E0024, @@ -675,7 +689,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name); for pat in subpats { - check_pat(pcx, &**pat, tcx.types.err); + check_pat(check_env, pcx, &**pat, tcx.types.err); } } else { span_err!(tcx.sess, pat.span, E0023, @@ -685,7 +699,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, arg_tys.len(), if arg_tys.len() == 1 {""} else {"s"}); for pat in subpats { - check_pat(pcx, &**pat, tcx.types.err); + check_pat(check_env, pcx, &**pat, tcx.types.err); } } } @@ -696,12 +710,13 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, /// `struct_fields` describes the type of each field of the struct. /// `struct_id` is the ID of the struct. /// `etc` is true if the pattern said '...' and false otherwise. -pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, - span: Span, - fields: &'tcx [Spanned], - struct_fields: &[ty::field<'tcx>], - struct_id: ast::DefId, - etc: bool) { +fn check_struct_pat_fields<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + pcx: &pat_ctxt<'a, 'tcx>, + span: Span, + fields: &'tcx [Spanned], + struct_fields: &[ty::field<'tcx>], + struct_id: ast::DefId, + etc: bool) { let tcx = pcx.fcx.ccx.tcx; // Index the struct fields' types. @@ -738,9 +753,12 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } }; - let field_type = pcx.fcx.normalize_associated_types_in(span, &field_type); + let field_type = { + let mut joined = FnCtxtJoined::new(check_env, pcx.fcx); + joined.normalize_associated_types_in(span, &field_type) + }; - check_pat(pcx, &*field.pat, field_type); + check_pat(check_env, pcx, &*field.pat, field_type); } // Report an error if not all the fields were specified. diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index b065eb2d2741c..a79f404729458 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -12,12 +12,15 @@ use super::autoderef; use super::check_argument_types; use super::check_expr; use super::check_method_argument_types; +use super::CheckEnv; use super::demand; use super::DeferredCallResolution; use super::err_args; use super::Expectation; use super::expected_types_for_fn_args; use super::FnCtxt; +use super::FnCtxtTyper; +use super::FnCtxtJoined; use super::LvaluePreference; use super::method; use super::structurally_resolved_type; @@ -67,41 +70,44 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: } } -pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn check_call<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, call_expr: &'tcx ast::Expr, callee_expr: &'tcx ast::Expr, arg_exprs: &'tcx [P], expected: Expectation<'tcx>) { - check_expr(fcx, callee_expr); - let original_callee_ty = fcx.expr_ty(callee_expr); + check_expr(check_env, fcx, callee_expr); + let original_callee_ty = fcx.expr_ty(&check_env.tt.node_types, callee_expr); let (callee_ty, _, result) = - autoderef(fcx, + autoderef(check_env, + fcx, callee_expr.span, original_callee_ty, Some(callee_expr), UnresolvedTypeAction::Error, LvaluePreference::NoPreference, - |adj_ty, idx| { - try_overloaded_call_step(fcx, call_expr, callee_expr, adj_ty, idx) + |check_env, adj_ty, idx| { + try_overloaded_call_step(check_env, fcx, call_expr, callee_expr, adj_ty, idx) }); match result { None => { // this will report an error since original_callee_ty is not a fn - confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs, expected); + confirm_builtin_call(check_env, + fcx, call_expr, original_callee_ty, arg_exprs, expected); } Some(CallStep::Builtin) => { - confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs, expected); + confirm_builtin_call(check_env, fcx, call_expr, callee_ty, arg_exprs, expected); } Some(CallStep::DeferredClosure(fn_sig)) => { - confirm_deferred_closure_call(fcx, call_expr, arg_exprs, expected, fn_sig); + confirm_deferred_closure_call(check_env, fcx, call_expr, arg_exprs, expected, fn_sig); } Some(CallStep::Overloaded(method_callee)) => { - confirm_overloaded_call(fcx, call_expr, callee_expr, + confirm_overloaded_call(check_env, fcx, call_expr, callee_expr, arg_exprs, expected, method_callee); } } @@ -113,7 +119,8 @@ enum CallStep<'tcx> { Overloaded(ty::MethodCallee<'tcx>) } -fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn try_overloaded_call_step<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, call_expr: &'tcx ast::Expr, callee_expr: &'tcx ast::Expr, adjusted_ty: Ty<'tcx>, @@ -126,9 +133,9 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, autoderefs); // If the callee is a bare function or a closure, then we're all set. - match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty { + match structurally_resolved_type(check_env, fcx, callee_expr.span, adjusted_ty).sty { ty::ty_bare_fn(..) => { - fcx.write_autoderef_adjustment(callee_expr.id, autoderefs); + fcx.write_autoderef_adjustment(check_env, callee_expr.id, autoderefs); return Some(CallStep::Builtin); } @@ -138,14 +145,21 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Check whether this is a call to a closure where we // haven't yet decided on whether the closure is fn vs // fnmut vs fnonce. If so, we have to defer further processing. - if fcx.closure_kind(def_id).is_none() { - let closure_ty = - fcx.closure_type(def_id, substs); - let fn_sig = - fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span, - infer::FnCall, - &closure_ty.sig).0; - fcx.record_deferred_call_resolution(def_id, Box::new(CallResolution { + let fn_sig = { + let typer = FnCtxtTyper::new(&check_env.tt, fcx); + match typer.closure_kind(def_id) { + Some(_) => None, + None => Some({ + let closure_ty = + typer.closure_type(def_id, substs); + fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span, + infer::FnCall, + &closure_ty.sig).0 + }) + } + }; + if let Some(fn_sig) = fn_sig { + check_env.record_deferred_call_resolution(def_id, Box::new(CallResolution { call_expr: call_expr, callee_expr: callee_expr, adjusted_ty: adjusted_ty, @@ -172,11 +186,12 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, _ => {} } - try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefs) + try_overloaded_call_traits(check_env, fcx, call_expr, callee_expr, adjusted_ty, autoderefs) .map(|method_callee| CallStep::Overloaded(method_callee)) } -fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn try_overloaded_call_traits<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, call_expr: &ast::Expr, callee_expr: &ast::Expr, adjusted_ty: Ty<'tcx>, @@ -194,7 +209,8 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, None => continue, }; - match method::lookup_in_trait_adjusted(fcx, + match method::lookup_in_trait_adjusted(check_env, + fcx, call_expr.span, Some(&*callee_expr), method_name, @@ -213,7 +229,8 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, None } -fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, +fn confirm_builtin_call<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, call_expr: &ast::Expr, callee_ty: Ty<'tcx>, arg_exprs: &'tcx [P], @@ -252,16 +269,20 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, fn_sig).0; - let fn_sig = - fcx.normalize_associated_types_in(call_expr.span, &fn_sig); + let fn_sig = { + let mut joined = FnCtxtJoined::new(check_env, fcx); + joined.normalize_associated_types_in(call_expr.span, &fn_sig) + }; // Call the generic checker. - let expected_arg_tys = expected_types_for_fn_args(fcx, + let expected_arg_tys = expected_types_for_fn_args(check_env, + fcx, call_expr.span, expected, fn_sig.output, &fn_sig.inputs); - check_argument_types(fcx, + check_argument_types(check_env, + fcx, call_expr.span, &fn_sig.inputs, &expected_arg_tys[..], @@ -269,10 +290,11 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, fn_sig.variadic, TupleArgumentsFlag::DontTupleArguments); - write_call(fcx, call_expr, fn_sig.output); + write_call(check_env, fcx, call_expr, fn_sig.output); } -fn confirm_deferred_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, +fn confirm_deferred_closure_call<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, call_expr: &ast::Expr, arg_exprs: &'tcx [P], expected: Expectation<'tcx>, @@ -284,13 +306,15 @@ fn confirm_deferred_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // type. let expected_arg_tys = - expected_types_for_fn_args(fcx, + expected_types_for_fn_args(check_env, + fcx, call_expr.span, expected, fn_sig.output.clone(), &*fn_sig.inputs); - check_argument_types(fcx, + check_argument_types(check_env, + fcx, call_expr.span, &*fn_sig.inputs, &*expected_arg_tys, @@ -298,10 +322,11 @@ fn confirm_deferred_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, fn_sig.variadic, TupleArgumentsFlag::TupleArguments); - write_call(fcx, call_expr, fn_sig.output); + write_call(check_env, fcx, call_expr, fn_sig.output); } -fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn confirm_overloaded_call<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, call_expr: &ast::Expr, callee_expr: &'tcx ast::Expr, arg_exprs: &'tcx [P], @@ -309,23 +334,26 @@ fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_callee: ty::MethodCallee<'tcx>) { let output_type = - check_method_argument_types(fcx, + check_method_argument_types(check_env, + fcx, call_expr.span, method_callee.ty, callee_expr, arg_exprs, TupleArgumentsFlag::TupleArguments, expected); - write_call(fcx, call_expr, output_type); + write_call(check_env, fcx, call_expr, output_type); - write_overloaded_call_method_map(fcx, call_expr, method_callee); + write_overloaded_call_method_map(check_env, fcx, call_expr, method_callee); } -fn write_overloaded_call_method_map<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, +// FIXME: Figure out if we still need `FnCtxt` here. +fn write_overloaded_call_method_map<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + _: &FnCtxt<'a, 'tcx>, call_expr: &ast::Expr, method_callee: ty::MethodCallee<'tcx>) { let method_call = ty::MethodCall::expr(call_expr.id); - fcx.inh.method_map.borrow_mut().insert(method_call, method_callee); + check_env.tt.method_map.insert(method_call, method_callee); } struct CallResolution<'tcx> { @@ -351,16 +379,19 @@ impl<'tcx> Repr<'tcx> for CallResolution<'tcx> { } impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> { - fn resolve<'a>(&mut self, fcx: &FnCtxt<'a,'tcx>) { + fn resolve<'a>(&mut self, check_env: &mut CheckEnv<'tcx>, fcx: &FnCtxt<'a,'tcx>) { debug!("DeferredCallResolution::resolve() {}", self.repr(fcx.tcx())); // we should not be invoked until the closure kind has been // determined by upvar inference - assert!(fcx.closure_kind(self.closure_def_id).is_some()); + { + let typer = FnCtxtTyper::new(&check_env.tt, fcx); + assert!(typer.closure_kind(self.closure_def_id).is_some()); + } // We may now know enough to figure out fn vs fnmut etc. - match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr, + match try_overloaded_call_traits(check_env, fcx, self.call_expr, self.callee_expr, self.adjusted_ty, self.autoderefs) { Some(method_callee) => { // One problem is that when we get here, we are going @@ -390,7 +421,7 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> { method_sig.output.unwrap_or(nilty), self.fn_sig.output.unwrap_or(nilty)); - write_overloaded_call_method_map(fcx, self.call_expr, method_callee); + write_overloaded_call_method_map(check_env, fcx, self.call_expr, method_callee); } None => { fcx.tcx().sess.span_bug( diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index f0495436bc1b2..1aad68f45abb4 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -11,6 +11,7 @@ //! Code for type-checking cast expressions. use super::coercion; +use super::CheckEnv; use super::demand; use super::FnCtxt; use super::structurally_resolved_type; @@ -43,7 +44,8 @@ impl<'tcx> CastCheck<'tcx> { } } -pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { +pub fn check_cast<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, t_1: Ty<'tcx>, @@ -58,12 +60,12 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { let span = cast.span; let e = &cast.expr; - let t_e = structurally_resolved_type(fcx, span, cast.expr_ty); - let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty); + let t_e = structurally_resolved_type(check_env, fcx, span, cast.expr_ty); + let t_1 = structurally_resolved_type(check_env, fcx, span, cast.cast_ty); // Check for trivial casts. if !ty::type_has_ty_infer(t_1) { - if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) { + if let Ok(()) = coercion::mk_assignty(check_env, fcx, e, t_e, t_1) { if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) { fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS, e.id, @@ -104,7 +106,7 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn; if t_e_is_bare_fn_item && t_1_is_bare_fn { - demand::coerce(fcx, e.span, t_1, &e); + demand::coerce(check_env, fcx, e.span, t_1, &e); } else if t_1_is_char { let t_e = fcx.infcx().shallow_resolve(t_e); if t_e.sty != ty::ty_uint(ast::TyU8) { @@ -167,7 +169,7 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { /* this case is allowed */ } _ => { - demand::coerce(fcx, e.span, t_1, &e); + demand::coerce(check_env, fcx, e.span, t_1, &e); } } } else if fcx.type_is_fat_ptr(t_e, span) != fcx.type_is_fat_ptr(t_1, span) { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index d2a06fcf99091..c3ef630f3bc14 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -10,7 +10,7 @@ //! Code for type-checking closure expressions. -use super::{check_fn, Expectation, FnCtxt}; +use super::{check_fn, CheckEnv, Expectation, FnCtxt, FnCtxtJoined}; use astconv; use middle::region; @@ -22,7 +22,8 @@ use syntax::ast; use syntax::ast_util; use util::ppaux::Repr; -pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, +pub fn check_expr_closure<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, expr: &ast::Expr, _capture: ast::CaptureClause, decl: &'tcx ast::FnDecl, @@ -36,13 +37,14 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // closure sooner rather than later, so first examine the expected // type, and see if can glean a closure kind from there. let (expected_sig,expected_kind) = match expected.to_option(fcx) { - Some(ty) => deduce_expectations_from_expected_type(fcx, ty), + Some(ty) => deduce_expectations_from_expected_type(check_env, fcx, ty), None => (None, None) }; - check_closure(fcx, expr, expected_kind, decl, body, expected_sig) + check_closure(check_env, fcx, expr, expected_kind, decl, body, expected_sig) } -fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, +fn check_closure<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, expr: &ast::Expr, opt_kind: Option, decl: &'tcx ast::FnDecl, @@ -54,26 +56,30 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, opt_kind, expected_sig.repr(fcx.tcx())); - let mut fn_ty = astconv::ty_of_closure( - fcx, - ast::Unsafety::Normal, - decl, - abi::RustCall, - expected_sig); + let mut fn_ty = { + let mut joined = FnCtxtJoined::new(check_env, fcx); + astconv::ty_of_closure( + &mut joined, + ast::Unsafety::Normal, + decl, + abi::RustCall, + expected_sig) + }; let closure_type = ty::mk_closure(fcx.ccx.tcx, expr_def_id, fcx.ccx.tcx.mk_substs( fcx.inh.param_env.free_substs.clone())); - fcx.write_ty(expr.id, closure_type); + fcx.write_ty(check_env, expr.id, closure_type); let fn_sig = ty::liberate_late_bound_regions(fcx.tcx(), region::DestructionScopeData::new(body.id), &fn_ty.sig); - check_fn(fcx.ccx, + check_fn(check_env, + fcx.ccx, ast::Unsafety::Normal, expr.id, &fn_sig, @@ -91,7 +97,7 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, fn_ty.sig.repr(fcx.tcx()), opt_kind); - fcx.inh.closure_tys.borrow_mut().insert(expr_def_id, fn_ty); + check_env.tt.closure_tys.insert(expr_def_id, fn_ty); match opt_kind { Some(kind) => { fcx.inh.closure_kinds.borrow_mut().insert(expr_def_id, kind); } None => { } @@ -99,6 +105,7 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, } fn deduce_expectations_from_expected_type<'a,'tcx>( + check_env: &mut CheckEnv<'tcx>, fcx: &FnCtxt<'a,'tcx>, expected_ty: Ty<'tcx>) -> (Option>,Option) @@ -117,7 +124,7 @@ fn deduce_expectations_from_expected_type<'a,'tcx>( (sig, kind) } ty::ty_infer(ty::TyVar(vid)) => { - deduce_expectations_from_obligations(fcx, vid) + deduce_expectations_from_obligations(check_env, fcx, vid) } _ => { (None, None) @@ -126,15 +133,15 @@ fn deduce_expectations_from_expected_type<'a,'tcx>( } fn deduce_expectations_from_obligations<'a,'tcx>( + check_env: &mut CheckEnv<'tcx>, fcx: &FnCtxt<'a,'tcx>, expected_vid: ty::TyVid) -> (Option>, Option) { - let fulfillment_cx = fcx.inh.fulfillment_cx.borrow(); // Here `expected_ty` is known to be a type inference variable. let expected_sig = - fulfillment_cx + check_env.fulfillment_cx .pending_obligations() .iter() .filter_map(|obligation| { @@ -161,7 +168,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>( // like `F : Fn`. Note that due to subtyping we could encounter // many viable options, so pick the most restrictive. let expected_kind = - fulfillment_cx + check_env.fulfillment_cx .pending_obligations() .iter() .filter_map(|obligation| { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 28df1c2159577..eb12129f193d4 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -60,8 +60,8 @@ //! sort of a minor point so I've opted to leave it for later---after all //! we may want to adjust precisely when coercions occur. -use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction}; -use check::vtable; +use super::{autoderef, CheckEnv, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction}; +use super::vtable; use middle::infer::{self, Coercion}; use middle::subst; @@ -110,6 +110,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } fn coerce(&self, + check_env: &mut CheckEnv<'tcx>, expr_a: &ast::Expr, a: Ty<'tcx>, b: Ty<'tcx>) @@ -139,7 +140,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::ty_rptr(_, mt_b) => { return self.unpack_actual_value(a, |a| { - self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl) + self.coerce_borrowed_pointer(check_env, expr_a, a, b, mt_b.mutbl) }); } @@ -171,6 +172,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { /// To match `A` with `B`, autoderef will be performed, /// calling `deref`/`deref_mut` where necessary. fn coerce_borrowed_pointer(&self, + check_env: &mut CheckEnv<'tcx>, expr_a: &ast::Expr, a: Ty<'tcx>, b: Ty<'tcx>, @@ -203,13 +205,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ast::MutImmutable => NoPreference }; let mut first_error = None; - let (_, autoderefs, success) = autoderef(self.fcx, + let (_, autoderefs, success) = autoderef(check_env, + self.fcx, expr_a.span, a, Some(expr_a), UnresolvedTypeAction::Ignore, lvalue_pref, - |inner_ty, autoderef| { + |_, inner_ty, autoderef| { if autoderef == 0 { // Don't let this pass, otherwise it would cause // &T to autoref to &&T. @@ -490,7 +493,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } -pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn mk_assignty<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, expr: &ast::Expr, a: Ty<'tcx>, b: Ty<'tcx>) @@ -503,7 +507,7 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, origin: infer::ExprAssignable(expr.span), unsizing_obligation: Cell::new(None) }; - Ok((try!(coerce.coerce(expr, a, b)), + Ok((try!(coerce.coerce(check_env, expr, a, b)), coerce.unsizing_obligation.get())) }) })); @@ -518,7 +522,8 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // If the type is `Foo+'a`, ensures that the type // being cast to `Foo+'a` implements `Foo`: - vtable::register_object_cast_obligations(fcx, + vtable::register_object_cast_obligations(check_env, + fcx, expr.span, ty_trait, source); @@ -530,14 +535,15 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, body_id: fcx.body_id, code: traits::ObjectCastObligation(source) }; - fcx.register_region_obligation(source, ty_trait.bounds.region_bound, cause); + fcx.register_region_obligation(&mut check_env.fulfillment_cx, + source, ty_trait.bounds.region_bound, cause); } } } if let Some(adjustment) = adjustment { debug!("Success, coerced with {}", adjustment.repr(fcx.tcx())); - fcx.write_adjustment(expr.id, adjustment); + fcx.write_adjustment(check_env, expr.id, adjustment); } Ok(()) } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index cd6a1226e00c9..b3c76b56b282b 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -9,7 +9,7 @@ // except according to those terms. -use check::{coercion, FnCtxt}; +use super::{coercion, CheckEnv, FnCtxt}; use middle::ty::{self, Ty}; use middle::infer; @@ -54,17 +54,18 @@ pub fn eqtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, } // Checks that the type of `expr` can be coerced to `expected`. -pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn coerce<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, sp: Span, expected: Ty<'tcx>, expr: &ast::Expr) { - let expr_ty = fcx.expr_ty(expr); + let expr_ty = fcx.expr_ty(&check_env.tt.node_types, expr); debug!("demand::coerce(expected = {}, expr_ty = {})", expected.repr(fcx.ccx.tcx), expr_ty.repr(fcx.ccx.tcx)); - let expr_ty = fcx.resolve_type_vars_if_possible(expr_ty); - let expected = fcx.resolve_type_vars_if_possible(expected); - match coercion::mk_assignty(fcx, expr, expr_ty, expected) { + let expr_ty = fcx.resolve_type_vars_if_possible(check_env, expr_ty); + let expected = fcx.resolve_type_vars_if_possible(check_env, expected); + match coercion::mk_assignty(check_env, fcx, expr, expr_ty, expected) { Ok(()) => { /* ok */ } Err(ref err) => { fcx.report_mismatched_types(sp, expected, expr_ty, err); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index c068bfaa82eb7..b6a85798f233a 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -10,7 +10,8 @@ use super::probe; -use check::{self, FnCtxt, NoPreference, PreferMutLvalue, callee, demand}; +use check::{self, CheckEnv, FnCtxt, FnCtxtTyper, FnCtxtJoined, NoPreference, PreferMutLvalue, + callee, demand}; use check::UnresolvedTypeAction; use middle::mem_categorization::Typer; use middle::subst::{self}; @@ -47,7 +48,8 @@ struct InstantiatedMethodSig<'tcx> { method_predicates: ty::InstantiatedPredicates<'tcx>, } -pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn confirm<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, self_expr: &'tcx ast::Expr, call_expr: &'tcx ast::Expr, @@ -62,7 +64,7 @@ pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, supplied_method_types.repr(fcx.tcx())); let mut confirm_cx = ConfirmContext::new(fcx, span, self_expr, call_expr); - confirm_cx.confirm(unadjusted_self_ty, pick, supplied_method_types) + confirm_cx.confirm(check_env, unadjusted_self_ty, pick, supplied_method_types) } impl<'a,'tcx> ConfirmContext<'a,'tcx> { @@ -72,24 +74,30 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { call_expr: &'tcx ast::Expr) -> ConfirmContext<'a, 'tcx> { - ConfirmContext { fcx: fcx, span: span, self_expr: self_expr, call_expr: call_expr } + ConfirmContext { + fcx: fcx, + span: span, + self_expr: self_expr, + call_expr: call_expr, + } } fn confirm(&mut self, + check_env: &mut CheckEnv<'tcx>, unadjusted_self_ty: Ty<'tcx>, pick: probe::Pick<'tcx>, supplied_method_types: Vec>) -> MethodCallee<'tcx> { // Adjust the self expression the user provided and obtain the adjusted type. - let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick); + let self_ty = self.adjust_self_ty(check_env, unadjusted_self_ty, &pick); // Make sure nobody calls `drop()` explicitly. self.enforce_illegal_method_limitations(&pick); // Create substitutions for the method's type parameters. let (rcvr_substs, method_origin) = - self.fresh_receiver_substs(self_ty, &pick); + self.fresh_receiver_substs(check_env, self_ty, &pick); let (method_types, method_regions) = self.instantiate_method_substs(&pick, supplied_method_types); let all_substs = rcvr_substs.with_method(method_types, method_regions); @@ -98,14 +106,14 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Create the final signature for the method, replacing late-bound regions. let InstantiatedMethodSig { method_sig, all_substs, method_predicates - } = self.instantiate_method_sig(&pick, all_substs); + } = self.instantiate_method_sig(check_env, &pick, all_substs); let method_self_ty = method_sig.inputs[0]; // Unify the (adjusted) self type with what the method expects. self.unify_receivers(self_ty, method_self_ty); // Add any trait/regions obligations specified on the method's type parameters. - self.add_obligations(&pick, &all_substs, &method_predicates); + self.add_obligations(check_env, &pick, &all_substs, &method_predicates); // Create the final `MethodCallee`. let method_ty = pick.item.as_opt_method().unwrap(); @@ -123,7 +131,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // If this is an `&mut self` method, bias the receiver // expression towards mutability (this will switch // e.g. `Deref` to `DerefMut` in overloaded derefs and so on). - self.fixup_derefs_on_method_receiver_if_necessary(&callee); + self.fixup_derefs_on_method_receiver_if_necessary(check_env, &callee); callee } @@ -132,6 +140,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // ADJUSTMENTS fn adjust_self_ty(&mut self, + check_env: &mut CheckEnv<'tcx>, unadjusted_self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>) -> Ty<'tcx> @@ -153,13 +162,14 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Commit the autoderefs by calling `autoderef again, but this // time writing the results into the various tables. - let (autoderefd_ty, n, result) = check::autoderef(self.fcx, + let (autoderefd_ty, n, result) = check::autoderef(check_env, + self.fcx, self.span, unadjusted_self_ty, Some(self.self_expr), UnresolvedTypeAction::Error, NoPreference, - |_, n| { + |_, _, n| { if n == pick.autoderefs { Some(()) } else { @@ -170,7 +180,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { assert_eq!(result, Some(())); // Write out the final adjustment. - self.fcx.write_adjustment(self.self_expr.id, + self.fcx.write_adjustment(check_env, self.self_expr.id, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: pick.autoderefs, autoref: autoref, @@ -194,6 +204,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { /// Note that this substitution may include late-bound regions from the impl level. If so, /// these are instantiated later in the `instantiate_method_sig` routine. fn fresh_receiver_substs(&mut self, + check_env: &mut CheckEnv<'tcx>, self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>) -> (subst::Substs<'tcx>, MethodOrigin<'tcx>) @@ -202,13 +213,14 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { probe::InherentImplPick(impl_def_id) => { assert!(ty::impl_trait_ref(self.tcx(), impl_def_id).is_none(), "impl {:?} is not an inherent impl", impl_def_id); - let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id); + let impl_polytype = + check::impl_self_ty(check_env, self.fcx, self.span, impl_def_id); (impl_polytype.substs, MethodStatic(pick.item.def_id())) } probe::ObjectPick(trait_def_id, method_num, vtable_index) => { - self.extract_trait_ref(self_ty, |this, object_ty, data| { + self.extract_trait_ref(check_env, self_ty, |this, object_ty, data| { // The object data has no entry for the Self // Type. For the purposes of this method call, we // substitute the object type itself. This @@ -250,9 +262,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // respectively, then we want to return the type // parameters from the trait ([$A,$B]), not those from // the impl ([$A,$B,$C]) not the receiver type ([$C]). - let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id); + let impl_polytype = + check::impl_self_ty(check_env, self.fcx, self.span, impl_def_id); + let mut joined = FnCtxtJoined::new(check_env, self.fcx); let impl_trait_ref = - self.fcx.instantiate_type_scheme( + joined.instantiate_type_scheme( self.span, &impl_polytype.substs, &ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap()); @@ -295,7 +309,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } } - fn extract_trait_ref(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R where + fn extract_trait_ref(&mut self, + check_env: &mut CheckEnv<'tcx>, + self_ty: Ty<'tcx>, + mut closure: F + ) -> R where F: FnMut(&mut ConfirmContext<'a, 'tcx>, Ty<'tcx>, &ty::TyTrait<'tcx>) -> R, { // If we specified that this is an object method, then the @@ -303,13 +321,14 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // yield an object-type (e.g., `&Object` or `Box` // etc). - let (_, _, result) = check::autoderef(self.fcx, + let (_, _, result) = check::autoderef(check_env, + self.fcx, self.span, self_ty, None, UnresolvedTypeAction::Error, NoPreference, - |ty, _| { + |_, ty, _| { match ty.sty { ty::ty_trait(ref data) => Some(closure(self, ty, &**data)), _ => None, @@ -388,6 +407,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // fn instantiate_method_sig(&mut self, + check_env: &mut CheckEnv<'tcx>, pick: &probe::Pick<'tcx>, all_substs: subst::Substs<'tcx>) -> InstantiatedMethodSig<'tcx> @@ -401,8 +421,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // be no late-bound regions appearing here. let method_predicates = pick.item.as_opt_method().unwrap() .predicates.instantiate(self.tcx(), &all_substs); - let method_predicates = self.fcx.normalize_associated_types_in(self.span, - &method_predicates); + let mut joined = FnCtxtJoined::new(check_env, self.fcx); + let method_predicates = joined.normalize_associated_types_in(self.span, + &method_predicates); debug!("method_predicates after subst = {}", method_predicates.repr(self.tcx())); @@ -418,7 +439,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { debug!("late-bound lifetimes from method instantiated, method_sig={}", method_sig.repr(self.tcx())); - let method_sig = self.fcx.instantiate_type_scheme(self.span, &all_substs, &method_sig); + let method_sig = joined.instantiate_type_scheme(self.span, &all_substs, &method_sig); debug!("type scheme substituted, method_sig={}", method_sig.repr(self.tcx())); @@ -430,6 +451,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } fn add_obligations(&mut self, + check_env: &mut CheckEnv<'tcx>, pick: &probe::Pick<'tcx>, all_substs: &subst::Substs<'tcx>, method_predicates: &ty::InstantiatedPredicates<'tcx>) { @@ -439,10 +461,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { method_predicates.repr(self.tcx())); self.fcx.add_obligations_for_parameters( + check_env, traits::ObligationCause::misc(self.span, self.fcx.body_id), method_predicates); self.fcx.add_default_region_param_bounds( + &mut check_env.fulfillment_cx, all_substs, self.call_expr); } @@ -453,7 +477,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { /// When we select a method with an `&mut self` receiver, we have to go convert any /// auto-derefs, indices, etc from `Deref` and `Index` into `DerefMut` and `IndexMut` /// respectively. - fn fixup_derefs_on_method_receiver_if_necessary(&self, + fn fixup_derefs_on_method_receiver_if_necessary(&mut self, + check_env: &mut CheckEnv<'tcx>, method_callee: &MethodCallee) { let sig = match method_callee.ty.sty { ty::ty_bare_fn(_, ref f) => f.sig.clone(), @@ -489,11 +514,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Fix up autoderefs and derefs. for (i, &expr) in exprs.iter().rev().enumerate() { // Count autoderefs. - let autoderef_count = match self.fcx - .inh - .adjustments - .borrow() - .get(&expr.id) { + let autoderef_count = match check_env.tt.adjustments.get(&expr.id) { Some(&ty::AdjustDerefRef(ref adj)) => adj.autoderefs, Some(_) | None => 0, }; @@ -502,13 +523,15 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { i, expr.repr(self.tcx()), autoderef_count); if autoderef_count > 0 { - check::autoderef(self.fcx, + let expr_ty = self.fcx.expr_ty(&check_env.tt.node_types, expr); + check::autoderef(check_env, + self.fcx, expr.span, - self.fcx.expr_ty(expr), + expr_ty, Some(expr), UnresolvedTypeAction::Error, PreferMutLvalue, - |_, autoderefs| { + |_, _, autoderefs| { if autoderefs == autoderef_count + 1 { Some(()) } else { @@ -529,7 +552,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // expects. This is annoying and horrible. We // ought to recode this routine so it doesn't // (ab)use the normal type checking paths. - let adj = self.fcx.inh.adjustments.borrow().get(&base_expr.id).cloned(); + let adj = check_env.tt.adjustments.get(&base_expr.id).cloned(); let (autoderefs, unsize) = match adj { Some(ty::AdjustDerefRef(adr)) => match adr.autoref { None => { @@ -560,16 +583,19 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let (adjusted_base_ty, unsize) = if let Some(target) = unsize { (target, true) } else { - (self.fcx.adjust_expr_ty(base_expr, + let typer = FnCtxtTyper::new(&check_env.tt, self.fcx); + (typer.adjust_expr_ty(base_expr, Some(&ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, autoref: None, unsize: None }))), false) }; - let index_expr_ty = self.fcx.expr_ty(&**index_expr); + let index_expr_ty = self.fcx.expr_ty(&check_env.tt.node_types, + &**index_expr); let result = check::try_index_step( + check_env, self.fcx, MethodCall::expr(expr.id), expr, @@ -583,7 +609,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { if let Some((input_ty, return_ty)) = result { demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty); - let expr_ty = self.fcx.expr_ty(&*expr); + let expr_ty = self.fcx.expr_ty(&check_env.tt.node_types, &*expr); demand::suptype(self.fcx, expr.span, expr_ty, return_ty); } } @@ -591,13 +617,15 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // if this is an overloaded deref, then re-evaluate with // a preference for mut let method_call = MethodCall::expr(expr.id); - if self.fcx.inh.method_map.borrow().contains_key(&method_call) { + let expr_ty = self.fcx.expr_ty(&check_env.tt.node_types, &**base_expr); + if check_env.tt.method_map.contains_key(&method_call) { check::try_overloaded_deref( + check_env, self.fcx, expr.span, Some(method_call), Some(&**base_expr), - self.fcx.expr_ty(&**base_expr), + expr_ty, PreferMutLvalue); } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index c070df6b5939d..5e04338226f3a 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -11,9 +11,12 @@ //! Method lookup: the secret sauce of Rust. See `README.md`. use astconv::AstConv; -use check::FnCtxt; -use check::vtable; -use check::vtable::select_new_fcx_obligations; +use super::CheckEnv; +use super::FnCtxt; +use super::FnCtxtTyper; +use super::FnCtxtJoined; +use super::vtable; +use super::vtable::select_new_fcx_obligations; use middle::def; use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod}; use middle::subst; @@ -61,7 +64,8 @@ pub enum CandidateSource { type ItemIndex = usize; // just for doc purposes /// Determines whether the type `self_ty` supports a method name `method_name` or not. -pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn exists<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, method_name: ast::Name, self_ty: Ty<'tcx>, @@ -69,7 +73,7 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, -> bool { let mode = probe::Mode::MethodCall; - match probe::probe(fcx, span, mode, method_name, self_ty, call_expr_id) { + match probe::probe(check_env, fcx, span, mode, method_name, self_ty, call_expr_id) { Ok(..) => true, Err(NoMatch(..)) => false, Err(Ambiguity(..)) => true, @@ -91,7 +95,8 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// * `self_ty`: the (unadjusted) type of the self expression (`foo`) /// * `supplied_method_types`: the explicit method type parameters, if any (`T1..Tn`) /// * `self_expr`: the self expression (`foo`) -pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn lookup<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, method_name: ast::Name, self_ty: Ty<'tcx>, @@ -108,11 +113,19 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let mode = probe::Mode::MethodCall; let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty); - let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, call_expr.id)); - Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types)) + let pick = try!(probe::probe(check_env, fcx, span, mode, method_name, self_ty, call_expr.id)); + Ok(confirm::confirm(check_env, + fcx, + span, + self_expr, + call_expr, + self_ty, + pick, + supplied_method_types)) } -pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn lookup_in_trait<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, self_expr: Option<&ast::Expr>, m_name: ast::Name, @@ -121,7 +134,7 @@ pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, opt_input_types: Option>>) -> Option> { - lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id, + lookup_in_trait_adjusted(check_env, fcx, span, self_expr, m_name, trait_def_id, 0, false, self_ty, opt_input_types) } @@ -134,7 +147,8 @@ pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// method-lookup code. In particular, autoderef on index is basically identical to autoderef with /// normal probes, except that the test also looks for built-in indexing. Also, the second half of /// this method is basically the same as confirmation. -pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn lookup_in_trait_adjusted<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, self_expr: Option<&ast::Expr>, m_name: ast::Name, @@ -178,11 +192,14 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fcx.body_id, poly_trait_ref.as_predicate()); - // Now we want to know if this can be matched - let mut selcx = traits::SelectionContext::new(fcx.infcx(), fcx); - if !selcx.evaluate_obligation(&obligation) { - debug!("--> Cannot match obligation"); - return None; // Cannot be matched, no such method resolution is possible. + { + // Now we want to know if this can be matched + let typer = FnCtxtTyper::new(&check_env.tt, fcx); + let mut selcx = traits::SelectionContext::new(fcx.infcx(), &typer); + if !selcx.evaluate_obligation(&obligation) { + debug!("--> Cannot match obligation"); + return None; // Cannot be matched, no such method resolution is possible. + } } // Trait must have a method named `m_name` and it should not have @@ -204,7 +221,10 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &method_ty.fty.sig).0; - let fn_sig = fcx.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); + let fn_sig = { + let mut joined = FnCtxtJoined::new(check_env, fcx); + joined.instantiate_type_scheme(span, trait_ref.substs, &fn_sig) + }; let transformed_self_ty = fn_sig.inputs[0]; let fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(ty::BareFnTy { sig: ty::Binder(fn_sig), @@ -224,16 +244,20 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // // Note that as the method comes from a trait, it should not have // any late-bound regions appearing in its bounds. - let method_bounds = fcx.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates); + let method_bounds = { + let mut joined = FnCtxtJoined::new(check_env, fcx); + joined.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates) + }; assert!(!method_bounds.has_escaping_regions()); fcx.add_obligations_for_parameters( + check_env, traits::ObligationCause::misc(span, fcx.body_id), &method_bounds); // FIXME(#18653) -- Try to resolve obligations, giving us more // typing information, which can sometimes be needed to avoid // pathological region inference failures. - vtable::select_new_fcx_obligations(fcx); + vtable::select_new_fcx_obligations(check_env, fcx); // Insert any adjustments needed (always an autoref of some mutability). match self_expr { @@ -249,7 +273,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ty::ByValueExplicitSelfCategory => { // Trait method is fn(self), no transformation needed. assert!(!unsize); - fcx.write_autoderef_adjustment(self_expr.id, autoderefs); + fcx.write_autoderef_adjustment(check_env, self_expr.id, autoderefs); } ty::ByReferenceExplicitSelfCategory(..) => { @@ -257,7 +281,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // autoref. Pull the region etc out of the type of first argument. match transformed_self_ty.sty { ty::ty_rptr(region, ty::mt { mutbl, ty: _ }) => { - fcx.write_adjustment(self_expr.id, + fcx.write_adjustment(check_env, self_expr.id, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, autoref: Some(ty::AutoPtr(region, mutbl)), @@ -303,7 +327,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(callee) } -pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn resolve_ufcs<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, method_name: ast::Name, self_ty: Ty<'tcx>, @@ -311,7 +336,7 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, -> Result<(def::Def, LastPrivate), MethodError> { let mode = probe::Mode::Path; - let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id)); + let pick = try!(probe::probe(check_env, fcx, span, mode, method_name, self_ty, expr_id)); let def_id = pick.item.def_id(); let mut lp = LastMod(AllPublic); let provenance = match pick.kind { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c94fa03702681..2c3893968b517 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -14,7 +14,7 @@ use super::{CandidateSource,ImplSource,TraitSource}; use super::suggest; use check; -use check::{FnCtxt, NoPreference, UnresolvedTypeAction}; +use check::{CheckEnv, FnCtxt, FnCtxtTyper, FnCtxtJoined, NoPreference, UnresolvedTypeAction}; use middle::fast_reject; use middle::subst; use middle::subst::Subst; @@ -113,7 +113,8 @@ pub enum Mode { Path } -pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn probe<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, mode: Mode, item_name: ast::Name, @@ -134,7 +135,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // think cause spurious errors. Really though this part should // take place in the `fcx.infcx().probe` below. let steps = if mode == Mode::MethodCall { - match create_steps(fcx, span, self_ty) { + match create_steps(check_env, fcx, span, self_ty) { Some(steps) => steps, None => return Err(MethodError::NoMatch(Vec::new(), Vec::new())), } @@ -174,25 +175,27 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, item_name, steps, opt_simplified_steps); - probe_cx.assemble_inherent_candidates(); + probe_cx.assemble_inherent_candidates(check_env); try!(probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)); - probe_cx.pick() + probe_cx.pick(check_env) }) } -fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn create_steps<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, self_ty: Ty<'tcx>) -> Option>> { let mut steps = Vec::new(); - let (final_ty, dereferences, _) = check::autoderef(fcx, + let (final_ty, dereferences, _) = check::autoderef(check_env, + fcx, span, self_ty, None, UnresolvedTypeAction::Error, NoPreference, - |t, d| { + |_, t, d| { steps.push(CandidateStep { self_ty: t, autoderefs: d, @@ -258,30 +261,31 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { /////////////////////////////////////////////////////////////////////////// // CANDIDATE ASSEMBLY - fn assemble_inherent_candidates(&mut self) { + fn assemble_inherent_candidates(&mut self, check_env: &mut CheckEnv<'tcx>) { let steps = self.steps.clone(); for step in &*steps { - self.assemble_probe(step.self_ty); + self.assemble_probe(check_env, step.self_ty); } } - fn assemble_probe(&mut self, self_ty: Ty<'tcx>) { + fn assemble_probe(&mut self, check_env: &mut CheckEnv<'tcx>, self_ty: Ty<'tcx>) { debug!("assemble_probe: self_ty={}", self_ty.repr(self.tcx())); match self_ty.sty { ty::ty_trait(box ref data) => { self.assemble_inherent_candidates_from_object(self_ty, data); - self.assemble_inherent_impl_candidates_for_type(data.principal_def_id()); + self.assemble_inherent_impl_candidates_for_type(check_env, + data.principal_def_id()); } ty::ty_enum(did, _) | ty::ty_struct(did, _) | ty::ty_closure(did, _) => { - self.assemble_inherent_impl_candidates_for_type(did); + self.assemble_inherent_impl_candidates_for_type(check_env, did); } ty::ty_uniq(_) => { if let Some(box_did) = self.tcx().lang_items.owned_box() { - self.assemble_inherent_impl_candidates_for_type(box_did); + self.assemble_inherent_impl_candidates_for_type(check_env, box_did); } } ty::ty_param(p) => { @@ -289,98 +293,107 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } ty::ty_char => { let lang_def_id = self.tcx().lang_items.char_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_str => { let lang_def_id = self.tcx().lang_items.str_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_vec(_, None) => { let lang_def_id = self.tcx().lang_items.slice_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutImmutable }) => { let lang_def_id = self.tcx().lang_items.const_ptr_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutMutable }) => { let lang_def_id = self.tcx().lang_items.mut_ptr_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_int(ast::TyI8) => { let lang_def_id = self.tcx().lang_items.i8_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_int(ast::TyI16) => { let lang_def_id = self.tcx().lang_items.i16_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_int(ast::TyI32) => { let lang_def_id = self.tcx().lang_items.i32_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_int(ast::TyI64) => { let lang_def_id = self.tcx().lang_items.i64_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_int(ast::TyIs) => { let lang_def_id = self.tcx().lang_items.isize_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_uint(ast::TyU8) => { let lang_def_id = self.tcx().lang_items.u8_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_uint(ast::TyU16) => { let lang_def_id = self.tcx().lang_items.u16_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_uint(ast::TyU32) => { let lang_def_id = self.tcx().lang_items.u32_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_uint(ast::TyU64) => { let lang_def_id = self.tcx().lang_items.u64_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_uint(ast::TyUs) => { let lang_def_id = self.tcx().lang_items.usize_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_float(ast::TyF32) => { let lang_def_id = self.tcx().lang_items.f32_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } ty::ty_float(ast::TyF64) => { let lang_def_id = self.tcx().lang_items.f64_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + self.assemble_inherent_impl_for_primitive(check_env, lang_def_id); } _ => { } } } - fn assemble_inherent_impl_for_primitive(&mut self, lang_def_id: Option) { + fn assemble_inherent_impl_for_primitive(&mut self, + check_env: &mut CheckEnv<'tcx>, + lang_def_id: Option) + { if let Some(impl_def_id) = lang_def_id { ty::populate_implementations_for_primitive_if_necessary(self.tcx(), impl_def_id); - self.assemble_inherent_impl_probe(impl_def_id); + self.assemble_inherent_impl_probe(check_env, impl_def_id); } } - fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: ast::DefId) { + fn assemble_inherent_impl_candidates_for_type(&mut self, + check_env: &mut CheckEnv<'tcx>, + def_id: ast::DefId) + { // Read the inherent implementation candidates for this type from the // metadata if necessary. ty::populate_implementations_for_type_if_necessary(self.tcx(), def_id); if let Some(impl_infos) = self.tcx().inherent_impls.borrow().get(&def_id) { for &impl_def_id in &***impl_infos { - self.assemble_inherent_impl_probe(impl_def_id); + self.assemble_inherent_impl_probe(check_env, impl_def_id); } } } - fn assemble_inherent_impl_probe(&mut self, impl_def_id: ast::DefId) { + fn assemble_inherent_impl_probe(&mut self, + check_env: &mut CheckEnv<'tcx>, + impl_def_id: ast::DefId) + { if !self.impl_dups.insert(impl_def_id) { return; // already visited } @@ -398,7 +411,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); - let impl_ty = self.fcx.instantiate_type_scheme(self.span, &impl_substs, &impl_ty); + let mut joined = FnCtxtJoined::new(check_env, self.fcx); + let impl_ty = joined.instantiate_type_scheme(self.span, &impl_substs, &impl_ty); // Determine the receiver type that the method itself expects. let xform_self_ty = @@ -835,8 +849,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { /////////////////////////////////////////////////////////////////////////// // THE ACTUAL SEARCH - fn pick(mut self) -> PickResult<'tcx> { - match self.pick_core() { + fn pick(mut self, check_env: &mut CheckEnv<'tcx>) -> PickResult<'tcx> { + match self.pick_core(check_env) { Some(r) => return r, None => {} } @@ -851,7 +865,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { try!(self.assemble_extension_candidates_for_all_traits()); - let out_of_scope_traits = match self.pick_core() { + let out_of_scope_traits = match self.pick_core(check_env) { Some(Ok(p)) => vec![p.item.container().id()], Some(Err(MethodError::Ambiguity(v))) => v.into_iter().map(|source| { match source { @@ -880,29 +894,33 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { Err(MethodError::NoMatch(static_candidates, out_of_scope_traits)) } - fn pick_core(&mut self) -> Option> { + fn pick_core(&mut self, check_env: &mut CheckEnv<'tcx>) -> Option> { let steps = self.steps.clone(); // find the first step that works - steps.iter().filter_map(|step| self.pick_step(step)).next() + steps.iter().filter_map(|step| self.pick_step(check_env, step)).next() } - fn pick_step(&mut self, step: &CandidateStep<'tcx>) -> Option> { + fn pick_step(&mut self, + check_env: &mut CheckEnv<'tcx>, + step: &CandidateStep<'tcx>) -> Option> + { debug!("pick_step: step={}", step.repr(self.tcx())); if ty::type_is_error(step.self_ty) { return None; } - match self.pick_by_value_method(step) { + match self.pick_by_value_method(check_env, step) { Some(result) => return Some(result), None => {} } - self.pick_autorefd_method(step) + self.pick_autorefd_method(check_env, step) } fn pick_by_value_method(&mut self, + check_env: &mut CheckEnv<'tcx>, step: &CandidateStep<'tcx>) -> Option> { @@ -920,7 +938,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { return None; } - self.pick_method(step.self_ty).map(|r| r.map(|mut pick| { + self.pick_method(check_env, step.self_ty).map(|r| r.map(|mut pick| { pick.autoderefs = step.autoderefs; // Insert a `&*` or `&mut *` if this is a reference type: @@ -934,6 +952,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } fn pick_autorefd_method(&mut self, + check_env: &mut CheckEnv<'tcx>, step: &CandidateStep<'tcx>) -> Option> { @@ -949,7 +968,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { ty: step.self_ty, mutbl: m }); - self.pick_method(autoref_ty).map(|r| r.map(|mut pick| { + self.pick_method(check_env, autoref_ty).map(|r| r.map(|mut pick| { pick.autoderefs = step.autoderefs; pick.autoref = Some(m); pick.unsize = if step.unsize { @@ -962,11 +981,14 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { }).nth(0) } - fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option> { + fn pick_method(&mut self, + check_env: &mut CheckEnv<'tcx>, + self_ty: Ty<'tcx>) -> Option> + { debug!("pick_method(self_ty={})", self.infcx().ty_to_string(self_ty)); debug!("searching inherent candidates"); - match self.consider_candidates(self_ty, &self.inherent_candidates) { + match self.consider_candidates(check_env, self_ty, &self.inherent_candidates) { None => {} Some(pick) => { return Some(pick); @@ -974,16 +996,17 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } debug!("searching extension candidates"); - self.consider_candidates(self_ty, &self.extension_candidates) + self.consider_candidates(check_env, self_ty, &self.extension_candidates) } fn consider_candidates(&self, + check_env: &mut CheckEnv<'tcx>, self_ty: Ty<'tcx>, probes: &[Candidate<'tcx>]) -> Option> { let mut applicable_candidates: Vec<_> = probes.iter() - .filter(|&probe| self.consider_probe(self_ty, probe)) + .filter(|&probe| self.consider_probe(check_env, self_ty, probe)) .collect(); debug!("applicable_candidates: {}", applicable_candidates.repr(self.tcx())); @@ -1006,7 +1029,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { }) } - fn consider_probe(&self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>) -> bool { + fn consider_probe(&self, + check_env: &mut CheckEnv<'tcx>, + self_ty: Ty<'tcx>, + probe: &Candidate<'tcx>) -> bool + { debug!("consider_probe: self_ty={} probe={}", self_ty.repr(self.tcx()), probe.repr(self.tcx())); @@ -1028,7 +1055,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { match probe.kind { InherentImplCandidate(impl_def_id, ref substs) | ExtensionImplCandidate(impl_def_id, _, ref substs, _) => { - let selcx = &mut traits::SelectionContext::new(self.infcx(), self.fcx); + let typer = FnCtxtTyper::new(&check_env.tt, self.fcx); + let selcx = &mut traits::SelectionContext::new(self.infcx(), &typer); let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); // Check whether the impl imposes obligations we have to worry about. diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 17658675ee280..a9be6d5815110 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -14,7 +14,7 @@ use CrateCtxt; use astconv::AstConv; -use check::{self, FnCtxt}; +use check::{self, CheckEnv, FnCtxt}; use middle::ty::{self, Ty}; use middle::def; use metadata::{csearch, cstore, decoder}; @@ -29,7 +29,8 @@ use std::cmp::Ordering; use super::{MethodError, CandidateSource, impl_method, trait_method}; -pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn report_error<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, rcvr_ty: Ty<'tcx>, method_name: ast::Name, @@ -72,10 +73,10 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span, "found defined static methods, maybe a `self` is missing?"); - report_candidates(fcx, span, method_name, static_sources); + report_candidates(check_env, fcx, span, method_name, static_sources); } - suggest_traits_to_import(fcx, span, rcvr_ty, method_name, + suggest_traits_to_import(check_env, fcx, span, rcvr_ty, method_name, rcvr_expr, out_of_scope_traits) } @@ -83,7 +84,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span_err!(fcx.sess(), span, E0034, "multiple applicable methods in scope"); - report_candidates(fcx, span, method_name, sources); + report_candidates(check_env, fcx, span, method_name, sources); } MethodError::ClosureAmbiguity(trait_def_id) => { @@ -102,10 +103,12 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } - fn report_candidates(fcx: &FnCtxt, - span: Span, - method_name: ast::Name, - mut sources: Vec) { + fn report_candidates<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, + span: Span, + method_name: ast::Name, + mut sources: Vec) + { sources.sort(); sources.dedup(); @@ -118,7 +121,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let impl_span = fcx.tcx().map.def_id_span(impl_did, span); let method_span = fcx.tcx().map.def_id_span(method.def_id, impl_span); - let impl_ty = check::impl_self_ty(fcx, span, impl_did).ty; + let impl_ty = check::impl_self_ty(check_env, fcx, span, impl_did).ty; let insertion = match ty::impl_trait_ref(fcx.tcx(), impl_did) { None => format!(""), @@ -149,7 +152,8 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, pub type AllTraitsVec = Vec; -fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn suggest_traits_to_import<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, rcvr_ty: Ty<'tcx>, method_name: ast::Name, @@ -182,7 +186,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, return } - let type_is_local = type_derefs_to_local(fcx, span, rcvr_ty, rcvr_expr); + let type_is_local = type_derefs_to_local(check_env, fcx, span, rcvr_ty, rcvr_expr); // there's no implemented traits, so lets suggest some traits to // implement, by finding ones that have the method name, and are @@ -229,7 +233,8 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// Checks whether there is a local type somewhere in the chain of /// autoderefs of `rcvr_ty`. -fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn type_derefs_to_local<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, rcvr_ty: Ty<'tcx>, rcvr_expr: Option<&ast::Expr>) -> bool { @@ -252,12 +257,12 @@ fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // This occurs for UFCS desugaring of `T::method`, where there is no // receiver expression for the method call, and thus no autoderef. if rcvr_expr.is_none() { - return is_local(fcx.resolve_type_vars_if_possible(rcvr_ty)); + return is_local(fcx.resolve_type_vars_if_possible(check_env, rcvr_ty)); } - check::autoderef(fcx, span, rcvr_ty, None, + check::autoderef(check_env, fcx, span, rcvr_ty, None, check::UnresolvedTypeAction::Ignore, check::NoPreference, - |ty, _| { + |_, ty, _| { if is_local(ty) { Some(()) } else { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3769e9fa0f36a..b38642d12a099 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -80,9 +80,9 @@ pub use self::LvaluePreference::*; pub use self::Expectation::*; pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::TupleArgumentsFlag::*; +use self::_match::pat_ctxt; use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode}; -use check::_match::pat_ctxt; use fmt_macros::{Parser, Piece, Position}; use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS}; use middle::def; @@ -98,7 +98,7 @@ use middle::ty::{FnSig, GenericPredicates, TypeScheme}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty}; use middle::ty::liberate_late_bound_regions; -use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap}; +use middle::ty::{MethodCall, MethodCallee}; use middle::ty_fold::{TypeFolder, TypeFoldable}; use rscope::RegionScope; use session::Session; @@ -110,7 +110,7 @@ use util::ppaux::{self, Repr}; use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; use util::lev_distance::lev_distance; -use std::cell::{Cell, Ref, RefCell}; +use std::cell::{Cell, RefCell}; use std::mem::replace; use std::iter::repeat; use std::slice; @@ -128,15 +128,15 @@ use syntax::visit::{self, Visitor}; mod assoc; pub mod dropck; -pub mod _match; -pub mod vtable; +mod _match; +mod vtable; pub mod writeback; -pub mod regionck; -pub mod coercion; +mod regionck; +mod coercion; pub mod demand; pub mod method; mod upvar; -pub mod wf; +mod wf; mod cast; mod closure; mod callee; @@ -154,26 +154,37 @@ mod op; /// share the inherited fields. pub struct Inherited<'a, 'tcx: 'a> { infcx: infer::InferCtxt<'a, 'tcx>, - locals: RefCell>>, param_env: ty::ParameterEnvironment<'a, 'tcx>, // Temporary tables: - node_types: RefCell>>, - item_substs: RefCell>>, - adjustments: RefCell>>, - method_map: MethodMap<'tcx>, upvar_capture_map: RefCell, - closure_tys: RefCell>>, closure_kinds: RefCell>, - object_cast_map: ObjectCastMap<'tcx>, +} + +type MethodMap<'tcx> = FnvHashMap>; + +/// Temporary tables +struct CheckEnvTables<'tcx> { + node_types: NodeMap>, + item_substs: NodeMap>, + adjustments: NodeMap>, + method_map: MethodMap<'tcx>, + closure_tys: DefIdMap>, +} + +pub struct CheckEnv<'tcx> { + locals: NodeMap>, + + // Temporary tables: + tt: CheckEnvTables<'tcx>, // A mapping from each fn's id to its signature, with all bound // regions replaced with free ones. Unlike the other tables, this // one is never copied into the tcx: it is only used by regionck. - fn_sig_map: RefCell>>>, + fn_sig_map: NodeMap>>, // Tracks trait obligations incurred during this function body. - fulfillment_cx: RefCell>, + fulfillment_cx: traits::FulfillmentContext<'tcx>, // When we process a call like `c()` where `c` is a closure type, // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or @@ -182,13 +193,13 @@ pub struct Inherited<'a, 'tcx: 'a> { // decision. We keep these deferred resolutions grouped by the // def-id of the closure, so that once we decide, we can easily go // back and process them. - deferred_call_resolutions: RefCell>>>, + deferred_call_resolutions: DefIdMap>>, - deferred_cast_checks: RefCell>>, + deferred_cast_checks: Vec>, } trait DeferredCallResolution<'tcx> { - fn resolve<'a>(&mut self, fcx: &FnCtxt<'a,'tcx>); + fn resolve<'a>(&mut self, check_env: &mut CheckEnv<'tcx>, fcx: &FnCtxt<'a,'tcx>); } type DeferredCallResolutionHandler<'tcx> = Box+'tcx>; @@ -247,18 +258,18 @@ impl<'tcx> Expectation<'tcx> { } #[derive(Copy, Clone)] -pub struct UnsafetyState { - pub def: ast::NodeId, - pub unsafety: ast::Unsafety, +struct UnsafetyState { + def: ast::NodeId, + unsafety: ast::Unsafety, from_fn: bool } impl UnsafetyState { - pub fn function(unsafety: ast::Unsafety, def: ast::NodeId) -> UnsafetyState { + fn function(unsafety: ast::Unsafety, def: ast::NodeId) -> UnsafetyState { UnsafetyState { def: def, unsafety: unsafety, from_fn: true } } - pub fn recurse(&mut self, blk: &ast::Block) -> UnsafetyState { + fn recurse(&self, blk: &ast::Block) -> UnsafetyState { match self.unsafety { // If this unsafe, then if the outer function was already marked as // unsafe we shouldn't attribute the unsafe'ness to the block. This @@ -295,64 +306,251 @@ pub struct FnCtxt<'a, 'tcx: 'a> { ret_ty: ty::FnOutput<'tcx>, - ps: RefCell, + ps: Cell, inh: &'a Inherited<'a, 'tcx>, ccx: &'a CrateCtxt<'a, 'tcx>, } -impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxt<'a, 'tcx> { +pub struct FnCtxtJoined<'a, 'tcx: 'a> { + fcx: &'a FnCtxt<'a, 'tcx>, + + check_env: &'a mut CheckEnv<'tcx>, +} + +impl<'a, 'tcx> FnCtxtJoined<'a, 'tcx> { + fn new(check_env: &'a mut CheckEnv<'tcx>, fcx: &'a FnCtxt<'a, 'tcx>) -> Self { + FnCtxtJoined { check_env: check_env, fcx: fcx } + } + + fn normalize_associated_types_in(&mut self, span: Span, value: &T) -> T + where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx> + { + let typer = FnCtxtTyper::new(&self.check_env.tt, self.fcx); + self.fcx.inh.normalize_associated_types_in(&typer, + &mut self.check_env.fulfillment_cx, + span, self.fcx.body_id, value) + } + + fn normalize_associated_type(&mut self, + span: Span, + trait_ref: ty::TraitRef<'tcx>, + item_name: ast::Name) + -> Ty<'tcx> + { + let cause = traits::ObligationCause::new(span, + self.fcx.body_id, + traits::ObligationCauseCode::MiscObligation); + let typer = FnCtxtTyper::new(&self.check_env.tt, self.fcx); + self.check_env.fulfillment_cx + .normalize_projection_type(self.fcx.infcx(), + &typer, + ty::ProjectionTy { + trait_ref: trait_ref, + item_name: item_name, + }, + cause) + } + + /// Basically whenever we are converting from a type scheme into + /// the fn body space, we always want to normalize associated + /// types as well. This function combines the two. + fn instantiate_type_scheme(&mut self, + span: Span, + substs: &Substs<'tcx>, + value: &T) + -> T + where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx> + { + let value = value.subst(self.tcx(), substs); + let result = self.normalize_associated_types_in(span, &value); + debug!("instantiate_type_scheme(value={}, substs={}) = {}", + value.repr(self.tcx()), + substs.repr(self.tcx()), + result.repr(self.tcx())); + result + } + + /// As `instantiate_type_scheme`, but for the bounds found in a + /// generic type scheme. + fn instantiate_bounds(&mut self, + span: Span, + substs: &Substs<'tcx>, + bounds: &ty::GenericPredicates<'tcx>) + -> ty::InstantiatedPredicates<'tcx> + { + ty::InstantiatedPredicates { + predicates: self.instantiate_type_scheme(span, substs, &bounds.predicates) + } + } + + + /// Returns the type of `def_id` with all generics replaced by by fresh type/region variables. + /// Also returns the substitution from the type parameters on `def_id` to the fresh variables. + /// Registers any trait obligations specified on `def_id` at the same time. + /// + /// Note that function is only intended to be used with types (notably, not fns). This is + /// because it doesn't do any instantiation of late-bound regions. + fn instantiate_type(&mut self, + span: Span, + def_id: ast::DefId) + -> TypeAndSubsts<'tcx> + { + let type_scheme = + ty::lookup_item_type(self.tcx(), def_id); + let type_predicates = + ty::lookup_predicates(self.tcx(), def_id); + let substs = + self.fcx.infcx().fresh_substs_for_generics( + span, + &type_scheme.generics); + let bounds = + self.instantiate_bounds(span, &substs, &type_predicates); + self.fcx.add_obligations_for_parameters( + self.check_env, + traits::ObligationCause::new( + span, + self.fcx.body_id, + traits::ItemObligation(def_id)), + &bounds); + let monotype = + self.instantiate_type_scheme(span, &substs, &type_scheme.ty); + + TypeAndSubsts { + ty: monotype, + substs: substs + } + } + + /// Returns the type that this AST path refers to. If the path has no type + /// parameters and the corresponding type has type parameters, fresh type + /// and/or region variables are substituted. + /// + /// This is used when checking the constructor in struct literals. + fn instantiate_struct_literal_ty(&mut self, + did: ast::DefId, + path: &ast::Path) + -> TypeAndSubsts<'tcx> + { + let ty::TypeScheme { generics, ty: decl_ty } = { + let tcx = self.tcx(); + ty::lookup_item_type(tcx, did) + }; + + let substs = astconv::ast_path_substs_for_ty(self, self.fcx, + path.span, + PathParamMode::Optional, + &generics, + path.segments.last().unwrap()); + + let ty = self.instantiate_type_scheme(path.span, &substs, &decl_ty); + + TypeAndSubsts { substs: substs, ty: ty } + } + + fn to_ty(&mut self, ast_t: &ast::Ty) -> Ty<'tcx> { + let t = ast_ty_to_ty(self, self.fcx, ast_t); + + let mut bounds_checker = wf::BoundsChecker::new(self.check_env, + self.fcx, + ast_t.span, + self.fcx.body_id, + None); + bounds_checker.check_ty(t); + + t + } +} + +// FIXME: Determine whether we actually need these. +#[derive(Clone,Copy)] +struct FnCtxtTyper<'a, 'tcx: 'a> { + tt: &'a CheckEnvTables<'tcx>, + + fcx: &'a FnCtxt<'a, 'tcx>, +} + +impl<'a, 'tcx> FnCtxtTyper<'a, 'tcx> { + fn new(tt: &'a CheckEnvTables<'tcx>, fcx: &'a FnCtxt<'a, 'tcx>) -> Self { + FnCtxtTyper { + tt: tt, + fcx: fcx, + } + } + + /// Apply `adjustment` to the type of `expr` + fn adjust_expr_ty(&self, + expr: &ast::Expr, + adjustment: Option<&ty::AutoAdjustment<'tcx>>) + -> Ty<'tcx> + { + let raw_ty = self.fcx.expr_ty(&self.tt.node_types, expr); + let raw_ty = self.fcx.infcx().shallow_resolve(raw_ty); + let resolve_ty = |ty: Ty<'tcx>| self.fcx.infcx().resolve_type_vars_if_possible(&ty); + ty::adjust_ty(self.fcx.ccx.tcx, + expr.span, + expr.id, + raw_ty, + adjustment, + |method_call| self.tt.method_map.get(&method_call) + .map(|method| resolve_ty(method.ty))) + } +} + +impl<'a, 'tcx> mc::Typer<'tcx> for FnCtxtTyper<'a, 'tcx> { fn node_ty(&self, id: ast::NodeId) -> McResult> { - let ty = self.node_ty(id); - self.resolve_type_vars_or_error(&ty) + let ty = self.fcx.node_ty(&self.tt.node_types, id); + self.fcx.resolve_type_vars_or_error(&ty) } fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult> { - let ty = self.adjust_expr_ty(expr, self.inh.adjustments.borrow().get(&expr.id)); - self.resolve_type_vars_or_error(&ty) + let ty = self.adjust_expr_ty(expr, + self.tt.adjustments.get(&expr.id)); + self.fcx.resolve_type_vars_or_error(&ty) } fn type_moves_by_default(&self, span: Span, ty: Ty<'tcx>) -> bool { - let ty = self.infcx().resolve_type_vars_if_possible(&ty); - !traits::type_known_to_meet_builtin_bound(self.infcx(), self, ty, ty::BoundCopy, span) + let ty = self.fcx.infcx().resolve_type_vars_if_possible(&ty); + !traits::type_known_to_meet_builtin_bound(self.fcx.infcx(), self, ty, ty::BoundCopy, span) } fn node_method_ty(&self, method_call: ty::MethodCall) -> Option> { - self.inh.method_map.borrow() - .get(&method_call) - .map(|method| method.ty) - .map(|ty| self.infcx().resolve_type_vars_if_possible(&ty)) + self.tt.method_map.get(&method_call) + .map(|method| method.ty) + .map(|ty| self.fcx + .infcx() + .resolve_type_vars_if_possible(&ty)) } fn node_method_origin(&self, method_call: ty::MethodCall) -> Option> { - self.inh.method_map.borrow() - .get(&method_call) - .map(|method| method.origin.clone()) + self.tt.method_map.get(&method_call) + .map(|method| method.origin.clone()) } - fn adjustments(&self) -> &RefCell>> { - &self.inh.adjustments + fn adjustments(&self, closure: F) -> T + where F: FnOnce(&NodeMap>) -> T { + closure(&self.tt.adjustments) } fn is_method_call(&self, id: ast::NodeId) -> bool { - self.inh.method_map.borrow().contains_key(&ty::MethodCall::expr(id)) + self.tt.method_map.contains_key(&ty::MethodCall::expr(id)) } fn temporary_scope(&self, rvalue_id: ast::NodeId) -> Option { - self.param_env().temporary_scope(rvalue_id) + self.fcx.param_env().temporary_scope(rvalue_id) } fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { - self.inh.upvar_capture_map.borrow().get(&upvar_id).cloned() + self.fcx.inh.upvar_capture_map.borrow().get(&upvar_id).cloned() } } -impl<'a, 'tcx> ty::ClosureTyper<'tcx> for FnCtxt<'a, 'tcx> { +impl<'a, 'tcx> ty::ClosureTyper<'tcx> for FnCtxtTyper<'a, 'tcx> { fn param_env<'b>(&'b self) -> &'b ty::ParameterEnvironment<'b,'tcx> { - &self.inh.param_env + &self.fcx.inh.param_env } fn closure_kind(&self, def_id: ast::DefId) -> Option { - self.inh.closure_kinds.borrow().get(&def_id).cloned() + self.fcx.inh.closure_kinds.borrow().get(&def_id).cloned() } fn closure_type(&self, @@ -360,7 +558,7 @@ impl<'a, 'tcx> ty::ClosureTyper<'tcx> for FnCtxt<'a, 'tcx> { substs: &subst::Substs<'tcx>) -> ty::ClosureTy<'tcx> { - self.inh.closure_tys.borrow().get(&def_id).unwrap().subst(self.tcx(), substs) + self.tt.closure_tys.get(&def_id).unwrap().subst(self.fcx.tcx(), substs) } fn closure_upvars(&self, @@ -378,43 +576,71 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { -> Inherited<'a, 'tcx> { Inherited { infcx: infer::new_infer_ctxt(tcx), - locals: RefCell::new(NodeMap()), param_env: param_env, - node_types: RefCell::new(NodeMap()), - item_substs: RefCell::new(NodeMap()), - adjustments: RefCell::new(NodeMap()), - method_map: RefCell::new(FnvHashMap()), - object_cast_map: RefCell::new(NodeMap()), upvar_capture_map: RefCell::new(FnvHashMap()), - closure_tys: RefCell::new(DefIdMap()), closure_kinds: RefCell::new(DefIdMap()), - fn_sig_map: RefCell::new(NodeMap()), - fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), - deferred_call_resolutions: RefCell::new(DefIdMap()), - deferred_cast_checks: RefCell::new(Vec::new()), } } fn normalize_associated_types_in(&self, typer: &ty::ClosureTyper<'tcx>, + fulfillment_cx: &mut traits::FulfillmentContext<'tcx>, span: Span, body_id: ast::NodeId, value: &T) -> T where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx> { - let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); assoc::normalize_associated_types_in(&self.infcx, typer, - &mut *fulfillment_cx, span, + fulfillment_cx, span, body_id, value) } +} + +impl<'tcx> CheckEnv<'tcx> { + fn new() -> Self { + CheckEnv { + locals: NodeMap(), + tt: CheckEnvTables { + node_types: NodeMap(), + item_substs: NodeMap(), + adjustments: NodeMap(), + method_map: FnvHashMap(), + closure_tys: DefIdMap(), + }, + fn_sig_map: NodeMap(), + fulfillment_cx: traits::FulfillmentContext::new(), + deferred_call_resolutions: DefIdMap(), + deferred_cast_checks: Vec::new(), + } + } + fn record_deferred_call_resolution(&mut self, + closure_def_id: ast::DefId, + r: DeferredCallResolutionHandler<'tcx>) { + self.deferred_call_resolutions.entry(closure_def_id).or_insert(vec![]).push(r); + } + + fn remove_deferred_call_resolutions(&mut self, + closure_def_id: ast::DefId) + -> Vec> + { + self.deferred_call_resolutions.remove(&closure_def_id).unwrap_or(Vec::new()) + } + + fn check_casts<'a>(&mut self, fcx: &'a FnCtxt<'a, 'tcx>) { + let mut deferred_cast_checks = replace(&mut self.deferred_cast_checks, Vec::new()); + for check in deferred_cast_checks.drain(..) { + cast::check_cast(self, fcx, &check); + } + replace(&mut self.deferred_cast_checks, deferred_cast_checks); + } } // Used by check_const and check_enum_variants -pub fn blank_fn_ctxt<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, +fn blank_fn_ctxt<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, inh: &'a Inherited<'a, 'tcx>, rty: ty::FnOutput<'tcx>, body_id: ast::NodeId) @@ -424,18 +650,18 @@ pub fn blank_fn_ctxt<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, writeback_errors: Cell::new(false), err_count_on_creation: ccx.tcx.sess.err_count(), ret_ty: rty, - ps: RefCell::new(UnsafetyState::function(ast::Unsafety::Normal, 0)), + ps: Cell::new(UnsafetyState::function(ast::Unsafety::Normal, 0)), inh: inh, ccx: ccx } } -fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>) - -> Inherited<'a, 'tcx> { +fn static_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>) + -> (CheckEnv<'tcx>, Inherited<'a, 'tcx>) { // It's kind of a kludge to manufacture a fake function context // and statement context, but we might as well do write the code only once let param_env = ty::empty_parameter_environment(ccx.tcx); - Inherited::new(ccx.tcx, param_env) + (CheckEnv::new(), Inherited::new(ccx.tcx, param_env)) } struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> } @@ -511,6 +737,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, match raw_fty.sty { ty::ty_bare_fn(_, ref fn_ty) => { let inh = Inherited::new(ccx.tcx, param_env); + let mut check_env = CheckEnv::new(); // Compute the fty from point of view of inside fn. let fn_sig = @@ -520,17 +747,21 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, region::DestructionScopeData::new(body.id), &fn_sig); let fn_sig = - inh.normalize_associated_types_in(&inh.param_env, body.span, body.id, &fn_sig); + inh.normalize_associated_types_in(&inh.param_env, + &mut check_env.fulfillment_cx, + body.span, + body.id, + &fn_sig); - let fcx = check_fn(ccx, fn_ty.unsafety, fn_id, &fn_sig, + let fcx = check_fn(&mut check_env, ccx, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body, &inh); - vtable::select_all_fcx_obligations_and_apply_defaults(&fcx); - upvar::closure_analyze_fn(&fcx, fn_id, decl, body); - vtable::select_all_fcx_obligations_or_error(&fcx); - fcx.check_casts(); - regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body); - writeback::resolve_type_vars_in_fn(&fcx, decl, body); + vtable::select_all_fcx_obligations_and_apply_defaults(&mut check_env, &fcx); + upvar::closure_analyze_fn(&mut check_env, &fcx, fn_id, decl, body); + vtable::select_all_fcx_obligations_or_error(&mut check_env, &fcx); + check_env.check_casts(&fcx); + regionck::regionck_fn(&mut check_env, &fcx, fn_id, fn_span, decl, body); + writeback::resolve_type_vars_in_fn(&mut check_env, &fcx, decl, body); } _ => ccx.tcx.sess.impossible_case(body.span, "check_bare_fn: function type expected") @@ -538,6 +769,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } struct GatherLocalsVisitor<'a, 'tcx: 'a> { + check_env: &'a mut CheckEnv<'tcx>, fcx: &'a FnCtxt<'a, 'tcx> } @@ -547,12 +779,12 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { None => { // infer the variable's type let var_ty = self.fcx.infcx().next_ty_var(); - self.fcx.inh.locals.borrow_mut().insert(nid, var_ty); + self.check_env.locals.insert(nid, var_ty); var_ty } Some(typ) => { // take type that the user specified - self.fcx.inh.locals.borrow_mut().insert(nid, typ); + self.check_env.locals.insert(nid, typ); typ } } @@ -562,15 +794,15 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { // Add explicitly-declared locals. fn visit_local(&mut self, local: &'tcx ast::Local) { - let o_ty = match local.ty { - Some(ref ty) => Some(self.fcx.to_ty(&**ty)), - None => None - }; + let o_ty = local.ty.as_ref().map( |ty| { + let mut joined = FnCtxtJoined::new(self.check_env, self.fcx); + joined.to_ty(&**ty) + } ); self.assign(local.span, local.id, o_ty); debug!("Local variable {} is assigned type {}", self.fcx.pat_to_string(&*local.pat), self.fcx.infcx().ty_to_string( - self.fcx.inh.locals.borrow().get(&local.id).unwrap().clone())); + self.check_env.locals.get(&local.id).unwrap().clone())); visit::walk_local(self, local); } @@ -580,13 +812,14 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map, p) { let var_ty = self.assign(p.span, p.id, None); - self.fcx.require_type_is_sized(var_ty, p.span, + self.fcx.require_type_is_sized(self.check_env, + var_ty, p.span, traits::VariableType(p.id)); debug!("Pattern binding {} is assigned to {} with type {}", token::get_ident(path1.node), self.fcx.infcx().ty_to_string( - self.fcx.inh.locals.borrow().get(&p.id).unwrap().clone()), + self.check_env.locals.get(&p.id).unwrap().clone()), var_ty.repr(self.fcx.tcx())); } } @@ -606,7 +839,8 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { match t.node { ast::TyFixedLengthVec(ref ty, ref count_expr) => { self.visit_ty(&**ty); - check_expr_with_hint(self.fcx, &**count_expr, self.fcx.tcx().types.usize); + check_expr_with_hint(self.check_env, self.fcx, &**count_expr, + self.fcx.tcx().types.usize); } _ => visit::walk_ty(self, t) } @@ -625,7 +859,8 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { /// /// * ... /// * inherited: other fields inherited from the enclosing fn (if any) -fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, +fn check_fn<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + ccx: &'a CrateCtxt<'a, 'tcx>, unsafety: ast::Unsafety, unsafety_id: ast::NodeId, fn_sig: &ty::FnSig<'tcx>, @@ -653,7 +888,7 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, writeback_errors: Cell::new(false), err_count_on_creation: err_count_on_creation, ret_ty: ret_ty, - ps: RefCell::new(UnsafetyState::function(unsafety, unsafety_id)), + ps: Cell::new(UnsafetyState::function(unsafety, unsafety_id)), inh: inherited, ccx: ccx }; @@ -665,7 +900,7 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, .collect(); if let ty::FnConverging(ret_ty) = ret_ty { - fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType); + fcx.require_type_is_sized(check_env, ret_ty, decl.output.span(), traits::ReturnType); fn_sig_tys.push(ret_ty); } @@ -673,10 +908,10 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, fn_id, fn_sig_tys.repr(tcx)); - inherited.fn_sig_map.borrow_mut().insert(fn_id, fn_sig_tys); + check_env.fn_sig_map.insert(fn_id, fn_sig_tys); { - let mut visit = GatherLocalsVisitor { fcx: &fcx, }; + let mut visit = GatherLocalsVisitor { check_env: check_env, fcx: &fcx, }; // Add formal parameters. for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) { @@ -686,7 +921,8 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, &*input.pat, |_bm, pat_id, sp, _path| { let var_ty = visit.assign(sp, pat_id, None); - fcx.require_type_is_sized(var_ty, sp, + fcx.require_type_is_sized(visit.check_env, + var_ty, sp, traits::VariableType(pat_id)); }); @@ -695,25 +931,25 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, fcx: &fcx, map: pat_id_map(&tcx.def_map, &*input.pat), }; - _match::check_pat(&pcx, &*input.pat, *arg_ty); + _match::check_pat(visit.check_env, &pcx, &*input.pat, *arg_ty); } visit.visit_block(body); } - check_block_with_expected(&fcx, body, match ret_ty { + check_block_with_expected(check_env, &fcx, body, match ret_ty { ty::FnConverging(result_type) => ExpectHasType(result_type), ty::FnDiverging => NoExpectation }); for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) { - fcx.write_ty(input.id, *arg); + fcx.write_ty(check_env, input.id, *arg); } fcx } -pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { +fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { let tcx = ccx.tcx; check_representable(tcx, span, id, "struct"); @@ -724,7 +960,7 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { } } -pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { +fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { debug!("check_item_type(it.id={}, it.ident={})", it.id, ty::item_path_str(ccx.tcx, local_def(it.id))); @@ -788,7 +1024,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { } } -pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { +fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { debug!("check_item_body(it.id={}, it.ident={})", it.id, ty::item_path_str(ccx.tcx, local_def(it.id))); @@ -1109,7 +1345,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn report_cast_to_unsized_type<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, t_span: Span, e_span: Span, @@ -1159,12 +1396,12 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, "consider using a box or reference as appropriate"); } } - fcx.write_error(id); + fcx.write_error(check_env, id); } -impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { - fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx } +impl<'a, 'tcx> AstConv<'tcx> for FnCtxtJoined<'a, 'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { self.fcx.ccx.tcx } fn get_item_type_scheme(&self, _: Span, id: ast::DefId) -> Result, ErrorReported> @@ -1184,32 +1421,33 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } fn get_free_substs(&self) -> Option<&Substs<'tcx>> { - Some(&self.inh.param_env.free_substs) + Some(&self.fcx.inh.param_env.free_substs) } - fn get_type_parameter_bounds(&self, + fn get_type_parameter_bounds(&mut self, _: Span, node_id: ast::NodeId) -> Result>, ErrorReported> { let def = self.tcx().type_parameter_def(node_id); - let r = self.inh.param_env.caller_bounds - .iter() - .filter_map(|predicate| { - match *predicate { - ty::Predicate::Trait(ref data) => { - if data.0.self_ty().is_param(def.space, def.index) { - Some(data.to_poly_trait_ref()) - } else { - None - } - } - _ => { - None - } - } - }) - .collect(); + let r = self.fcx.inh.param_env + .caller_bounds + .iter() + .filter_map(|predicate| { + match *predicate { + ty::Predicate::Trait(ref data) => { + if data.0.self_ty().is_param(def.space, def.index) { + Some(data.to_poly_trait_ref()) + } else { + None + } + } + _ => { + None + } + } + }) + .collect(); Ok(r) } @@ -1218,22 +1456,22 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { assoc_name: ast::Name) -> bool { - let trait_def = ty::lookup_trait_def(self.ccx.tcx, trait_def_id); + let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id); trait_def.associated_type_names.contains(&assoc_name) } fn ty_infer(&self, _span: Span) -> Ty<'tcx> { - self.infcx().next_ty_var() + self.fcx.infcx().next_ty_var() } - fn projected_ty_from_poly_trait_ref(&self, + fn projected_ty_from_poly_trait_ref(&mut self, span: Span, poly_trait_ref: ty::PolyTraitRef<'tcx>, item_name: ast::Name) -> Ty<'tcx> { let (trait_ref, _) = - self.infcx().replace_late_bound_regions_with_fresh_var( + self.fcx.infcx().replace_late_bound_regions_with_fresh_var( span, infer::LateBoundRegionConversionTime::AssocTypeProjection(item_name), &poly_trait_ref); @@ -1241,7 +1479,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { self.normalize_associated_type(span, trait_ref, item_name) } - fn projected_ty(&self, + fn projected_ty(&mut self, span: Span, trait_ref: ty::TraitRef<'tcx>, item_name: ast::Name) @@ -1254,26 +1492,27 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx } - pub fn infcx(&self) -> &infer::InferCtxt<'a,'tcx> { + fn infcx(&self) -> &infer::InferCtxt<'a,'tcx> { &self.inh.infcx } - pub fn param_env(&self) -> &ty::ParameterEnvironment<'a,'tcx> { + fn param_env(&self) -> &ty::ParameterEnvironment<'a,'tcx> { &self.inh.param_env } - pub fn sess(&self) -> &Session { + fn sess(&self) -> &Session { &self.tcx().sess } - pub fn err_count_since_creation(&self) -> usize { + fn err_count_since_creation(&self) -> usize { self.ccx.tcx.sess.err_count() - self.err_count_on_creation } /// Resolves type variables in `ty` if possible. Unlike the infcx /// version, this version will also select obligations if it seems /// useful, in an effort to get more type information. - fn resolve_type_vars_if_possible(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + fn resolve_type_vars_if_possible(&self, check_env: &mut CheckEnv<'tcx>, + mut ty: Ty<'tcx>) -> Ty<'tcx> { debug!("resolve_type_vars_if_possible(ty={})", ty.repr(self.tcx())); // No ty::infer()? Nothing needs doing. @@ -1290,7 +1529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If not, try resolving any new fcx obligations that have cropped up. - vtable::select_new_fcx_obligations(self); + vtable::select_new_fcx_obligations(check_env, self); ty = self.infcx().resolve_type_vars_if_possible(&ty); if !ty::type_has_ty_infer(ty) { debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx())); @@ -1301,7 +1540,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // possible. This can help substantially when there are // indirect dependencies that don't seem worth tracking // precisely. - vtable::select_fcx_obligations_where_possible(self); + vtable::select_fcx_obligations_where_possible(check_env, self); ty = self.infcx().resolve_type_vars_if_possible(&ty); debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx())); @@ -1318,28 +1557,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if ty::type_has_ty_infer(t) || ty::type_is_error(t) { Err(()) } else { Ok(t) } } - fn record_deferred_call_resolution(&self, - closure_def_id: ast::DefId, - r: DeferredCallResolutionHandler<'tcx>) { - let mut deferred_call_resolutions = self.inh.deferred_call_resolutions.borrow_mut(); - deferred_call_resolutions.entry(closure_def_id).or_insert(vec![]).push(r); - } - - fn remove_deferred_call_resolutions(&self, - closure_def_id: ast::DefId) - -> Vec> - { - let mut deferred_call_resolutions = self.inh.deferred_call_resolutions.borrow_mut(); - deferred_call_resolutions.remove(&closure_def_id).unwrap_or(Vec::new()) - } - - pub fn tag(&self) -> String { + fn tag(&self) -> String { let self_ptr: *const FnCtxt = self; format!("{:?}", self_ptr) } - pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> Ty<'tcx> { - match self.inh.locals.borrow().get(&nid) { + fn local_ty(&self, + check_env: &mut CheckEnv<'tcx>, + span: Span, + nid: ast::NodeId) -> Ty<'tcx> { + match check_env.locals.get(&nid) { Some(&t) => t, None => { self.tcx().sess.span_err( @@ -1352,9 +1579,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Apply "fallbacks" to some types /// ! gets replaced with (), unconstrained ints with i32, and unconstrained floats with f64. - pub fn default_type_parameters(&self) { + fn default_type_parameters(&self, check_env: &mut CheckEnv<'tcx>) { use middle::ty::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat, Neither}; - for (_, &mut ref ty) in &mut *self.inh.node_types.borrow_mut() { + for (_, &mut ref ty) in &mut check_env.tt.node_types { let resolved = self.infcx().resolve_type_vars_if_possible(ty); if self.infcx().type_var_diverges(resolved) { demand::eqtype(self, codemap::DUMMY_SP, *ty, ty::mk_nil(self.tcx())); @@ -1373,27 +1600,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[inline] - pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) { + fn write_ty(&self, check_env: &mut CheckEnv<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) { debug!("write_ty({}, {}) in fcx {}", node_id, ppaux::ty_to_string(self.tcx(), ty), self.tag()); - self.inh.node_types.borrow_mut().insert(node_id, ty); + check_env.tt.node_types.insert(node_id, ty); } - pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { + fn write_substs(&self, + check_env: &mut CheckEnv<'tcx>, + node_id: ast::NodeId, + substs: ty::ItemSubsts<'tcx>) + { if !substs.substs.is_noop() { debug!("write_substs({}, {}) in fcx {}", node_id, substs.repr(self.tcx()), self.tag()); - self.inh.item_substs.borrow_mut().insert(node_id, substs); + check_env.tt.item_substs.insert(node_id, substs); } } - pub fn write_autoderef_adjustment(&self, - node_id: ast::NodeId, - derefs: usize) { + fn write_autoderef_adjustment(&self, + check_env: &mut CheckEnv<'tcx>, + node_id: ast::NodeId, + derefs: usize) { self.write_adjustment( + check_env, node_id, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: derefs, @@ -1403,177 +1636,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - pub fn write_adjustment(&self, - node_id: ast::NodeId, - adj: ty::AutoAdjustment<'tcx>) { + fn write_adjustment(&self, + check_env: &mut CheckEnv<'tcx>, + node_id: ast::NodeId, + adj: ty::AutoAdjustment<'tcx>) { debug!("write_adjustment(node_id={}, adj={})", node_id, adj.repr(self.tcx())); if adj.is_identity() { return; } - self.inh.adjustments.borrow_mut().insert(node_id, adj); - } - - /// Basically whenever we are converting from a type scheme into - /// the fn body space, we always want to normalize associated - /// types as well. This function combines the two. - fn instantiate_type_scheme(&self, - span: Span, - substs: &Substs<'tcx>, - value: &T) - -> T - where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx> - { - let value = value.subst(self.tcx(), substs); - let result = self.normalize_associated_types_in(span, &value); - debug!("instantiate_type_scheme(value={}, substs={}) = {}", - value.repr(self.tcx()), - substs.repr(self.tcx()), - result.repr(self.tcx())); - result - } - - /// As `instantiate_type_scheme`, but for the bounds found in a - /// generic type scheme. - fn instantiate_bounds(&self, - span: Span, - substs: &Substs<'tcx>, - bounds: &ty::GenericPredicates<'tcx>) - -> ty::InstantiatedPredicates<'tcx> - { - ty::InstantiatedPredicates { - predicates: self.instantiate_type_scheme(span, substs, &bounds.predicates) - } - } - - - fn normalize_associated_types_in(&self, span: Span, value: &T) -> T - where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx> - { - self.inh.normalize_associated_types_in(self, span, self.body_id, value) - } - - fn normalize_associated_type(&self, - span: Span, - trait_ref: ty::TraitRef<'tcx>, - item_name: ast::Name) - -> Ty<'tcx> - { - let cause = traits::ObligationCause::new(span, - self.body_id, - traits::ObligationCauseCode::MiscObligation); - self.inh.fulfillment_cx - .borrow_mut() - .normalize_projection_type(self.infcx(), - self, - ty::ProjectionTy { - trait_ref: trait_ref, - item_name: item_name, - }, - cause) - } - - /// Returns the type of `def_id` with all generics replaced by by fresh type/region variables. - /// Also returns the substitution from the type parameters on `def_id` to the fresh variables. - /// Registers any trait obligations specified on `def_id` at the same time. - /// - /// Note that function is only intended to be used with types (notably, not fns). This is - /// because it doesn't do any instantiation of late-bound regions. - pub fn instantiate_type(&self, - span: Span, - def_id: ast::DefId) - -> TypeAndSubsts<'tcx> - { - let type_scheme = - ty::lookup_item_type(self.tcx(), def_id); - let type_predicates = - ty::lookup_predicates(self.tcx(), def_id); - let substs = - self.infcx().fresh_substs_for_generics( - span, - &type_scheme.generics); - let bounds = - self.instantiate_bounds(span, &substs, &type_predicates); - self.add_obligations_for_parameters( - traits::ObligationCause::new( - span, - self.body_id, - traits::ItemObligation(def_id)), - &bounds); - let monotype = - self.instantiate_type_scheme(span, &substs, &type_scheme.ty); - - TypeAndSubsts { - ty: monotype, - substs: substs - } - } - - /// Returns the type that this AST path refers to. If the path has no type - /// parameters and the corresponding type has type parameters, fresh type - /// and/or region variables are substituted. - /// - /// This is used when checking the constructor in struct literals. - fn instantiate_struct_literal_ty(&self, - did: ast::DefId, - path: &ast::Path) - -> TypeAndSubsts<'tcx> - { - let tcx = self.tcx(); - - let ty::TypeScheme { generics, ty: decl_ty } = - ty::lookup_item_type(tcx, did); - - let substs = astconv::ast_path_substs_for_ty(self, self, - path.span, - PathParamMode::Optional, - &generics, - path.segments.last().unwrap()); - - let ty = self.instantiate_type_scheme(path.span, &substs, &decl_ty); - - TypeAndSubsts { substs: substs, ty: ty } + check_env.tt.adjustments.insert(node_id, adj); } - pub fn write_nil(&self, node_id: ast::NodeId) { - self.write_ty(node_id, ty::mk_nil(self.tcx())); + fn write_nil(&self, check_env: &mut CheckEnv<'tcx>, node_id: ast::NodeId) { + self.write_ty(check_env, node_id, ty::mk_nil(self.tcx())); } - pub fn write_error(&self, node_id: ast::NodeId) { - self.write_ty(node_id, self.tcx().types.err); + fn write_error(&self, check_env: &mut CheckEnv<'tcx>, node_id: ast::NodeId) { + self.write_ty(check_env, node_id, self.tcx().types.err); } - pub fn require_type_meets(&self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - bound: ty::BuiltinBound) + fn require_type_meets(&self, + check_env: &mut CheckEnv<'tcx>, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + bound: ty::BuiltinBound) { self.register_builtin_bound( + check_env, ty, bound, traits::ObligationCause::new(span, self.body_id, code)); } - pub fn require_type_is_sized(&self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>) + fn require_type_is_sized(&self, + check_env: &mut CheckEnv<'tcx>, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>) { - self.require_type_meets(ty, span, code, ty::BoundSized); + self.require_type_meets(check_env, ty, span, code, ty::BoundSized); } - pub fn require_expr_have_sized_type(&self, - expr: &ast::Expr, - code: traits::ObligationCauseCode<'tcx>) + fn require_expr_have_sized_type(&self, + check_env: &mut CheckEnv<'tcx>, + expr: &ast::Expr, + code: traits::ObligationCauseCode<'tcx>) { - self.require_type_is_sized(self.expr_ty(expr), expr.span, code); + let expr_ty = self.expr_ty(&check_env.tt.node_types, expr); + self.require_type_is_sized(check_env, expr_ty, expr.span, code); } - pub fn type_is_known_to_be_sized(&self, - ty: Ty<'tcx>, - span: Span) - -> bool + fn type_is_known_to_be_sized(&self, + ty: Ty<'tcx>, + span: Span) + -> bool { traits::type_known_to_meet_builtin_bound(self.infcx(), self.param_env(), @@ -1582,50 +1700,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span) } - pub fn type_is_fat_ptr(&self, ty: Ty<'tcx>, span: Span) -> bool { + fn type_is_fat_ptr(&self, ty: Ty<'tcx>, span: Span) -> bool { if let Some(mt) = ty::deref(ty, true) { return !self.type_is_known_to_be_sized(mt.ty, span); } false } - pub fn register_builtin_bound(&self, - ty: Ty<'tcx>, - builtin_bound: ty::BuiltinBound, - cause: traits::ObligationCause<'tcx>) + fn register_builtin_bound(&self, + check_env: &mut CheckEnv<'tcx>, + ty: Ty<'tcx>, + builtin_bound: ty::BuiltinBound, + cause: traits::ObligationCause<'tcx>) { - self.inh.fulfillment_cx.borrow_mut() + check_env.fulfillment_cx .register_builtin_bound(self.infcx(), ty, builtin_bound, cause); } - pub fn register_predicate(&self, - obligation: traits::PredicateObligation<'tcx>) + fn register_predicate(&self, + check_env: &mut CheckEnv<'tcx>, + obligation: traits::PredicateObligation<'tcx>) { debug!("register_predicate({})", obligation.repr(self.tcx())); - self.inh.fulfillment_cx - .borrow_mut() + check_env.fulfillment_cx .register_predicate_obligation(self.infcx(), obligation); } - pub fn to_ty(&self, ast_t: &ast::Ty) -> Ty<'tcx> { - let t = ast_ty_to_ty(self, self, ast_t); - - let mut bounds_checker = wf::BoundsChecker::new(self, - ast_t.span, - self.body_id, - None); - bounds_checker.check_ty(t); - - t - } - - pub fn pat_to_string(&self, pat: &ast::Pat) -> String { + fn pat_to_string(&self, pat: &ast::Pat) -> String { pat.repr(self.tcx()) } - pub fn expr_ty(&self, ex: &ast::Expr) -> Ty<'tcx> { - match self.inh.node_types.borrow().get(&ex.id) { + fn expr_ty(&self, node_types: &NodeMap>, ex: &ast::Expr) -> Ty<'tcx> { + match node_types.get(&ex.id) { Some(&t) => t, None => { self.tcx().sess.bug(&format!("no type for expr in fcx {}", @@ -1634,27 +1741,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - /// Apply `adjustment` to the type of `expr` - pub fn adjust_expr_ty(&self, - expr: &ast::Expr, - adjustment: Option<&ty::AutoAdjustment<'tcx>>) - -> Ty<'tcx> - { - let raw_ty = self.expr_ty(expr); - let raw_ty = self.infcx().shallow_resolve(raw_ty); - let resolve_ty = |ty: Ty<'tcx>| self.infcx().resolve_type_vars_if_possible(&ty); - ty::adjust_ty(self.tcx(), - expr.span, - expr.id, - raw_ty, - adjustment, - |method_call| self.inh.method_map.borrow() - .get(&method_call) - .map(|method| resolve_ty(method.ty))) - } - - pub fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> { - match self.inh.node_types.borrow().get(&id) { + fn node_ty(&self, node_types: &NodeMap>, id: ast::NodeId) -> Ty<'tcx> { + match node_types.get(&id) { Some(&t) => t, None if self.err_count_since_creation() != 0 => self.tcx().types.err, None => { @@ -1666,84 +1754,87 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub fn item_substs(&self) -> Ref>> { - self.inh.item_substs.borrow() + fn item_substs<'b>(&'b self, + check_env: &'b CheckEnv<'tcx>) -> &'b NodeMap> { + &check_env.tt.item_substs } - pub fn opt_node_ty_substs(&self, - id: ast::NodeId, - f: F) where + fn opt_node_ty_substs(&self, + tt: &CheckEnvTables<'tcx>, + id: ast::NodeId, + f: F) where F: FnOnce(&ty::ItemSubsts<'tcx>), { - match self.inh.item_substs.borrow().get(&id) { + match tt.item_substs.get(&id) { Some(s) => { f(s) } None => { } } } - pub fn mk_subty(&self, - a_is_expected: bool, - origin: infer::TypeOrigin, - sub: Ty<'tcx>, - sup: Ty<'tcx>) - -> Result<(), ty::type_err<'tcx>> { + fn mk_subty(&self, + a_is_expected: bool, + origin: infer::TypeOrigin, + sub: Ty<'tcx>, + sup: Ty<'tcx>) + -> Result<(), ty::type_err<'tcx>> { infer::mk_subty(self.infcx(), a_is_expected, origin, sub, sup) } - pub fn mk_eqty(&self, - a_is_expected: bool, - origin: infer::TypeOrigin, - sub: Ty<'tcx>, - sup: Ty<'tcx>) - -> Result<(), ty::type_err<'tcx>> { + fn mk_eqty(&self, + a_is_expected: bool, + origin: infer::TypeOrigin, + sub: Ty<'tcx>, + sup: Ty<'tcx>) + -> Result<(), ty::type_err<'tcx>> { infer::mk_eqty(self.infcx(), a_is_expected, origin, sub, sup) } - pub fn mk_subr(&self, - origin: infer::SubregionOrigin<'tcx>, - sub: ty::Region, - sup: ty::Region) { + fn mk_subr(&self, + origin: infer::SubregionOrigin<'tcx>, + sub: ty::Region, + sup: ty::Region) { infer::mk_subr(self.infcx(), origin, sub, sup) } - pub fn type_error_message(&self, - sp: Span, - mk_msg: M, - actual_ty: Ty<'tcx>, - err: Option<&ty::type_err<'tcx>>) where + fn type_error_message(&self, + sp: Span, + mk_msg: M, + actual_ty: Ty<'tcx>, + err: Option<&ty::type_err<'tcx>>) where M: FnOnce(String) -> String, { self.infcx().type_error_message(sp, mk_msg, actual_ty, err); } - pub fn report_mismatched_types(&self, - sp: Span, - e: Ty<'tcx>, - a: Ty<'tcx>, - err: &ty::type_err<'tcx>) { + fn report_mismatched_types(&self, + sp: Span, + e: Ty<'tcx>, + a: Ty<'tcx>, + err: &ty::type_err<'tcx>) { self.infcx().report_mismatched_types(sp, e, a, err) } /// Registers an obligation for checking later, during regionck, that the type `ty` must /// outlive the region `r`. - pub fn register_region_obligation(&self, - ty: Ty<'tcx>, - region: ty::Region, - cause: traits::ObligationCause<'tcx>) + fn register_region_obligation(&self, + fulfillment_cx: &mut traits::FulfillmentContext<'tcx>, + ty: Ty<'tcx>, + region: ty::Region, + cause: traits::ObligationCause<'tcx>) { - let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut(); fulfillment_cx.register_region_obligation(self.infcx(), ty, region, cause); } - pub fn add_default_region_param_bounds(&self, - substs: &Substs<'tcx>, - expr: &ast::Expr) + fn add_default_region_param_bounds(&self, + fulfillment_cx: &mut traits::FulfillmentContext<'tcx>, + substs: &Substs<'tcx>, + expr: &ast::Expr) { for &ty in substs.types.iter() { let default_bound = ty::ReScope(CodeExtent::from_node_id(expr.id)); let cause = traits::ObligationCause::new(expr.span, self.body_id, traits::MiscObligation); - self.register_region_obligation(ty, default_bound, cause); + self.register_region_obligation(fulfillment_cx, ty, default_bound, cause); } } @@ -1765,9 +1856,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a` /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally. - pub fn add_obligations_for_parameters(&self, - cause: traits::ObligationCause<'tcx>, - predicates: &ty::InstantiatedPredicates<'tcx>) + fn add_obligations_for_parameters(&self, + check_env: &mut CheckEnv<'tcx>, + cause: traits::ObligationCause<'tcx>, + predicates: &ty::InstantiatedPredicates<'tcx>) { assert!(!predicates.has_escaping_regions()); @@ -1778,44 +1870,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause, predicates); - obligations.map_move(|o| self.register_predicate(o)); + obligations.map_move(|o| self.register_predicate(check_env, o)); } // Only for fields! Returns for methods> // Indifferent to privacy flags - pub fn lookup_field_ty(&self, - span: Span, - class_id: ast::DefId, - items: &[ty::field_ty], - fieldname: ast::Name, - substs: &subst::Substs<'tcx>) - -> Option> + fn lookup_field_ty(&self, + check_env: &mut CheckEnv<'tcx>, + span: Span, + class_id: ast::DefId, + items: &[ty::field_ty], + fieldname: ast::Name, + substs: &subst::Substs<'tcx>) + -> Option> { let o_field = items.iter().find(|f| f.name == fieldname); o_field.map(|f| ty::lookup_field_type(self.tcx(), class_id, f.id, substs)) - .map(|t| self.normalize_associated_types_in(span, &t)) + .map(|t| { + let mut joined = FnCtxtJoined::new(check_env, self); + joined.normalize_associated_types_in(span, &t) + }) } - pub fn lookup_tup_field_ty(&self, - span: Span, - class_id: ast::DefId, - items: &[ty::field_ty], - idx: usize, - substs: &subst::Substs<'tcx>) - -> Option> + fn lookup_tup_field_ty(&self, + check_env: &mut CheckEnv<'tcx>, + span: Span, + class_id: ast::DefId, + items: &[ty::field_ty], + idx: usize, + substs: &subst::Substs<'tcx>) + -> Option> { let o_field = if idx < items.len() { Some(&items[idx]) } else { None }; o_field.map(|f| ty::lookup_field_type(self.tcx(), class_id, f.id, substs)) - .map(|t| self.normalize_associated_types_in(span, &t)) - } - - fn check_casts(&self) { - let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut(); - for check in deferred_cast_checks.iter() { - cast::check_cast(self, check); - } - - deferred_cast_checks.clear(); + .map(|t| { + let mut joined = FnCtxtJoined::new(check_env, self); + joined.normalize_associated_types_in(span, &t) + }) } } @@ -1861,15 +1952,16 @@ pub enum UnresolvedTypeAction { /// /// Note: this method does not modify the adjustments table. The caller is responsible for /// inserting an AutoAdjustment record into the `fcx` using one of the suitable methods. -pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, - sp: Span, - base_ty: Ty<'tcx>, - opt_expr: Option<&ast::Expr>, - unresolved_type_action: UnresolvedTypeAction, - mut lvalue_pref: LvaluePreference, - mut should_stop: F) - -> (Ty<'tcx>, usize, Option) - where F: FnMut(Ty<'tcx>, usize) -> Option, +fn autoderef<'a, 'tcx, T, F>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, + sp: Span, + base_ty: Ty<'tcx>, + opt_expr: Option<&ast::Expr>, + unresolved_type_action: UnresolvedTypeAction, + mut lvalue_pref: LvaluePreference, + mut should_stop: F) + -> (Ty<'tcx>, usize, Option) + where F: FnMut(&mut CheckEnv<'tcx>, Ty<'tcx>, usize) -> Option, { debug!("autoderef(base_ty={}, opt_expr={}, lvalue_pref={:?})", base_ty.repr(fcx.tcx()), @@ -1880,7 +1972,7 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() { let resolved_t = match unresolved_type_action { UnresolvedTypeAction::Error => { - let resolved_t = structurally_resolved_type(fcx, sp, t); + let resolved_t = structurally_resolved_type(check_env, fcx, sp, t); if ty::type_is_error(resolved_t) { return (resolved_t, autoderefs, None); } @@ -1891,11 +1983,11 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, // (i.e. it is an inference variable) because `ty::deref` // and `try_overloaded_deref` both simply return `None` // in such a case without producing spurious errors. - fcx.resolve_type_vars_if_possible(t) + fcx.resolve_type_vars_if_possible(check_env, t) } }; - match should_stop(resolved_t, autoderefs) { + match should_stop(check_env, resolved_t, autoderefs) { Some(x) => return (resolved_t, autoderefs, Some(x)), None => {} } @@ -1918,7 +2010,7 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, // when they encounter an overloaded autoderef, have // to do some reconstructive surgery. This is a pretty // complex mess that is begging for a proper MIR. - try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref) + try_overloaded_deref(check_env, fcx, sp, method_call, None, resolved_t, lvalue_pref) } }; match mt { @@ -1939,7 +2031,8 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, (fcx.tcx().types.err, 0, None) } -fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn try_overloaded_deref<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, method_call: Option, base_expr: Option<&ast::Expr>, @@ -1950,7 +2043,7 @@ fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Try DerefMut first, if preferred. let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) { (PreferMutLvalue, Some(trait_did)) => { - method::lookup_in_trait(fcx, span, base_expr, + method::lookup_in_trait(check_env, fcx, span, base_expr, token::intern("deref_mut"), trait_did, base_ty, None) } @@ -1960,20 +2053,21 @@ fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Otherwise, fall back to Deref. let method = match (method, fcx.tcx().lang_items.deref_trait()) { (None, Some(trait_did)) => { - method::lookup_in_trait(fcx, span, base_expr, + method::lookup_in_trait(check_env, fcx, span, base_expr, token::intern("deref"), trait_did, base_ty, None) } (method, _) => method }; - make_overloaded_lvalue_return_type(fcx, method_call, method) + make_overloaded_lvalue_return_type(check_env, fcx, method_call, method) } /// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait returns a type of `&T`, but the /// actual type we assign to the *expression* is `T`. So this function just peels off the return /// type by one layer to yield `T`. It also inserts the `method-callee` into the method map. -fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn make_overloaded_lvalue_return_type<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, method_call: Option, method: Option>) -> Option> @@ -1986,7 +2080,7 @@ fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let ret_ty = ty::no_late_bound_regions(fcx.tcx(), &ret_ty).unwrap().unwrap(); if let Some(method_call) = method_call { - fcx.inh.method_map.borrow_mut().insert(method_call, method); + check_env.tt.method_map.insert(method_call, method); } // method returns &T, but the type as visible to user is T, so deref @@ -1996,7 +2090,8 @@ fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } -fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn lookup_indexing<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, expr: &ast::Expr, base_expr: &'tcx ast::Expr, base_ty: Ty<'tcx>, @@ -2008,14 +2103,15 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // autoderef that normal method probing does. They could likely be // consolidated. - let (ty, autoderefs, final_mt) = autoderef(fcx, + let (ty, autoderefs, final_mt) = autoderef(check_env, + fcx, base_expr.span, base_ty, Some(base_expr), UnresolvedTypeAction::Error, lvalue_pref, - |adj_ty, idx| { - try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr, + |check_env, adj_ty, idx| { + try_index_step(check_env, fcx, MethodCall::expr(expr.id), expr, base_expr, adj_ty, idx, false, lvalue_pref, idx_ty) }); @@ -2027,7 +2123,7 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // do a final unsized coercion to yield [T]. if let ty::ty_vec(element_ty, Some(_)) = ty.sty { let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None); - try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr, + try_index_step(check_env, fcx, MethodCall::expr(expr.id), expr, base_expr, adjusted_ty, autoderefs, true, lvalue_pref, idx_ty) } else { None @@ -2038,7 +2134,8 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// `base_expr`, looking for a type which either supports builtin indexing or overloaded indexing. /// This loop implements one step in that search; the autoderef loop is implemented by /// `lookup_indexing`. -fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn try_index_step<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, method_call: MethodCall, expr: &ast::Expr, base_expr: &'tcx ast::Expr, @@ -2067,7 +2164,7 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, debug!("try_index_step: success, using built-in indexing"); // If we had `[T; N]`, we should've caught it before unsizing to `[T]`. assert!(!unsize); - fcx.write_autoderef_adjustment(base_expr.id, autoderefs); + fcx.write_autoderef_adjustment(check_env, base_expr.id, autoderefs); return Some((tcx.types.usize, ty)); } _ => {} @@ -2076,7 +2173,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Try `IndexMut` first, if preferred. let method = match (lvalue_pref, tcx.lang_items.index_mut_trait()) { (PreferMutLvalue, Some(trait_did)) => { - method::lookup_in_trait_adjusted(fcx, + method::lookup_in_trait_adjusted(check_env, + fcx, expr.span, Some(&*base_expr), token::intern("index_mut"), @@ -2092,7 +2190,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Otherwise, fall back to `Index`. let method = match (method, tcx.lang_items.index_trait()) { (None, Some(trait_did)) => { - method::lookup_in_trait_adjusted(fcx, + method::lookup_in_trait_adjusted(check_env, + fcx, expr.span, Some(&*base_expr), token::intern("index"), @@ -2110,12 +2209,13 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // If some lookup succeeded, install method in table method.and_then(|method| { debug!("try_index_step: success, using overloaded indexing"); - make_overloaded_lvalue_return_type(fcx, Some(method_call), Some(method)). + make_overloaded_lvalue_return_type(check_env, fcx, Some(method_call), Some(method)). map(|ret| (input_ty, ret.ty)) }) } -fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn check_method_argument_types<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, sp: Span, method_fn_ty: Ty<'tcx>, callee_expr: &'tcx ast::Expr, @@ -2131,7 +2231,8 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, TupleArguments => vec![ty::mk_tup(fcx.tcx(), err_inputs)], }; - check_argument_types(fcx, + check_argument_types(check_env, + fcx, sp, &err_inputs[..], &[], @@ -2143,12 +2244,14 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match method_fn_ty.sty { ty::ty_bare_fn(_, ref fty) => { // HACK(eddyb) ignore self in the definition (see above). - let expected_arg_tys = expected_types_for_fn_args(fcx, + let expected_arg_tys = expected_types_for_fn_args(check_env, + fcx, sp, expected, fty.sig.0.output, &fty.sig.0.inputs[1..]); - check_argument_types(fcx, + check_argument_types(check_env, + fcx, sp, &fty.sig.0.inputs[1..], &expected_arg_tys[..], @@ -2167,7 +2270,8 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// Generic function that factors out common logic from function calls, method calls and overloaded /// operators. -fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn check_argument_types<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, sp: Span, fn_inputs: &[Ty<'tcx>], expected_arg_tys: &[Ty<'tcx>], @@ -2187,7 +2291,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let mut expected_arg_tys = expected_arg_tys; let expected_arg_count = fn_inputs.len(); let formal_tys = if tuple_arguments == TupleArguments { - let tuple_type = structurally_resolved_type(fcx, sp, fn_inputs[0]); + let tuple_type = structurally_resolved_type(check_env, fcx, sp, fn_inputs[0]); match tuple_type.sty { ty::ty_tup(ref arg_types) => { if arg_types.len() != args.len() { @@ -2263,7 +2367,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // an "opportunistic" vtable resolution of any trait bounds on // the call. This helps coercions. if check_blocks { - vtable::select_new_fcx_obligations(fcx); + vtable::select_new_fcx_obligations(check_env, fcx); } // For variadic functions, we don't have a declared type for all of @@ -2292,14 +2396,15 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Expectation::rvalue_hint(ty) }); - check_expr_with_unifier(fcx, &**arg, + check_expr_with_unifier(check_env, fcx, &**arg, expected.unwrap_or(ExpectHasType(formal_ty)), - NoPreference, || { + NoPreference, |check_env| { // 2. Coerce to the most detailed type that could be coerced // to, which is `expected_ty` if `rvalue_hint` returns an // `ExprHasType(expected_ty)`, or the `formal_ty` otherwise. let coerce_ty = expected.and_then(|e| e.only_has_type(fcx)); - demand::coerce(fcx, arg.span, coerce_ty.unwrap_or(formal_ty), &**arg); + demand::coerce(check_env, fcx, + arg.span, coerce_ty.unwrap_or(formal_ty), &**arg); // 3. Relate the expected type and the formal one, // if the expected type was used for the coercion. @@ -2313,12 +2418,12 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // arguments which we skipped above. if variadic { for arg in args.iter().skip(expected_arg_count) { - check_expr(fcx, &**arg); + check_expr(check_env, fcx, &**arg); // There are a few types which get autopromoted when passed via varargs // in C but we just error out instead and require explicit casts. - let arg_ty = structurally_resolved_type(fcx, arg.span, - fcx.expr_ty(&**arg)); + let expr_ty = fcx.expr_ty(&check_env.tt.node_types, &**arg); + let arg_ty = structurally_resolved_type(check_env, fcx, arg.span, expr_ty); match arg_ty.sty { ty::ty_float(ast::TyF32) => { fcx.type_error_message(arg.span, @@ -2352,10 +2457,11 @@ fn err_args<'tcx>(tcx: &ty::ctxt<'tcx>, len: usize) -> Vec> { (0..len).map(|_| tcx.types.err).collect() } -fn write_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn write_call<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, call_expr: &ast::Expr, output: ty::FnOutput<'tcx>) { - fcx.write_ty(call_expr.id, match output { + fcx.write_ty(check_env, call_expr.id, match output { ty::FnConverging(output_ty) => output_ty, ty::FnDiverging => fcx.infcx().next_diverging_ty_var() }); @@ -2409,62 +2515,71 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } -pub fn check_expr_has_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx ast::Expr, - expected: Ty<'tcx>) { +fn check_expr_has_type<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, + expr: &'tcx ast::Expr, + expected: Ty<'tcx>) { check_expr_with_unifier( - fcx, expr, ExpectHasType(expected), NoPreference, - || demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr))); + check_env, fcx, expr, ExpectHasType(expected), NoPreference, + |check_env| demand::suptype(fcx, expr.span, expected, + fcx.expr_ty(&check_env.tt.node_types, expr))); } -fn check_expr_coercable_to_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn check_expr_coercable_to_type<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx ast::Expr, expected: Ty<'tcx>) { check_expr_with_unifier( - fcx, expr, ExpectHasType(expected), NoPreference, - || demand::coerce(fcx, expr.span, expected, expr)); + check_env, fcx, expr, ExpectHasType(expected), NoPreference, + |check_env| demand::coerce(check_env, fcx, expr.span, expected, expr)); } -fn check_expr_with_hint<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx ast::Expr, +fn check_expr_with_hint<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx ast::Expr, expected: Ty<'tcx>) { check_expr_with_unifier( - fcx, expr, ExpectHasType(expected), NoPreference, - || ()) + check_env, fcx, expr, ExpectHasType(expected), NoPreference, + |_| ()) } -fn check_expr_with_expectation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn check_expr_with_expectation<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx ast::Expr, expected: Expectation<'tcx>) { check_expr_with_unifier( - fcx, expr, expected, NoPreference, - || ()) + check_env, fcx, expr, expected, NoPreference, + |_| ()) } -fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx ast::Expr, expected: Expectation<'tcx>, lvalue_pref: LvaluePreference) { - check_expr_with_unifier(fcx, expr, expected, lvalue_pref, || ()) + check_expr_with_unifier(check_env, fcx, expr, expected, lvalue_pref, |_| ()) } -fn check_expr<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx ast::Expr) { - check_expr_with_unifier(fcx, expr, NoExpectation, NoPreference, || ()) +fn check_expr<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, expr: &'tcx ast::Expr) { + check_expr_with_unifier(check_env, fcx, expr, NoExpectation, NoPreference, |_| ()) } -fn check_expr_with_lvalue_pref<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx ast::Expr, +fn check_expr_with_lvalue_pref<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, expr: &'tcx ast::Expr, lvalue_pref: LvaluePreference) { - check_expr_with_unifier(fcx, expr, NoExpectation, lvalue_pref, || ()) + check_expr_with_unifier(check_env, fcx, expr, NoExpectation, lvalue_pref, |_| ()) } // determine the `self` type, using fresh variables for all variables // declared on the impl declaration e.g., `impl for Vec<(A,B)>` // would return ($0, $1) where $0 and $1 are freshly instantiated type // variables. -pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, // (potential) receiver for this impl - did: ast::DefId) - -> TypeAndSubsts<'tcx> { +fn impl_self_ty<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, + span: Span, // (potential) receiver for this impl + did: ast::DefId) + -> TypeAndSubsts<'tcx> { let tcx = fcx.tcx(); let ity = ty::lookup_item_type(tcx, did); @@ -2476,7 +2591,8 @@ pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let rps = fcx.inh.infcx.region_vars_for_defs(span, rps); let tps = fcx.inh.infcx.next_ty_vars(n_tps); let substs = subst::Substs::new_type(tps, rps); - let substd_ty = fcx.instantiate_type_scheme(span, &substs, &raw_ty); + let mut joined = FnCtxtJoined::new(check_env, fcx); + let substd_ty = joined.instantiate_type_scheme(span, &substs, &raw_ty); TypeAndSubsts { substs: substs, ty: substd_ty } } @@ -2505,7 +2621,9 @@ enum TupleArgumentsFlag { /// Unifies the return type with the expected type early, for more coercions /// and forward type information on the argument expressions. -fn expected_types_for_fn_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +// FIXME: Figure out whether we actually need CheckEnv here. +fn expected_types_for_fn_args<'a, 'tcx>(_: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, call_span: Span, expected_ret: Expectation<'tcx>, formal_ret: ty::FnOutput<'tcx>, @@ -2552,18 +2670,20 @@ fn expected_types_for_fn_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// Note that inspecting a type's structure *directly* may expose the fact /// that there are actually multiple representations for `ty_err`, so avoid /// that when err needs to be handled differently. -fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, +fn check_expr_with_unifier<'a, 'tcx, F>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx ast::Expr, expected: Expectation<'tcx>, lvalue_pref: LvaluePreference, unifier: F) where - F: FnOnce(), + F: FnOnce(&mut CheckEnv<'tcx>), { debug!(">> typechecking: expr={} expected={}", expr.repr(fcx.tcx()), expected.repr(fcx.tcx())); // Checks a method call. - fn check_method_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + fn check_method_call<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx ast::Expr, method_name: ast::SpannedIdent, args: &'tcx [P], @@ -2571,15 +2691,18 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, expected: Expectation<'tcx>, lvalue_pref: LvaluePreference) { let rcvr = &*args[0]; - check_expr_with_lvalue_pref(fcx, &*rcvr, lvalue_pref); + check_expr_with_lvalue_pref(check_env, fcx, &*rcvr, lvalue_pref); // no need to check for bot/err -- callee does that - let expr_t = structurally_resolved_type(fcx, - expr.span, - fcx.expr_ty(&*rcvr)); + let expr_ty = fcx.expr_ty(&check_env.tt.node_types, &*rcvr); + let expr_t = structurally_resolved_type(check_env, fcx, expr.span, expr_ty); - let tps = tps.iter().map(|ast_ty| fcx.to_ty(&**ast_ty)).collect::>(); - let fn_ty = match method::lookup(fcx, + let tps = { + let mut joined = FnCtxtJoined::new(check_env, fcx); + tps.iter().map(|ast_ty| joined.to_ty(&**ast_ty)).collect::>() + }; + let fn_ty = match method::lookup(check_env, + fcx, method_name.span, method_name.node.name, expr_t, @@ -2589,19 +2712,20 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, Ok(method) => { let method_ty = method.ty; let method_call = MethodCall::expr(expr.id); - fcx.inh.method_map.borrow_mut().insert(method_call, method); + check_env.tt.method_map.insert(method_call, method); method_ty } Err(error) => { - method::report_error(fcx, method_name.span, expr_t, + method::report_error(check_env, fcx, method_name.span, expr_t, method_name.node.name, Some(rcvr), error); - fcx.write_error(expr.id); + fcx.write_error(check_env, expr.id); fcx.tcx().types.err } }; // Call the generic checker. - let ret_ty = check_method_argument_types(fcx, + let ret_ty = check_method_argument_types(check_env, + fcx, method_name.span, fn_ty, expr, @@ -2609,28 +2733,29 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, DontTupleArguments, expected); - write_call(fcx, expr, ret_ty); + write_call(check_env, fcx, expr, ret_ty); } // A generic function for checking the then and else in an if // or if-else. - fn check_then_else<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + fn check_then_else<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, cond_expr: &'tcx ast::Expr, then_blk: &'tcx ast::Block, opt_else_expr: Option<&'tcx ast::Expr>, id: ast::NodeId, sp: Span, expected: Expectation<'tcx>) { - check_expr_has_type(fcx, cond_expr, fcx.tcx().types.bool); + check_expr_has_type(check_env, fcx, cond_expr, fcx.tcx().types.bool); let expected = expected.adjust_for_branches(fcx); - check_block_with_expected(fcx, then_blk, expected); - let then_ty = fcx.node_ty(then_blk.id); + check_block_with_expected(check_env, fcx, then_blk, expected); + let then_ty = fcx.node_ty(&check_env.tt.node_types, then_blk.id); let branches_ty = match opt_else_expr { Some(ref else_expr) => { - check_expr_with_expectation(fcx, &**else_expr, expected); - let else_ty = fcx.expr_ty(&**else_expr); + check_expr_with_expectation(check_env, fcx, &**else_expr, expected); + let else_ty = fcx.expr_ty(&check_env.tt.node_types, &**else_expr); infer::common_supertype(fcx.infcx(), infer::IfExpression(sp), true, @@ -2646,39 +2771,41 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } }; - let cond_ty = fcx.expr_ty(cond_expr); + let cond_ty = fcx.expr_ty(&check_env.tt.node_types, cond_expr); let if_ty = if ty::type_is_error(cond_ty) { fcx.tcx().types.err } else { branches_ty }; - fcx.write_ty(id, if_ty); + fcx.write_ty(check_env, id, if_ty); } // Check field access expressions - fn check_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, + fn check_field<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, expr: &'tcx ast::Expr, lvalue_pref: LvaluePreference, base: &'tcx ast::Expr, field: &ast::SpannedIdent) { let tcx = fcx.ccx.tcx; - check_expr_with_lvalue_pref(fcx, base, lvalue_pref); - let expr_t = structurally_resolved_type(fcx, expr.span, - fcx.expr_ty(base)); + check_expr_with_lvalue_pref(check_env, fcx, base, lvalue_pref); + let expr_ty = fcx.expr_ty(&check_env.tt.node_types, base); + let expr_t = structurally_resolved_type(check_env, fcx, expr.span, expr_ty); // FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop. - let (_, autoderefs, field_ty) = autoderef(fcx, + let (_, autoderefs, field_ty) = autoderef(check_env, fcx, expr.span, expr_t, Some(base), UnresolvedTypeAction::Error, lvalue_pref, - |base_t, _| { + |check_env, base_t, _| { match base_t.sty { ty::ty_struct(base_id, substs) => { debug!("struct named {}", ppaux::ty_to_string(tcx, base_t)); let fields = ty::lookup_struct_fields(tcx, base_id); - fcx.lookup_field_ty(expr.span, base_id, &fields[..], + fcx.lookup_field_ty(check_env, + expr.span, base_id, &fields[..], field.node.name, &(*substs)) } _ => None @@ -2686,14 +2813,14 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }); match field_ty { Some(field_ty) => { - fcx.write_ty(expr.id, field_ty); - fcx.write_autoderef_adjustment(base.id, autoderefs); + fcx.write_ty(check_env, expr.id, field_ty); + fcx.write_autoderef_adjustment(check_env, base.id, autoderefs); return; } None => {} } - if method::exists(fcx, field.span, field.node.name, expr_t, expr.id) { + if method::exists(check_env, fcx, field.span, field.node.name, expr_t, expr.id) { fcx.type_error_message( field.span, |actual| { @@ -2721,7 +2848,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } } - fcx.write_error(expr.id); + fcx.write_error(check_env, expr.id); } // displays hints about the closest matches in field names @@ -2758,31 +2885,33 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } // Check tuple index expressions - fn check_tup_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, + fn check_tup_field<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, expr: &'tcx ast::Expr, lvalue_pref: LvaluePreference, base: &'tcx ast::Expr, idx: codemap::Spanned) { let tcx = fcx.ccx.tcx; - check_expr_with_lvalue_pref(fcx, base, lvalue_pref); - let expr_t = structurally_resolved_type(fcx, expr.span, - fcx.expr_ty(base)); + check_expr_with_lvalue_pref(check_env, fcx, base, lvalue_pref); + let expr_ty = fcx.expr_ty(&check_env.tt.node_types, base); + let expr_t = structurally_resolved_type(check_env, fcx, expr.span, expr_ty); let mut tuple_like = false; // FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop. - let (_, autoderefs, field_ty) = autoderef(fcx, + let (_, autoderefs, field_ty) = autoderef(check_env, fcx, expr.span, expr_t, Some(base), UnresolvedTypeAction::Error, lvalue_pref, - |base_t, _| { + |check_env, base_t, _| { match base_t.sty { ty::ty_struct(base_id, substs) => { tuple_like = ty::is_tuple_struct(tcx, base_id); if tuple_like { debug!("tuple struct named {}", ppaux::ty_to_string(tcx, base_t)); let fields = ty::lookup_struct_fields(tcx, base_id); - fcx.lookup_tup_field_ty(expr.span, base_id, &fields[..], + fcx.lookup_tup_field_ty(check_env, + expr.span, base_id, &fields[..], idx.node, &(*substs)) } else { None @@ -2797,8 +2926,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }); match field_ty { Some(field_ty) => { - fcx.write_ty(expr.id, field_ty); - fcx.write_autoderef_adjustment(base.id, autoderefs); + fcx.write_ty(check_env, expr.id, field_ty); + fcx.write_autoderef_adjustment(check_env, base.id, autoderefs); return; } None => {} @@ -2820,10 +2949,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }, expr_t, None); - fcx.write_error(expr.id); + fcx.write_error(check_env, expr.id); } - fn check_struct_or_variant_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + fn check_struct_or_variant_fields<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, struct_ty: Ty<'tcx>, span: Span, class_id: ast::DefId, @@ -2888,8 +3018,9 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, expected_field_type = ty::lookup_field_type( tcx, class_id, field_id, substitutions); + let mut joined = FnCtxtJoined::new(check_env, fcx); expected_field_type = - fcx.normalize_associated_types_in( + joined.normalize_associated_types_in( field.span, &expected_field_type); class_field_map.insert( field.ident.node.name, (field_id, true)); @@ -2899,11 +3030,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Make sure to give a type to the field even if there's // an error, so we can continue typechecking - check_expr_coercable_to_type(fcx, &*field.expr, expected_field_type); + check_expr_coercable_to_type(check_env, fcx, &*field.expr, expected_field_type); } if error_happened { - fcx.write_error(node_id); + fcx.write_error(check_env, node_id); } if check_completeness && !error_happened { @@ -2928,12 +3059,13 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } if !error_happened { - fcx.write_ty(node_id, ty::mk_struct(fcx.ccx.tcx, - class_id, substitutions)); + fcx.write_ty(check_env, node_id, + ty::mk_struct(fcx.ccx.tcx, class_id, substitutions)); } } - fn check_struct_constructor<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, + fn check_struct_constructor<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, id: ast::NodeId, span: codemap::Span, class_id: ast::DefId, @@ -2945,11 +3077,15 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let TypeAndSubsts { ty: mut struct_type, substs: struct_substs - } = fcx.instantiate_type(span, class_id); + } = { + let mut joined = FnCtxtJoined::new(check_env, fcx); + joined.instantiate_type(span, class_id) + }; // Look up and check the fields. let class_fields = ty::lookup_struct_fields(tcx, class_id); - check_struct_or_variant_fields(fcx, + check_struct_or_variant_fields(check_env, + fcx, struct_type, span, class_id, @@ -2959,7 +3095,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fields, base_expr.is_none(), None); - if ty::type_is_error(fcx.node_ty(id)) { + if ty::type_is_error(fcx.node_ty(&check_env.tt.node_types, id)) { struct_type = tcx.types.err; } @@ -2967,15 +3103,16 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, match base_expr { None => {} Some(base_expr) => { - check_expr_has_type(fcx, &*base_expr, struct_type); + check_expr_has_type(check_env, fcx, &*base_expr, struct_type); } } // Write in the resulting type. - fcx.write_ty(id, struct_type); + fcx.write_ty(check_env, id, struct_type); } - fn check_struct_enum_variant<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, + fn check_struct_enum_variant<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, id: ast::NodeId, span: codemap::Span, enum_id: ast::DefId, @@ -2988,11 +3125,15 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let TypeAndSubsts { ty: enum_type, substs: substitutions - } = fcx.instantiate_type(span, enum_id); + } = { + let mut joined = FnCtxtJoined::new(check_env, fcx); + joined.instantiate_type(span, enum_id) + }; // Look up and check the enum variant fields. let variant_fields = ty::lookup_struct_fields(tcx, variant_id); - check_struct_or_variant_fields(fcx, + check_struct_or_variant_fields(check_env, + fcx, enum_type, span, variant_id, @@ -3002,21 +3143,22 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fields, true, Some(enum_id)); - fcx.write_ty(id, enum_type); + fcx.write_ty(check_env, id, enum_type); } - fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, + fn check_struct_fields_on_error<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, id: ast::NodeId, fields: &'tcx [ast::Field], base_expr: &'tcx Option>) { // Make sure to still write the types // otherwise we might ICE - fcx.write_error(id); + fcx.write_error(check_env, id); for field in fields { - check_expr(fcx, &*field.expr); + check_expr(check_env, fcx, &*field.expr); } match *base_expr { - Some(ref base) => check_expr(fcx, &**base), + Some(ref base) => check_expr(check_env, fcx, &**base), None => {} } } @@ -3027,8 +3169,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let id = expr.id; match expr.node { ast::ExprBox(ref opt_place, ref subexpr) => { - opt_place.as_ref().map(|place|check_expr(fcx, &**place)); - check_expr(fcx, &**subexpr); + opt_place.as_ref().map(|place|check_expr(check_env, fcx, &**place)); + check_expr(check_env, fcx, &**subexpr); let mut checked = false; opt_place.as_ref().map(|place| match place.node { @@ -3037,9 +3179,9 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // places: the exchange heap and the managed heap. let definition = lookup_full_def(tcx, path.span, place.id); let def_id = definition.def_id(); - let referent_ty = fcx.expr_ty(&**subexpr); + let referent_ty = fcx.expr_ty(&check_env.tt.node_types, &**subexpr); if tcx.lang_items.exchange_heap() == Some(def_id) { - fcx.write_ty(id, ty::mk_uniq(tcx, referent_ty)); + fcx.write_ty(check_env, id, ty::mk_uniq(tcx, referent_ty)); checked = true } } @@ -3049,19 +3191,19 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, if !checked { span_err!(tcx.sess, expr.span, E0066, "only the managed heap and exchange heap are currently supported"); - fcx.write_ty(id, tcx.types.err); + fcx.write_ty(check_env, id, tcx.types.err); } } ast::ExprLit(ref lit) => { let typ = check_lit(fcx, &**lit, expected); - fcx.write_ty(id, typ); + fcx.write_ty(check_env, id, typ); } ast::ExprBinary(op, ref lhs, ref rhs) => { - op::check_binop(fcx, expr, op, lhs, rhs); + op::check_binop(check_env, fcx, expr, op, lhs, rhs); } ast::ExprAssignOp(op, ref lhs, ref rhs) => { - op::check_binop_assign(fcx, expr, op, lhs, rhs); + op::check_binop_assign(check_env, fcx, expr, op, lhs, rhs); } ast::ExprUnary(unop, ref oprnd) => { let expected_inner = expected.to_option(fcx).map_or(NoExpectation, |ty| { @@ -3087,8 +3229,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, _ => NoPreference }; check_expr_with_expectation_and_lvalue_pref( - fcx, &**oprnd, expected_inner, lvalue_pref); - let mut oprnd_t = fcx.expr_ty(&**oprnd); + check_env, fcx, &**oprnd, expected_inner, lvalue_pref); + let mut oprnd_t = fcx.expr_ty(&check_env.tt.node_types, &**oprnd); if !ty::type_is_error(oprnd_t) { match unop { @@ -3096,10 +3238,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, oprnd_t = ty::mk_uniq(tcx, oprnd_t); } ast::UnDeref => { - oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t); + oprnd_t = structurally_resolved_type(check_env, fcx, expr.span, oprnd_t); oprnd_t = match ty::deref(oprnd_t, true) { Some(mt) => mt.ty, - None => match try_overloaded_deref(fcx, expr.span, + None => match try_overloaded_deref(check_env, fcx, expr.span, Some(MethodCall::expr(expr.id)), Some(&**oprnd), oprnd_t, lvalue_pref) { Some(mt) => mt.ty, @@ -3130,21 +3272,21 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }; } ast::UnNot => { - oprnd_t = structurally_resolved_type(fcx, oprnd.span, + oprnd_t = structurally_resolved_type(check_env, fcx, oprnd.span, oprnd_t); if !(ty::type_is_integral(oprnd_t) || oprnd_t.sty == ty::ty_bool) { - oprnd_t = op::check_user_unop(fcx, "!", "not", + oprnd_t = op::check_user_unop(check_env, fcx, "!", "not", tcx.lang_items.not_trait(), expr, &**oprnd, oprnd_t, unop); } } ast::UnNeg => { - oprnd_t = structurally_resolved_type(fcx, oprnd.span, + oprnd_t = structurally_resolved_type(check_env, fcx, oprnd.span, oprnd_t); if !(ty::type_is_integral(oprnd_t) || ty::type_is_fp(oprnd_t)) { - oprnd_t = op::check_user_unop(fcx, "-", "neg", + oprnd_t = op::check_user_unop(check_env, fcx, "-", "neg", tcx.lang_items.neg_trait(), expr, &**oprnd, oprnd_t, unop); } @@ -3160,7 +3302,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } } } - fcx.write_ty(id, oprnd_t); + fcx.write_ty(check_env, id, oprnd_t); } ast::ExprAddrOf(mutbl, ref oprnd) => { let hint = expected.only_has_type(fcx).map_or(NoExpectation, |ty| { @@ -3182,12 +3324,13 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ast::MutMutable => PreferMutLvalue, ast::MutImmutable => NoPreference }; - check_expr_with_expectation_and_lvalue_pref(fcx, + check_expr_with_expectation_and_lvalue_pref(check_env, + fcx, &**oprnd, hint, lvalue_pref); - let tm = ty::mt { ty: fcx.expr_ty(&**oprnd), mutbl: mutbl }; + let tm = ty::mt { ty: fcx.expr_ty(&check_env.tt.node_types, &**oprnd), mutbl: mutbl }; let oprnd_t = if ty::type_is_error(tm.ty) { tcx.types.err } else { @@ -3207,11 +3350,12 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let region = fcx.infcx().next_region_var(infer::AddrOfRegion(expr.span)); ty::mk_rptr(tcx, tcx.mk_region(region), tm) }; - fcx.write_ty(id, oprnd_t); + fcx.write_ty(check_env, id, oprnd_t); } ast::ExprPath(ref maybe_qself, ref path) => { let opt_self_ty = maybe_qself.as_ref().map(|qself| { - fcx.to_ty(&qself.ty) + let mut joined = FnCtxtJoined::new(check_env, fcx); + joined.to_ty(&qself.ty) }); let path_res = if let Some(&d) = tcx.def_map.borrow().get(&id) { @@ -3229,12 +3373,14 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }; if let Some((opt_ty, segments, def)) = - resolve_ty_and_def_ufcs(fcx, path_res, opt_self_ty, path, + resolve_ty_and_def_ufcs(check_env, fcx, path_res, opt_self_ty, path, expr.span, expr.id) { - let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, + let (scheme, predicates) = type_scheme_and_predicates_for_def(check_env, + fcx, expr.span, def); - instantiate_path(fcx, + instantiate_path(check_env, + fcx, segments, scheme, &predicates, @@ -3246,20 +3392,20 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. - constrain_path_type_parameters(fcx, expr); + constrain_path_type_parameters(check_env, fcx, expr); } ast::ExprInlineAsm(ref ia) => { for &(_, ref input) in &ia.inputs { - check_expr(fcx, &**input); + check_expr(check_env, fcx, &**input); } for &(_, ref out, _) in &ia.outputs { - check_expr(fcx, &**out); + check_expr(check_env, fcx, &**out); } - fcx.write_nil(id); + fcx.write_nil(check_env, id); } ast::ExprMac(_) => tcx.sess.bug("unexpanded macro"), - ast::ExprBreak(_) => { fcx.write_ty(id, fcx.infcx().next_diverging_ty_var()); } - ast::ExprAgain(_) => { fcx.write_ty(id, fcx.infcx().next_diverging_ty_var()); } + ast::ExprBreak(_) => { fcx.write_ty(check_env, id, fcx.infcx().next_diverging_ty_var()); } + ast::ExprAgain(_) => { fcx.write_ty(check_env, id, fcx.infcx().next_diverging_ty_var()); } ast::ExprRet(ref expr_opt) => { match fcx.ret_ty { ty::FnConverging(result_type) => { @@ -3271,29 +3417,31 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, "`return;` in function returning non-nil"); }, Some(ref e) => { - check_expr_coercable_to_type(fcx, &**e, result_type); + check_expr_coercable_to_type(check_env, fcx, &**e, result_type); } } } ty::FnDiverging => { if let Some(ref e) = *expr_opt { - check_expr(fcx, &**e); + check_expr(check_env, fcx, &**e); } span_err!(tcx.sess, expr.span, E0166, "`return` in a function declared as diverging"); } } - fcx.write_ty(id, fcx.infcx().next_diverging_ty_var()); + fcx.write_ty(check_env, id, fcx.infcx().next_diverging_ty_var()); } ast::ExprParen(ref a) => { - check_expr_with_expectation_and_lvalue_pref(fcx, + check_expr_with_expectation_and_lvalue_pref(check_env, + fcx, &**a, expected, lvalue_pref); - fcx.write_ty(id, fcx.expr_ty(&**a)); + let expr_ty = fcx.expr_ty(&check_env.tt.node_types, &**a); + fcx.write_ty(check_env, id, expr_ty); } ast::ExprAssign(ref lhs, ref rhs) => { - check_expr_with_lvalue_pref(fcx, &**lhs, PreferMutLvalue); + check_expr_with_lvalue_pref(check_env, fcx, &**lhs, PreferMutLvalue); let tcx = fcx.tcx(); if !ty::expr_is_lval(tcx, &**lhs) { @@ -3301,35 +3449,35 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, "illegal left-hand side expression"); } - let lhs_ty = fcx.expr_ty(&**lhs); - check_expr_coercable_to_type(fcx, &**rhs, lhs_ty); - let rhs_ty = fcx.expr_ty(&**rhs); + let lhs_ty = fcx.expr_ty(&check_env.tt.node_types, &**lhs); + check_expr_coercable_to_type(check_env, fcx, &**rhs, lhs_ty); + let rhs_ty = fcx.expr_ty(&check_env.tt.node_types, &**rhs); - fcx.require_expr_have_sized_type(&**lhs, traits::AssignmentLhsSized); + fcx.require_expr_have_sized_type(check_env, &**lhs, traits::AssignmentLhsSized); if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) { - fcx.write_error(id); + fcx.write_error(check_env, id); } else { - fcx.write_nil(id); + fcx.write_nil(check_env, id); } } ast::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => { - check_then_else(fcx, &**cond, &**then_blk, opt_else_expr.as_ref().map(|e| &**e), + check_then_else(check_env, fcx, &**cond, &**then_blk, opt_else_expr.as_ref().map(|e| &**e), id, expr.span, expected); } ast::ExprIfLet(..) => { tcx.sess.span_bug(expr.span, "non-desugared ExprIfLet"); } ast::ExprWhile(ref cond, ref body, _) => { - check_expr_has_type(fcx, &**cond, tcx.types.bool); - check_block_no_value(fcx, &**body); - let cond_ty = fcx.expr_ty(&**cond); - let body_ty = fcx.node_ty(body.id); + check_expr_has_type(check_env, fcx, &**cond, tcx.types.bool); + check_block_no_value(check_env, fcx, &**body); + let cond_ty = fcx.expr_ty(&check_env.tt.node_types, &**cond); + let body_ty = fcx.node_ty(&check_env.tt.node_types, body.id); if ty::type_is_error(cond_ty) || ty::type_is_error(body_ty) { - fcx.write_error(id); + fcx.write_error(check_env, id); } else { - fcx.write_nil(id); + fcx.write_nil(check_env, id); } } ast::ExprWhileLet(..) => { @@ -3339,62 +3487,65 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop"); } ast::ExprLoop(ref body, _) => { - check_block_no_value(fcx, &**body); + check_block_no_value(check_env, fcx, &**body); if !may_break(tcx, expr.id, &**body) { - fcx.write_ty(id, fcx.infcx().next_diverging_ty_var()); + fcx.write_ty(check_env, id, fcx.infcx().next_diverging_ty_var()); } else { - fcx.write_nil(id); + fcx.write_nil(check_env, id); } } ast::ExprMatch(ref discrim, ref arms, match_src) => { - _match::check_match(fcx, expr, &**discrim, arms, expected, match_src); + _match::check_match(check_env, fcx, expr, &**discrim, arms, expected, match_src); } ast::ExprClosure(capture, ref decl, ref body) => { - closure::check_expr_closure(fcx, expr, capture, &**decl, &**body, expected); + closure::check_expr_closure(check_env, fcx, expr, capture, &**decl, &**body, expected); } ast::ExprBlock(ref b) => { - check_block_with_expected(fcx, &**b, expected); - fcx.write_ty(id, fcx.node_ty(b.id)); + check_block_with_expected(check_env, fcx, &**b, expected); + let node_ty = fcx.node_ty(&check_env.tt.node_types, b.id); + fcx.write_ty(check_env, id, node_ty); } ast::ExprCall(ref callee, ref args) => { - callee::check_call(fcx, expr, &**callee, &args[..], expected); + callee::check_call(check_env, fcx, expr, &**callee, &args[..], expected); } ast::ExprMethodCall(ident, ref tps, ref args) => { - check_method_call(fcx, expr, ident, &args[..], &tps[..], expected, lvalue_pref); - let arg_tys = args.iter().map(|a| fcx.expr_ty(&**a)); - let args_err = arg_tys.fold(false, - |rest_err, a| { - rest_err || ty::type_is_error(a)}); + check_method_call(check_env, fcx, expr, ident, &args[..], &tps[..], expected, lvalue_pref); + let args_err = { + let arg_tys = args.iter().map(|a| fcx.expr_ty(&check_env.tt.node_types, &**a)); + arg_tys.fold(false, |rest_err, a| rest_err || ty::type_is_error(a)) + }; if args_err { - fcx.write_error(id); + fcx.write_error(check_env, id); } } ast::ExprCast(ref e, ref t) => { if let ast::TyFixedLengthVec(_, ref count_expr) = t.node { - check_expr_with_hint(fcx, &**count_expr, tcx.types.usize); + check_expr_with_hint(check_env, fcx, &**count_expr, tcx.types.usize); } // Find the type of `e`. Supply hints based on the type we are casting to, // if appropriate. - let t_1 = fcx.to_ty(t); - let t_1 = structurally_resolved_type(fcx, expr.span, t_1); - check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1)); - let t_e = fcx.expr_ty(e); + let t_1 = { + let mut joined = FnCtxtJoined::new(check_env, fcx); + joined.to_ty(t) + }; + let t_1 = structurally_resolved_type(check_env, fcx, expr.span, t_1); + check_expr_with_expectation(check_env, fcx, e, ExpectCastableToType(t_1)); + let t_e = fcx.expr_ty(&check_env.tt.node_types, e); // Eagerly check for some obvious errors. if ty::type_is_error(t_e) { - fcx.write_error(id); + fcx.write_error(check_env, id); } else if !fcx.type_is_known_to_be_sized(t_1, expr.span) { - report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_1, t_e, id); + report_cast_to_unsized_type(check_env, fcx, expr.span, t.span, e.span, t_1, t_e, id); } else { // Write a type for the whole expression, assuming everything is going // to work out Ok. - fcx.write_ty(id, t_1); + fcx.write_ty(check_env, id, t_1); // Defer other checks until we're done type checking. - let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut(); let cast_check = cast::CastCheck::new((**e).clone(), t_e, t_1, expr.span); - deferred_cast_checks.push(cast_check); + check_env.deferred_cast_checks.push(cast_check); } } ast::ExprVec(ref args) => { @@ -3408,23 +3559,23 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let typ = match uty { Some(uty) => { for e in args { - check_expr_coercable_to_type(fcx, &**e, uty); + check_expr_coercable_to_type(check_env, fcx, &**e, uty); } uty } None => { let t: Ty = fcx.infcx().next_ty_var(); for e in args { - check_expr_has_type(fcx, &**e, t); + check_expr_has_type(check_env, fcx, &**e, t); } t } }; let typ = ty::mk_vec(tcx, typ, Some(args.len())); - fcx.write_ty(id, typ); + fcx.write_ty(check_env, id, typ); } ast::ExprRepeat(ref element, ref count_expr) => { - check_expr_has_type(fcx, &**count_expr, tcx.types.usize); + check_expr_has_type(check_env, fcx, &**count_expr, tcx.types.usize); let count = ty::eval_repeat_count(fcx.tcx(), &**count_expr); let uty = match expected { @@ -3439,13 +3590,13 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let (element_ty, t) = match uty { Some(uty) => { - check_expr_coercable_to_type(fcx, &**element, uty); + check_expr_coercable_to_type(check_env, fcx, &**element, uty); (uty, uty) } None => { let t: Ty = fcx.infcx().next_ty_var(); - check_expr_has_type(fcx, &**element, t); - (fcx.expr_ty(&**element), t) + check_expr_has_type(check_env, fcx, &**element, t); + (fcx.expr_ty(&check_env.tt.node_types, &**element), t) } }; @@ -3453,6 +3604,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // For [foo, ..n] where n > 1, `foo` must have // Copy type: fcx.require_type_meets( + check_env, t, expr.span, traits::RepeatVec, @@ -3460,10 +3612,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } if ty::type_is_error(element_ty) { - fcx.write_error(id); + fcx.write_error(check_env, id); } else { let t = ty::mk_vec(tcx, t, Some(count)); - fcx.write_ty(id, t); + fcx.write_ty(check_env, id, t); } } ast::ExprTup(ref elts) => { @@ -3479,22 +3631,22 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let t = match flds { Some(ref fs) if i < fs.len() => { let ety = fs[i]; - check_expr_coercable_to_type(fcx, &**e, ety); + check_expr_coercable_to_type(check_env, fcx, &**e, ety); ety } _ => { - check_expr_with_expectation(fcx, &**e, NoExpectation); - fcx.expr_ty(&**e) + check_expr_with_expectation(check_env, fcx, &**e, NoExpectation); + fcx.expr_ty(&check_env.tt.node_types, &**e) } }; err_field = err_field || ty::type_is_error(t); t }).collect(); if err_field { - fcx.write_error(id); + fcx.write_error(check_env, id); } else { let typ = ty::mk_tup(tcx, elt_ts); - fcx.write_ty(id, typ); + fcx.write_ty(check_env, id, typ); } } ast::ExprStruct(ref path, ref fields, ref base_expr) => { @@ -3502,7 +3654,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let def = lookup_full_def(tcx, path.span, id); let struct_id = match def { def::DefVariant(enum_id, variant_id, true) => { - check_struct_enum_variant(fcx, id, expr.span, enum_id, + check_struct_enum_variant(check_env, fcx, id, expr.span, enum_id, variant_id, &fields[..]); enum_id } @@ -3510,7 +3662,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, span_err!(tcx.sess, path.span, E0159, "use of trait `{}` as a struct constructor", pprust::path_to_string(path)); - check_struct_fields_on_error(fcx, + check_struct_fields_on_error(check_env, + fcx, id, &fields[..], base_expr); @@ -3521,7 +3674,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let typ = ty::lookup_item_type(fcx.ccx.tcx, def.def_id()); match typ.ty.sty { ty::ty_struct(struct_did, _) => { - check_struct_constructor(fcx, + check_struct_constructor(check_env, + fcx, id, expr.span, struct_did, @@ -3532,7 +3686,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, span_err!(tcx.sess, path.span, E0071, "`{}` does not name a structure", pprust::path_to_string(path)); - check_struct_fields_on_error(fcx, + check_struct_fields_on_error(check_env, + fcx, id, &fields[..], base_expr); @@ -3546,9 +3701,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Turn the path into a type and verify that that type unifies with // the resulting structure type. This is needed to handle type // parameters correctly. - let actual_structure_type = fcx.expr_ty(&*expr); + let actual_structure_type = fcx.expr_ty(&check_env.tt.node_types, &*expr); if !ty::type_is_error(actual_structure_type) { - let type_and_substs = fcx.instantiate_struct_literal_ty(struct_id, path); + let mut joined = FnCtxtJoined::new(check_env, fcx); + let type_and_substs = joined.instantiate_struct_literal_ty(struct_id, path); match fcx.mk_subty(false, infer::Misc(path.span), actual_structure_type, @@ -3572,35 +3728,35 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } } - fcx.require_expr_have_sized_type(expr, traits::StructInitializerSized); + fcx.require_expr_have_sized_type(check_env, expr, traits::StructInitializerSized); } ast::ExprField(ref base, ref field) => { - check_field(fcx, expr, lvalue_pref, &**base, field); + check_field(check_env, fcx, expr, lvalue_pref, &**base, field); } ast::ExprTupField(ref base, idx) => { - check_tup_field(fcx, expr, lvalue_pref, &**base, idx); + check_tup_field(check_env, fcx, expr, lvalue_pref, &**base, idx); } ast::ExprIndex(ref base, ref idx) => { - check_expr_with_lvalue_pref(fcx, &**base, lvalue_pref); - check_expr(fcx, &**idx); + check_expr_with_lvalue_pref(check_env, fcx, &**base, lvalue_pref); + check_expr(check_env, fcx, &**idx); - let base_t = fcx.expr_ty(&**base); - let idx_t = fcx.expr_ty(&**idx); + let base_t = fcx.expr_ty(&check_env.tt.node_types, &**base); + let idx_t = fcx.expr_ty(&check_env.tt.node_types, &**idx); if ty::type_is_error(base_t) { - fcx.write_ty(id, base_t); + fcx.write_ty(check_env, id, base_t); } else if ty::type_is_error(idx_t) { - fcx.write_ty(id, idx_t); + fcx.write_ty(check_env, id, idx_t); } else { - let base_t = structurally_resolved_type(fcx, expr.span, base_t); - match lookup_indexing(fcx, expr, base, base_t, idx_t, lvalue_pref) { + let base_t = structurally_resolved_type(check_env, fcx, expr.span, base_t); + match lookup_indexing(check_env, fcx, expr, base, base_t, idx_t, lvalue_pref) { Some((index_ty, element_ty)) => { - let idx_expr_ty = fcx.expr_ty(idx); + let idx_expr_ty = fcx.expr_ty(&check_env.tt.node_types, idx); demand::eqtype(fcx, expr.span, index_ty, idx_expr_ty); - fcx.write_ty(id, element_ty); + fcx.write_ty(check_env, id, element_ty); } None => { - check_expr_has_type(fcx, &**idx, fcx.tcx().types.err); + check_expr_has_type(check_env, fcx, &**idx, fcx.tcx().types.err); fcx.type_error_message( expr.span, |actual| { @@ -3609,19 +3765,19 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }, base_t, None); - fcx.write_ty(id, fcx.tcx().types.err); + fcx.write_ty(check_env, id, fcx.tcx().types.err); } } } } ast::ExprRange(ref start, ref end) => { let t_start = start.as_ref().map(|e| { - check_expr(fcx, &**e); - fcx.expr_ty(&**e) + check_expr(check_env, fcx, &**e); + fcx.expr_ty(&check_env.tt.node_types, &**e) }); let t_end = end.as_ref().map(|e| { - check_expr(fcx, &**e); - fcx.expr_ty(&**e) + check_expr(check_env, fcx, &**e); + fcx.expr_ty(&check_env.tt.node_types, &**e) }); let idx_type = match (t_start, t_end) { @@ -3664,8 +3820,12 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, if let Some(did) = did { let predicates = ty::lookup_predicates(tcx, did); let substs = Substs::new_type(vec![idx_type], vec![]); - let bounds = fcx.instantiate_bounds(expr.span, &substs, &predicates); + let bounds = { + let mut joined = FnCtxtJoined::new(check_env, fcx); + joined.instantiate_bounds(expr.span, &substs, &predicates) + }; fcx.add_obligations_for_parameters( + check_env, traits::ObligationCause::new(expr.span, fcx.body_id, traits::ItemObligation(did)), @@ -3689,7 +3849,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } }; - fcx.write_ty(id, range_type); + fcx.write_ty(check_env, id, range_type); } } @@ -3697,13 +3857,14 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, debug!("type of expr({}) {} is...", expr.id, syntax::print::pprust::expr_to_string(expr)); debug!("... {}, expected is {}", - ppaux::ty_to_string(tcx, fcx.expr_ty(expr)), + ppaux::ty_to_string(tcx, fcx.expr_ty(&check_env.tt.node_types, expr)), expected.repr(tcx)); - unifier(); + unifier(check_env); } -pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, +fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'b, 'tcx>, path_res: def::PathResolution, opt_self_ty: Option>, path: &'a ast::Path, @@ -3720,15 +3881,18 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, let mut def = path_res.base_def; let ty_segments = path.segments.init(); let base_ty_end = path.segments.len() - path_res.depth; - let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, span, - PathParamMode::Optional, - &mut def, - opt_self_ty, - &ty_segments[..base_ty_end], - &ty_segments[base_ty_end..]); + let ty = { + let mut joined = FnCtxtJoined::new(check_env, fcx); + astconv::finish_resolving_def_to_ty(&mut joined, fcx, span, + PathParamMode::Optional, + &mut def, + opt_self_ty, + &ty_segments[..base_ty_end], + &ty_segments[base_ty_end..]) + }; let item_segment = path.segments.last().unwrap(); let item_name = item_segment.identifier.name; - match method::resolve_ufcs(fcx, span, item_name, ty, node_id) { + match method::resolve_ufcs(check_env, fcx, span, item_name, ty, node_id) { Ok((def, lp)) => { // Write back the new resolution. fcx.ccx.tcx.def_map.borrow_mut() @@ -3740,20 +3904,22 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, Some((Some(ty), slice::ref_slice(item_segment), def)) } Err(error) => { - method::report_error(fcx, span, ty, + method::report_error(check_env, fcx, span, ty, item_name, None, error); - fcx.write_error(node_id); + fcx.write_error(check_env, node_id); None } } } } -fn constrain_path_type_parameters(fcx: &FnCtxt, - expr: &ast::Expr) +fn constrain_path_type_parameters<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, + expr: &ast::Expr) { - fcx.opt_node_ty_substs(expr.id, |item_substs| { - fcx.add_default_region_param_bounds(&item_substs.substs, expr); + let CheckEnv { ref tt, ref mut fulfillment_cx, .. } = *check_env; + fcx.opt_node_ty_substs(tt, expr.id, |item_substs| { + fcx.add_default_region_param_bounds(fulfillment_cx, &item_substs.substs, expr); }); } @@ -3789,7 +3955,8 @@ impl<'tcx> Expectation<'tcx> { // Resolves `expected` by a single level if it is a variable. If // there is no expected type or resolution is not possible (e.g., // no constraints yet present), just returns `None`. - fn resolve<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { + fn resolve<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> + { match self { NoExpectation => { NoExpectation @@ -3840,15 +4007,16 @@ impl<'tcx> Repr<'tcx> for Expectation<'tcx> { } } -pub fn check_decl_initializer<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, - local: &'tcx ast::Local, - init: &'tcx ast::Expr) +fn check_decl_initializer<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, + local: &'tcx ast::Local, + init: &'tcx ast::Expr) { let ref_bindings = fcx.tcx().pat_contains_ref_binding(&local.pat); - let local_ty = fcx.local_ty(init.span, local.id); + let local_ty = fcx.local_ty(check_env, init.span, local.id); if !ref_bindings { - check_expr_coercable_to_type(fcx, init, local_ty) + check_expr_coercable_to_type(check_env, fcx, init, local_ty) } else { // Somewhat subtle: if we have a `ref` binding in the pattern, // we want to avoid introducing coercions for the RHS. This is @@ -3858,23 +4026,24 @@ pub fn check_decl_initializer<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // referent for the reference that results is *equal to* the // type of the lvalue it is referencing, and not some // supertype thereof. - check_expr(fcx, init); - let init_ty = fcx.expr_ty(init); + check_expr(check_env, fcx, init); + let init_ty = fcx.expr_ty(&check_env.tt.node_types, init); demand::eqtype(fcx, init.span, init_ty, local_ty); }; } -pub fn check_decl_local<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, local: &'tcx ast::Local) { +fn check_decl_local<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, local: &'tcx ast::Local) { let tcx = fcx.ccx.tcx; - let t = fcx.local_ty(local.span, local.id); - fcx.write_ty(local.id, t); + let t = fcx.local_ty(check_env, local.span, local.id); + fcx.write_ty(check_env, local.id, t); if let Some(ref init) = local.init { - check_decl_initializer(fcx, local, &**init); - let init_ty = fcx.expr_ty(&**init); + check_decl_initializer(check_env, fcx, local, &**init); + let init_ty = fcx.expr_ty(&check_env.tt.node_types, &**init); if ty::type_is_error(init_ty) { - fcx.write_ty(local.id, init_ty); + fcx.write_ty(check_env, local.id, init_ty); } } @@ -3882,14 +4051,15 @@ pub fn check_decl_local<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, local: &'tcx ast::Local) fcx: fcx, map: pat_id_map(&tcx.def_map, &*local.pat), }; - _match::check_pat(&pcx, &*local.pat, t); - let pat_ty = fcx.node_ty(local.pat.id); + _match::check_pat(check_env, &pcx, &*local.pat, t); + let pat_ty = fcx.node_ty(&check_env.tt.node_types, local.pat.id); if ty::type_is_error(pat_ty) { - fcx.write_ty(local.id, pat_ty); + fcx.write_ty(check_env, local.id, pat_ty); } } -pub fn check_stmt<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, stmt: &'tcx ast::Stmt) { +fn check_stmt<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, stmt: &'tcx ast::Stmt) { let node_id; let mut saw_bot = false; let mut saw_err = false; @@ -3898,8 +4068,8 @@ pub fn check_stmt<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, stmt: &'tcx ast::Stmt) { node_id = id; match decl.node { ast::DeclLocal(ref l) => { - check_decl_local(fcx, &**l); - let l_t = fcx.node_ty(l.id); + check_decl_local(check_env, fcx, &**l); + let l_t = fcx.node_ty(&check_env.tt.node_types, l.id); saw_bot = saw_bot || fcx.infcx().type_var_diverges(l_t); saw_err = saw_err || ty::type_is_error(l_t); } @@ -3909,58 +4079,61 @@ pub fn check_stmt<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, stmt: &'tcx ast::Stmt) { ast::StmtExpr(ref expr, id) => { node_id = id; // Check with expected type of () - check_expr_has_type(fcx, &**expr, ty::mk_nil(fcx.tcx())); - let expr_ty = fcx.expr_ty(&**expr); + check_expr_has_type(check_env, fcx, &**expr, ty::mk_nil(fcx.tcx())); + let expr_ty = fcx.expr_ty(&check_env.tt.node_types, &**expr); saw_bot = saw_bot || fcx.infcx().type_var_diverges(expr_ty); saw_err = saw_err || ty::type_is_error(expr_ty); } ast::StmtSemi(ref expr, id) => { node_id = id; - check_expr(fcx, &**expr); - let expr_ty = fcx.expr_ty(&**expr); + check_expr(check_env, fcx, &**expr); + let expr_ty = fcx.expr_ty(&check_env.tt.node_types, &**expr); saw_bot |= fcx.infcx().type_var_diverges(expr_ty); saw_err |= ty::type_is_error(expr_ty); } ast::StmtMac(..) => fcx.ccx.tcx.sess.bug("unexpanded macro") } if saw_bot { - fcx.write_ty(node_id, fcx.infcx().next_diverging_ty_var()); + fcx.write_ty(check_env, node_id, fcx.infcx().next_diverging_ty_var()); } else if saw_err { - fcx.write_error(node_id); + fcx.write_error(check_env, node_id); } else { - fcx.write_nil(node_id) + fcx.write_nil(check_env, node_id) } } -pub fn check_block_no_value<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, blk: &'tcx ast::Block) { - check_block_with_expected(fcx, blk, ExpectHasType(ty::mk_nil(fcx.tcx()))); - let blkty = fcx.node_ty(blk.id); +fn check_block_no_value<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, blk: &'tcx ast::Block) { + check_block_with_expected(check_env, fcx, blk, ExpectHasType(ty::mk_nil(fcx.tcx()))); + let blkty = fcx.node_ty(&check_env.tt.node_types, blk.id); if ty::type_is_error(blkty) { - fcx.write_error(blk.id); + fcx.write_error(check_env, blk.id); } else { let nilty = ty::mk_nil(fcx.tcx()); demand::suptype(fcx, blk.span, nilty, blkty); } } -fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn check_block_with_expected<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, blk: &'tcx ast::Block, expected: Expectation<'tcx>) { let prev = { - let mut fcx_ps = fcx.ps.borrow_mut(); + let fcx_ps = fcx.ps.get(); let unsafety_state = fcx_ps.recurse(blk); - replace(&mut *fcx_ps, unsafety_state) + fcx.ps.set(unsafety_state); + fcx_ps }; let mut warned = false; let mut any_diverges = false; let mut any_err = false; for s in &blk.stmts { - check_stmt(fcx, &**s); + check_stmt(check_env, fcx, &**s); let s_id = ast_util::stmt_id(&**s); - let s_ty = fcx.node_ty(s_id); + let s_ty = fcx.node_ty(&check_env.tt.node_types, s_id); if any_diverges && !warned && match s.node { ast::StmtDecl(ref decl, _) => { match decl.node { @@ -3985,11 +4158,11 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } match blk.expr { None => if any_err { - fcx.write_error(blk.id); + fcx.write_error(check_env, blk.id); } else if any_diverges { - fcx.write_ty(blk.id, fcx.infcx().next_diverging_ty_var()); + fcx.write_ty(check_env, blk.id, fcx.infcx().next_diverging_ty_var()); } else { - fcx.write_nil(blk.id); + fcx.write_nil(check_env, blk.id); }, Some(ref e) => { if any_diverges && !warned { @@ -4003,26 +4176,26 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } let ety = match expected { ExpectHasType(ety) => { - check_expr_coercable_to_type(fcx, &**e, ety); + check_expr_coercable_to_type(check_env, fcx, &**e, ety); ety } _ => { - check_expr_with_expectation(fcx, &**e, expected); - fcx.expr_ty(&**e) + check_expr_with_expectation(check_env, fcx, &**e, expected); + fcx.expr_ty(&check_env.tt.node_types, &**e) } }; if any_err { - fcx.write_error(blk.id); + fcx.write_error(check_env, blk.id); } else if any_diverges { - fcx.write_ty(blk.id, fcx.infcx().next_diverging_ty_var()); + fcx.write_ty(check_env, blk.id, fcx.infcx().next_diverging_ty_var()); } else { - fcx.write_ty(blk.id, ety); + fcx.write_ty(check_env, blk.id, ety); } } }; - *fcx.ps.borrow_mut() = prev; + fcx.ps.set(prev); } /// Checks a constant appearing in a type. At the moment this is just the @@ -4031,23 +4204,24 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn check_const_in_type<'a,'tcx>(ccx: &'a CrateCtxt<'a,'tcx>, expr: &'tcx ast::Expr, expected_type: Ty<'tcx>) { - let inh = static_inherited_fields(ccx); + let (mut check_env, inh) = static_fields(ccx); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(expected_type), expr.id); - check_const_with_ty(&fcx, expr.span, expr, expected_type); + check_const_with_ty(&mut check_env, &fcx, expr.span, expr, expected_type); } fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, sp: Span, e: &'tcx ast::Expr, id: ast::NodeId) { - let inh = static_inherited_fields(ccx); + let (mut check_env, inh) = static_fields(ccx); let rty = ty::node_id_to_type(ccx.tcx, id); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id); let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).unwrap().ty; - check_const_with_ty(&fcx, sp, e, declty); + check_const_with_ty(&mut check_env, &fcx, sp, e, declty); } -fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn check_const_with_ty<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, _: Span, e: &'tcx ast::Expr, declty: Ty<'tcx>) { @@ -4055,14 +4229,14 @@ fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // This is technically unnecessary because locals in static items are forbidden, // but prevents type checking from blowing up before const checking can properly // emit a error. - GatherLocalsVisitor { fcx: fcx }.visit_expr(e); - - check_expr_with_hint(fcx, e, declty); - demand::coerce(fcx, e.span, declty, e); - vtable::select_all_fcx_obligations_or_error(fcx); - fcx.check_casts(); - regionck::regionck_expr(fcx, e); - writeback::resolve_type_vars_in_expr(fcx, e); + GatherLocalsVisitor { check_env: check_env, fcx: fcx }.visit_expr(e); + + check_expr_with_hint(check_env, fcx, e, declty); + demand::coerce(check_env, fcx, e.span, declty, e); + vtable::select_all_fcx_obligations_or_error(check_env, fcx); + check_env.check_casts(fcx); + regionck::regionck_expr(check_env, fcx, e); + writeback::resolve_type_vars_in_expr(check_env, fcx, e); } /// Checks whether a type can be represented in memory. In particular, it @@ -4070,10 +4244,10 @@ fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// pointer, which would mean their size is unbounded. This is different from /// the question of whether a type can be instantiated. See the definition of /// `check_instantiable`. -pub fn check_representable(tcx: &ty::ctxt, - sp: Span, - item_id: ast::NodeId, - designation: &str) -> bool { +fn check_representable(tcx: &ty::ctxt, + sp: Span, + item_id: ast::NodeId, + designation: &str) -> bool { let rty = ty::node_id_to_type(tcx, item_id); // Check that it is possible to represent this type. This call identifies @@ -4105,10 +4279,10 @@ pub fn check_representable(tcx: &ty::ctxt, /// enum foo { Some(@foo) } /// /// is representable, but not instantiable. -pub fn check_instantiable(tcx: &ty::ctxt, - sp: Span, - item_id: ast::NodeId) - -> bool { +fn check_instantiable(tcx: &ty::ctxt, + sp: Span, + item_id: ast::NodeId) + -> bool { let item_ty = ty::node_id_to_type(tcx, item_id); if !ty::is_instantiable(tcx, item_ty) { span_err!(tcx.sess, sp, E0073, @@ -4122,7 +4296,7 @@ pub fn check_instantiable(tcx: &ty::ctxt, } } -pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { +fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { let t = ty::node_id_to_type(tcx, id); if ty::type_needs_subst(t) { span_err!(tcx.sess, sp, E0074, "SIMD vector cannot be generic"); @@ -4151,10 +4325,10 @@ pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { } } -pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - sp: Span, - vs: &'tcx [P], - id: ast::NodeId) { +fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + sp: Span, + vs: &'tcx [P], + id: ast::NodeId) { fn disr_in_range(ccx: &CrateCtxt, ty: attr::IntType, @@ -4192,13 +4366,13 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let rty = ty::node_id_to_type(ccx.tcx, id); let mut disr_vals: Vec = Vec::new(); - let inh = static_inherited_fields(ccx); + let (mut check_env, inh) = static_fields(ccx); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), id); let (_, repr_type_ty) = ty::enum_repr_type(ccx.tcx, Some(&hint)); for v in vs { if let Some(ref e) = v.node.disr_expr { - check_const_with_ty(&fcx, e.span, e, repr_type_ty); + check_const_with_ty(&mut check_env, &fcx, e.span, e, repr_type_ty); } } @@ -4265,13 +4439,14 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } // Returns the type parameter count and the type for the given definition. -fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn type_scheme_and_predicates_for_def<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, sp: Span, defn: def::Def) -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) { match defn { def::DefLocal(nid) | def::DefUpvar(nid, _) => { - let typ = fcx.local_ty(sp, nid); + let typ = fcx.local_ty(check_env, sp, nid); (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ }, ty::GenericPredicates::empty()) } @@ -4298,14 +4473,15 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. -pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - segments: &[ast::PathSegment], - type_scheme: TypeScheme<'tcx>, - type_predicates: &ty::GenericPredicates<'tcx>, - opt_self_ty: Option>, - def: def::Def, - span: Span, - node_id: ast::NodeId) { +fn instantiate_path<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, + segments: &[ast::PathSegment], + type_scheme: TypeScheme<'tcx>, + type_predicates: &ty::GenericPredicates<'tcx>, + opt_self_ty: Option>, + def: def::Def, + span: Span, + node_id: ast::NodeId) { debug!("instantiate_path(path={:?}, def={}, node_id={}, type_scheme={})", segments, def.repr(fcx.tcx()), @@ -4487,7 +4663,8 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } Some(space) => { - push_explicit_parameters_from_segment_to_substs(fcx, + push_explicit_parameters_from_segment_to_substs(check_env, + fcx, space, span, type_defs, @@ -4525,15 +4702,21 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Add all the obligations that are required, substituting and // normalized appropriately. - let bounds = fcx.instantiate_bounds(span, &substs, &type_predicates); - fcx.add_obligations_for_parameters( + let ty_substituted = { + let bounds = { + let mut joined = FnCtxtJoined::new(check_env, fcx); + joined.instantiate_bounds(span, &substs, &type_predicates) + }; + fcx.add_obligations_for_parameters( + check_env, traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def.def_id())), &bounds); - // Substitute the values for the type parameters into the type of - // the referenced item. - let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &type_scheme.ty); - + // Substitute the values for the type parameters into the type of + // the referenced item. + let mut joined = FnCtxtJoined::new(check_env, fcx); + joined.instantiate_type_scheme(span, &substs, &type_scheme.ty) + }; if let Some((def::FromImpl(impl_def_id), self_ty)) = ufcs_method { // In the case of `Foo::method` and `>::method`, if `method` @@ -4546,7 +4729,8 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, assert_eq!(substs.regions().len(subst::TypeSpace), impl_scheme.generics.regions.len(subst::TypeSpace)); - let impl_ty = fcx.instantiate_type_scheme(span, &substs, &impl_scheme.ty); + let mut joined = FnCtxtJoined::new(check_env, fcx); + let impl_ty = joined.instantiate_type_scheme(span, &substs, &impl_scheme.ty); if fcx.mk_subty(false, infer::Misc(span), self_ty, impl_ty).is_err() { fcx.tcx().sess.span_bug(span, &format!( @@ -4556,8 +4740,8 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } - fcx.write_ty(node_id, ty_substituted); - fcx.write_substs(node_id, ty::ItemSubsts { substs: substs }); + fcx.write_ty(check_env, node_id, ty_substituted); + fcx.write_substs(check_env, node_id, ty::ItemSubsts { substs: substs }); return; /// Finds the parameters that the user provided and adds them to `substs`. If too many @@ -4570,6 +4754,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// etc that is more complicated. I wanted however to do the reporting of *too many* parameters /// here because we can easily use the precise span of the N+1'th parameter. fn push_explicit_parameters_from_segment_to_substs<'a, 'tcx>( + check_env: &mut CheckEnv<'tcx>, fcx: &FnCtxt<'a, 'tcx>, space: subst::ParamSpace, span: Span, @@ -4581,19 +4766,20 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match segment.parameters { ast::AngleBracketedParameters(ref data) => { push_explicit_angle_bracketed_parameters_from_segment_to_substs( - fcx, space, type_defs, region_defs, data, substs); + check_env, fcx, space, type_defs, region_defs, data, substs); } ast::ParenthesizedParameters(ref data) => { span_err!(fcx.tcx().sess, span, E0238, "parenthesized parameters may only be used with a trait"); push_explicit_parenthesized_parameters_from_segment_to_substs( - fcx, space, span, type_defs, data, substs); + check_env, fcx, space, span, type_defs, data, substs); } } } fn push_explicit_angle_bracketed_parameters_from_segment_to_substs<'a, 'tcx>( + check_env: &mut CheckEnv<'tcx>, fcx: &FnCtxt<'a, 'tcx>, space: subst::ParamSpace, type_defs: &VecPerParamSpace>, @@ -4605,7 +4791,8 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let type_count = type_defs.len(space); assert_eq!(substs.types.len(space), 0); for (i, typ) in data.types.iter().enumerate() { - let t = fcx.to_ty(&**typ); + let mut joined = FnCtxtJoined::new(check_env, fcx); + let t = joined.to_ty(&**typ); if i < type_count { substs.types.push(space, t); } else if i == type_count { @@ -4653,6 +4840,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// difference has to do with the treatment of anonymous /// regions, which are translated into bound regions (NYI). fn push_explicit_parenthesized_parameters_from_segment_to_substs<'a, 'tcx>( + check_env: &mut CheckEnv<'tcx>, fcx: &FnCtxt<'a, 'tcx>, space: subst::ParamSpace, span: Span, @@ -4668,8 +4856,9 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, type_count); } + let mut joined = FnCtxtJoined::new(check_env, fcx); let input_tys: Vec = - data.inputs.iter().map(|ty| fcx.to_ty(&**ty)).collect(); + data.inputs.iter().map(|ty| joined.to_ty(&**ty)).collect(); let tuple_ty = ty::mk_tup(fcx.tcx(), input_tys); @@ -4679,7 +4868,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } let output_ty: Option = - data.output.as_ref().map(|ty| fcx.to_ty(&**ty)); + data.output.as_ref().map(|ty| joined.to_ty(&**ty)); let output_ty = output_ty.unwrap_or(ty::mk_nil(fcx.tcx())); @@ -4791,13 +4980,14 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } -fn structurally_resolve_type_or_else<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, +fn structurally_resolve_type_or_else<'a, 'tcx, F>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, sp: Span, ty: Ty<'tcx>, f: F) -> Ty<'tcx> where F: Fn() -> Ty<'tcx> { - let mut ty = fcx.resolve_type_vars_if_possible(ty); + let mut ty = fcx.resolve_type_vars_if_possible(check_env, ty); if ty::type_is_ty_var(ty) { let alternative = f(); @@ -4820,18 +5010,19 @@ fn structurally_resolve_type_or_else<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Resolves `typ` by a single level if `typ` is a type variable. If no // resolution is possible, then an error is reported. -pub fn structurally_resolved_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - sp: Span, - ty: Ty<'tcx>) - -> Ty<'tcx> +fn structurally_resolved_type<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, + sp: Span, + ty: Ty<'tcx>) + -> Ty<'tcx> { - structurally_resolve_type_or_else(fcx, sp, ty, || { + structurally_resolve_type_or_else(check_env, fcx, sp, ty, || { fcx.tcx().types.err }) } // Returns true if b contains a break that can exit from b -pub fn may_break(cx: &ty::ctxt, id: ast::NodeId, b: &ast::Block) -> bool { +fn may_break(cx: &ty::ctxt, id: ast::NodeId, b: &ast::Block) -> bool { // First: is there an unlabeled break immediately // inside the loop? (loop_query(&*b, |e| { @@ -4851,10 +5042,10 @@ pub fn may_break(cx: &ty::ctxt, id: ast::NodeId, b: &ast::Block) -> bool { })) } -pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - span: Span, - tps: &OwnedSlice, - ty: Ty<'tcx>) { +fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + span: Span, + tps: &OwnedSlice, + ty: Ty<'tcx>) { debug!("check_bounds_are_used(n_tps={}, ty={})", tps.len(), ppaux::ty_to_string(ccx.tcx, ty)); @@ -4883,7 +5074,7 @@ pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, /// Remember to add all intrinsics here, in librustc_trans/trans/intrinsic.rs, /// and in libcore/intrinsics.rs -pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { +fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> { let name = token::intern(&format!("P{}", n)); ty::mk_param(ccx.tcx, subst::FnSpace, n, name) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index b4000788d1998..35e8773cd9ae4 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -14,6 +14,7 @@ use super::{ check_expr, check_expr_coercable_to_type, check_expr_with_lvalue_pref, + CheckEnv, demand, method, FnCtxt, @@ -28,7 +29,8 @@ use syntax::parse::token; use util::ppaux::{Repr, UserString}; /// Check a `a = b` -pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, +pub fn check_binop_assign<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, expr: &'tcx ast::Expr, op: ast::BinOp, lhs_expr: &'tcx ast::Expr, @@ -36,15 +38,17 @@ pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, { let tcx = fcx.ccx.tcx; - check_expr_with_lvalue_pref(fcx, lhs_expr, PreferMutLvalue); - check_expr(fcx, rhs_expr); + check_expr_with_lvalue_pref(check_env, fcx, lhs_expr, PreferMutLvalue); + check_expr(check_env, fcx, rhs_expr); - let lhs_ty = structurally_resolved_type(fcx, lhs_expr.span, fcx.expr_ty(lhs_expr)); - let rhs_ty = structurally_resolved_type(fcx, rhs_expr.span, fcx.expr_ty(rhs_expr)); + let expr_ty = fcx.expr_ty(&check_env.tt.node_types, lhs_expr); + let lhs_ty = structurally_resolved_type(check_env, fcx, lhs_expr.span, expr_ty); + let expr_ty = fcx.expr_ty(&check_env.tt.node_types, rhs_expr); + let rhs_ty = structurally_resolved_type(check_env, fcx, rhs_expr.span, expr_ty); if is_builtin_binop(fcx.tcx(), lhs_ty, rhs_ty, op) { enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); - fcx.write_nil(expr.id); + fcx.write_nil(check_env, expr.id); } else { // error types are considered "builtin" assert!(!ty::type_is_error(lhs_ty) || !ty::type_is_error(rhs_ty)); @@ -53,7 +57,7 @@ pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, ast_util::binop_to_string(op.node), lhs_ty.user_string(fcx.tcx()), rhs_ty.user_string(fcx.tcx())); - fcx.write_error(expr.id); + fcx.write_error(check_env, expr.id); } let tcx = fcx.tcx(); @@ -61,11 +65,12 @@ pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, span_err!(tcx.sess, lhs_expr.span, E0067, "illegal left-hand side expression"); } - fcx.require_expr_have_sized_type(lhs_expr, traits::AssignmentLhsSized); + fcx.require_expr_have_sized_type(check_env, lhs_expr, traits::AssignmentLhsSized); } /// Check a potentially overloaded binary operator. -pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn check_binop<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx ast::Expr, op: ast::BinOp, lhs_expr: &'tcx ast::Expr, @@ -80,18 +85,20 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, lhs_expr.repr(tcx), rhs_expr.repr(tcx)); - check_expr(fcx, lhs_expr); - let lhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr)); + check_expr(check_env, fcx, lhs_expr); + let expr_ty = fcx.expr_ty(&check_env.tt.node_types, lhs_expr); + let lhs_ty = fcx.resolve_type_vars_if_possible(check_env, expr_ty); // Annoyingly, SIMD ops don't fit into the PartialEq/PartialOrd // traits, because their return type is not bool. Perhaps this // should change, but for now if LHS is SIMD we go down a // different path that bypassess all traits. if ty::type_is_simd(fcx.tcx(), lhs_ty) { - check_expr_coercable_to_type(fcx, rhs_expr, lhs_ty); - let rhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr)); + check_expr_coercable_to_type(check_env, fcx, rhs_expr, lhs_ty); + let expr_ty = fcx.expr_ty(&check_env.tt.node_types, lhs_expr); + let rhs_ty = fcx.resolve_type_vars_if_possible(check_env, expr_ty); let return_ty = enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); - fcx.write_ty(expr.id, return_ty); + fcx.write_ty(check_env, expr.id, return_ty); return; } @@ -99,15 +106,15 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, BinOpCategory::Shortcircuit => { // && and || are a simple case. demand::suptype(fcx, lhs_expr.span, ty::mk_bool(tcx), lhs_ty); - check_expr_coercable_to_type(fcx, rhs_expr, ty::mk_bool(tcx)); - fcx.write_ty(expr.id, ty::mk_bool(tcx)); + check_expr_coercable_to_type(check_env, fcx, rhs_expr, ty::mk_bool(tcx)); + fcx.write_ty(check_env, expr.id, ty::mk_bool(tcx)); } _ => { // Otherwise, we always treat operators as if they are // overloaded. This is the way to be most flexible w/r/t // types that get inferred. let (rhs_ty, return_ty) = - check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op); + check_overloaded_binop(check_env, fcx, expr, lhs_expr, lhs_ty, rhs_expr, op); // Supply type inference hints if relevant. Probably these // hints should be enforced during select as part of the @@ -121,7 +128,7 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // deduce that the result type should be `u32`, even // though we don't know yet what type 2 has and hence // can't pin this down to a specific impl. - let rhs_ty = fcx.resolve_type_vars_if_possible(rhs_ty); + let rhs_ty = fcx.resolve_type_vars_if_possible(check_env, rhs_ty); if !ty::type_is_ty_var(lhs_ty) && !ty::type_is_ty_var(rhs_ty) && @@ -132,7 +139,7 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, demand::suptype(fcx, expr.span, builtin_return_ty, return_ty); } - fcx.write_ty(expr.id, return_ty); + fcx.write_ty(check_env, expr.id, return_ty); } } } @@ -201,7 +208,8 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } -fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn check_overloaded_binop<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx ast::Expr, lhs_expr: &'tcx ast::Expr, lhs_ty: Ty<'tcx>, @@ -223,7 +231,8 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // particularly for things like `String + &String`. let rhs_ty_var = fcx.infcx().next_ty_var(); - let return_ty = match lookup_op_method(fcx, expr, lhs_ty, vec![rhs_ty_var], + let return_ty = match lookup_op_method(check_env, fcx, + expr, lhs_ty, vec![rhs_ty_var], token::intern(name), trait_def_id, lhs_expr) { Ok(return_ty) => return_ty, @@ -240,12 +249,13 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }; // see `NB` above - check_expr_coercable_to_type(fcx, rhs_expr, rhs_ty_var); + check_expr_coercable_to_type(check_env, fcx, rhs_expr, rhs_ty_var); (rhs_ty_var, return_ty) } -pub fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn check_user_unop<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, op_str: &str, mname: &str, trait_did: Option, @@ -256,7 +266,8 @@ pub fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, -> Ty<'tcx> { assert!(ast_util::is_by_value_unop(op)); - match lookup_op_method(fcx, ex, operand_ty, vec![], + match lookup_op_method(check_env, fcx, + ex, operand_ty, vec![], token::intern(mname), trait_did, operand_expr) { Ok(t) => t, @@ -295,7 +306,8 @@ fn name_and_trait_def_id(fcx: &FnCtxt, op: ast::BinOp) -> (&'static str, Option< } } -fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, +fn lookup_op_method<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &'a FnCtxt<'a, 'tcx>, expr: &'tcx ast::Expr, lhs_ty: Ty<'tcx>, other_tys: Vec>, @@ -313,7 +325,8 @@ fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, let method = match trait_did { Some(trait_did) => { - method::lookup_in_trait_adjusted(fcx, + method::lookup_in_trait_adjusted(check_env, + fcx, expr.span, Some(lhs_expr), opname, @@ -332,7 +345,7 @@ fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, // HACK(eddyb) Fully qualified path to work around a resolve bug. let method_call = ::middle::ty::MethodCall::expr(expr.id); - fcx.inh.method_map.borrow_mut().insert(method_call, method); + check_env.tt.method_map.insert(method_call, method); // extract return type for method; all late bound regions // should have been instantiated by now diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 19cb570c82d13..7d63528060067 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -83,9 +83,12 @@ //! contents. use astconv::AstConv; -use check::dropck; -use check::FnCtxt; -use check::vtable; +use super::dropck; +use super::CheckEnv; +use super::FnCtxt; +use super::FnCtxtTyper; +use super::FnCtxtJoined; +use super::vtable; use middle::free_region::FreeRegionMap; use middle::implicator; use middle::mem_categorization as mc; @@ -113,8 +116,9 @@ macro_rules! ignore_err { /////////////////////////////////////////////////////////////////////////// // PUBLIC ENTRY POINTS -pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { - let mut rcx = Rcx::new(fcx, RepeatingScope(e.id), e.id, Subject(e.id)); +pub fn regionck_expr<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, e: &ast::Expr) { + let mut rcx = Rcx::new(check_env, fcx, RepeatingScope(e.id), e.id, Subject(e.id)); if fcx.err_count_since_creation() == 0 { // regionck assumes typeck succeeded rcx.visit_expr(e); @@ -123,21 +127,23 @@ pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { rcx.resolve_regions_and_report_errors(); } -pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) { - let mut rcx = Rcx::new(fcx, RepeatingScope(item.id), item.id, Subject(item.id)); +pub fn regionck_item<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, item: &ast::Item) { + let mut rcx = Rcx::new(check_env, fcx, RepeatingScope(item.id), item.id, Subject(item.id)); let tcx = fcx.tcx(); rcx.free_region_map.relate_free_regions_from_predicates(tcx, &fcx.inh.param_env.caller_bounds); rcx.visit_region_obligations(item.id); rcx.resolve_regions_and_report_errors(); } -pub fn regionck_fn(fcx: &FnCtxt, - fn_id: ast::NodeId, - fn_span: Span, - decl: &ast::FnDecl, - blk: &ast::Block) { +pub fn regionck_fn<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, + fn_id: ast::NodeId, + fn_span: Span, + decl: &ast::FnDecl, + blk: &ast::Block) { debug!("regionck_fn(id={})", fn_id); - let mut rcx = Rcx::new(fcx, RepeatingScope(blk.id), blk.id, Subject(fn_id)); + let mut rcx = Rcx::new(check_env, fcx, RepeatingScope(blk.id), blk.id, Subject(fn_id)); if fcx.err_count_since_creation() == 0 { // regionck assumes typeck succeeded @@ -157,10 +163,11 @@ pub fn regionck_fn(fcx: &FnCtxt, /// Checks that the types in `component_tys` are well-formed. This will add constraints into the /// region graph. Does *not* run `resolve_regions_and_report_errors` and so forth. -pub fn regionck_ensure_component_tys_wf<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn regionck_ensure_component_tys_wf<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, component_tys: &[Ty<'tcx>]) { - let mut rcx = Rcx::new(fcx, RepeatingScope(0), 0, SubjectNode::None); + let mut rcx = Rcx::new(check_env, fcx, RepeatingScope(0), 0, SubjectNode::None); for &component_ty in component_tys { // Check that each type outlives the empty region. Since the // empty region is a subregion of all others, this can't fail @@ -175,6 +182,8 @@ pub fn regionck_ensure_component_tys_wf<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // INTERNALS pub struct Rcx<'a, 'tcx: 'a> { + check_env: &'a mut CheckEnv<'tcx>, + fcx: &'a FnCtxt<'a, 'tcx>, region_bound_pairs: Vec<(ty::Region, GenericKind<'tcx>)>, @@ -195,13 +204,111 @@ pub struct Rcx<'a, 'tcx: 'a> { pub struct RepeatingScope(ast::NodeId); pub enum SubjectNode { Subject(ast::NodeId), None } +/// Try to resolve the type for the given node, returning t_err if an error results. Note that +/// we never care about the details of the error, the same error will be detected and reported +/// in the writeback phase. +/// +/// Note one important point: we do not attempt to resolve *region variables* here. This is +/// because regionck is essentially adding constraints to those region variables and so may yet +/// influence how they are resolved. +/// +/// Consider this silly example: +/// +/// ``` +/// fn borrow(x: &int) -> &int {x} +/// fn foo(x: @int) -> int { // block: B +/// let b = borrow(x); // region: +/// *b +/// } +/// ``` +/// +/// Here, the region of `b` will be ``. `` is constrained to be some subregion of the +/// block B and some superregion of the call. If we forced it now, we'd choose the smaller +/// region (the call). But that would make the *b illegal. Since we don't resolve, the type +/// of b will be `&.int` and then `*b` will require that `` be bigger than the let and +/// the `*b` expression, so we will effectively resolve `` to be the block B. +fn resolve_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> { + fcx.infcx().resolve_type_vars_if_possible(&unresolved_ty) +} + +/// This method populates the region map's `free_region_map`. It walks over the transformed +/// argument and return types for each function just before we check the body of that function, +/// looking for types where you have a borrowed pointer to other borrowed data (e.g., `&'a &'b +/// [usize]`. We do not allow references to outlive the things they point at, so we can assume +/// that `'a <= 'b`. This holds for both the argument and return types, basically because, on +/// the caller side, the caller is responsible for checking that the type of every expression +/// (including the actual values for the arguments, as well as the return type of the fn call) +/// is well-formed. +/// +/// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs` +fn relate_free_regions<'a, 'tcx>(check_env: &CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, + tcx: &ty::ctxt<'tcx>, + free_region_map: &mut FreeRegionMap, + region_bound_pairs: &mut Vec<(ty::Region, GenericKind<'tcx>)>, + fn_sig_tys: &[Ty<'tcx>], + body_id: ast::NodeId, + span: Span) { + debug!("relate_free_regions >>"); + + for &ty in fn_sig_tys { + let ty = resolve_type(fcx, ty); + debug!("relate_free_regions(t={})", ty.repr(tcx)); + let body_scope = CodeExtent::from_node_id(body_id); + let body_scope = ty::ReScope(body_scope); + let typer = FnCtxtTyper::new(&check_env.tt, fcx); + let implications = implicator::implications(fcx.infcx(), &typer, body_id, + ty, body_scope, span); + + // Record any relations between free regions that we observe into the free-region-map. + free_region_map.relate_free_regions_from_implications(tcx, &implications); + + // But also record other relationships, such as `T:'x`, + // that don't go into the free-region-map but which we use + // here. + for implication in implications { + debug!("implication: {}", implication.repr(tcx)); + match implication { + implicator::Implication::RegionSubRegion(_, + ty::ReFree(free_a), + ty::ReInfer(ty::ReVar(vid_b))) => { + fcx.inh.infcx.add_given(free_a, vid_b); + } + implicator::Implication::RegionSubGeneric(_, r_a, ref generic_b) => { + debug!("RegionSubGeneric: {} <= {}", + r_a.repr(tcx), generic_b.repr(tcx)); + + region_bound_pairs.push((r_a, generic_b.clone())); + } + implicator::Implication::RegionSubRegion(..) | + implicator::Implication::RegionSubClosure(..) | + implicator::Implication::Predicate(..) => { + // In principle, we could record (and take + // advantage of) every relationship here, but + // we are also free not to -- it simply means + // strictly less that we can successfully type + // check. (It may also be that we should + // revise our inference system to be more + // general and to make use of *every* + // relationship that arises here, but + // presently we do not.) + } + } + } + } + + debug!("<< relate_free_regions"); +} + impl<'a, 'tcx> Rcx<'a, 'tcx> { - pub fn new(fcx: &'a FnCtxt<'a, 'tcx>, - initial_repeating_scope: RepeatingScope, - initial_body_id: ast::NodeId, - subject: SubjectNode) -> Rcx<'a, 'tcx> { + fn new(check_env: &'a mut CheckEnv<'tcx>, + fcx: &'a FnCtxt<'a, 'tcx>, + initial_repeating_scope: RepeatingScope, + initial_body_id: ast::NodeId, + subject: SubjectNode) -> Rcx<'a, 'tcx>{ let RepeatingScope(initial_repeating_scope) = initial_repeating_scope; - Rcx { fcx: fcx, + Rcx { check_env: check_env, + fcx: fcx, repeating_scope: initial_repeating_scope, body_id: initial_body_id, subject: subject, @@ -222,54 +329,27 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { mem::replace(&mut self.repeating_scope, scope) } - /// Try to resolve the type for the given node, returning t_err if an error results. Note that - /// we never care about the details of the error, the same error will be detected and reported - /// in the writeback phase. - /// - /// Note one important point: we do not attempt to resolve *region variables* here. This is - /// because regionck is essentially adding constraints to those region variables and so may yet - /// influence how they are resolved. - /// - /// Consider this silly example: - /// - /// ``` - /// fn borrow(x: &int) -> &int {x} - /// fn foo(x: @int) -> int { // block: B - /// let b = borrow(x); // region: - /// *b - /// } - /// ``` - /// - /// Here, the region of `b` will be ``. `` is constrained to be some subregion of the - /// block B and some superregion of the call. If we forced it now, we'd choose the smaller - /// region (the call). But that would make the *b illegal. Since we don't resolve, the type - /// of b will be `&.int` and then `*b` will require that `` be bigger than the let and - /// the `*b` expression, so we will effectively resolve `` to be the block B. - pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> { - self.fcx.infcx().resolve_type_vars_if_possible(&unresolved_ty) - } - /// Try to resolve the type for the given node. fn resolve_node_type(&self, id: ast::NodeId) -> Ty<'tcx> { - let t = self.fcx.node_ty(id); - self.resolve_type(t) + let t = self.fcx.node_ty(&self.check_env.tt.node_types, id); + resolve_type(self.fcx, t) } fn resolve_method_type(&self, method_call: MethodCall) -> Option> { - let method_ty = self.fcx.inh.method_map.borrow() + let method_ty = self.check_env.tt.method_map .get(&method_call).map(|method| method.ty); - method_ty.map(|method_ty| self.resolve_type(method_ty)) + method_ty.map(|method_ty| resolve_type(self.fcx, method_ty)) } /// Try to resolve the type for the given node. - pub fn resolve_expr_type_adjusted(&mut self, expr: &ast::Expr) -> Ty<'tcx> { + fn resolve_expr_type_adjusted(&mut self, expr: &ast::Expr) -> Ty<'tcx> { let ty_unadjusted = self.resolve_node_type(expr.id); if ty::type_is_error(ty_unadjusted) { ty_unadjusted } else { let tcx = self.fcx.tcx(); ty::adjust_ty(tcx, expr.span, expr.id, ty_unadjusted, - self.fcx.inh.adjustments.borrow().get(&expr.id), + self.check_env.tt.adjustments.get(&expr.id), |method_call| self.resolve_method_type(method_call)) } } @@ -280,22 +360,26 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { body: &ast::Block, span: Span) { + // When we enter a function, we can derive debug!("visit_fn_body(id={})", id); - let fn_sig_map = self.fcx.inh.fn_sig_map.borrow(); - let fn_sig = match fn_sig_map.get(&id) { - Some(f) => f, + let old_region_bounds_pairs_len = self.region_bound_pairs.len(); + + let old_body_id = self.set_body_id(body.id); + + match self.check_env.fn_sig_map.get(&id) { + Some(fn_sig) => { + relate_free_regions(self.check_env, self.fcx, self.tcx(), + &mut self.free_region_map, &mut self.region_bound_pairs, + &fn_sig[..], body.id, span); + }, None => { self.tcx().sess.bug( &format!("No fn-sig entry for id={}", id)); } }; - let old_region_bounds_pairs_len = self.region_bound_pairs.len(); - - let old_body_id = self.set_body_id(body.id); - self.relate_free_regions(&fn_sig[..], body.id, span); link_fn_args(self, CodeExtent::from_node_id(body.id), &fn_decl.inputs[..]); self.visit_block(body); self.visit_region_obligations(body.id); @@ -312,91 +396,24 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { // region checking can introduce new pending obligations // which, when processed, might generate new region // obligations. So make sure we process those. - vtable::select_all_fcx_obligations_or_error(self.fcx); + vtable::select_all_fcx_obligations_or_error(self.check_env, self.fcx); // Make a copy of the region obligations vec because we'll need // to be able to borrow the fulfillment-cx below when projecting. let region_obligations = - self.fcx.inh.fulfillment_cx.borrow() - .region_obligations(node_id) - .to_vec(); + self.check_env.fulfillment_cx.region_obligations(node_id).to_vec(); for r_o in ®ion_obligations { debug!("visit_region_obligations: r_o={}", r_o.repr(self.tcx())); - let sup_type = self.resolve_type(r_o.sup_type); + let sup_type = resolve_type(self.fcx, r_o.sup_type); let origin = infer::RelateParamBound(r_o.cause.span, sup_type); type_must_outlive(self, origin, sup_type, r_o.sub_region); } // Processing the region obligations should not cause the list to grow further: assert_eq!(region_obligations.len(), - self.fcx.inh.fulfillment_cx.borrow().region_obligations(node_id).len()); - } - - /// This method populates the region map's `free_region_map`. It walks over the transformed - /// argument and return types for each function just before we check the body of that function, - /// looking for types where you have a borrowed pointer to other borrowed data (e.g., `&'a &'b - /// [usize]`. We do not allow references to outlive the things they point at, so we can assume - /// that `'a <= 'b`. This holds for both the argument and return types, basically because, on - /// the caller side, the caller is responsible for checking that the type of every expression - /// (including the actual values for the arguments, as well as the return type of the fn call) - /// is well-formed. - /// - /// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs` - fn relate_free_regions(&mut self, - fn_sig_tys: &[Ty<'tcx>], - body_id: ast::NodeId, - span: Span) { - debug!("relate_free_regions >>"); - let tcx = self.tcx(); - - for &ty in fn_sig_tys { - let ty = self.resolve_type(ty); - debug!("relate_free_regions(t={})", ty.repr(tcx)); - let body_scope = CodeExtent::from_node_id(body_id); - let body_scope = ty::ReScope(body_scope); - let implications = implicator::implications(self.fcx.infcx(), self.fcx, body_id, - ty, body_scope, span); - - // Record any relations between free regions that we observe into the free-region-map. - self.free_region_map.relate_free_regions_from_implications(tcx, &implications); - - // But also record other relationships, such as `T:'x`, - // that don't go into the free-region-map but which we use - // here. - for implication in implications { - debug!("implication: {}", implication.repr(tcx)); - match implication { - implicator::Implication::RegionSubRegion(_, - ty::ReFree(free_a), - ty::ReInfer(ty::ReVar(vid_b))) => { - self.fcx.inh.infcx.add_given(free_a, vid_b); - } - implicator::Implication::RegionSubGeneric(_, r_a, ref generic_b) => { - debug!("RegionSubGeneric: {} <= {}", - r_a.repr(tcx), generic_b.repr(tcx)); - - self.region_bound_pairs.push((r_a, generic_b.clone())); - } - implicator::Implication::RegionSubRegion(..) | - implicator::Implication::RegionSubClosure(..) | - implicator::Implication::Predicate(..) => { - // In principle, we could record (and take - // advantage of) every relationship here, but - // we are also free not to -- it simply means - // strictly less that we can successfully type - // check. (It may also be that we should - // revise our inference system to be more - // general and to make use of *every* - // relationship that arises here, but - // presently we do not.) - } - } - } - } - - debug!("<< relate_free_regions"); + self.check_env.fulfillment_cx.region_obligations(node_id).len()); } fn resolve_regions_and_report_errors(&self) { @@ -514,17 +531,20 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { expr_ty, ty::ReScope(CodeExtent::from_node_id(expr.id))); let method_call = MethodCall::expr(expr.id); - let has_method_map = rcx.fcx.inh.method_map.borrow().contains_key(&method_call); + let has_method_map = rcx.check_env.tt.method_map.contains_key(&method_call); // Check any autoderefs or autorefs that appear. - if let Some(adjustment) = rcx.fcx.inh.adjustments.borrow().get(&expr.id) { + let adjustment = { + rcx.check_env.tt.adjustments.get(&expr.id).map( |&adj| adj ) + }; + if let Some(adjustment) = adjustment { debug!("adjustment={:?}", adjustment); - match *adjustment { - ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, ref autoref, ..}) => { + match adjustment { + ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, autoref, ..}) => { let expr_ty = rcx.resolve_node_type(expr.id); constrain_autoderefs(rcx, expr, autoderefs, expr_ty); - if let Some(ref autoref) = *autoref { - link_autoref(rcx, expr, autoderefs, autoref); + if let Some(autoref) = autoref { + link_autoref(rcx, expr, autoderefs, &autoref); // Require that the resulting region encompasses // the current node. @@ -551,7 +571,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // If necessary, constrain destructors in the unadjusted form of this // expression. let cmt_result = { - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let typer = FnCtxtTyper::new(&rcx.check_env.tt, rcx.fcx); + let mc = mc::MemCategorizationContext::new(&typer); mc.cat_expr_unadjusted(expr) }; match cmt_result { @@ -570,7 +591,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // If necessary, constrain destructors in this expression. This will be // the adjusted form if there is an adjustment. let cmt_result = { - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let typer = FnCtxtTyper::new(&rcx.check_env.tt, rcx.fcx); + let mc = mc::MemCategorizationContext::new(&typer); mc.cat_expr(expr) }; match cmt_result { @@ -660,12 +682,13 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { ast::ExprUnary(ast::UnDeref, ref base) => { // For *a, the lifetime of a must enclose the deref let method_call = MethodCall::expr(expr.id); - let base_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) { - Some(method) => { + let method_ty = rcx.check_env.tt.method_map.get(&method_call).map( |method| method.ty ); + let base_ty = match method_ty { + Some(method_ty) => { constrain_call(rcx, expr, Some(&**base), None::.iter(), true); let fn_ret = // late-bound regions in overloaded method calls are instantiated - ty::no_late_bound_regions(rcx.tcx(), &ty::ty_fn_ret(method.ty)).unwrap(); + ty::no_late_bound_regions(rcx.tcx(), &ty::ty_fn_ret(method_ty)).unwrap(); fn_ret.unwrap() } None => rcx.resolve_node_type(base.id) @@ -888,7 +911,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, let method_call = MethodCall::autoderef(deref_expr.id, i as u32); debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs); - derefd_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) { + let result = match rcx.check_env.tt.method_map.get(&method_call) { Some(method) => { debug!("constrain_autoderefs: #{} is overloaded, method={}", i, method.repr(rcx.tcx())); @@ -912,29 +935,30 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, debug!("constrain_autoderefs: receiver r={:?} m={:?}", r.repr(rcx.tcx()), m); - { - let mc = mc::MemCategorizationContext::new(rcx.fcx); - let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i)); - debug!("constrain_autoderefs: self_cmt={:?}", - self_cmt.repr(rcx.tcx())); - link_region(rcx, deref_expr.span, r, - ty::BorrowKind::from_mutbl(m), self_cmt); - } - - // Specialized version of constrain_call. - type_must_outlive(rcx, infer::CallRcvr(deref_expr.span), - self_ty, r_deref_expr); - match fn_sig.output { - ty::FnConverging(return_type) => { - type_must_outlive(rcx, infer::CallReturn(deref_expr.span), - return_type, r_deref_expr); - return_type - } - ty::FnDiverging => unreachable!() - } + let typer = FnCtxtTyper::new(&rcx.check_env.tt, rcx.fcx); + let mc = mc::MemCategorizationContext::new(&typer); + let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i)); + debug!("constrain_autoderefs: self_cmt={:?}", + self_cmt.repr(rcx.tcx())); + link_region(rcx, deref_expr.span, r, + ty::BorrowKind::from_mutbl(m), self_cmt); + Some((fn_sig, self_ty)) } - None => derefd_ty + None => None }; + if let Some((fn_sig, self_ty)) = result { + // Specialized version of constrain_call. + type_must_outlive(rcx, infer::CallRcvr(deref_expr.span), + self_ty, r_deref_expr); + derefd_ty = match fn_sig.output { + ty::FnConverging(return_type) => { + type_must_outlive(rcx, infer::CallReturn(deref_expr.span), + return_type, r_deref_expr); + return_type + } + ty::FnDiverging => unreachable!() + }; + } if let ty::ty_rptr(r_ptr, _) = derefd_ty.sty { mk_subregion_due_to_dereference(rcx, deref_expr.span, @@ -965,7 +989,7 @@ fn check_safety_of_rvalue_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 't mc::cat_rvalue(region) => { match region { ty::ReScope(rvalue_scope) => { - let typ = rcx.resolve_type(cmt.ty); + let typ = resolve_type(rcx.fcx, cmt.ty); dropck::check_safety_of_destructor_if_necessary(rcx, typ, span, @@ -1022,7 +1046,7 @@ fn type_of_node_must_outlive<'a, 'tcx>( // report errors later on in the writeback phase. let ty0 = rcx.resolve_node_type(id); let ty = ty::adjust_ty(tcx, origin.span(), id, ty0, - rcx.fcx.inh.adjustments.borrow().get(&id), + rcx.check_env.tt.adjustments.get(&id), |method_call| rcx.resolve_method_type(method_call)); debug!("constrain_regions_in_type_of_node(\ ty={}, ty0={}, id={}, minimum_lifetime={:?})", @@ -1038,7 +1062,8 @@ fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr, debug!("link_addr_of(expr={}, base={})", expr.repr(rcx.tcx()), base.repr(rcx.tcx())); let cmt = { - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let typer = FnCtxtTyper::new(&rcx.check_env.tt, rcx.fcx); + let mc = mc::MemCategorizationContext::new(&typer); ignore_err!(mc.cat_expr(base)) }; @@ -1056,7 +1081,8 @@ fn link_local(rcx: &Rcx, local: &ast::Local) { None => { return; } Some(ref expr) => &**expr, }; - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let typer = FnCtxtTyper::new(&rcx.check_env.tt, rcx.fcx); + let mc = mc::MemCategorizationContext::new(&typer); let discr_cmt = ignore_err!(mc.cat_expr(init_expr)); link_pattern(rcx, mc, discr_cmt, &*local.pat); } @@ -1066,7 +1092,8 @@ fn link_local(rcx: &Rcx, local: &ast::Local) { /// linked to the lifetime of its guarantor (if any). fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) { debug!("regionck::for_match()"); - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let typer = FnCtxtTyper::new(&rcx.check_env.tt, rcx.fcx); + let mc = mc::MemCategorizationContext::new(&typer); let discr_cmt = ignore_err!(mc.cat_expr(discr)); debug!("discr_cmt={}", discr_cmt.repr(rcx.tcx())); for arm in arms { @@ -1081,9 +1108,10 @@ fn link_match(rcx: &Rcx, discr: &ast::Expr, arms: &[ast::Arm]) { /// linked to the lifetime of its guarantor (if any). fn link_fn_args(rcx: &Rcx, body_scope: CodeExtent, args: &[ast::Arg]) { debug!("regionck::link_fn_args(body_scope={:?})", body_scope); - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let typer = FnCtxtTyper::new(&rcx.check_env.tt, rcx.fcx); + let mc = mc::MemCategorizationContext::new(&typer); for arg in args { - let arg_ty = rcx.fcx.node_ty(arg.id); + let arg_ty = rcx.fcx.node_ty(&rcx.check_env.tt.node_types, arg.id); let re_scope = ty::ReScope(body_scope); let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty); debug!("arg_ty={} arg_cmt={}", @@ -1096,7 +1124,7 @@ fn link_fn_args(rcx: &Rcx, body_scope: CodeExtent, args: &[ast::Arg]) { /// Link lifetimes of any ref bindings in `root_pat` to the pointers found in the discriminant, if /// needed. fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, - mc: mc::MemCategorizationContext>, + mc: mc::MemCategorizationContext>, discr_cmt: mc::cmt<'tcx>, root_pat: &ast::Pat) { debug!("link_pattern(discr_cmt={}, root_pat={})", @@ -1135,7 +1163,8 @@ fn link_autoref(rcx: &Rcx, autoref: &ty::AutoRef) { debug!("link_autoref(autoref={:?})", autoref); - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let typer = FnCtxtTyper::new(&rcx.check_env.tt, rcx.fcx); + let mc = mc::MemCategorizationContext::new(&typer); let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs)); debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx())); @@ -1160,7 +1189,8 @@ fn link_by_ref(rcx: &Rcx, let tcx = rcx.tcx(); debug!("link_by_ref(expr={}, callee_scope={:?})", expr.repr(tcx), callee_scope); - let mc = mc::MemCategorizationContext::new(rcx.fcx); + let typer = FnCtxtTyper::new(&rcx.check_env.tt, rcx.fcx); + let mc = mc::MemCategorizationContext::new(&typer); let expr_cmt = ignore_err!(mc.cat_expr(expr)); let borrow_region = ty::ReScope(callee_scope); link_region(rcx, expr.span, &borrow_region, ty::ImmBorrow, expr_cmt); @@ -1406,8 +1436,11 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, ty.repr(rcx.tcx()), region.repr(rcx.tcx())); - let implications = implicator::implications(rcx.fcx.infcx(), rcx.fcx, rcx.body_id, - ty, region, origin.span()); + let implications = { + let typer = FnCtxtTyper::new(&rcx.check_env.tt, rcx.fcx); + implicator::implications(rcx.fcx.infcx(), &typer, rcx.body_id, + ty, region, origin.span()) + }; for implication in implications { debug!("implication: {}", implication.repr(rcx.tcx())); match implication { @@ -1433,7 +1466,7 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, rcx.body_id, traits::ItemObligation(def_id)); let obligation = traits::Obligation::new(cause, predicate); - rcx.fcx.register_predicate(obligation); + rcx.fcx.register_predicate(rcx.check_env, obligation); } } } @@ -1447,7 +1480,10 @@ fn closure_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, debug!("closure_must_outlive(region={}, def_id={}, substs={})", region.repr(rcx.tcx()), def_id.repr(rcx.tcx()), substs.repr(rcx.tcx())); - let upvars = rcx.fcx.closure_upvars(def_id, substs).unwrap(); + let upvars = { + let typer = FnCtxtTyper::new(&rcx.check_env.tt, rcx.fcx); + typer.closure_upvars(def_id, substs).unwrap() + }; for upvar in upvars { let var_id = upvar.def.def_id().local_id(); type_must_outlive( @@ -1456,7 +1492,7 @@ fn closure_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, } } -fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, +fn generic_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, origin: infer::SubregionOrigin<'tcx>, region: ty::Region, generic: &GenericKind<'tcx>) { @@ -1513,7 +1549,7 @@ fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, param_bounds); } -fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>, +fn projection_bounds<'a,'tcx>(rcx: &mut Rcx<'a, 'tcx>, span: Span, projection_ty: &ty::ProjectionTy<'tcx>) -> Vec @@ -1551,9 +1587,10 @@ fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>, outlives.repr(tcx)); // apply the substitutions (and normalize any projected types) - let outlives = fcx.instantiate_type_scheme(span, - projection_ty.trait_ref.substs, - &outlives); + let mut joined = FnCtxtJoined::new(rcx.check_env, fcx); + let outlives = joined.instantiate_type_scheme(span, + projection_ty.trait_ref.substs, + &outlives); debug!("projection_bounds: outlives={} (2)", outlives.repr(tcx)); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 340cca7d47e7a..02cbe9e13a148 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -40,7 +40,7 @@ //! then mean that all later passes would have to check for these figments //! and report an error, and it just seems like more mess in the end.) -use super::FnCtxt; +use super::{CheckEnv, FnCtxt, FnCtxtTyper}; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; @@ -56,20 +56,21 @@ use util::ppaux::Repr; /////////////////////////////////////////////////////////////////////////// // PUBLIC ENTRY POINTS -pub fn closure_analyze_fn(fcx: &FnCtxt, - _id: ast::NodeId, - _decl: &ast::FnDecl, - body: &ast::Block) +pub fn closure_analyze_fn<'a,'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a,'tcx>, + _id: ast::NodeId, + _decl: &ast::FnDecl, + body: &ast::Block) { let mut seed = SeedBorrowKind::new(fcx); seed.visit_block(body); let closures_with_inferred_kinds = seed.closures_with_inferred_kinds; - let mut adjust = AdjustBorrowKind::new(fcx, &closures_with_inferred_kinds); + let mut adjust = AdjustBorrowKind::new(check_env, fcx, &closures_with_inferred_kinds); adjust.visit_block(body); // it's our job to process these. - assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty()); + assert!(adjust.check_env.deferred_call_resolutions.is_empty()); } /////////////////////////////////////////////////////////////////////////// @@ -167,81 +168,21 @@ impl<'a,'tcx> SeedBorrowKind<'a,'tcx> { // ADJUST BORROW KIND struct AdjustBorrowKind<'a,'tcx:'a> { + check_env: &'a mut CheckEnv<'tcx>, fcx: &'a FnCtxt<'a,'tcx>, closures_with_inferred_kinds: &'a HashSet, } -impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { - fn new(fcx: &'a FnCtxt<'a,'tcx>, - closures_with_inferred_kinds: &'a HashSet) - -> AdjustBorrowKind<'a,'tcx> { - AdjustBorrowKind { fcx: fcx, closures_with_inferred_kinds: closures_with_inferred_kinds } - } +struct AdjustBorrowDelegate<'a,'tcx:'a> { + fcx: &'a FnCtxt<'a,'tcx>, + closures_with_inferred_kinds: &'a HashSet, +} +impl<'a,'tcx> AdjustBorrowDelegate<'a,'tcx> { fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fcx.tcx() } - - fn analyze_closure(&mut self, id: ast::NodeId, decl: &ast::FnDecl, body: &ast::Block) { - /*! - * Analysis starting point. - */ - - self.visit_block(body); - - debug!("analyzing closure `{}` with fn body id `{}`", id, body.id); - - let mut euv = euv::ExprUseVisitor::new(self, self.fcx); - euv.walk_fn(decl, body); - - // If we had not yet settled on a closure kind for this closure, - // then we should have by now. Process and remove any deferred resolutions. - // - // Interesting fact: all calls to this closure must come - // *after* its definition. Initially, I thought that some - // kind of fixed-point iteration would be required, due to the - // possibility of twisted examples like this one: - // - // ```rust - // let mut closure0 = None; - // let vec = vec!(1, 2, 3); - // - // loop { - // { - // let closure1 = || { - // match closure0.take() { - // Some(c) => { - // return c(); // (*) call to `closure0` before it is defined - // } - // None => { } - // } - // }; - // closure1(); - // } - // - // closure0 = || vec; - // } - // ``` - // - // However, this turns out to be wrong. Examples like this - // fail to compile because the type of the variable `c` above - // is an inference variable. And in fact since closure types - // cannot be written, there is no way to make this example - // work without a boxed closure. This implies that we can't - // have two closures that recursively call one another without - // some form of boxing (and hence explicit writing of a - // closure kind) involved. Huzzah. -nmatsakis - let closure_def_id = ast_util::local_def(id); - if self.closures_with_inferred_kinds.contains(&id) { - let mut deferred_call_resolutions = - self.fcx.remove_deferred_call_resolutions(closure_def_id); - for deferred_call_resolution in deferred_call_resolutions.iter_mut() { - deferred_call_resolution.resolve(self.fcx); - } - } - } - - fn adjust_upvar_borrow_kind_for_consume(&self, + fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) { @@ -329,7 +270,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { } } - fn adjust_upvar_borrow_kind_for_unique(&self, cmt: mc::cmt<'tcx>) { + fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) { debug!("adjust_upvar_borrow_kind_for_unique(cmt={})", cmt.repr(self.tcx())); @@ -360,7 +301,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { } } - fn try_adjust_upvar_deref(&self, + fn try_adjust_upvar_deref(&mut self, note: &mc::Note, borrow_kind: ty::BorrowKind) -> bool @@ -402,11 +343,12 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { } } + /// We infer the borrow_kind with which to borrow upvars in a stack closure. The borrow_kind /// basically follows a lattice of `imm < unique-imm < mut`, moving from left to right as needed /// (but never right to left). Here the argument `mutbl` is the borrow_kind that is required by /// some particular use. - fn adjust_upvar_borrow_kind(&self, + fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, upvar_capture: &mut ty::UpvarCapture, kind: ty::BorrowKind) { @@ -436,7 +378,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { } } - fn adjust_closure_kind(&self, + fn adjust_closure_kind(&mut self, closure_id: ast::NodeId, new_kind: ty::ClosureKind) { debug!("adjust_closure_kind(closure_id={}, new_kind={:?})", @@ -471,6 +413,85 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { } } +impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { + fn new(check_env: &'a mut CheckEnv<'tcx>, + fcx: &'a FnCtxt<'a,'tcx>, + closures_with_inferred_kinds: &'a HashSet) + -> AdjustBorrowKind<'a,'tcx> { + AdjustBorrowKind { + check_env: check_env, + fcx: fcx, + closures_with_inferred_kinds: closures_with_inferred_kinds, + } + } + + fn analyze_closure(&mut self, id: ast::NodeId, decl: &ast::FnDecl, body: &ast::Block) { + /*! + * Analysis starting point. + */ + + self.visit_block(body); + + debug!("analyzing closure `{}` with fn body id `{}`", id, body.id); + + { + let mut delegate = AdjustBorrowDelegate { + fcx: self.fcx, + closures_with_inferred_kinds: self.closures_with_inferred_kinds, + }; + let typer = FnCtxtTyper::new(&self.check_env.tt, self.fcx); + let mut euv = euv::ExprUseVisitor::new(&mut delegate, &typer); + euv.walk_fn(decl, body); + } + + // If we had not yet settled on a closure kind for this closure, + // then we should have by now. Process and remove any deferred resolutions. + // + // Interesting fact: all calls to this closure must come + // *after* its definition. Initially, I thought that some + // kind of fixed-point iteration would be required, due to the + // possibility of twisted examples like this one: + // + // ```rust + // let mut closure0 = None; + // let vec = vec!(1, 2, 3); + // + // loop { + // { + // let closure1 = || { + // match closure0.take() { + // Some(c) => { + // return c(); // (*) call to `closure0` before it is defined + // } + // None => { } + // } + // }; + // closure1(); + // } + // + // closure0 = || vec; + // } + // ``` + // + // However, this turns out to be wrong. Examples like this + // fail to compile because the type of the variable `c` above + // is an inference variable. And in fact since closure types + // cannot be written, there is no way to make this example + // work without a boxed closure. This implies that we can't + // have two closures that recursively call one another without + // some form of boxing (and hence explicit writing of a + // closure kind) involved. Huzzah. -nmatsakis + let closure_def_id = ast_util::local_def(id); + if self.closures_with_inferred_kinds.contains(&id) { + let mut deferred_call_resolutions = + self.check_env.remove_deferred_call_resolutions(closure_def_id); + for deferred_call_resolution in &mut deferred_call_resolutions { + deferred_call_resolution.resolve(self.check_env, self.fcx); + } + } + } +} + impl<'a, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'tcx> { fn visit_fn(&mut self, fn_kind: visit::FnKind<'v>, @@ -491,7 +512,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'tcx> { } } -impl<'a,'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a,'tcx> { +impl<'a,'tcx> euv::Delegate<'tcx> for AdjustBorrowDelegate<'a,'tcx> { fn consume(&mut self, _consume_id: ast::NodeId, _consume_span: Span, diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index a9094fce57c61..112649ba579aa 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use check::FnCtxt; +use super::{CheckEnv, FnCtxt, FnCtxtTyper}; use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode}; use middle::traits::{Obligation, ObligationCause}; use middle::traits::report_fulfillment_errors; @@ -77,7 +77,8 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>, } } -pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +pub fn register_object_cast_obligations<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, span: Span, object_trait: &ty::TyTrait<'tcx>, referent_ty: Ty<'tcx>) @@ -85,6 +86,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, { // We can only make objects from sized types. fcx.register_builtin_bound( + check_env, referent_ty, ty::BoundSized, traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized)); @@ -109,7 +111,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, object_trait.principal_trait_ref_with_self_ty(fcx.tcx(), referent_ty); let object_obligation = Obligation::new(cause.clone(), object_trait_ref.as_predicate()); - fcx.register_predicate(object_obligation); + fcx.register_predicate(check_env, object_obligation); // Create additional obligations for all the various builtin // bounds attached to the object cast. (In other words, if the @@ -117,6 +119,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // for the Send check.) for builtin_bound in &object_trait.bounds.builtin_bounds { fcx.register_builtin_bound( + check_env, referent_ty, builtin_bound, cause.clone()); @@ -128,30 +131,32 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, for projection_bound in &projection_bounds { let projection_obligation = Obligation::new(cause.clone(), projection_bound.as_predicate()); - fcx.register_predicate(projection_obligation); + fcx.register_predicate(check_env, projection_obligation); } object_trait_ref } -pub fn select_all_fcx_obligations_and_apply_defaults(fcx: &FnCtxt) { +pub fn select_all_fcx_obligations_and_apply_defaults<'a, 'ctx>(check_env: &mut CheckEnv<'ctx>, + fcx: &FnCtxt<'a, 'ctx>) { debug!("select_all_fcx_obligations_and_apply_defaults"); - select_fcx_obligations_where_possible(fcx); - fcx.default_type_parameters(); - select_fcx_obligations_where_possible(fcx); + select_fcx_obligations_where_possible(check_env, fcx); + fcx.default_type_parameters(check_env); + select_fcx_obligations_where_possible(check_env, fcx); } -pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) { +pub fn select_all_fcx_obligations_or_error<'a, 'ctx>(check_env: &mut CheckEnv<'ctx>, + fcx: &FnCtxt<'a, 'ctx>) { debug!("select_all_fcx_obligations_or_error"); // upvar inference should have ensured that all deferred call // resolutions are handled by now. - assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty()); + assert!(check_env.deferred_call_resolutions.is_empty()); - select_all_fcx_obligations_and_apply_defaults(fcx); - let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut(); - let r = fulfillment_cx.select_all_or_error(fcx.infcx(), fcx); + select_all_fcx_obligations_and_apply_defaults(check_env, fcx); + let typer = FnCtxtTyper::new(&check_env.tt, fcx); + let r = check_env.fulfillment_cx.select_all_or_error(fcx.infcx(), &typer); match r { Ok(()) => { } Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); } @@ -159,12 +164,13 @@ pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) { } /// Select as many obligations as we can at present. -pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) +pub fn select_fcx_obligations_where_possible<'a, 'ctx>(check_env: &mut CheckEnv<'ctx>, + fcx: &FnCtxt<'a, 'ctx>) { + let typer = FnCtxtTyper::new(&check_env.tt, fcx); match - fcx.inh.fulfillment_cx - .borrow_mut() - .select_where_possible(fcx.infcx(), fcx) + check_env.fulfillment_cx + .select_where_possible(fcx.infcx(), &typer) { Ok(()) => { } Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); } @@ -174,11 +180,13 @@ pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) /// Try to select any fcx obligation that we haven't tried yet, in an effort to improve inference. /// You could just call `select_fcx_obligations_where_possible` except that it leads to repeated /// work. -pub fn select_new_fcx_obligations(fcx: &FnCtxt) { +pub fn select_new_fcx_obligations<'a, 'ctx>(check_env: &mut CheckEnv<'ctx>, + fcx: &FnCtxt<'a, 'ctx>) +{ + let typer = FnCtxtTyper::new(&check_env.tt, fcx); match - fcx.inh.fulfillment_cx - .borrow_mut() - .select_new_obligations(fcx.infcx(), fcx) + check_env.fulfillment_cx + .select_new_obligations(fcx.infcx(), &typer) { Ok(()) => { } Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); } diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index c2209ba2dc647..6f2422c7401c9 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -9,7 +9,8 @@ // except according to those terms. use astconv::AstConv; -use check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck}; +use super::{CheckEnv, FnCtxt, FnCtxtTyper, FnCtxtJoined, Inherited, blank_fn_ctxt, vtable, + regionck}; use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; use middle::region; @@ -104,15 +105,15 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { self.check_item_type(item); } ast::ItemStruct(ref struct_def, ref ast_generics) => { - self.check_type_defn(item, |fcx| { - vec![struct_variant(fcx, &**struct_def)] + self.check_type_defn(item, |check_env, fcx| { + vec![struct_variant(check_env, fcx, &**struct_def)] }); self.check_variances_for_type_defn(item, ast_generics); } ast::ItemEnum(ref enum_def, ref ast_generics) => { - self.check_type_defn(item, |fcx| { - enum_variants(fcx, enum_def) + self.check_type_defn(item, |check_env, fcx| { + enum_variants(check_env, fcx, enum_def) }); self.check_variances_for_type_defn(item, ast_generics); @@ -135,7 +136,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } fn with_fcx(&mut self, item: &ast::Item, mut f: F) where - F: for<'fcx> FnMut(&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, &FnCtxt<'fcx, 'tcx>), + F: for<'fcx> FnMut(&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, + &mut CheckEnv<'tcx>, &FnCtxt<'fcx, 'tcx>), { let ccx = self.ccx; let item_def_id = local_def(item.id); @@ -148,40 +150,45 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { &type_scheme.generics, &type_predicates, item.id); + let mut check_env = CheckEnv::new(); let inh = Inherited::new(ccx.tcx, param_env); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id); - f(self, &fcx); - vtable::select_all_fcx_obligations_or_error(&fcx); - regionck::regionck_item(&fcx, item); + f(self, &mut check_env, &fcx); + vtable::select_all_fcx_obligations_or_error(&mut check_env, &fcx); + regionck::regionck_item(&mut check_env, &fcx, item); } /// In a type definition, we check that to ensure that the types of the fields are well-formed. fn check_type_defn(&mut self, item: &ast::Item, mut lookup_fields: F) where - F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec>, + F: for<'fcx> FnMut(&mut CheckEnv<'tcx>, &FnCtxt<'fcx, 'tcx>) -> Vec>, { - self.with_fcx(item, |this, fcx| { - let variants = lookup_fields(fcx); - let mut bounds_checker = BoundsChecker::new(fcx, - item.span, - item.id, - Some(&mut this.cache)); - debug!("check_type_defn at bounds_checker.scope: {:?}", bounds_checker.scope); - - for variant in &variants { - for field in &variant.fields { - // Regions are checked below. - bounds_checker.check_traits_in_ty(field.ty); - } + self.with_fcx(item, |this, check_env, fcx| { + let variants = lookup_fields(check_env, fcx); + { + let mut bounds_checker = BoundsChecker::new(check_env, + fcx, + item.span, + item.id, + Some(&mut this.cache)); + debug!("check_type_defn at bounds_checker.scope: {:?}", bounds_checker.scope); + + for variant in &variants { + for field in &variant.fields { + // Regions are checked below. + bounds_checker.check_traits_in_ty(field.ty); + } - // For DST, all intermediate types must be sized. - if !variant.fields.is_empty() { - for field in variant.fields.init() { - fcx.register_builtin_bound( - field.ty, - ty::BoundSized, - traits::ObligationCause::new(field.span, - fcx.body_id, - traits::FieldSized)); + // For DST, all intermediate types must be sized. + if !variant.fields.is_empty() { + for field in variant.fields.init() { + fcx.register_builtin_bound( + bounds_checker.check_env, + field.ty, + ty::BoundSized, + traits::ObligationCause::new(field.span, + fcx.body_id, + traits::FieldSized)); + } } } } @@ -190,24 +197,28 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { variants.iter().flat_map(|v| v.fields.iter().map(|f| f.ty)).collect(); regionck::regionck_ensure_component_tys_wf( - fcx, item.span, &field_tys); + check_env, fcx, item.span, &field_tys); }); } fn check_item_type(&mut self, item: &ast::Item) { - self.with_fcx(item, |this, fcx| { - let mut bounds_checker = BoundsChecker::new(fcx, + self.with_fcx(item, |this, check_env, fcx| { + let mut bounds_checker = BoundsChecker::new(check_env, + fcx, item.span, item.id, Some(&mut this.cache)); debug!("check_item_type at bounds_checker.scope: {:?}", bounds_checker.scope); let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id)); - let item_ty = fcx.instantiate_type_scheme(item.span, - &fcx.inh.param_env.free_substs, - &type_scheme.ty); + let item_ty = { + let mut joined = FnCtxtJoined::new(bounds_checker.check_env, fcx); + joined.instantiate_type_scheme(item.span, + &fcx.inh.param_env.free_substs, + &type_scheme.ty) + }; bounds_checker.check_traits_in_ty(item_ty); }); @@ -216,8 +227,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { fn check_impl(&mut self, item: &ast::Item) { - self.with_fcx(item, |this, fcx| { - let mut bounds_checker = BoundsChecker::new(fcx, + self.with_fcx(item, |this, check_env, fcx| { + let mut bounds_checker = BoundsChecker::new(check_env, + fcx, item.span, item.id, Some(&mut this.cache)); @@ -227,9 +239,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // that is, with all type parameters converted from bound // to free. let self_ty = ty::node_id_to_type(fcx.tcx(), item.id); - let self_ty = fcx.instantiate_type_scheme(item.span, - &fcx.inh.param_env.free_substs, - &self_ty); + let self_ty = { + let mut joined = FnCtxtJoined::new(bounds_checker.check_env, fcx); + joined.instantiate_type_scheme(item.span, + &fcx.inh.param_env.free_substs, + &self_ty) + }; bounds_checker.check_traits_in_ty(self_ty); @@ -240,9 +255,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { Some(t) => { t } }; - let trait_ref = fcx.instantiate_type_scheme(item.span, - &fcx.inh.param_env.free_substs, - &trait_ref); + let trait_ref = { + let mut joined = FnCtxtJoined::new(bounds_checker.check_env, fcx); + joined.instantiate_type_scheme(item.span, + &fcx.inh.param_env.free_substs, + &trait_ref) + }; // We are stricter on the trait-ref in an impl than the // self-type. In particular, we enforce region @@ -265,14 +283,16 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let predicates = ty::lookup_super_predicates(fcx.tcx(), poly_trait_ref.def_id()); let predicates = predicates.instantiate_supertrait(fcx.tcx(), &poly_trait_ref); let predicates = { - let selcx = &mut traits::SelectionContext::new(fcx.infcx(), fcx); + let typer = FnCtxtTyper::new(&bounds_checker.check_env.tt, fcx); + let selcx = &mut traits::SelectionContext::new(fcx.infcx(), &typer); traits::normalize(selcx, cause.clone(), &predicates) }; for predicate in predicates.value.predicates { - fcx.register_predicate(traits::Obligation::new(cause.clone(), predicate)); + fcx.register_predicate(bounds_checker.check_env, + traits::Obligation::new(cause.clone(), predicate)); } for obligation in predicates.obligations { - fcx.register_predicate(obligation); + fcx.register_predicate(bounds_checker.check_env, obligation); } }); } @@ -471,6 +491,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { } pub struct BoundsChecker<'cx,'tcx:'cx> { + check_env: &'cx mut CheckEnv<'tcx>, fcx: &'cx FnCtxt<'cx,'tcx>, span: Span, @@ -484,12 +505,14 @@ pub struct BoundsChecker<'cx,'tcx:'cx> { } impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { - pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>, + pub fn new(check_env: &'cx mut CheckEnv<'tcx>, + fcx: &'cx FnCtxt<'cx,'tcx>, span: Span, scope: ast::NodeId, cache: Option<&'cx mut HashSet>>) -> BoundsChecker<'cx,'tcx> { - BoundsChecker { fcx: fcx, span: span, scope: scope, + BoundsChecker { check_env: check_env, + fcx: fcx, span: span, scope: scope, cache: cache, binding_count: 0 } } @@ -505,11 +528,15 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) { let trait_predicates = ty::lookup_predicates(self.fcx.tcx(), trait_ref.def_id); - let bounds = self.fcx.instantiate_bounds(self.span, - trait_ref.substs, - &trait_predicates); + let bounds = { + let mut joined = FnCtxtJoined::new(self.check_env, self.fcx); + joined.instantiate_bounds(self.span, + trait_ref.substs, + &trait_predicates) + }; self.fcx.add_obligations_for_parameters( + self.check_env, traits::ObligationCause::new( self.span, self.fcx.body_id, @@ -573,11 +600,15 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { ty::ty_struct(type_id, substs) | ty::ty_enum(type_id, substs) => { let type_predicates = ty::lookup_predicates(self.fcx.tcx(), type_id); - let bounds = self.fcx.instantiate_bounds(self.span, substs, - &type_predicates); + let bounds = { + let mut joined = FnCtxtJoined::new(self.check_env, self.fcx); + joined.instantiate_bounds(self.span, substs, + &type_predicates) + }; if self.binding_count == 0 { self.fcx.add_obligations_for_parameters( + self.check_env, traits::ObligationCause::new(self.span, self.fcx.body_id, traits::ItemObligation(type_id)), @@ -607,6 +638,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { // that will require an RFC. -nmatsakis) let bounds = filter_to_trait_obligations(bounds); self.fcx.add_obligations_for_parameters( + self.check_env, traits::ObligationCause::new(self.span, self.fcx.body_id, traits::ItemObligation(type_id)), @@ -636,7 +668,8 @@ struct AdtField<'tcx> { span: Span, } -fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn struct_variant<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, struct_def: &ast::StructDef) -> AdtVariant<'tcx> { let fields = @@ -644,16 +677,18 @@ fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, .iter() .map(|field| { let field_ty = ty::node_id_to_type(fcx.tcx(), field.node.id); - let field_ty = fcx.instantiate_type_scheme(field.span, - &fcx.inh.param_env.free_substs, - &field_ty); + let mut joined = FnCtxtJoined::new(check_env, fcx); + let field_ty = joined.instantiate_type_scheme(field.span, + &fcx.inh.param_env.free_substs, + &field_ty); AdtField { ty: field_ty, span: field.span } }) .collect(); AdtVariant { fields: fields } } -fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn enum_variants<'a, 'tcx>(check_env: &mut CheckEnv<'tcx>, + fcx: &FnCtxt<'a, 'tcx>, enum_def: &ast::EnumDef) -> Vec> { enum_def.variants.iter() @@ -670,10 +705,11 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, AdtVariant { fields: args.iter().enumerate().map(|(index, arg)| { let arg_ty = arg_tys[index]; + let mut joined = FnCtxtJoined::new(check_env, fcx); let arg_ty = - fcx.instantiate_type_scheme(variant.span, - &fcx.inh.param_env.free_substs, - &arg_ty); + joined.instantiate_type_scheme(variant.span, + &fcx.inh.param_env.free_substs, + &arg_ty); AdtField { ty: arg_ty, span: arg.ty.span @@ -687,7 +723,7 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } ast::StructVariantKind(ref struct_def) => { - struct_variant(fcx, &**struct_def) + struct_variant(check_env, fcx, &**struct_def) } } }) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 889975f0eb2f9..10c7561d3c66c 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -14,7 +14,7 @@ use self::ResolveReason::*; use astconv::AstConv; -use check::FnCtxt; +use super::{CheckEnv, FnCtxt}; use middle::pat_util; use middle::ty::{self, Ty, MethodCall, MethodCallee}; use middle::ty_fold::{TypeFolder,TypeFoldable}; @@ -35,20 +35,21 @@ use syntax::visit::Visitor; /////////////////////////////////////////////////////////////////////////// // Entry point functions -pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) { +pub fn resolve_type_vars_in_expr<'a, 'ctx>(check_env: &mut CheckEnv<'ctx>, + fcx: &FnCtxt<'a, 'ctx>, e: &ast::Expr) { assert_eq!(fcx.writeback_errors.get(), false); - let mut wbcx = WritebackCx::new(fcx); + let mut wbcx = WritebackCx::new(check_env, fcx); wbcx.visit_expr(e); wbcx.visit_upvar_borrow_map(); wbcx.visit_closures(); - wbcx.visit_object_cast_map(); } -pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, - decl: &ast::FnDecl, - blk: &ast::Block) { +pub fn resolve_type_vars_in_fn<'a, 'ctx>(check_env: &mut CheckEnv<'ctx>, + fcx: &FnCtxt<'a, 'ctx>, + decl: &ast::FnDecl, + blk: &ast::Block) { assert_eq!(fcx.writeback_errors.get(), false); - let mut wbcx = WritebackCx::new(fcx); + let mut wbcx = WritebackCx::new(check_env, fcx); wbcx.visit_block(blk); for arg in &decl.inputs { wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id); @@ -62,7 +63,6 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, } wbcx.visit_upvar_borrow_map(); wbcx.visit_closures(); - wbcx.visit_object_cast_map(); } /////////////////////////////////////////////////////////////////////////// @@ -74,12 +74,15 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, // do elsewhere. struct WritebackCx<'cx, 'tcx: 'cx> { + check_env: &'cx mut CheckEnv<'tcx>, fcx: &'cx FnCtxt<'cx, 'tcx>, } impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { - fn new(fcx: &'cx FnCtxt<'cx, 'tcx>) -> WritebackCx<'cx, 'tcx> { - WritebackCx { fcx: fcx } + fn new(check_env: &'cx mut CheckEnv<'tcx>, + fcx: &'cx FnCtxt<'cx, 'tcx>) -> WritebackCx<'cx, 'tcx> + { + WritebackCx { check_env: check_env, fcx: fcx } } fn tcx(&self) -> &'cx ty::ctxt<'tcx> { @@ -92,21 +95,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // operating on scalars, we clear the overload. fn fix_scalar_binary_expr(&mut self, e: &ast::Expr) { if let ast::ExprBinary(ref op, ref lhs, ref rhs) = e.node { - let lhs_ty = self.fcx.node_ty(lhs.id); + let lhs_ty = self.fcx.node_ty(&self.check_env.tt.node_types, lhs.id); let lhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&lhs_ty); - let rhs_ty = self.fcx.node_ty(rhs.id); + let rhs_ty = self.fcx.node_ty(&self.check_env.tt.node_types, rhs.id); let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty); if ty::type_is_scalar(lhs_ty) && ty::type_is_scalar(rhs_ty) { - self.fcx.inh.method_map.borrow_mut().remove(&MethodCall::expr(e.id)); + self.check_env.tt.method_map.remove(&MethodCall::expr(e.id)); // weird but true: the by-ref binops put an // adjustment on the lhs but not the rhs; the // adjustment for rhs is kind of baked into the // system. if !ast_util::is_by_value_binop(op.node) { - self.fcx.inh.adjustments.borrow_mut().remove(&lhs.id); + self.check_env.tt.adjustments.remove(&lhs.id); } } } @@ -184,8 +187,8 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> { return; } - let var_ty = self.fcx.local_ty(l.span, l.id); - let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span)); + let var_ty = self.fcx.local_ty(self.check_env, l.span, l.id); + let var_ty = resolve(self.fcx, &var_ty, ResolvingLocal(l.span)); write_ty_to_tcx(self.tcx(), l.id, var_ty); visit::walk_local(self, l); } @@ -212,7 +215,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue, ty::UpvarCapture::ByRef(ref upvar_borrow) => { let r = upvar_borrow.region; - let r = self.resolve(&r, ResolvingUpvar(*upvar_id)); + let r = resolve(self.fcx, &r, ResolvingUpvar(*upvar_id)); ty::UpvarCapture::ByRef( ty::UpvarBorrow { kind: upvar_borrow.kind, region: r }) } @@ -229,8 +232,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { return } - for (def_id, closure_ty) in &*self.fcx.inh.closure_tys.borrow() { - let closure_ty = self.resolve(closure_ty, ResolvingClosure(*def_id)); + for (def_id, closure_ty) in &self.check_env.tt.closure_tys { + let closure_ty = resolve(self.fcx, closure_ty, ResolvingClosure(*def_id)); self.fcx.tcx().closure_tys.borrow_mut().insert(*def_id, closure_ty); } @@ -239,46 +242,25 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - fn visit_object_cast_map(&self) { - if self.fcx.writeback_errors.get() { - return - } - - for (&node_id, trait_ref) in self.fcx - .inh - .object_cast_map - .borrow() - .iter() - { - let span = ty::expr_span(self.tcx(), node_id); - let reason = ResolvingExpr(span); - let closure_ty = self.resolve(trait_ref, reason); - self.tcx() - .object_cast_map - .borrow_mut() - .insert(node_id, closure_ty); - } - } - - fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) { + fn visit_node_id(&mut 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 = self.resolve(&n_ty, reason); + let n_ty = self.fcx.node_ty(&self.check_env.tt.node_types, id); + let n_ty = resolve(self.fcx, &n_ty, 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, |item_substs| { + self.fcx.opt_node_ty_substs(&self.check_env.tt, id, |item_substs| { write_substs_to_tcx(self.tcx(), id, - self.resolve(item_substs, reason)); + resolve(self.fcx, item_substs, reason)); }); } - fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) { - match self.fcx.inh.adjustments.borrow_mut().remove(&id) { + fn visit_adjustments(&mut self, reason: ResolveReason, id: ast::NodeId) { + match self.check_env.tt.adjustments.remove(&id) { None => { debug!("No adjustments for node {}", id); } @@ -299,8 +281,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: adj.autoderefs, - autoref: self.resolve(&adj.autoref, reason), - unsize: self.resolve(&adj.unsize, reason), + autoref: resolve(self.fcx, &adj.autoref, reason), + unsize: resolve(self.fcx, &adj.unsize, reason), }) } }; @@ -311,19 +293,19 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - fn visit_method_map_entry(&self, + fn visit_method_map_entry(&mut self, reason: ResolveReason, method_call: MethodCall) { // Resolve any method map entry - match self.fcx.inh.method_map.borrow_mut().remove(&method_call) { + match self.check_env.tt.method_map.remove(&method_call) { Some(method) => { debug!("writeback::resolve_method_map_entry(call={:?}, entry={})", method_call, method.repr(self.tcx())); let new_method = MethodCallee { - origin: self.resolve(&method.origin, reason), - ty: self.resolve(&method.ty, reason), - substs: self.resolve(&method.substs, reason), + origin: resolve(self.fcx, &method.origin, reason), + ty: resolve(self.fcx, &method.ty, reason), + substs: resolve(self.fcx, &method.substs, reason), }; self.tcx().method_map.borrow_mut().insert( @@ -334,9 +316,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - fn resolve>(&self, t: &T, reason: ResolveReason) -> T { - t.fold_with(&mut Resolver::new(self.fcx, reason)) - } +} + +fn resolve<'a, 'tcx, T:TypeFoldable<'tcx>>(fcx: &FnCtxt<'a, 'tcx>, + t: &T, reason: ResolveReason) -> T +{ + t.fold_with(&mut Resolver::new(fcx, reason)) } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 014991f7ea560..d6bc1246332ee 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -344,7 +344,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { } impl<'a,'tcx> ItemCtxt<'a,'tcx> { - fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> { + fn to_ty(&mut self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> { ast_ty_to_ty(self, rs, ast_ty) } } @@ -380,7 +380,7 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { } - fn get_type_parameter_bounds(&self, + fn get_type_parameter_bounds(&mut self, span: Span, node_id: ast::NodeId) -> Result>, ErrorReported> @@ -413,7 +413,7 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { self.tcx().types.err } - fn projected_ty(&self, + fn projected_ty(&mut self, _span: Span, trait_ref: ty::TraitRef<'tcx>, item_name: ast::Name) @@ -427,7 +427,7 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { /// an `ItemCtxt`. This allows us to use multiple kinds of sources. trait GetTypeParameterBounds<'tcx> { fn get_type_parameter_bounds(&self, - astconv: &AstConv<'tcx>, + astconv: &mut AstConv<'tcx>, span: Span, node_id: ast::NodeId) -> Vec>; @@ -438,7 +438,7 @@ impl<'a,'b,'tcx,A,B> GetTypeParameterBounds<'tcx> for (&'a A,&'b B) where A : GetTypeParameterBounds<'tcx>, B : GetTypeParameterBounds<'tcx> { fn get_type_parameter_bounds(&self, - astconv: &AstConv<'tcx>, + astconv: &mut AstConv<'tcx>, span: Span, node_id: ast::NodeId) -> Vec> @@ -452,7 +452,7 @@ impl<'a,'b,'tcx,A,B> GetTypeParameterBounds<'tcx> for (&'a A,&'b B) /// Empty set of bounds. impl<'tcx> GetTypeParameterBounds<'tcx> for () { fn get_type_parameter_bounds(&self, - _astconv: &AstConv<'tcx>, + _astconv: &mut AstConv<'tcx>, _span: Span, _node_id: ast::NodeId) -> Vec> @@ -466,7 +466,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for () { /// from the trait/impl have been fully converted. impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { fn get_type_parameter_bounds(&self, - astconv: &AstConv<'tcx>, + astconv: &mut AstConv<'tcx>, _span: Span, node_id: ast::NodeId) -> Vec> @@ -501,7 +501,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { /// bounds for those a type parameter `X` if `X::Foo` is used. impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics { fn get_type_parameter_bounds(&self, - astconv: &AstConv<'tcx>, + astconv: &mut AstConv<'tcx>, _: Span, node_id: ast::NodeId) -> Vec> @@ -513,26 +513,25 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics { let def = astconv.tcx().type_parameter_def(node_id); let ty = ty::mk_param_from_def(astconv.tcx(), &def); - let from_ty_params = + let mut bounds = self.ty_params .iter() .filter(|p| p.id == node_id) .flat_map(|p| p.bounds.iter()) - .flat_map(|b| predicates_from_bound(astconv, ty, b).into_iter()); + .flat_map(|b| predicates_from_bound(astconv, ty, b).into_iter()) + .collect::>(); + + for wp in &self.where_clause.predicates { + if let ast::WherePredicate::BoundPredicate(ref bp) = *wp { + if is_param(astconv.tcx(), &bp.bounded_ty, node_id) { + for b in bp.bounds.iter() { + bounds.extend(predicates_from_bound(astconv, ty, b)); + } + } + } + } - let from_where_clauses = - self.where_clause - .predicates - .iter() - .filter_map(|wp| match *wp { - ast::WherePredicate::BoundPredicate(ref bp) => Some(bp), - _ => None - }) - .filter(|bp| is_param(astconv.tcx(), &bp.bounded_ty, node_id)) - .flat_map(|bp| bp.bounds.iter()) - .flat_map(|b| predicates_from_bound(astconv, ty, b).into_iter()); - - from_ty_params.chain(from_where_clauses).collect() + bounds } } @@ -568,7 +567,7 @@ fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, enum_predicates: ty::GenericPredicates<'tcx>, variants: &[P]) { let tcx = ccx.tcx; - let icx = ccx.icx(&enum_predicates); + let mut icx = ccx.icx(&enum_predicates); // Create a set of parameter types shared among all the variants. for variant in variants { @@ -620,7 +619,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty_generic_predicates_for_fn(ccx, &sig.generics, rcvr_ty_predicates); let (fty, explicit_self_category) = - astconv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), + astconv::ty_of_method(&mut ccx.icx(&(rcvr_ty_predicates, &sig.generics)), sig, untransformed_rcvr_ty); let def_id = local_def(id); @@ -813,7 +812,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { }, ast::ItemDefaultImpl(_, ref ast_trait_ref) => { let trait_ref = - astconv::instantiate_mono_trait_ref(&ccx.icx(&()), + astconv::instantiate_mono_trait_ref(&mut ccx.icx(&()), &ExplicitRscope, ast_trait_ref, None); @@ -928,7 +927,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { if let Some(ref ast_trait_ref) = *opt_trait_ref { let trait_ref = - astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), + astconv::instantiate_mono_trait_ref(&mut ccx.icx(&ty_predicates), &ExplicitRscope, ast_trait_ref, Some(selfty)); @@ -1175,13 +1174,14 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt, // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`. let self_param_ty = ty::mk_self_type(tcx); - let superbounds1 = compute_bounds(&ccx.icx(scope), self_param_ty, bounds, + let superbounds1 = compute_bounds(&mut ccx.icx(scope), self_param_ty, bounds, SizedByDefault::No, item.span); let superbounds1 = ty::predicates(tcx, self_param_ty, &superbounds1); // Convert any explicit superbounds in the where clause, // e.g. `trait Foo where Self : Bar`: - let superbounds2 = generics.get_type_parameter_bounds(&ccx.icx(scope), item.span, item.id); + let superbounds2 = generics.get_type_parameter_bounds(&mut ccx.icx(scope), item.span, + item.id); // Combine the two lists to form the complete set of superbounds: let superbounds = superbounds1.into_iter().chain(superbounds2.into_iter()).collect(); @@ -1386,7 +1386,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) self_trait_ref, trait_item.ident.name); - let bounds = compute_bounds(&ccx.icx(&(ast_generics, trait_predicates)), + let bounds = compute_bounds(&mut ccx.icx(&(ast_generics, trait_predicates)), assoc_ty, bounds, SizedByDefault::Yes, @@ -1442,7 +1442,7 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } ast::ItemFn(ref decl, unsafety, abi, ref generics, _) => { let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty()); - let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &**decl); + let tofd = astconv::ty_of_bare_fn(&mut ccx.icx(generics), unsafety, abi, &**decl); let ty = ty::mk_bare_fn(tcx, Some(local_def(it.id)), tcx.mk_bare_fn(tofd)); ty::TypeScheme { ty: ty, generics: ty_generics } } @@ -1566,7 +1566,7 @@ fn compute_type_scheme_of_foreign_item<'a, 'tcx>( ast::ForeignItemStatic(ref t, _) => { ty::TypeScheme { generics: ty::Generics::empty(), - ty: ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, t) + ty: ast_ty_to_ty(&mut ccx.icx(&()), &ExplicitRscope, t) } } } @@ -1661,7 +1661,7 @@ fn ty_generic_predicates_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } // Add the Sized bound, unless the type parameter is marked as `?Sized`. -fn add_unsized_bound<'tcx>(astconv: &AstConv<'tcx>, +fn add_unsized_bound<'tcx>(astconv: &mut AstConv<'tcx>, bounds: &mut ty::BuiltinBounds, ast_bounds: &[ast::TyParamBound], span: Span) @@ -1736,7 +1736,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, for (index, param) in ast_generics.ty_params.iter().enumerate() { let index = index as u32; let param_ty = ty::ParamTy::new(space, index, param.ident.name).to_ty(ccx.tcx); - let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)), + let bounds = compute_bounds(&mut ccx.icx(&(base_predicates, ast_generics)), param_ty, ¶m.bounds, SizedByDefault::Yes, @@ -1770,7 +1770,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, for predicate in &where_clause.predicates { match predicate { &ast::WherePredicate::BoundPredicate(ref bound_pred) => { - let ty = ast_ty_to_ty(&ccx.icx(&(base_predicates, ast_generics)), + let ty = ast_ty_to_ty(&mut ccx.icx(&(base_predicates, ast_generics)), &ExplicitRscope, &*bound_pred.bounded_ty); @@ -1780,7 +1780,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let mut projections = Vec::new(); let trait_ref = - conv_poly_trait_ref(&ccx.icx(&(base_predicates, ast_generics)), + conv_poly_trait_ref(&mut ccx.icx(&(base_predicates, ast_generics)), ty, poly_trait_ref, &mut projections); @@ -1873,7 +1873,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let default = match param.default { None => None, Some(ref path) => { - let ty = ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, &**path); + let ty = ast_ty_to_ty(&mut ccx.icx(&()), &ExplicitRscope, &**path); let cur_idx = index; ty::walk_ty(ty, |t| { @@ -1982,7 +1982,7 @@ enum SizedByDefault { Yes, No, } /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the /// built-in trait (formerly known as kind): Send. -fn compute_bounds<'tcx>(astconv: &AstConv<'tcx>, +fn compute_bounds<'tcx>(astconv: &mut AstConv<'tcx>, param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound], sized_by_default: SizedByDefault, @@ -2011,7 +2011,7 @@ fn compute_bounds<'tcx>(astconv: &AstConv<'tcx>, /// because this can be anywhere from 0 predicates (`T:?Sized` adds no /// predicates) to 1 (`T:Foo`) to many (`T:Bar` adds `T:Bar` /// and `::X == i32`). -fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx>, +fn predicates_from_bound<'tcx>(astconv: &mut AstConv<'tcx>, param_ty: Ty<'tcx>, bound: &ast::TyParamBound) -> Vec> @@ -2036,7 +2036,7 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx>, } } -fn conv_poly_trait_ref<'tcx>(astconv: &AstConv<'tcx>, +fn conv_poly_trait_ref<'tcx>(astconv: &mut AstConv<'tcx>, param_ty: Ty<'tcx>, trait_ref: &ast::PolyTraitRef, projections: &mut Vec>) @@ -2049,18 +2049,17 @@ fn conv_poly_trait_ref<'tcx>(astconv: &AstConv<'tcx>, projections) } -fn conv_param_bounds<'a,'tcx>(astconv: &AstConv<'tcx>, +fn conv_param_bounds<'a,'tcx>(astconv: &mut AstConv<'tcx>, span: Span, param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound]) -> ty::ParamBounds<'tcx> { - let tcx = astconv.tcx(); let astconv::PartitionedBounds { builtin_bounds, trait_bounds, region_bounds - } = astconv::partition_bounds(tcx, span, &ast_bounds); + } = astconv::partition_bounds(astconv.tcx(), span, &ast_bounds); let mut projection_bounds = Vec::new(); @@ -2074,7 +2073,7 @@ fn conv_param_bounds<'a,'tcx>(astconv: &AstConv<'tcx>, let region_bounds: Vec = region_bounds.into_iter() - .map(|r| ast_region_to_region(tcx, r)) + .map(|r| ast_region_to_region(astconv.tcx(), r)) .collect(); ty::ParamBounds { @@ -2108,12 +2107,12 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( let rb = BindingRscope::new(); let input_tys = decl.inputs .iter() - .map(|a| ty_of_arg(&ccx.icx(ast_generics), &rb, a, None)) + .map(|a| ty_of_arg(&mut ccx.icx(ast_generics), &rb, a, None)) .collect(); let output = match decl.output { ast::Return(ref ty) => - ty::FnConverging(ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &**ty)), + ty::FnConverging(ast_ty_to_ty(&mut ccx.icx(ast_generics), &rb, &**ty)), ast::DefaultReturn(..) => ty::FnConverging(ty::mk_nil(ccx.tcx)), ast::NoReturn(..) => diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index e50693ea804b6..9389cab6c577c 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -78,6 +78,7 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(collections)] +#![feature(collections_drain)] #![feature(core)] #![feature(quote)] #![feature(rustc_diagnostic_macros)]