diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 656fac54a82..8634c8cf9bd 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -154,7 +154,7 @@ impl<'tcx> Callee<'tcx> { let method_item = tcx.impl_or_trait_item(def_id); let trait_id = method_item.container().id(); let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id)); - let trait_ref = infer::normalize_associated_type(tcx, &trait_ref); + let trait_ref = tcx.normalize_associated_type(&trait_ref); match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) { traits::VtableImpl(vtable_impl) => { let impl_did = vtable_impl.impl_def_id; diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index b07437d299b..8e9138cf779 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -14,11 +14,7 @@ use hir::pat_util::{PatIdMap, pat_id_map, pat_is_binding}; use hir::pat_util::pat_is_resolved_const; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; -use check::{check_expr, check_expr_has_type, check_expr_with_expectation}; -use check::{demand, FnCtxt, Expectation}; -use check::{check_expr_with_lvalue_pref}; -use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type}; -use check::coercion; +use check::{FnCtxt, Expectation}; use lint; use require_same_types; use util::nodemap::FnvHashMap; @@ -26,6 +22,7 @@ use session::Session; use std::cmp; use std::collections::hash_map::Entry::{Occupied, Vacant}; +use std::ops::Deref; use syntax::ast; use syntax::codemap::{Span, Spanned}; use syntax::ptr::P; @@ -33,31 +30,52 @@ use syntax::ptr::P; use rustc::hir::{self, PatKind}; use rustc::hir::print as pprust; -pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, - pat: &'tcx hir::Pat, - expected: Ty<'tcx>) -{ - let fcx = pcx.fcx; - let tcx = pcx.fcx.ccx.tcx; +pub struct PatCtxt<'a, 'tcx: 'a> { + pub fcx: &'a FnCtxt<'a, 'tcx>, + pub map: PatIdMap, +} - debug!("check_pat(pat={:?},expected={:?})", - pat, - expected); +impl<'a, 'tcx> Deref for PatCtxt<'a, 'tcx> { + type Target = FnCtxt<'a, 'tcx>; + fn deref(&self) -> &Self::Target { + self.fcx + } +} + +// This function exists due to the warning "diagnostic code E0164 already used" +fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: bool) { + let name = pprust::path_to_string(path); + let msg = format!("`{}` does not name a tuple variant or a tuple struct", name); + if lint { + sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, + pat.id, + pat.span, + msg); + } else { + span_err!(sess, pat.span, E0164, "{}", msg); + } +} + +impl<'a, 'tcx> PatCtxt<'a, 'tcx> { +pub fn check_pat(&self, pat: &'tcx hir::Pat, expected: Ty<'tcx>) { + let tcx = self.tcx(); + + debug!("check_pat(pat={:?},expected={:?})", pat, expected); match pat.node { PatKind::Wild => { - fcx.write_ty(pat.id, expected); + self.write_ty(pat.id, expected); } PatKind::Lit(ref lt) => { - check_expr(fcx, <); - let expr_ty = fcx.expr_ty(<); + self.check_expr(<); + let expr_ty = self.expr_ty(<); // 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 hir::ExprLit(ref lt) = lt.node { if let ast::LitKind::ByteStr(_) = lt.node { - let expected_ty = structurally_resolved_type(fcx, pat.span, expected); + let expected_ty = self.structurally_resolved_type(pat.span, expected); if let ty::TyRef(_, mt) = expected_ty.sty { if let ty::TySlice(_) = mt.ty.sty { pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), @@ -67,7 +85,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } } - fcx.write_ty(pat.id, pat_ty); + self.write_ty(pat.id, pat_ty); // somewhat surprising: in this case, the subtyping // relation goes the opposite way as the other @@ -81,14 +99,14 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // &'static str <: expected // // that's equivalent to there existing a LUB. - demand::suptype(fcx, pat.span, expected, pat_ty); + self.demand_suptype(pat.span, expected, pat_ty); } PatKind::Range(ref begin, ref end) => { - check_expr(fcx, begin); - check_expr(fcx, end); + self.check_expr(begin); + self.check_expr(end); - let lhs_ty = fcx.expr_ty(begin); - let rhs_ty = fcx.expr_ty(end); + let lhs_ty = self.expr_ty(begin); + let rhs_ty = self.expr_ty(end); // Check that both end-points are of numeric or char type. let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char(); @@ -108,15 +126,15 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, span_err!(tcx.sess, span, E0029, "only char and numeric types are allowed in range patterns\n \ start type: {}\n end type: {}", - fcx.infcx().ty_to_string(lhs_ty), - fcx.infcx().ty_to_string(rhs_ty) + self.infcx().ty_to_string(lhs_ty), + self.infcx().ty_to_string(rhs_ty) ); return; } // Check that the types of the end-points can be unified. let types_unify = require_same_types( - fcx.ccx, Some(fcx.infcx()), pat.span, rhs_ty, lhs_ty, + self.ccx, Some(self.infcx()), pat.span, rhs_ty, lhs_ty, "mismatched types in range", ); @@ -127,12 +145,12 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // Now that we know the types can be unified we find the unified type and use // it to type the entire expression. - let common_type = fcx.infcx().resolve_type_vars_if_possible(&lhs_ty); + let common_type = self.infcx().resolve_type_vars_if_possible(&lhs_ty); - fcx.write_ty(pat.id, common_type); + self.write_ty(pat.id, common_type); // subtyping doesn't matter here, as the value is some kind of scalar - demand::eqtype(fcx, pat.span, expected, lhs_ty); + self.demand_eqtype(pat.span, expected, lhs_ty); } PatKind::Path(..) | PatKind::Ident(..) if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => { @@ -140,141 +158,140 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let const_did = pat_def.def_id(); let const_scheme = tcx.lookup_item_type(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 = self.instantiate_type_scheme(pat.span, + &Substs::empty(), + &const_scheme.ty); + self.write_ty(pat.id, const_ty); // FIXME(#20489) -- we should limit the types here to scalars or something! // As with PatKind::Lit, what we really want here is that there // exist a LUB, but for the cases that can occur, subtype // is good enough. - demand::suptype(fcx, pat.span, expected, const_ty); + self.demand_suptype(pat.span, expected, const_ty); } else { - fcx.write_error(pat.id); + self.write_error(pat.id); } } PatKind::Ident(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map.borrow(), pat) => { - let typ = fcx.local_ty(pat.span, pat.id); + let typ = self.local_ty(pat.span, pat.id); match bm { hir::BindByRef(mutbl) => { // if the binding is like // ref x | ref const x | ref mut x // then `x` is assigned a value of type `&M T` where M is the mutability // and T is the expected type. - let region_var = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); + let region_var = self.infcx().next_region_var(infer::PatternRegion(pat.span)); let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl }; let region_ty = tcx.mk_ref(tcx.mk_region(region_var), mt); // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is // required. However, we use equality, which is stronger. See (*) for // an explanation. - demand::eqtype(fcx, pat.span, region_ty, typ); + self.demand_eqtype(pat.span, region_ty, typ); } // otherwise the type of x is the expected type T hir::BindByValue(_) => { // As above, `T <: typeof(x)` is required but we // use equality, see (*) below. - demand::eqtype(fcx, pat.span, expected, typ); + self.demand_eqtype(pat.span, expected, typ); } } - fcx.write_ty(pat.id, typ); + self.write_ty(pat.id, typ); // if there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be - if let Some(&canon_id) = pcx.map.get(&path.node.name) { + if let Some(&canon_id) = self.map.get(&path.node.name) { if canon_id != pat.id { - let ct = fcx.local_ty(pat.span, canon_id); - demand::eqtype(fcx, pat.span, ct, typ); + let ct = self.local_ty(pat.span, canon_id); + self.demand_eqtype(pat.span, ct, typ); } if let Some(ref p) = *sub { - check_pat(pcx, &p, expected); + self.check_pat(&p, expected); } } } PatKind::Ident(_, ref path, _) => { let path = hir::Path::from_ident(path.span, path.node); - check_pat_enum(pcx, pat, &path, Some(&[]), expected, false); + self.check_pat_enum(pat, &path, Some(&[]), expected, false); } PatKind::TupleStruct(ref path, ref subpats) => { - check_pat_enum(pcx, pat, path, subpats.as_ref().map(|v| &v[..]), expected, true); + self.check_pat_enum(pat, path, subpats.as_ref().map(|v| &v[..]), expected, true); } PatKind::Path(ref path) => { - check_pat_enum(pcx, pat, path, Some(&[]), expected, false); + self.check_pat_enum(pat, path, Some(&[]), expected, false); } PatKind::QPath(ref qself, ref path) => { - let self_ty = fcx.to_ty(&qself.ty); + let self_ty = self.to_ty(&qself.ty); let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) { if d.base_def == Def::Err { - fcx.infcx().set_tainted_by_errors(); - fcx.write_error(pat.id); + self.infcx().set_tainted_by_errors(); + self.write_error(pat.id); return; } d } else if qself.position == 0 { // This is just a sentinel for finish_resolving_def_to_ty. - let sentinel = fcx.tcx().map.local_def_id(ast::CRATE_NODE_ID); + let sentinel = self.tcx().map.local_def_id(ast::CRATE_NODE_ID); def::PathResolution { base_def: Def::Mod(sentinel), depth: path.segments.len() } } else { debug!("unbound path {:?}", pat); - fcx.write_error(pat.id); + self.write_error(pat.id); return; }; if let Some((opt_ty, segments, def)) = - resolve_ty_and_def_ufcs(fcx, path_res, Some(self_ty), - path, pat.span, pat.id) { - if check_assoc_item_is_const(pcx, def, pat.span) { + self.resolve_ty_and_def_ufcs(path_res, Some(self_ty), + path, pat.span, pat.id) { + if self.check_assoc_item_is_const(def, pat.span) { let scheme = tcx.lookup_item_type(def.def_id()); let predicates = tcx.lookup_predicates(def.def_id()); - instantiate_path(fcx, segments, - scheme, &predicates, - opt_ty, def, pat.span, pat.id); - let const_ty = fcx.node_ty(pat.id); - demand::suptype(fcx, pat.span, expected, const_ty); + self.instantiate_path(segments, scheme, &predicates, + opt_ty, def, pat.span, pat.id); + let const_ty = self.node_ty(pat.id); + self.demand_suptype(pat.span, expected, const_ty); } else { - fcx.write_error(pat.id) + self.write_error(pat.id) } } } PatKind::Struct(ref path, ref fields, etc) => { - check_pat_struct(pcx, pat, path, fields, etc, expected); + self.check_pat_struct(pat, path, fields, etc, expected); } PatKind::Tup(ref elements) => { let element_tys: Vec<_> = - (0..elements.len()).map(|_| fcx.infcx().next_ty_var()) + (0..elements.len()).map(|_| self.infcx().next_ty_var()) .collect(); let pat_ty = tcx.mk_tup(element_tys.clone()); - fcx.write_ty(pat.id, pat_ty); - demand::eqtype(fcx, pat.span, expected, pat_ty); + self.write_ty(pat.id, pat_ty); + self.demand_eqtype(pat.span, expected, pat_ty); for (element_pat, element_ty) in elements.iter().zip(element_tys) { - check_pat(pcx, &element_pat, element_ty); + self.check_pat(&element_pat, element_ty); } } PatKind::Box(ref inner) => { - let inner_ty = fcx.infcx().next_ty_var(); + let inner_ty = self.infcx().next_ty_var(); let uniq_ty = tcx.mk_box(inner_ty); - if check_dereferencable(pcx, pat.span, expected, &inner) { + if self.check_dereferencable(pat.span, expected, &inner) { // Here, `demand::subtype` is good enough, but I don't // 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); + self.demand_eqtype(pat.span, expected, uniq_ty); + self.write_ty(pat.id, uniq_ty); + self.check_pat(&inner, inner_ty); } else { - fcx.write_error(pat.id); - check_pat(pcx, &inner, tcx.types.err); + self.write_error(pat.id); + self.check_pat(&inner, tcx.types.err); } } PatKind::Ref(ref inner, mutbl) => { - let expected = fcx.infcx().shallow_resolve(expected); - if check_dereferencable(pcx, pat.span, expected, &inner) { + let expected = self.infcx().shallow_resolve(expected); + if self.check_dereferencable(pat.span, expected, &inner) { // `demand::subtype` would be good enough, but using // `eqtype` turns out to be equally general. See (*) // below for details. @@ -288,25 +305,25 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, (expected, mt.ty) } _ => { - let inner_ty = fcx.infcx().next_ty_var(); + let inner_ty = self.infcx().next_ty_var(); let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; - let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); + let region = self.infcx().next_region_var(infer::PatternRegion(pat.span)); let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt); - demand::eqtype(fcx, pat.span, expected, rptr_ty); + self.demand_eqtype(pat.span, expected, rptr_ty); (rptr_ty, inner_ty) } }; - fcx.write_ty(pat.id, rptr_ty); - check_pat(pcx, &inner, inner_ty); + self.write_ty(pat.id, rptr_ty); + self.check_pat(&inner, inner_ty); } else { - fcx.write_error(pat.id); - check_pat(pcx, &inner, tcx.types.err); + self.write_error(pat.id); + self.check_pat(&inner, tcx.types.err); } } PatKind::Vec(ref before, ref slice, ref after) => { - let expected_ty = structurally_resolved_type(fcx, pat.span, expected); - let inner_ty = fcx.infcx().next_ty_var(); + let expected_ty = self.structurally_resolved_type(pat.span, expected); + let inner_ty = self.infcx().next_ty_var(); let pat_ty = match expected_ty.sty { ty::TyArray(_, size) => tcx.mk_array(inner_ty, { let min_len = before.len() + after.len(); @@ -316,7 +333,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } }), _ => { - let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); + let region = self.infcx().next_region_var(infer::PatternRegion(pat.span)); tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut { ty: tcx.mk_slice(inner_ty), mutbl: expected_ty.builtin_deref(true, ty::NoPreference).map(|mt| mt.mutbl) @@ -325,18 +342,18 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } }; - fcx.write_ty(pat.id, pat_ty); + self.write_ty(pat.id, pat_ty); // `demand::subtype` would be good enough, but using // `eqtype` turns out to be equally general. See (*) // below for details. - demand::eqtype(fcx, pat.span, expected, pat_ty); + self.demand_eqtype(pat.span, expected, pat_ty); for elt in before { - check_pat(pcx, &elt, inner_ty); + self.check_pat(&elt, inner_ty); } if let Some(ref slice) = *slice { - let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span)); + let region = self.infcx().next_region_var(infer::PatternRegion(pat.span)); let mutbl = expected_ty.builtin_deref(true, ty::NoPreference) .map_or(hir::MutImmutable, |mt| mt.mutbl); @@ -344,10 +361,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, ty: tcx.mk_slice(inner_ty), mutbl: mutbl }); - check_pat(pcx, &slice, slice_ty); + self.check_pat(&slice, slice_ty); } for elt in after { - check_pat(pcx, &elt, inner_ty); + self.check_pat(&elt, inner_ty); } } } @@ -404,11 +421,11 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // subtyping. } -fn check_assoc_item_is_const(pcx: &pat_ctxt, def: Def, span: Span) -> bool { +fn check_assoc_item_is_const(&self, def: Def, span: Span) -> bool { match def { Def::AssociatedConst(..) => true, Def::Method(..) => { - span_err!(pcx.fcx.ccx.tcx.sess, span, E0327, + span_err!(self.tcx().sess, span, E0327, "associated items in match patterns must be constants"); false } @@ -418,20 +435,17 @@ fn check_assoc_item_is_const(pcx: &pat_ctxt, def: Def, span: Span) -> bool { } } -pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, - span: Span, expected: Ty<'tcx>, - inner: &hir::Pat) -> bool { - let fcx = pcx.fcx; - let tcx = pcx.fcx.ccx.tcx; +pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool { + let tcx = self.tcx(); if pat_is_binding(&tcx.def_map.borrow(), inner) { - let expected = fcx.infcx().shallow_resolve(expected); + let expected = self.infcx().shallow_resolve(expected); expected.builtin_deref(true, ty::NoPreference).map_or(true, |mt| match mt.ty.sty { ty::TyTrait(_) => { // This is "x = SomeTrait" being reduced from // "let &x = &SomeTrait" or "let box x = Box", an error. span_err!(tcx.sess, span, E0033, "type `{}` cannot be dereferenced", - fcx.infcx().ty_to_string(expected)); + self.infcx().ty_to_string(expected)); false } _ => true @@ -440,14 +454,16 @@ pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, true } } +} -pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - discrim: &'tcx hir::Expr, - arms: &'tcx [hir::Arm], - expected: Expectation<'tcx>, - match_src: hir::MatchSource) { - let tcx = fcx.ccx.tcx; +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { +pub fn check_match(&self, + expr: &'tcx hir::Expr, + discrim: &'tcx hir::Expr, + arms: &'tcx [hir::Arm], + expected: Expectation<'tcx>, + match_src: hir::MatchSource) { + let tcx = self.tcx(); // Not entirely obvious: if matches may create ref bindings, we // want to use the *precise* type of the discriminant, *not* some @@ -460,25 +476,25 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }); let discrim_ty; if let Some(m) = contains_ref_bindings { - check_expr_with_lvalue_pref(fcx, discrim, LvaluePreference::from_mutbl(m)); - discrim_ty = fcx.expr_ty(discrim); + self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m)); + discrim_ty = self.expr_ty(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); + discrim_ty = self.infcx().next_ty_var(); + self.check_expr_has_type(discrim, discrim_ty); }; // Typecheck the patterns first, so that we get types for all the // bindings. for arm in arms { - let mut pcx = pat_ctxt { - fcx: fcx, + let pcx = PatCtxt { + fcx: self, map: pat_id_map(&tcx.def_map, &arm.pats[0]), }; for p in &arm.pats { - check_pat(&mut pcx, &p, discrim_ty); + pcx.check_pat(&p, discrim_ty); } } @@ -491,25 +507,25 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // on any empty type and is therefore unreachable; should the flow // of execution reach it, we will panic, so bottom is an appropriate // type in that case) - let expected = expected.adjust_for_branches(fcx); - let mut result_ty = fcx.infcx().next_diverging_ty_var(); + let expected = expected.adjust_for_branches(self); + let mut result_ty = self.infcx().next_diverging_ty_var(); let coerce_first = match expected { // We don't coerce to `()` so that if the match expression is a // statement it's branches can have any consistent type. That allows // us to give better error messages (pointing to a usually better // arm for inconsistent arms or to the whole match when a `()` type // is required). - Expectation::ExpectHasType(ety) if ety != fcx.tcx().mk_nil() => { + Expectation::ExpectHasType(ety) if ety != self.tcx().mk_nil() => { ety } _ => result_ty }; for (i, arm) in arms.iter().enumerate() { if let Some(ref e) = arm.guard { - check_expr_has_type(fcx, e, tcx.types.bool); + self.check_expr_has_type(e, tcx.types.bool); } - check_expr_with_expectation(fcx, &arm.body, expected); - let arm_ty = fcx.expr_ty(&arm.body); + self.check_expr_with_expectation(&arm.body, expected); + let arm_ty = self.expr_ty(&arm.body); if result_ty.references_error() || arm_ty.references_error() { result_ty = tcx.types.err; @@ -531,7 +547,7 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }; let result = if is_if_let_fallback { - fcx.infcx().eq_types(true, origin, arm_ty, result_ty) + self.infcx().eq_types(true, origin, arm_ty, result_ty) .map(|InferOk { obligations, .. }| { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); @@ -539,10 +555,10 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }) } else if i == 0 { // Special-case the first arm, as it has no "previous expressions". - coercion::try(fcx, &arm.body, coerce_first) + self.try_coerce(&arm.body, coerce_first) } else { let prev_arms = || arms[..i].iter().map(|arm| &*arm.body); - coercion::try_find_lub(fcx, origin, prev_arms, result_ty, &arm.body) + self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body) }; result_ty = match result { @@ -553,88 +569,69 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } else { (result_ty, arm_ty) }; - fcx.infcx().report_mismatched_types(origin, expected, found, e); - fcx.tcx().types.err + self.infcx().report_mismatched_types(origin, expected, found, e); + self.tcx().types.err } }; } - fcx.write_ty(expr.id, result_ty); + self.write_ty(expr.id, result_ty); +} } -pub struct pat_ctxt<'a, 'tcx: 'a> { - pub fcx: &'a FnCtxt<'a, 'tcx>, - pub map: PatIdMap, -} - -pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx hir::Pat, - path: &hir::Path, fields: &'tcx [Spanned], - etc: bool, expected: Ty<'tcx>) { - let fcx = pcx.fcx; - let tcx = pcx.fcx.ccx.tcx; +impl<'a, 'tcx> PatCtxt<'a, 'tcx> { +pub fn check_pat_struct(&self, pat: &'tcx hir::Pat, + path: &hir::Path, fields: &'tcx [Spanned], + etc: bool, expected: Ty<'tcx>) { + let tcx = self.tcx(); let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); - let variant = match fcx.def_struct_variant(def, path.span) { + let variant = match self.def_struct_variant(def, path.span) { Some((_, variant)) => variant, None => { 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); + self.write_error(pat.id); for field in fields { - check_pat(pcx, &field.node.pat, tcx.types.err); + self.check_pat(&field.node.pat, tcx.types.err); } return; } }; - let pat_ty = pcx.fcx.instantiate_type(def.def_id(), path); + let pat_ty = self.instantiate_type(def.def_id(), path); let item_substs = match pat_ty.sty { ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, _ => span_bug!(pat.span, "struct variant is not an ADT") }; - demand::eqtype(fcx, pat.span, expected, pat_ty); - check_struct_pat_fields(pcx, pat.span, fields, variant, &item_substs, etc); + self.demand_eqtype(pat.span, expected, pat_ty); + self.check_struct_pat_fields(pat.span, fields, variant, &item_substs, etc); - fcx.write_ty(pat.id, pat_ty); - fcx.write_substs(pat.id, ty::ItemSubsts { substs: item_substs.clone() }); + self.write_ty(pat.id, pat_ty); + self.write_substs(pat.id, ty::ItemSubsts { substs: item_substs.clone() }); } -// This function exists due to the warning "diagnostic code E0164 already used" -fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: bool) { - let name = pprust::path_to_string(path); - let msg = format!("`{}` does not name a tuple variant or a tuple struct", name); - if lint { - sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, - pat.id, - pat.span, - msg); - } else { - span_err!(sess, pat.span, E0164, "{}", msg); - } -} - -fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, - pat: &hir::Pat, - path: &hir::Path, - subpats: Option<&'tcx [P]>, - expected: Ty<'tcx>, - is_tuple_struct_pat: bool) +fn check_pat_enum(&self, + pat: &hir::Pat, + path: &hir::Path, + subpats: Option<&'tcx [P]>, + expected: Ty<'tcx>, + is_tuple_struct_pat: bool) { // Typecheck the path. - let fcx = pcx.fcx; - let tcx = pcx.fcx.ccx.tcx; + let tcx = self.tcx(); let path_res = match tcx.def_map.borrow().get(&pat.id) { Some(&path_res) if path_res.base_def != Def::Err => path_res, _ => { - fcx.infcx().set_tainted_by_errors(); - fcx.write_error(pat.id); + self.infcx().set_tainted_by_errors(); + self.write_error(pat.id); if let Some(subpats) = subpats { for pat in subpats { - check_pat(pcx, &pat, tcx.types.err); + self.check_pat(&pat, tcx.types.err); } } @@ -642,9 +639,9 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } }; - let (opt_ty, segments, def) = match resolve_ty_and_def_ufcs(fcx, path_res, - None, path, - pat.span, pat.id) { + let (opt_ty, segments, def) = match self.resolve_ty_and_def_ufcs(path_res, + None, path, + pat.span, pat.id) { Some(resolution) => resolution, // Error handling done inside resolve_ty_and_def_ufcs, so if // resolution fails just return. @@ -653,8 +650,8 @@ 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); + if path_res.depth != 0 && !self.check_assoc_item_is_const(def, pat.span) { + self.write_error(pat.id); return; } @@ -672,17 +669,16 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } else { ctor_scheme }; - instantiate_path(pcx.fcx, segments, - path_scheme, &ctor_predicates, - opt_ty, def, pat.span, pat.id); + self.instantiate_path(segments, path_scheme, &ctor_predicates, + opt_ty, def, pat.span, pat.id); let report_bad_struct_kind = |is_warning| { bad_struct_kind_err(tcx.sess, pat, path, is_warning); if is_warning { return; } - fcx.write_error(pat.id); + self.write_error(pat.id); if let Some(subpats) = subpats { for pat in subpats { - check_pat(pcx, &pat, tcx.types.err); + self.check_pat(&pat, tcx.types.err); } } }; @@ -694,16 +690,16 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, if is_tuple_struct_pat { report_bad_struct_kind(false); } else { - let pat_ty = fcx.node_ty(pat.id); - demand::suptype(fcx, pat.span, expected, pat_ty); + let pat_ty = self.node_ty(pat.id); + self.demand_suptype(pat.span, expected, pat_ty); } return; } - let pat_ty = fcx.node_ty(pat.id); - demand::eqtype(fcx, pat.span, expected, pat_ty); + let pat_ty = self.node_ty(pat.id); + self.demand_eqtype(pat.span, expected, pat_ty); - let real_path_ty = fcx.node_ty(pat.id); + let real_path_ty = self.node_ty(pat.id); let (kind_name, variant, expected_substs) = match real_path_ty.sty { ty::TyEnum(enum_def, expected_substs) => { let variant = enum_def.variant_of_def(def); @@ -735,8 +731,8 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, if let Some(subpats) = subpats { if subpats.len() == variant.fields.len() { for (subpat, field) in subpats.iter().zip(&variant.fields) { - let field_ty = fcx.field_ty(subpat.span, field, expected_substs); - check_pat(pcx, &subpat, field_ty); + let field_ty = self.field_ty(subpat.span, field, expected_substs); + self.check_pat(&subpat, field_ty); } } else if variant.fields.is_empty() { span_err!(tcx.sess, pat.span, E0024, @@ -744,7 +740,7 @@ 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); + self.check_pat(&pat, tcx.types.err); } } else { span_err!(tcx.sess, pat.span, E0023, @@ -754,7 +750,7 @@ fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"}); for pat in subpats { - check_pat(pcx, &pat, tcx.types.err); + self.check_pat(&pat, tcx.types.err); } } } @@ -765,13 +761,13 @@ 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], - variant: ty::VariantDef<'tcx>, - substs: &Substs<'tcx>, - etc: bool) { - let tcx = pcx.fcx.ccx.tcx; +pub fn check_struct_pat_fields(&self, + span: Span, + fields: &'tcx [Spanned], + variant: ty::VariantDef<'tcx>, + substs: &Substs<'tcx>, + etc: bool) { + let tcx = self.tcx(); // Index the struct fields' types. let field_map = variant.fields @@ -798,7 +794,7 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, Vacant(vacant) => { vacant.insert(span); field_map.get(&field.name) - .map(|f| pcx.fcx.field_ty(span, f, substs)) + .map(|f| self.field_ty(span, f, substs)) .unwrap_or_else(|| { span_err!(tcx.sess, span, E0026, "struct `{}` does not have a field named `{}`", @@ -809,7 +805,7 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } }; - check_pat(pcx, &field.pat, field_ty); + self.check_pat(&field.pat, field_ty); } // Report an error if not all the fields were specified. @@ -823,3 +819,4 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } } } +} diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 5d37d5123e4..15307864a42 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -8,21 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::autoderef; -use super::check_argument_types; -use super::check_expr; -use super::check_method_argument_types; -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::method; -use super::structurally_resolved_type; -use super::TupleArgumentsFlag; -use super::UnresolvedTypeAction; -use super::write_call; +use super::{DeferredCallResolution, Expectation, FnCtxt, + TupleArgumentsFlag, UnresolvedTypeAction}; use CrateCtxt; use middle::cstore::LOCAL_CRATE; @@ -70,58 +57,58 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: } } -pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - call_expr: &'tcx hir::Expr, - callee_expr: &'tcx hir::Expr, - arg_exprs: &'tcx [P], - expected: Expectation<'tcx>) -{ - check_expr(fcx, callee_expr); - let original_callee_ty = fcx.expr_ty(callee_expr); - let (callee_ty, _, result) = - autoderef(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) - }); - - 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); - } - - Some(CallStep::Builtin) => { - confirm_builtin_call(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); - } - - Some(CallStep::Overloaded(method_callee)) => { - confirm_overloaded_call(fcx, call_expr, callee_expr, - arg_exprs, expected, method_callee); - } - } -} - enum CallStep<'tcx> { Builtin, DeferredClosure(ty::FnSig<'tcx>), Overloaded(ty::MethodCallee<'tcx>) } -fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - call_expr: &'tcx hir::Expr, - callee_expr: &'tcx hir::Expr, - adjusted_ty: Ty<'tcx>, - autoderefs: usize) - -> Option> +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { +pub fn check_call(&self, + call_expr: &'tcx hir::Expr, + callee_expr: &'tcx hir::Expr, + arg_exprs: &'tcx [P], + expected: Expectation<'tcx>) +{ + self.check_expr(callee_expr); + let original_callee_ty = self.expr_ty(callee_expr); + let (callee_ty, _, result) = + self.autoderef(callee_expr.span, + original_callee_ty, + || Some(callee_expr), + UnresolvedTypeAction::Error, + LvaluePreference::NoPreference, + |adj_ty, idx| { + self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx) + }); + + match result { + None => { + // this will report an error since original_callee_ty is not a fn + self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected); + } + + Some(CallStep::Builtin) => { + self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected); + } + + Some(CallStep::DeferredClosure(fn_sig)) => { + self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig); + } + + Some(CallStep::Overloaded(method_callee)) => { + self.confirm_overloaded_call(call_expr, callee_expr, + arg_exprs, expected, method_callee); + } + } +} + +fn try_overloaded_call_step(&self, + call_expr: &'tcx hir::Expr, + callee_expr: &'tcx hir::Expr, + adjusted_ty: Ty<'tcx>, + autoderefs: usize) + -> Option> { debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})", call_expr, @@ -129,9 +116,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 self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty { ty::TyFnDef(..) | ty::TyFnPtr(_) => { - fcx.write_autoderef_adjustment(callee_expr.id, autoderefs); + self.write_autoderef_adjustment(callee_expr.id, autoderefs); return Some(CallStep::Builtin); } @@ -141,14 +128,14 @@ 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.infcx().closure_kind(def_id).is_none() { + if self.infcx().closure_kind(def_id).is_none() { let closure_ty = - fcx.infcx().closure_type(def_id, substs); + self.infcx().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 { + self.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span, + infer::FnCall, + &closure_ty.sig).0; + self.record_deferred_call_resolution(def_id, Box::new(CallResolution { call_expr: call_expr, callee_expr: callee_expr, adjusted_ty: adjusted_ty, @@ -175,37 +162,36 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, _ => {} } - try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefs) + self.try_overloaded_call_traits(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>, - call_expr: &hir::Expr, - callee_expr: &hir::Expr, - adjusted_ty: Ty<'tcx>, - autoderefs: usize) - -> Option> +fn try_overloaded_call_traits(&self, + call_expr: &hir::Expr, + callee_expr: &hir::Expr, + adjusted_ty: Ty<'tcx>, + autoderefs: usize) + -> Option> { // Try the options that are least restrictive on the caller first. for &(opt_trait_def_id, method_name) in &[ - (fcx.tcx().lang_items.fn_trait(), token::intern("call")), - (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")), - (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")), + (self.tcx().lang_items.fn_trait(), token::intern("call")), + (self.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")), + (self.tcx().lang_items.fn_once_trait(), token::intern("call_once")), ] { let trait_def_id = match opt_trait_def_id { Some(def_id) => def_id, None => continue, }; - match method::lookup_in_trait_adjusted(fcx, - call_expr.span, - Some(&callee_expr), - method_name, - trait_def_id, - autoderefs, - false, - adjusted_ty, - None) { + match self.lookup_method_in_trait_adjusted(call_expr.span, + Some(&callee_expr), + method_name, + trait_def_id, + autoderefs, + false, + adjusted_ty, + None) { None => continue, Some(method_callee) => { return Some(method_callee); @@ -216,11 +202,11 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, None } -fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, - call_expr: &hir::Expr, - callee_ty: Ty<'tcx>, - arg_exprs: &'tcx [P], - expected: Expectation<'tcx>) +fn confirm_builtin_call(&self, + call_expr: &hir::Expr, + callee_ty: Ty<'tcx>, + arg_exprs: &'tcx [P], + expected: Expectation<'tcx>) { let error_fn_sig; @@ -230,12 +216,12 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, sig } _ => { - let mut err = fcx.type_error_struct(call_expr.span, |actual| { + let mut err = self.type_error_struct(call_expr.span, |actual| { format!("expected function, found `{}`", actual) }, callee_ty, None); if let hir::ExprCall(ref expr, _) = call_expr.node { - let tcx = fcx.tcx(); + let tcx = self.tcx(); if let Some(pr) = tcx.def_map.borrow().get(&expr.id) { if pr.depth == 0 && pr.base_def != Def::Err { if let Some(span) = tcx.map.span_if_local(pr.def_id()) { @@ -251,8 +237,8 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // In that case, we check each argument against "error" in order to // set up all the node type bindings. error_fn_sig = ty::Binder(ty::FnSig { - inputs: err_args(fcx, arg_exprs.len()), - output: ty::FnConverging(fcx.tcx().types.err), + inputs: self.err_args(arg_exprs.len()), + output: ty::FnConverging(self.tcx().types.err), variadic: false }); @@ -266,34 +252,32 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // previously appeared within a `Binder<>` and hence would not // have been normalized before. let fn_sig = - fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span, - infer::FnCall, - fn_sig).0; + self.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); + self.normalize_associated_types_in(call_expr.span, &fn_sig); // Call the generic checker. - let expected_arg_tys = expected_types_for_fn_args(fcx, - call_expr.span, - expected, - fn_sig.output, - &fn_sig.inputs); - check_argument_types(fcx, - call_expr.span, - &fn_sig.inputs, - &expected_arg_tys[..], - arg_exprs, - fn_sig.variadic, - TupleArgumentsFlag::DontTupleArguments); + let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span, + expected, + fn_sig.output, + &fn_sig.inputs); + self.check_argument_types(call_expr.span, + &fn_sig.inputs, + &expected_arg_tys[..], + arg_exprs, + fn_sig.variadic, + TupleArgumentsFlag::DontTupleArguments); - write_call(fcx, call_expr, fn_sig.output); + self.write_call(call_expr, fn_sig.output); } -fn confirm_deferred_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, - call_expr: &hir::Expr, - arg_exprs: &'tcx [P], - expected: Expectation<'tcx>, - fn_sig: ty::FnSig<'tcx>) +fn confirm_deferred_closure_call(&self, + call_expr: &hir::Expr, + arg_exprs: &'tcx [P], + expected: Expectation<'tcx>, + fn_sig: ty::FnSig<'tcx>) { // `fn_sig` is the *signature* of the cosure being called. We // don't know the full details yet (`Fn` vs `FnMut` etc), but we @@ -301,48 +285,46 @@ fn confirm_deferred_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // type. let expected_arg_tys = - expected_types_for_fn_args(fcx, - call_expr.span, - expected, - fn_sig.output.clone(), - &fn_sig.inputs); + self.expected_types_for_fn_args(call_expr.span, + expected, + fn_sig.output.clone(), + &fn_sig.inputs); - check_argument_types(fcx, - call_expr.span, - &fn_sig.inputs, - &expected_arg_tys, - arg_exprs, - fn_sig.variadic, - TupleArgumentsFlag::TupleArguments); + self.check_argument_types(call_expr.span, + &fn_sig.inputs, + &expected_arg_tys, + arg_exprs, + fn_sig.variadic, + TupleArgumentsFlag::TupleArguments); - write_call(fcx, call_expr, fn_sig.output); + self.write_call(call_expr, fn_sig.output); } -fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, - call_expr: &hir::Expr, - callee_expr: &'tcx hir::Expr, - arg_exprs: &'tcx [P], - expected: Expectation<'tcx>, - method_callee: ty::MethodCallee<'tcx>) +fn confirm_overloaded_call(&self, + call_expr: &hir::Expr, + callee_expr: &'tcx hir::Expr, + arg_exprs: &'tcx [P], + expected: Expectation<'tcx>, + method_callee: ty::MethodCallee<'tcx>) { let output_type = - check_method_argument_types(fcx, - call_expr.span, - method_callee.ty, - callee_expr, - arg_exprs, - TupleArgumentsFlag::TupleArguments, - expected); - write_call(fcx, call_expr, output_type); + self.check_method_argument_types(call_expr.span, + method_callee.ty, + callee_expr, + arg_exprs, + TupleArgumentsFlag::TupleArguments, + expected); + self.write_call(call_expr, output_type); - write_overloaded_call_method_map(fcx, call_expr, method_callee); + self.write_overloaded_call_method_map(call_expr, method_callee); } -fn write_overloaded_call_method_map<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, - call_expr: &hir::Expr, - method_callee: ty::MethodCallee<'tcx>) { +fn write_overloaded_call_method_map(&self, + call_expr: &hir::Expr, + method_callee: ty::MethodCallee<'tcx>) { let method_call = ty::MethodCall::expr(call_expr.id); - fcx.inh.tables.borrow_mut().method_map.insert(method_call, method_callee); + self.inh.tables.borrow_mut().method_map.insert(method_call, method_callee); +} } #[derive(Debug)] @@ -365,7 +347,7 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> { assert!(fcx.infcx().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 fcx.try_overloaded_call_traits(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 @@ -385,16 +367,15 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> { for (&method_arg_ty, &self_arg_ty) in method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs) { - demand::eqtype(fcx, self.call_expr.span, self_arg_ty, method_arg_ty); + fcx.demand_eqtype(self.call_expr.span, self_arg_ty, method_arg_ty); } let nilty = fcx.tcx().mk_nil(); - demand::eqtype(fcx, - self.call_expr.span, - method_sig.output.unwrap_or(nilty), - self.fn_sig.output.unwrap_or(nilty)); + fcx.demand_eqtype(self.call_expr.span, + method_sig.output.unwrap_or(nilty), + self.fn_sig.output.unwrap_or(nilty)); - write_overloaded_call_method_map(fcx, self.call_expr, method_callee); + fcx.write_overloaded_call_method_map(self.call_expr, method_callee); } None => { span_bug!( diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 249ab27ec59..506347679a4 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -38,10 +38,7 @@ //! expression, `e as U2` is not necessarily so (in fact it will only be valid if //! `U1` coerces to `U2`). -use super::coercion; -use super::demand; use super::FnCtxt; -use super::structurally_resolved_type; use lint; use hir::def_id::DefId; @@ -75,11 +72,10 @@ enum UnsizeKind<'tcx> { OfParam(&'tcx ty::ParamTy) } +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Returns the kind of unsize information of t, or None /// if t is sized or it is unknown. -fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, - t: Ty<'tcx>) - -> Option> { +fn unsize_kind(&self, t: Ty<'tcx>) -> Option> { match t.sty { ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length), ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal_def_id())), @@ -87,7 +83,7 @@ fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, // FIXME(arielb1): do some kind of normalization match def.struct_variant().fields.last() { None => None, - Some(f) => unsize_kind(fcx, f.ty(fcx.tcx(), substs)) + Some(f) => self.unsize_kind(f.ty(self.tcx(), substs)) } } // We should really try to normalize here. @@ -96,6 +92,7 @@ fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, _ => None } } +} #[derive(Copy, Clone)] enum CastError { @@ -112,14 +109,14 @@ enum CastError { NonScalar, } -impl<'tcx> CastCheck<'tcx> { - pub fn new<'a>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - expr_ty: Ty<'tcx>, - cast_ty: Ty<'tcx>, - cast_span: Span, - span: Span) - -> Result, ErrorReported> { +impl<'a, 'tcx> CastCheck<'tcx> { + pub fn new(fcx: &FnCtxt<'a, 'tcx>, + expr: &'tcx hir::Expr, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, + cast_span: Span, + span: Span) + -> Result, ErrorReported> { let check = CastCheck { expr: expr, expr_ty: expr_ty, @@ -142,9 +139,7 @@ impl<'tcx> CastCheck<'tcx> { } } - fn report_cast_error<'a>(&self, - fcx: &FnCtxt<'a, 'tcx>, - e: CastError) { + fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) { match e { CastError::NeedViaPtr | CastError::NeedViaThinPtr | @@ -207,8 +202,7 @@ impl<'tcx> CastCheck<'tcx> { } } - fn report_cast_to_unsized_type<'a>(&self, - fcx: &FnCtxt<'a, 'tcx>) { + fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'tcx>) { if self.cast_ty.references_error() || self.expr_ty.references_error() @@ -262,7 +256,7 @@ impl<'tcx> CastCheck<'tcx> { err.emit(); } - fn trivial_cast_lint<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { + fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { let t_cast = self.cast_ty; let t_expr = self.expr_ty; if t_cast.is_numeric() && t_expr.is_numeric() { @@ -287,9 +281,9 @@ impl<'tcx> CastCheck<'tcx> { } - pub fn check<'a>(mut self, fcx: &FnCtxt<'a, 'tcx>) { - self.expr_ty = structurally_resolved_type(fcx, self.span, self.expr_ty); - self.cast_ty = structurally_resolved_type(fcx, self.span, self.cast_ty); + pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { + self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); + self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", self.expr.id, self.expr_ty, self.cast_ty); @@ -315,7 +309,7 @@ impl<'tcx> CastCheck<'tcx> { /// Check a cast, and report an error if one exists. In some cases, this /// can return Ok and create type errors in the fcx rather than returning /// directly. coercion-cast is handled in check instead of here. - fn do_check<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result { + fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result { use rustc::ty::cast::IntTy::*; use rustc::ty::cast::CastTy::*; @@ -326,8 +320,8 @@ impl<'tcx> CastCheck<'tcx> { (None, Some(t_cast)) => { if let ty::TyFnDef(_, _, f) = self.expr_ty.sty { // Attempt a coercion to a fn pointer type. - let res = coercion::try(fcx, self.expr, - fcx.tcx().mk_ty(ty::TyFnPtr(f))); + let res = fcx.try_coerce(self.expr, + fcx.tcx().mk_ty(ty::TyFnPtr(f))); if !res.is_ok() { return Err(CastError::NonScalar); } @@ -382,11 +376,11 @@ impl<'tcx> CastCheck<'tcx> { } } - fn check_ptr_ptr_cast<'a>(&self, - fcx: &FnCtxt<'a, 'tcx>, - m_expr: &'tcx ty::TypeAndMut<'tcx>, - m_cast: &'tcx ty::TypeAndMut<'tcx>) - -> Result + fn check_ptr_ptr_cast(&self, + fcx: &FnCtxt<'a, 'tcx>, + m_expr: &'tcx ty::TypeAndMut<'tcx>, + m_cast: &'tcx ty::TypeAndMut<'tcx>) + -> Result { debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast); @@ -403,16 +397,16 @@ impl<'tcx> CastCheck<'tcx> { } // vtable kinds must match - match (unsize_kind(fcx, m_cast.ty), unsize_kind(fcx, m_expr.ty)) { + match (fcx.unsize_kind(m_cast.ty), fcx.unsize_kind(m_expr.ty)) { (Some(a), Some(b)) if a == b => Ok(CastKind::PtrPtrCast), _ => Err(CastError::DifferingKinds) } } - fn check_fptr_ptr_cast<'a>(&self, - fcx: &FnCtxt<'a, 'tcx>, - m_cast: &'tcx ty::TypeAndMut<'tcx>) - -> Result + fn check_fptr_ptr_cast(&self, + fcx: &FnCtxt<'a, 'tcx>, + m_cast: &'tcx ty::TypeAndMut<'tcx>) + -> Result { // fptr-ptr cast. must be to sized ptr @@ -423,10 +417,10 @@ impl<'tcx> CastCheck<'tcx> { } } - fn check_ptr_addr_cast<'a>(&self, - fcx: &FnCtxt<'a, 'tcx>, - m_expr: &'tcx ty::TypeAndMut<'tcx>) - -> Result + fn check_ptr_addr_cast(&self, + fcx: &FnCtxt<'a, 'tcx>, + m_expr: &'tcx ty::TypeAndMut<'tcx>) + -> Result { // ptr-addr cast. must be from sized ptr @@ -437,11 +431,11 @@ impl<'tcx> CastCheck<'tcx> { } } - fn check_ref_cast<'a>(&self, - fcx: &FnCtxt<'a, 'tcx>, - m_expr: &'tcx ty::TypeAndMut<'tcx>, - m_cast: &'tcx ty::TypeAndMut<'tcx>) - -> Result + fn check_ref_cast(&self, + fcx: &FnCtxt<'a, 'tcx>, + m_expr: &'tcx ty::TypeAndMut<'tcx>, + m_cast: &'tcx ty::TypeAndMut<'tcx>) + -> Result { // array-ptr-cast. @@ -455,7 +449,7 @@ impl<'tcx> CastCheck<'tcx> { // from a region pointer to a vector. // this will report a type mismatch if needed - demand::eqtype(fcx, self.span, ety, m_cast.ty); + fcx.demand_eqtype(self.span, ety, m_cast.ty); return Ok(CastKind::ArrayPtrCast); } } @@ -463,10 +457,10 @@ impl<'tcx> CastCheck<'tcx> { Err(CastError::IllegalCast) } - fn check_addr_ptr_cast<'a>(&self, - fcx: &FnCtxt<'a, 'tcx>, - m_cast: &'tcx ty::TypeAndMut<'tcx>) - -> Result + fn check_addr_ptr_cast(&self, + fcx: &FnCtxt<'a, 'tcx>, + m_cast: &'tcx ty::TypeAndMut<'tcx>) + -> Result { // ptr-addr cast. pointer must be thin. if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) { @@ -476,8 +470,8 @@ impl<'tcx> CastCheck<'tcx> { } } - fn try_coercion_cast<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool { - coercion::try(fcx, self.expr, self.cast_ty).is_ok() + fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool { + fcx.try_coerce(self.expr, self.cast_ty).is_ok() } } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index b84ded1ea7a..7632f58f057 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -19,12 +19,13 @@ use std::cmp; use syntax::abi::Abi; use rustc::hir; -pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, - expr: &hir::Expr, - _capture: hir::CaptureClause, - decl: &'tcx hir::FnDecl, - body: &'tcx hir::Block, - expected: Expectation<'tcx>) { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { +pub fn check_expr_closure(&self, + expr: &hir::Expr, + _capture: hir::CaptureClause, + decl: &'tcx hir::FnDecl, + body: &'tcx hir::Block, + expected: Expectation<'tcx>) { debug!("check_expr_closure(expr={:?},expected={:?})", expr, expected); @@ -32,26 +33,26 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // It's always helpful for inference if we know the kind of // 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), + let (expected_sig,expected_kind) = match expected.to_option(self) { + Some(ty) => self.deduce_expectations_from_expected_type(ty), None => (None, None) }; - check_closure(fcx, expr, expected_kind, decl, body, expected_sig) + self.check_closure(expr, expected_kind, decl, body, expected_sig) } -fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, - expr: &hir::Expr, - opt_kind: Option, - decl: &'tcx hir::FnDecl, - body: &'tcx hir::Block, - expected_sig: Option>) { - let expr_def_id = fcx.tcx().map.local_def_id(expr.id); +fn check_closure(&self, + expr: &hir::Expr, + opt_kind: Option, + decl: &'tcx hir::FnDecl, + body: &'tcx hir::Block, + expected_sig: Option>) { + let expr_def_id = self.tcx().map.local_def_id(expr.id); debug!("check_closure opt_kind={:?} expected_sig={:?}", opt_kind, expected_sig); - let mut fn_ty = astconv::ty_of_closure(fcx, + let mut fn_ty = astconv::ty_of_closure(self, hir::Unsafety::Normal, decl, Abi::RustCall, @@ -60,51 +61,47 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // Create type variables (for now) to represent the transformed // types of upvars. These will be unified during the upvar // inference phase (`upvar.rs`). - let num_upvars = fcx.tcx().with_freevars(expr.id, |fv| fv.len()); - let upvar_tys = fcx.infcx().next_ty_vars(num_upvars); + let num_upvars = self.tcx().with_freevars(expr.id, |fv| fv.len()); + let upvar_tys = self.infcx().next_ty_vars(num_upvars); debug!("check_closure: expr.id={:?} upvar_tys={:?}", expr.id, upvar_tys); - let closure_type = - fcx.ccx.tcx.mk_closure( - expr_def_id, - fcx.ccx.tcx.mk_substs(fcx.inh.infcx.parameter_environment.free_substs.clone()), - upvar_tys); + let closure_type = self.tcx().mk_closure(expr_def_id, + self.tcx().mk_substs(self.inh.infcx.parameter_environment.free_substs.clone()), + upvar_tys); - fcx.write_ty(expr.id, closure_type); + self.write_ty(expr.id, closure_type); - let fn_sig = fcx.tcx().liberate_late_bound_regions( - fcx.tcx().region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig); + let fn_sig = self.tcx().liberate_late_bound_regions( + self.tcx().region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig); - check_fn(fcx.ccx, + check_fn(self.ccx, hir::Unsafety::Normal, expr.id, &fn_sig, decl, expr.id, &body, - fcx.inh); + self.inh); // Tuple up the arguments and insert the resulting function type into // the `closures` table. - fn_ty.sig.0.inputs = vec![fcx.tcx().mk_tup(fn_ty.sig.0.inputs)]; + fn_ty.sig.0.inputs = vec![self.tcx().mk_tup(fn_ty.sig.0.inputs)]; debug!("closure for {:?} --> sig={:?} opt_kind={:?}", expr_def_id, fn_ty.sig, opt_kind); - fcx.inh.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty); + self.inh.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty); match opt_kind { - Some(kind) => { fcx.inh.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); } + Some(kind) => { self.inh.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); } None => { } } } -fn deduce_expectations_from_expected_type<'a,'tcx>( - fcx: &FnCtxt<'a,'tcx>, - expected_ty: Ty<'tcx>) +fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>) -> (Option>,Option) { debug!("deduce_expectations_from_expected_type(expected_ty={:?})", @@ -112,16 +109,16 @@ fn deduce_expectations_from_expected_type<'a,'tcx>( match expected_ty.sty { ty::TyTrait(ref object_type) => { - let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(), - fcx.tcx().types.err); + let proj_bounds = object_type.projection_bounds_with_self_ty(self.tcx(), + self.tcx().types.err); let sig = proj_bounds.iter() - .filter_map(|pb| deduce_sig_from_projection(fcx, pb)) + .filter_map(|pb| self.deduce_sig_from_projection(pb)) .next(); - let kind = fcx.tcx().lang_items.fn_trait_kind(object_type.principal_def_id()); + let kind = self.tcx().lang_items.fn_trait_kind(object_type.principal_def_id()); (sig, kind) } ty::TyInfer(ty::TyVar(vid)) => { - deduce_expectations_from_obligations(fcx, vid) + self.deduce_expectations_from_obligations(vid) } _ => { (None, None) @@ -129,12 +126,10 @@ fn deduce_expectations_from_expected_type<'a,'tcx>( } } -fn deduce_expectations_from_obligations<'a,'tcx>( - fcx: &FnCtxt<'a,'tcx>, - expected_vid: ty::TyVid) +fn deduce_expectations_from_obligations(&self, expected_vid: ty::TyVid) -> (Option>, Option) { - let fulfillment_cx = fcx.inh.fulfillment_cx.borrow(); + let fulfillment_cx = self.inh.fulfillment_cx.borrow(); // Here `expected_ty` is known to be a type inference variable. let expected_sig = @@ -151,8 +146,8 @@ fn deduce_expectations_from_obligations<'a,'tcx>( // the complete signature. ty::Predicate::Projection(ref proj_predicate) => { let trait_ref = proj_predicate.to_poly_trait_ref(); - self_type_matches_expected_vid(fcx, trait_ref, expected_vid) - .and_then(|_| deduce_sig_from_projection(fcx, proj_predicate)) + self.self_type_matches_expected_vid(trait_ref, expected_vid) + .and_then(|_| self.deduce_sig_from_projection(proj_predicate)) } _ => { None @@ -192,32 +187,21 @@ fn deduce_expectations_from_obligations<'a,'tcx>( ty::Predicate::ClosureKind(..) => None, }; opt_trait_ref - .and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid)) - .and_then(|trait_ref| fcx.tcx().lang_items.fn_trait_kind(trait_ref.def_id())) + .and_then(|trait_ref| self.self_type_matches_expected_vid(trait_ref, expected_vid)) + .and_then(|trait_ref| self.tcx().lang_items.fn_trait_kind(trait_ref.def_id())) }) - .fold(None, pick_most_restrictive_closure_kind); + .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur)))); (expected_sig, expected_kind) } -fn pick_most_restrictive_closure_kind(best: Option, - cur: ty::ClosureKind) - -> Option -{ - match best { - None => Some(cur), - Some(best) => Some(cmp::min(best, cur)) - } -} - /// Given a projection like "::Result == Y", we can deduce /// everything we need to know about a closure. -fn deduce_sig_from_projection<'a,'tcx>( - fcx: &FnCtxt<'a,'tcx>, +fn deduce_sig_from_projection(&self, projection: &ty::PolyProjectionPredicate<'tcx>) -> Option> { - let tcx = fcx.tcx(); + let tcx = self.tcx(); debug!("deduce_sig_from_projection({:?})", projection); @@ -229,7 +213,7 @@ fn deduce_sig_from_projection<'a,'tcx>( } let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0); - let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty); + let arg_param_ty = self.infcx().resolve_type_vars_if_possible(&arg_param_ty); debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty); let input_tys = match arg_param_ty.sty { @@ -239,7 +223,7 @@ fn deduce_sig_from_projection<'a,'tcx>( debug!("deduce_sig_from_projection: input_tys {:?}", input_tys); let ret_param_ty = projection.0.ty; - let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty); + let ret_param_ty = self.infcx().resolve_type_vars_if_possible(&ret_param_ty); debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty); let fn_sig = ty::FnSig { @@ -252,13 +236,12 @@ fn deduce_sig_from_projection<'a,'tcx>( Some(fn_sig) } -fn self_type_matches_expected_vid<'a,'tcx>( - fcx: &FnCtxt<'a,'tcx>, +fn self_type_matches_expected_vid(&self, trait_ref: ty::PolyTraitRef<'tcx>, expected_vid: ty::TyVid) -> Option> { - let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty()); + let self_ty = self.infcx().shallow_resolve(trait_ref.self_ty()); debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})", trait_ref, self_ty); @@ -267,3 +250,4 @@ fn self_type_matches_expected_vid<'a,'tcx>( _ => None, } } +} diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index b30277d745e..ae23ee79e91 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -60,7 +60,7 @@ //! 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, UnresolvedTypeAction}; +use check::{FnCtxt, UnresolvedTypeAction}; use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace}; use rustc::traits::{self, ObligationCause}; @@ -241,10 +241,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let lvalue_pref = LvaluePreference::from_mutbl(mt_b.mutbl); let mut first_error = None; let mut r_borrow_var = None; - let (_, autoderefs, success) = autoderef(self.fcx, span, a, exprs, - UnresolvedTypeAction::Ignore, - lvalue_pref, - |referent_ty, autoderef| + let (_, autoderefs, success) = self.fcx.autoderef(span, a, exprs, + UnresolvedTypeAction::Ignore, + lvalue_pref, + |referent_ty, autoderef| { if autoderef == 0 { // Don't let this pass, otherwise it would cause @@ -616,25 +616,26 @@ fn apply<'a, 'b, 'tcx, E, I>(coerce: &mut Coerce<'a, 'tcx>, Ok((ty, adjustment)) } +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Attempt to coerce an expression to a type, and return the /// adjusted type of the expression, if successful. /// Adjustments are only recorded if the coercion succeeded. /// The expressions *must not* have any pre-existing adjustments. -pub fn try<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &hir::Expr, - target: Ty<'tcx>) - -> RelateResult<'tcx, Ty<'tcx>> { - let source = fcx.resolve_type_vars_if_possible(fcx.expr_ty(expr)); +pub fn try_coerce(&self, + expr: &hir::Expr, + target: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> { + let source = self.resolve_type_vars_if_possible(self.expr_ty(expr)); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); - let mut coerce = Coerce::new(fcx, TypeOrigin::ExprAssignable(expr.span)); - fcx.infcx().commit_if_ok(|_| { + let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span)); + self.infcx().commit_if_ok(|_| { let (ty, adjustment) = apply(&mut coerce, &|| Some(expr), source, target)?; if !adjustment.is_identity() { debug!("Success, coerced with {:?}", adjustment); - assert!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id)); - fcx.write_adjustment(expr.id, adjustment); + assert!(!self.inh.tables.borrow().adjustments.contains_key(&expr.id)); + self.write_adjustment(expr.id, adjustment); } Ok(ty) }) @@ -643,18 +644,18 @@ pub fn try<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// Given some expressions, their known unified type and another expression, /// tries to unify the types, potentially inserting coercions on any of the /// provided expressions and returns their LUB (aka "common supertype"). -pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>, - origin: TypeOrigin, - exprs: E, - prev_ty: Ty<'tcx>, - new: &'b hir::Expr) - -> RelateResult<'tcx, Ty<'tcx>> +pub fn try_find_coercion_lub<'b, E, I>(&self, + origin: TypeOrigin, + exprs: E, + prev_ty: Ty<'tcx>, + new: &'b hir::Expr) + -> RelateResult<'tcx, Ty<'tcx>> // FIXME(eddyb) use copyable iterators when that becomes ergonomic. where E: Fn() -> I, I: IntoIterator { - let prev_ty = fcx.resolve_type_vars_if_possible(prev_ty); - let new_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(new)); + let prev_ty = self.resolve_type_vars_if_possible(prev_ty); + let new_ty = self.resolve_type_vars_if_possible(self.expr_ty(new)); debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty); let trace = TypeTrace::types(origin, true, prev_ty, new_ty); @@ -665,7 +666,7 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>, (&ty::TyFnDef(a_def_id, a_substs, a_fty), &ty::TyFnDef(b_def_id, b_substs, b_fty)) => { // The signature must always match. - let fty = fcx.infcx().lub(true, trace.clone(), a_fty, b_fty) + let fty = self.infcx().lub(true, trace.clone(), a_fty, b_fty) .map(|InferOk { value, obligations }| { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); @@ -674,46 +675,46 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>, if a_def_id == b_def_id { // Same function, maybe the parameters match. - let substs = fcx.infcx().commit_if_ok(|_| { - fcx.infcx().lub(true, trace.clone(), a_substs, b_substs) + let substs = self.infcx().commit_if_ok(|_| { + self.infcx().lub(true, trace.clone(), a_substs, b_substs) .map(|InferOk { value, obligations }| { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); value }) - }).map(|s| fcx.tcx().mk_substs(s)); + }).map(|s| self.tcx().mk_substs(s)); if let Ok(substs) = substs { // We have a LUB of prev_ty and new_ty, just return it. - return Ok(fcx.tcx().mk_fn_def(a_def_id, substs, fty)); + return Ok(self.tcx().mk_fn_def(a_def_id, substs, fty)); } } // Reify both sides and return the reified fn pointer type. for expr in exprs().into_iter().chain(Some(new)) { // No adjustments can produce a fn item, so this should never trip. - assert!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id)); - fcx.write_adjustment(expr.id, AdjustReifyFnPointer); + assert!(!self.inh.tables.borrow().adjustments.contains_key(&expr.id)); + self.write_adjustment(expr.id, AdjustReifyFnPointer); } - return Ok(fcx.tcx().mk_fn_ptr(fty)); + return Ok(self.tcx().mk_fn_ptr(fty)); } _ => {} } - let mut coerce = Coerce::new(fcx, origin); + let mut coerce = Coerce::new(self, origin); coerce.use_lub = true; // First try to coerce the new expression to the type of the previous ones, // but only if the new expression has no coercion already applied to it. let mut first_error = None; - if !fcx.inh.tables.borrow().adjustments.contains_key(&new.id) { - let result = fcx.infcx().commit_if_ok(|_| { + if !self.inh.tables.borrow().adjustments.contains_key(&new.id) { + let result = self.infcx().commit_if_ok(|_| { apply(&mut coerce, &|| Some(new), new_ty, prev_ty) }); match result { Ok((ty, adjustment)) => { if !adjustment.is_identity() { - fcx.write_adjustment(new.id, adjustment); + self.write_adjustment(new.id, adjustment); } return Ok(ty); } @@ -725,12 +726,12 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>, // This requires ensuring there are no coercions applied to *any* of the // previous expressions, other than noop reborrows (ignoring lifetimes). for expr in exprs() { - let noop = match fcx.inh.tables.borrow().adjustments.get(&expr.id) { + let noop = match self.inh.tables.borrow().adjustments.get(&expr.id) { Some(&AdjustDerefRef(AutoDerefRef { autoderefs: 1, autoref: Some(AutoPtr(_, mutbl_adj)), unsize: None - })) => match fcx.expr_ty(expr).sty { + })) => match self.expr_ty(expr).sty { ty::TyRef(_, mt_orig) => { // Reborrow that we can safely ignore. mutbl_adj == mt_orig.mutbl @@ -742,8 +743,8 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>, }; if !noop { - return fcx.infcx().commit_if_ok(|_| { - fcx.infcx().lub(true, trace.clone(), &prev_ty, &new_ty) + return self.infcx().commit_if_ok(|_| { + self.infcx().lub(true, trace.clone(), &prev_ty, &new_ty) .map(|InferOk { value, obligations }| { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); @@ -753,14 +754,14 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>, } } - match fcx.infcx().commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) { + match self.infcx().commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) { Err(_) => { // Avoid giving strange errors on failed attempts. if let Some(e) = first_error { Err(e) } else { - fcx.infcx().commit_if_ok(|_| { - fcx.infcx().lub(true, trace, &prev_ty, &new_ty) + self.infcx().commit_if_ok(|_| { + self.infcx().lub(true, trace, &prev_ty, &new_ty) .map(|InferOk { value, obligations }| { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); @@ -772,10 +773,11 @@ pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>, Ok((ty, adjustment)) => { if !adjustment.is_identity() { for expr in exprs() { - fcx.write_adjustment(expr.id, adjustment); + self.write_adjustment(expr.id, adjustment); } } Ok(ty) } } } +} diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 5b163eb7de4..8dfd62e1a66 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -9,52 +9,49 @@ // except according to those terms. -use check::{coercion, FnCtxt}; +use check::FnCtxt; use rustc::ty::Ty; use rustc::infer::{InferOk, TypeOrigin}; use syntax::codemap::Span; use rustc::hir; +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Requires that the two types unify, and prints an error message if // they don't. -pub fn suptype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, - expected: Ty<'tcx>, actual: Ty<'tcx>) { +pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { let origin = TypeOrigin::Misc(sp); - match fcx.infcx().sub_types(false, origin, actual, expected) { + match self.infcx().sub_types(false, origin, actual, expected) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); }, Err(e) => { - fcx.infcx().report_mismatched_types(origin, expected, actual, e); + self.infcx().report_mismatched_types(origin, expected, actual, e); } } } -pub fn eqtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, - expected: Ty<'tcx>, actual: Ty<'tcx>) { +pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { let origin = TypeOrigin::Misc(sp); - match fcx.infcx().eq_types(false, origin, actual, expected) { + match self.infcx().eq_types(false, origin, actual, expected) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); }, Err(e) => { - fcx.infcx().report_mismatched_types(origin, expected, actual, e); + self.infcx().report_mismatched_types(origin, expected, actual, e); } } } // Checks that the type of `expr` can be coerced to `expected`. -pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - sp: Span, - expected: Ty<'tcx>, - expr: &hir::Expr) { - let expected = fcx.resolve_type_vars_if_possible(expected); - if let Err(e) = coercion::try(fcx, expr, expected) { - let origin = TypeOrigin::Misc(sp); - let expr_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(expr)); - fcx.infcx().report_mismatched_types(origin, expected, expr_ty, e); +pub fn demand_coerce(&self, expr: &hir::Expr, expected: Ty<'tcx>) { + let expected = self.resolve_type_vars_if_possible(expected); + if let Err(e) = self.try_coerce(expr, expected) { + let origin = TypeOrigin::Misc(expr.span); + let expr_ty = self.resolve_type_vars_if_possible(self.expr_ty(expr)); + self.infcx().report_mismatched_types(origin, expected, expr_ty, e); } } +} diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index b98f1884f01..77c74078de7 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -10,7 +10,7 @@ use super::probe; -use check::{self, FnCtxt, callee, demand}; +use check::{FnCtxt, callee}; use check::UnresolvedTypeAction; use hir::def_id::DefId; use rustc::ty::subst::{self}; @@ -44,23 +44,25 @@ struct InstantiatedMethodSig<'tcx> { method_predicates: ty::InstantiatedPredicates<'tcx>, } -pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - self_expr: &'tcx hir::Expr, - call_expr: &'tcx hir::Expr, - unadjusted_self_ty: Ty<'tcx>, - pick: probe::Pick<'tcx>, - supplied_method_types: Vec>) - -> ty::MethodCallee<'tcx> +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { +pub fn confirm_method(&self, + span: Span, + self_expr: &'tcx hir::Expr, + call_expr: &'tcx hir::Expr, + unadjusted_self_ty: Ty<'tcx>, + pick: probe::Pick<'tcx>, + supplied_method_types: Vec>) + -> ty::MethodCallee<'tcx> { debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})", unadjusted_self_ty, pick, supplied_method_types); - let mut confirm_cx = ConfirmContext::new(fcx, span, self_expr, call_expr); + let mut confirm_cx = ConfirmContext::new(self, span, self_expr, call_expr); confirm_cx.confirm(unadjusted_self_ty, pick, supplied_method_types) } +} impl<'a,'tcx> ConfirmContext<'a,'tcx> { fn new(fcx: &'a FnCtxt<'a, 'tcx>, @@ -155,13 +157,12 @@ 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, - self.span, - unadjusted_self_ty, - || Some(self.self_expr), - UnresolvedTypeAction::Error, - NoPreference, - |_, n| { + let (autoderefd_ty, n, result) = self.fcx.autoderef(self.span, + unadjusted_self_ty, + || Some(self.self_expr), + UnresolvedTypeAction::Error, + NoPreference, + |_, n| { if n == pick.autoderefs { Some(()) } else { @@ -205,7 +206,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let impl_def_id = pick.item.container().id(); assert!(self.tcx().impl_trait_ref(impl_def_id).is_none(), "impl {:?} is not an inherent impl", impl_def_id); - check::impl_self_ty(self.fcx, self.span, impl_def_id).substs + self.fcx.impl_self_ty(self.span, impl_def_id).substs } probe::ObjectPick => { @@ -245,7 +246,7 @@ 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 = self.fcx.impl_self_ty(self.span, impl_def_id); let impl_trait_ref = self.fcx.instantiate_type_scheme( self.span, @@ -284,13 +285,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // yield an object-type (e.g., `&Object` or `Box` // etc). - let (_, _, result) = check::autoderef(self.fcx, - self.span, - self_ty, - || None, - UnresolvedTypeAction::Error, - NoPreference, - |ty, _| { + let (_, _, result) = self.fcx.autoderef(self.span, + self_ty, + || None, + UnresolvedTypeAction::Error, + NoPreference, + |ty, _| { match ty.sty { ty::TyTrait(ref data) => Some(closure(self, ty, &data)), _ => None, @@ -506,19 +506,18 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { i, expr, autoderef_count); if autoderef_count > 0 { - check::autoderef(self.fcx, - expr.span, - self.fcx.expr_ty(expr), - || Some(expr), - UnresolvedTypeAction::Error, - PreferMutLvalue, - |_, autoderefs| { - if autoderefs == autoderef_count + 1 { - Some(()) - } else { - None - } - }); + self.fcx.autoderef(expr.span, + self.fcx.expr_ty(expr), + || Some(expr), + UnresolvedTypeAction::Error, + PreferMutLvalue, + |_, autoderefs| { + if autoderefs == autoderef_count + 1 { + Some(()) + } else { + None + } + }); } // Don't retry the first one or we might infinite loop! @@ -576,8 +575,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { }; let index_expr_ty = self.fcx.expr_ty(&index_expr); - let result = check::try_index_step( - self.fcx, + let result = self.fcx.try_index_step( ty::MethodCall::expr(expr.id), expr, &base_expr, @@ -588,10 +586,10 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { index_expr_ty); if let Some((input_ty, return_ty)) = result { - demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty); + self.fcx.demand_suptype(index_expr.span, input_ty, index_expr_ty); let expr_ty = self.fcx.expr_ty(&expr); - demand::suptype(self.fcx, expr.span, expr_ty, return_ty); + self.fcx.demand_suptype(expr.span, expr_ty, return_ty); } } hir::ExprUnary(hir::UnDeref, ref base_expr) => { @@ -599,9 +597,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // a preference for mut let method_call = ty::MethodCall::expr(expr.id); if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) { - let method = check::try_overloaded_deref( - self.fcx, - expr.span, + let method = self.fcx.try_overloaded_deref(expr.span, Some(&base_expr), self.fcx.expr_ty(&base_expr), PreferMutLvalue); diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 467956b6497..63df0021852 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -27,7 +27,7 @@ use rustc::hir; pub use self::MethodError::*; pub use self::CandidateSource::*; -pub use self::suggest::{report_error, AllTraitsVec}; +pub use self::suggest::AllTraitsVec; mod confirm; mod probe; @@ -78,16 +78,17 @@ pub enum CandidateSource { TraitSource(/* trait id */ DefId), } +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Determines whether the type `self_ty` supports a method name `method_name` or not. -pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - method_name: ast::Name, - self_ty: ty::Ty<'tcx>, - call_expr_id: ast::NodeId) - -> bool +pub fn method_exists(&self, + span: Span, + method_name: ast::Name, + self_ty: ty::Ty<'tcx>, + call_expr_id: ast::NodeId) + -> bool { let mode = probe::Mode::MethodCall; - match probe::probe(fcx, span, mode, method_name, self_ty, call_expr_id) { + match self.probe_method(span, mode, method_name, self_ty, call_expr_id) { Ok(..) => true, Err(NoMatch(..)) => false, Err(Ambiguity(..)) => true, @@ -110,14 +111,14 @@ 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>, - span: Span, - method_name: ast::Name, - self_ty: ty::Ty<'tcx>, - supplied_method_types: Vec>, - call_expr: &'tcx hir::Expr, - self_expr: &'tcx hir::Expr) - -> Result, MethodError<'tcx>> +pub fn lookup_method(&self, + span: Span, + method_name: ast::Name, + self_ty: ty::Ty<'tcx>, + supplied_method_types: Vec>, + call_expr: &'tcx hir::Expr, + self_expr: &'tcx hir::Expr) + -> Result, MethodError<'tcx>> { debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})", method_name, @@ -126,27 +127,27 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, self_expr); let mode = probe::Mode::MethodCall; - let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty); - let pick = probe::probe(fcx, span, mode, method_name, self_ty, call_expr.id)?; + let self_ty = self.infcx().resolve_type_vars_if_possible(&self_ty); + let pick = self.probe_method(span, mode, method_name, self_ty, call_expr.id)?; if let Some(import_id) = pick.import_id { - fcx.tcx().used_trait_imports.borrow_mut().insert(import_id); + self.tcx().used_trait_imports.borrow_mut().insert(import_id); } - Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types)) + Ok(self.confirm_method(span, self_expr, call_expr, self_ty, pick, supplied_method_types)) } -pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - self_expr: Option<&hir::Expr>, - m_name: ast::Name, - trait_def_id: DefId, - self_ty: ty::Ty<'tcx>, - opt_input_types: Option>>) - -> Option> +pub fn lookup_method_in_trait(&self, + span: Span, + self_expr: Option<&hir::Expr>, + m_name: ast::Name, + trait_def_id: DefId, + self_ty: ty::Ty<'tcx>, + opt_input_types: Option>>) + -> Option> { - lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id, - 0, false, self_ty, opt_input_types) + self.lookup_method_in_trait_adjusted(span, self_expr, m_name, trait_def_id, + 0, false, self_ty, opt_input_types) } /// `lookup_in_trait_adjusted` is used for overloaded operators. It does a very narrow slice of @@ -158,16 +159,16 @@ 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>, - span: Span, - self_expr: Option<&hir::Expr>, - m_name: ast::Name, - trait_def_id: DefId, - autoderefs: usize, - unsize: bool, - self_ty: ty::Ty<'tcx>, - opt_input_types: Option>>) - -> Option> +pub fn lookup_method_in_trait_adjusted(&self, + span: Span, + self_expr: Option<&hir::Expr>, + m_name: ast::Name, + trait_def_id: DefId, + autoderefs: usize, + unsize: bool, + self_ty: ty::Ty<'tcx>, + opt_input_types: Option>>) + -> Option> { debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, m_name={}, trait_def_id={:?})", self_ty, @@ -175,7 +176,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, m_name, trait_def_id); - let trait_def = fcx.tcx().lookup_trait_def(trait_def_id); + let trait_def = self.tcx().lookup_trait_def(trait_def_id); let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace); let expected_number_of_input_types = type_parameter_defs.len(); @@ -193,7 +194,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } None => { - fcx.inh.infcx.type_vars_for_defs( + self.inh.infcx.type_vars_for_defs( span, subst::ParamSpace::TypeSpace, &mut substs, @@ -201,16 +202,16 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } - let trait_ref = ty::TraitRef::new(trait_def_id, fcx.tcx().mk_substs(substs)); + let trait_ref = ty::TraitRef::new(trait_def_id, self.tcx().mk_substs(substs)); // Construct an obligation let poly_trait_ref = trait_ref.to_poly_trait_ref(); let obligation = traits::Obligation::misc(span, - fcx.body_id, + self.body_id, poly_trait_ref.to_predicate()); // Now we want to know if this can be matched - let mut selcx = traits::SelectionContext::new(fcx.infcx()); + let mut selcx = traits::SelectionContext::new(self.infcx()); if !selcx.evaluate_obligation(&obligation) { debug!("--> Cannot match obligation"); return None; // Cannot be matched, no such method resolution is possible. @@ -218,8 +219,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Trait must have a method named `m_name` and it should not have // type parameters or early-bound regions. - let tcx = fcx.tcx(); - let method_item = trait_item(fcx, trait_def_id, m_name).unwrap(); + let tcx = self.tcx(); + let method_item = self.trait_item(trait_def_id, m_name).unwrap(); let method_ty = method_item.as_opt_method().unwrap(); assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0); assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0); @@ -233,10 +234,10 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - 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 = self.infcx().replace_late_bound_regions_with_fresh_var(span, + infer::FnCall, + &method_ty.fty.sig).0; + let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); let transformed_self_ty = fn_sig.inputs[0]; let def_id = method_item.def_id(); let fty = tcx.mk_fn_def(def_id, trait_ref.substs, ty::BareFnTy { @@ -257,19 +258,19 @@ 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 = self.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates); assert!(!method_bounds.has_escaping_regions()); - fcx.add_obligations_for_parameters( - traits::ObligationCause::misc(span, fcx.body_id), + self.add_obligations_for_parameters( + traits::ObligationCause::misc(span, self.body_id), &method_bounds); // Also register an obligation for the method type being well-formed. - fcx.register_wf_obligation(fty, span, traits::MiscObligation); + self.register_wf_obligation(fty, span, traits::MiscObligation); // FIXME(#18653) -- Try to resolve obligations, giving us more // typing information, which can sometimes be needed to avoid // pathological region inference failures. - fcx.select_obligations_where_possible(); + self.select_obligations_where_possible(); // Insert any adjustments needed (always an autoref of some mutability). match self_expr { @@ -285,7 +286,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ty::ExplicitSelfCategory::ByValue => { // Trait method is fn(self), no transformation needed. assert!(!unsize); - fcx.write_autoderef_adjustment(self_expr.id, autoderefs); + self.write_autoderef_adjustment(self_expr.id, autoderefs); } ty::ExplicitSelfCategory::ByReference(..) => { @@ -293,7 +294,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::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => { - fcx.write_adjustment(self_expr.id, + self.write_adjustment(self_expr.id, AdjustDerefRef(AutoDerefRef { autoderefs: autoderefs, autoref: Some(AutoPtr(region, mutbl)), @@ -335,25 +336,25 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(callee) } -pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - method_name: ast::Name, - self_ty: ty::Ty<'tcx>, - expr_id: ast::NodeId) - -> Result> +pub fn resolve_ufcs(&self, + span: Span, + method_name: ast::Name, + self_ty: ty::Ty<'tcx>, + expr_id: ast::NodeId) + -> Result> { let mode = probe::Mode::Path; - let pick = probe::probe(fcx, span, mode, method_name, self_ty, expr_id)?; + let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?; if let Some(import_id) = pick.import_id { - fcx.tcx().used_trait_imports.borrow_mut().insert(import_id); + self.tcx().used_trait_imports.borrow_mut().insert(import_id); } let def = pick.item.def(); if let probe::InherentImplPick = pick.kind { - if !pick.item.vis().is_accessible_from(fcx.body_id, &fcx.tcx().map) { + if !pick.item.vis().is_accessible_from(self.body_id, &self.tcx().map) { let msg = format!("{} `{}` is private", def.kind_name(), &method_name.as_str()); - fcx.tcx().sess.span_err(span, &msg); + self.tcx().sess.span_err(span, &msg); } } Ok(def) @@ -361,26 +362,27 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// Find item with name `item_name` defined in `trait_def_id` /// and return it, or `None`, if no such item. -pub fn trait_item<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - trait_def_id: DefId, - item_name: ast::Name) - -> Option> +pub fn trait_item(&self, + trait_def_id: DefId, + item_name: ast::Name) + -> Option> { - let trait_items = fcx.tcx().trait_items(trait_def_id); + let trait_items = self.tcx().trait_items(trait_def_id); trait_items.iter() .find(|item| item.name() == item_name) .cloned() } -pub fn impl_item<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - impl_def_id: DefId, - item_name: ast::Name) - -> Option> +pub fn impl_item(&self, + impl_def_id: DefId, + item_name: ast::Name) + -> Option> { - let impl_items = fcx.tcx().impl_items.borrow(); + let impl_items = self.tcx().impl_items.borrow(); let impl_items = impl_items.get(&impl_def_id).unwrap(); impl_items .iter() - .map(|&did| fcx.tcx().impl_or_trait_item(did.def_id())) + .map(|&did| self.tcx().impl_or_trait_item(did.def_id())) .find(|m| m.name() == item_name) } +} diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 96cedc76d05..56f1f4677c6 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -13,7 +13,6 @@ use super::NoMatchData; use super::{CandidateSource, ImplSource, TraitSource}; use super::suggest; -use check; use check::{FnCtxt, UnresolvedTypeAction}; use hir::def_id::DefId; use hir::def::Def; @@ -129,13 +128,14 @@ pub enum Mode { Path } -pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - mode: Mode, - item_name: ast::Name, - self_ty: Ty<'tcx>, - scope_expr_id: ast::NodeId) - -> PickResult<'tcx> +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { +pub fn probe_method(&self, + span: Span, + mode: Mode, + item_name: ast::Name, + self_ty: Ty<'tcx>, + scope_expr_id: ast::NodeId) + -> PickResult<'tcx> { debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})", self_ty, @@ -148,9 +148,9 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // side-effects. This is a bit of a pain to refactor. So just let // it ride, although it's really not great, and in fact could I // think cause spurious errors. Really though this part should - // take place in the `fcx.infcx().probe` below. + // take place in the `self.infcx().probe` below. let steps = if mode == Mode::MethodCall { - match create_steps(fcx, span, self_ty) { + match self.create_steps(span, self_ty) { Some(steps) => steps, None =>return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), Vec::new(), Vec::new(), mode))), @@ -166,7 +166,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Create a list of simplified self types, if we can. let mut simplified_steps = Vec::new(); for step in &steps { - match ty::fast_reject::simplify_type(fcx.tcx(), step.self_ty, true) { + match ty::fast_reject::simplify_type(self.tcx(), step.self_ty, true) { None => { break; } Some(simplified_type) => { simplified_steps.push(simplified_type); } } @@ -184,8 +184,8 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // this creates one big transaction so that all type variables etc // that we create during the probe process are removed later - fcx.infcx().probe(|_| { - let mut probe_cx = ProbeContext::new(fcx, + self.infcx().probe(|_| { + let mut probe_cx = ProbeContext::new(self, span, mode, item_name, @@ -197,19 +197,18 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }) } -fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - self_ty: Ty<'tcx>) - -> Option>> { +fn create_steps(&self, + span: Span, + self_ty: Ty<'tcx>) + -> Option>> { let mut steps = Vec::new(); - let (final_ty, dereferences, _) = check::autoderef(fcx, - span, - self_ty, - || None, - UnresolvedTypeAction::Error, - NoPreference, - |t, d| { + let (final_ty, dereferences, _) = self.autoderef(span, + self_ty, + || None, + UnresolvedTypeAction::Error, + NoPreference, + |t, d| { steps.push(CandidateStep { self_ty: t, autoderefs: d, @@ -221,7 +220,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match final_ty.sty { ty::TyArray(elem_ty, _) => { steps.push(CandidateStep { - self_ty: fcx.tcx().mk_slice(elem_ty), + self_ty: self.tcx().mk_slice(elem_ty), autoderefs: dereferences, unsize: true }); @@ -232,6 +231,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(steps) } +} impl<'a,'tcx> ProbeContext<'a,'tcx> { fn new(fcx: &'a FnCtxt<'a,'tcx>, @@ -1313,7 +1313,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn impl_item(&self, impl_def_id: DefId) -> Option> { - super::impl_item(self.fcx, impl_def_id, self.item_name) + self.fcx.impl_item(impl_def_id, self.item_name) } /// Find item with name `item_name` defined in `trait_def_id` @@ -1321,7 +1321,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn trait_item(&self, trait_def_id: DefId) -> Option> { - super::trait_item(self.fcx, trait_def_id, self.item_name) + self.fcx.trait_item(trait_def_id, self.item_name) } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 9b81c4e2e92..d9af3552d85 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -13,7 +13,7 @@ use CrateCtxt; -use check::{self, FnCtxt, UnresolvedTypeAction, autoderef}; +use check::{self, FnCtxt, UnresolvedTypeAction}; use rustc::hir::map as hir_map; use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable}; use middle::cstore; @@ -36,11 +36,12 @@ use rustc::hir::Expr_; use std::cell; use std::cmp::Ordering; -use super::{MethodError, NoMatchData, CandidateSource, impl_item, trait_item}; +use super::{MethodError, NoMatchData, CandidateSource}; use super::probe::Mode; -fn is_fn_ty<'a, 'tcx>(ty: &Ty<'tcx>, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> bool { - let cx = fcx.tcx(); +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { +fn is_fn_ty(&self, ty: &Ty<'tcx>, span: Span) -> bool { + let tcx = self.tcx(); match ty.sty { // Not all of these (e.g. unsafe fns) implement FnOnce // so we look for these beforehand @@ -48,26 +49,23 @@ fn is_fn_ty<'a, 'tcx>(ty: &Ty<'tcx>, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> bool // If it's not a simple function, look for things which implement FnOnce _ => { if let Ok(fn_once_trait_did) = - cx.lang_items.require(FnOnceTraitLangItem) { - let infcx = fcx.infcx(); - let (_, _, opt_is_fn) = autoderef(fcx, - span, - ty, - || None, - UnresolvedTypeAction::Ignore, - LvaluePreference::NoPreference, - |ty, _| { + tcx.lang_items.require(FnOnceTraitLangItem) { + let infcx = self.infcx(); + let (_, _, opt_is_fn) = self.autoderef(span, + ty, + || None, + UnresolvedTypeAction::Ignore, + LvaluePreference::NoPreference, + |ty, _| { infcx.probe(|_| { let fn_once_substs = - Substs::new_trait(vec![infcx.next_ty_var()], - Vec::new(), - ty); + Substs::new_trait(vec![infcx.next_ty_var()], vec![], ty); let trait_ref = - ty::TraitRef::new(fn_once_trait_did, - cx.mk_substs(fn_once_substs)); + ty::TraitRef::new(fn_once_trait_did, + tcx.mk_substs(fn_once_substs)); let poly_trait_ref = trait_ref.to_poly_trait_ref(); let obligation = Obligation::misc(span, - fcx.body_id, + self.body_id, poly_trait_ref .to_predicate()); let mut selcx = SelectionContext::new(infcx); @@ -87,144 +85,21 @@ fn is_fn_ty<'a, 'tcx>(ty: &Ty<'tcx>, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> bool } } } - -pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - rcvr_ty: Ty<'tcx>, - item_name: ast::Name, - rcvr_expr: Option<&hir::Expr>, - error: MethodError<'tcx>) +pub fn report_method_error(&self, + span: Span, + rcvr_ty: Ty<'tcx>, + item_name: ast::Name, + rcvr_expr: Option<&hir::Expr>, + error: MethodError<'tcx>) { // avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { return } - match error { - MethodError::NoMatch(NoMatchData { static_candidates: static_sources, - unsatisfied_predicates, - out_of_scope_traits, - mode, .. }) => { - let cx = fcx.tcx(); + let report_candidates = |err: &mut DiagnosticBuilder, + mut sources: Vec| { - let mut err = fcx.type_error_struct( - span, - |actual| { - format!("no {} named `{}` found for type `{}` \ - in the current scope", - if mode == Mode::MethodCall { "method" } - else { "associated item" }, - item_name, - actual) - }, - rcvr_ty, - None); - - // If the item has the name of a field, give a help note - if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { - if let Some(field) = def.struct_variant().find_field_named(item_name) { - let expr_string = match cx.sess.codemap().span_to_snippet(expr.span) { - Ok(expr_string) => expr_string, - _ => "s".into() // Default to a generic placeholder for the - // expression when we can't generate a string - // snippet - }; - - let field_ty = field.ty(cx, substs); - - if is_fn_ty(&field_ty, &fcx, span) { - err.span_note(span, - &format!("use `({0}.{1})(...)` if you meant to call \ - the function stored in the `{1}` field", - expr_string, item_name)); - } else { - err.span_note(span, &format!("did you mean to write `{0}.{1}`?", - expr_string, item_name)); - } - } - } - - if is_fn_ty(&rcvr_ty, &fcx, span) { - macro_rules! report_function { - ($span:expr, $name:expr) => { - err.note(&format!("{} is a function, perhaps you wish to call it", - $name)); - } - } - - if let Some(expr) = rcvr_expr { - if let Ok (expr_string) = cx.sess.codemap().span_to_snippet(expr.span) { - report_function!(expr.span, expr_string); - } - else if let Expr_::ExprPath(_, path) = expr.node.clone() { - if let Some(segment) = path.segments.last() { - report_function!(expr.span, segment.identifier.name); - } - } - } - } - - if !static_sources.is_empty() { - err.note( - "found the following associated functions; to be used as \ - methods, functions must have a `self` parameter"); - - report_candidates(fcx, &mut err, span, item_name, static_sources); - } - - if !unsatisfied_predicates.is_empty() { - let bound_list = unsatisfied_predicates.iter() - .map(|p| format!("`{} : {}`", - p.self_ty(), - p)) - .collect::>() - .join(", "); - err.note( - &format!("the method `{}` exists but the \ - following trait bounds were not satisfied: {}", - item_name, - bound_list)); - } - - suggest_traits_to_import(fcx, &mut err, span, rcvr_ty, item_name, - rcvr_expr, out_of_scope_traits); - err.emit(); - } - - MethodError::Ambiguity(sources) => { - let mut err = struct_span_err!(fcx.sess(), span, E0034, - "multiple applicable items in scope"); - - report_candidates(fcx, &mut err, span, item_name, sources); - err.emit(); - } - - MethodError::ClosureAmbiguity(trait_def_id) => { - let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \ - invoked on this closure as we have not yet inferred what \ - kind of closure it is", - item_name, - fcx.tcx().item_path_str(trait_def_id)); - let msg = if let Some(callee) = rcvr_expr { - format!("{}; use overloaded call notation instead (e.g., `{}()`)", - msg, pprust::expr_to_string(callee)) - } else { - msg - }; - fcx.sess().span_err(span, &msg); - } - - MethodError::PrivateMatch(def) => { - let msg = format!("{} `{}` is private", def.kind_name(), item_name); - fcx.tcx().sess.span_err(span, &msg); - } - } - - fn report_candidates(fcx: &FnCtxt, - err: &mut DiagnosticBuilder, - span: Span, - item_name: ast::Name, - mut sources: Vec) { sources.sort(); sources.dedup(); @@ -233,25 +108,25 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, CandidateSource::ImplSource(impl_did) => { // Provide the best span we can. Use the item, if local to crate, else // the impl, if local to crate (item may be defaulted), else nothing. - let item = impl_item(fcx, impl_did, item_name) + let item = self.impl_item(impl_did, item_name) .or_else(|| { - trait_item( - fcx, - fcx.tcx().impl_trait_ref(impl_did).unwrap().def_id, + self.trait_item( + self.tcx().impl_trait_ref(impl_did).unwrap().def_id, + item_name ) }).unwrap(); - let note_span = fcx.tcx().map.span_if_local(item.def_id()).or_else(|| { - fcx.tcx().map.span_if_local(impl_did) + let note_span = self.tcx().map.span_if_local(item.def_id()).or_else(|| { + self.tcx().map.span_if_local(impl_did) }); - let impl_ty = check::impl_self_ty(fcx, span, impl_did).ty; + let impl_ty = self.impl_self_ty(span, impl_did).ty; - let insertion = match fcx.tcx().impl_trait_ref(impl_did) { + let insertion = match self.tcx().impl_trait_ref(impl_did) { None => format!(""), Some(trait_ref) => { format!(" of the trait `{}`", - fcx.tcx().item_path_str(trait_ref.def_id)) + self.tcx().item_path_str(trait_ref.def_id)) } }; @@ -268,28 +143,145 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } CandidateSource::TraitSource(trait_did) => { - let item = trait_item(fcx, trait_did, item_name).unwrap(); - let item_span = fcx.tcx().map.def_id_span(item.def_id(), span); + let item = self.trait_item(trait_did, item_name).unwrap(); + let item_span = self.tcx().map.def_id_span(item.def_id(), span); span_note!(err, item_span, "candidate #{} is defined in the trait `{}`", idx + 1, - fcx.tcx().item_path_str(trait_did)); + self.tcx().item_path_str(trait_did)); } } } + }; + + match error { + MethodError::NoMatch(NoMatchData { static_candidates: static_sources, + unsatisfied_predicates, + out_of_scope_traits, + mode, .. }) => { + let tcx = self.tcx(); + + let mut err = self.type_error_struct( + span, + |actual| { + format!("no {} named `{}` found for type `{}` \ + in the current scope", + if mode == Mode::MethodCall { "method" } + else { "associated item" }, + item_name, + actual) + }, + rcvr_ty, + None); + + // If the item has the name of a field, give a help note + if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { + if let Some(field) = def.struct_variant().find_field_named(item_name) { + let expr_string = match tcx.sess.codemap().span_to_snippet(expr.span) { + Ok(expr_string) => expr_string, + _ => "s".into() // Default to a generic placeholder for the + // expression when we can't generate a string + // snippet + }; + + let field_ty = field.ty(tcx, substs); + + if self.is_fn_ty(&field_ty, span) { + err.span_note(span, + &format!("use `({0}.{1})(...)` if you meant to call \ + the function stored in the `{1}` field", + expr_string, item_name)); + } else { + err.span_note(span, &format!("did you mean to write `{0}.{1}`?", + expr_string, item_name)); + } + } + } + + if self.is_fn_ty(&rcvr_ty, span) { + macro_rules! report_function { + ($span:expr, $name:expr) => { + err.note(&format!("{} is a function, perhaps you wish to call it", + $name)); + } + } + + if let Some(expr) = rcvr_expr { + if let Ok (expr_string) = tcx.sess.codemap().span_to_snippet(expr.span) { + report_function!(expr.span, expr_string); + } + else if let Expr_::ExprPath(_, path) = expr.node.clone() { + if let Some(segment) = path.segments.last() { + report_function!(expr.span, segment.identifier.name); + } + } + } + } + + if !static_sources.is_empty() { + err.note( + "found the following associated functions; to be used as \ + methods, functions must have a `self` parameter"); + + report_candidates(&mut err, static_sources); + } + + if !unsatisfied_predicates.is_empty() { + let bound_list = unsatisfied_predicates.iter() + .map(|p| format!("`{} : {}`", + p.self_ty(), + p)) + .collect::>() + .join(", "); + err.note( + &format!("the method `{}` exists but the \ + following trait bounds were not satisfied: {}", + item_name, + bound_list)); + } + + self.suggest_traits_to_import(&mut err, span, rcvr_ty, item_name, + rcvr_expr, out_of_scope_traits); + err.emit(); + } + + MethodError::Ambiguity(sources) => { + let mut err = struct_span_err!(self.sess(), span, E0034, + "multiple applicable items in scope"); + + report_candidates(&mut err, sources); + err.emit(); + } + + MethodError::ClosureAmbiguity(trait_def_id) => { + let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \ + invoked on this closure as we have not yet inferred what \ + kind of closure it is", + item_name, + self.tcx().item_path_str(trait_def_id)); + let msg = if let Some(callee) = rcvr_expr { + format!("{}; use overloaded call notation instead (e.g., `{}()`)", + msg, pprust::expr_to_string(callee)) + } else { + msg + }; + self.sess().span_err(span, &msg); + } + + MethodError::PrivateMatch(def) => { + let msg = format!("{} `{}` is private", def.kind_name(), item_name); + self.tcx().sess.span_err(span, &msg); + } } } - -pub type AllTraitsVec = Vec; - -fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - err: &mut DiagnosticBuilder, - span: Span, - rcvr_ty: Ty<'tcx>, - item_name: ast::Name, - rcvr_expr: Option<&hir::Expr>, - valid_out_of_scope_traits: Vec) +fn suggest_traits_to_import(&self, + err: &mut DiagnosticBuilder, + span: Span, + rcvr_ty: Ty<'tcx>, + item_name: ast::Name, + rcvr_expr: Option<&hir::Expr>, + valid_out_of_scope_traits: Vec) { if !valid_out_of_scope_traits.is_empty() { let mut candidates = valid_out_of_scope_traits; @@ -307,17 +299,17 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, for (i, trait_did) in candidates.iter().enumerate() { err.help(&format!("candidate #{}: `use {}`", i + 1, - fcx.tcx().item_path_str(*trait_did))); + self.tcx().item_path_str(*trait_did))); } return } - let type_is_local = type_derefs_to_local(fcx, span, rcvr_ty, rcvr_expr); + let type_is_local = self.type_derefs_to_local(span, rcvr_ty, rcvr_expr); // there's no implemented traits, so lets suggest some traits to // implement, by finding ones that have the item name, and are // legal to implement. - let mut candidates = all_traits(fcx.ccx) + let mut candidates = all_traits(self.ccx) .filter(|info| { // we approximate the coherence rules to only suggest // traits that are legal to implement by requiring that @@ -326,7 +318,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // implementing a trait would be legal but is rejected // here). (type_is_local || info.def_id.is_local()) - && trait_item(fcx, info.def_id, item_name).is_some() + && self.trait_item(info.def_id, item_name).is_some() }) .collect::>(); @@ -351,17 +343,17 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, for (i, trait_info) in candidates.iter().enumerate() { err.help(&format!("candidate #{}: `{}`", i + 1, - fcx.tcx().item_path_str(trait_info.def_id))); + self.tcx().item_path_str(trait_info.def_id))); } } } /// 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>, - span: Span, - rcvr_ty: Ty<'tcx>, - rcvr_expr: Option<&hir::Expr>) -> bool { +fn type_derefs_to_local(&self, + span: Span, + rcvr_ty: Ty<'tcx>, + rcvr_expr: Option<&hir::Expr>) -> bool { fn is_local(ty: Ty) -> bool { match ty.sty { ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.did.is_local(), @@ -381,12 +373,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(self.resolve_type_vars_if_possible(rcvr_ty)); } - check::autoderef(fcx, span, rcvr_ty, || None, - check::UnresolvedTypeAction::Ignore, ty::NoPreference, - |ty, _| { + self.autoderef(span, rcvr_ty, || None, + check::UnresolvedTypeAction::Ignore, ty::NoPreference, + |ty, _| { if is_local(ty) { Some(()) } else { @@ -394,6 +386,9 @@ fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } }).2.is_some() } +} + +pub type AllTraitsVec = Vec; #[derive(Copy, Clone)] pub struct TraitInfo { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d9807cc7bae..0da41ba41e4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -81,7 +81,7 @@ pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::TupleArgumentsFlag::*; use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode}; -use check::_match::pat_ctxt; +use check::_match::PatCtxt; use dep_graph::DepNode; use fmt_macros::{Parser, Piece, Position}; use middle::astconv_util::prohibit_type_params; @@ -199,7 +199,7 @@ pub enum Expectation<'tcx> { ExpectRvalueLikeUnsized(Ty<'tcx>), } -impl<'tcx> Expectation<'tcx> { +impl<'a, 'tcx> Expectation<'tcx> { // Disregard "castable to" expectations because they // can lead us astray. Consider for example `if cond // {22} else {c} as u8` -- if we propagate the @@ -216,7 +216,7 @@ impl<'tcx> Expectation<'tcx> { // an expected type. Otherwise, we might write parts of the type // when checking the 'then' block which are incompatible with the // 'else' branch. - fn adjust_for_branches<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { + fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { match *self { ExpectHasType(ety) => { let ety = fcx.infcx().shallow_resolve(ety); @@ -232,6 +232,73 @@ impl<'tcx> Expectation<'tcx> { _ => NoExpectation } } + + /// Provide an expectation for an rvalue expression given an *optional* + /// hint, which is not required for type safety (the resulting type might + /// be checked higher up, as is the case with `&expr` and `box expr`), but + /// is useful in determining the concrete type. + /// + /// The primary use case is where the expected type is a fat pointer, + /// like `&[isize]`. For example, consider the following statement: + /// + /// let x: &[isize] = &[1, 2, 3]; + /// + /// In this case, the expected type for the `&[1, 2, 3]` expression is + /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the + /// expectation `ExpectHasType([isize])`, that would be too strong -- + /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`. + /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced + /// to the type `&[isize]`. Therefore, we propagate this more limited hint, + /// which still is useful, because it informs integer literals and the like. + /// See the test case `test/run-pass/coerce-expect-unsized.rs` and #20169 + /// for examples of where this comes up,. + fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> { + match fcx.tcx().struct_tail(ty).sty { + ty::TySlice(_) | ty::TyStr | ty::TyTrait(..) => { + ExpectRvalueLikeUnsized(ty) + } + _ => ExpectHasType(ty) + } + } + + // 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(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { + match self { + NoExpectation => { + NoExpectation + } + ExpectCastableToType(t) => { + ExpectCastableToType( + fcx.infcx().resolve_type_vars_if_possible(&t)) + } + ExpectHasType(t) => { + ExpectHasType( + fcx.infcx().resolve_type_vars_if_possible(&t)) + } + ExpectRvalueLikeUnsized(t) => { + ExpectRvalueLikeUnsized( + fcx.infcx().resolve_type_vars_if_possible(&t)) + } + } + } + + fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { + match self.resolve(fcx) { + NoExpectation => None, + ExpectCastableToType(ty) | + ExpectHasType(ty) | + ExpectRvalueLikeUnsized(ty) => Some(ty), + } + } + + fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { + match self.resolve(fcx) { + ExpectHasType(ty) => Some(ty), + _ => None + } + } } #[derive(Copy, Clone)] @@ -330,23 +397,6 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { } -// Used by check_const and check_enum_variants -pub fn blank_fn_ctxt<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, - inh: &'a Inherited<'a, 'tcx>, - rty: ty::FnOutput<'tcx>, - body_id: ast::NodeId) - -> FnCtxt<'a, 'tcx> { - FnCtxt { - body_id: body_id, - writeback_errors: Cell::new(false), - err_count_on_creation: ccx.tcx.sess.err_count(), - ret_ty: rty, - ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, 0)), - inh: inh, - ccx: ccx - } -} - fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, tables: &'a RefCell>) -> Inherited<'a, 'tcx> { @@ -452,13 +502,13 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, decl, fn_id, body, &inh); fcx.select_all_obligations_and_apply_defaults(); - upvar::closure_analyze_fn(&fcx, fn_id, decl, body); + fcx.closure_analyze_fn(body); fcx.select_obligations_where_possible(); fcx.check_casts(); fcx.select_all_obligations_or_error(); // Casts can introduce new obligations. - regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body); - writeback::resolve_type_vars_in_fn(&fcx, decl, body); + fcx.regionck_fn(fn_id, fn_span, decl, body); + fcx.resolve_type_vars_in_fn(decl, body); } _ => span_bug!(body.span, "check_bare_fn: function type expected") } @@ -504,7 +554,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { // Add pattern bindings. fn visit_pat(&mut self, p: &'tcx hir::Pat) { if let PatKind::Ident(_, ref path1, _) = p.node { - if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map.borrow(), p) { + if pat_util::pat_is_binding(&self.fcx.tcx().def_map.borrow(), p) { let var_ty = self.assign(p.span, p.id, None); self.fcx.require_type_is_sized(var_ty, p.span, @@ -533,7 +583,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { match t.node { hir::TyFixedLengthVec(ref ty, ref count_expr) => { self.visit_ty(&ty); - check_expr_with_hint(self.fcx, &count_expr, self.fcx.tcx().types.usize); + self.fcx.check_expr_with_hint(&count_expr, self.fcx.tcx().types.usize); } hir::TyBareFn(ref function_declaration) => { intravisit::walk_fn_decl_nopat(self, &function_declaration.decl); @@ -565,7 +615,6 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, -> FnCtxt<'a, 'tcx> { let tcx = ccx.tcx; - let err_count_on_creation = tcx.sess.err_count(); let arg_tys = &fn_sig.inputs; let ret_ty = fn_sig.output; @@ -577,15 +626,8 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, // Create the function context. This is either derived from scratch or, // in the case of function expressions, based on the outer context. - let fcx = FnCtxt { - body_id: body.id, - 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)), - inh: inherited, - ccx: ccx - }; + let fcx = FnCtxt::new(ccx, inherited, ret_ty, body.id); + *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id); if let ty::FnConverging(ret_ty) = ret_ty { fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType); @@ -619,17 +661,17 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, }); // Check the pattern. - let pcx = pat_ctxt { + let pcx = PatCtxt { fcx: &fcx, map: pat_id_map(&tcx.def_map, &input.pat), }; - _match::check_pat(&pcx, &input.pat, *arg_ty); + pcx.check_pat(&input.pat, *arg_ty); } visit.visit_block(body); } - check_block_with_expected(&fcx, body, match ret_ty { + fcx.check_block_with_expected(body, match ret_ty { ty::FnConverging(result_type) => ExpectHasType(result_type), ty::FnDiverging => NoExpectation }); @@ -1075,8 +1117,144 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } +/// Checks a constant appearing in a type. At the moment this is just the +/// length expression in a fixed-length vector, but someday it might be +/// extended to type-level numeric literals. +fn check_const_in_type<'a,'tcx>(ccx: &'a CrateCtxt<'a,'tcx>, + expr: &'tcx hir::Expr, + expected_type: Ty<'tcx>) { + let tables = RefCell::new(ty::Tables::empty()); + let inh = static_inherited_fields(ccx, &tables); + let fcx = FnCtxt::new(ccx, &inh, ty::FnConverging(expected_type), expr.id); + fcx.check_const_with_ty(expr.span, expr, expected_type); +} + +fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + sp: Span, + e: &'tcx hir::Expr, + id: ast::NodeId) { + let tables = RefCell::new(ty::Tables::empty()); + let inh = static_inherited_fields(ccx, &tables); + let rty = ccx.tcx.node_id_to_type(id); + let fcx = FnCtxt::new(ccx, &inh, ty::FnConverging(rty), e.id); + let declty = fcx.tcx().lookup_item_type(ccx.tcx.map.local_def_id(id)).ty; + fcx.check_const_with_ty(sp, e, declty); +} + +/// Checks whether a type can be represented in memory. In particular, it +/// identifies types that contain themselves without indirection through a +/// pointer, which would mean their size is unbounded. +pub fn check_representable(tcx: &TyCtxt, + sp: Span, + item_id: ast::NodeId, + _designation: &str) -> bool { + let rty = tcx.node_id_to_type(item_id); + + // Check that it is possible to represent this type. This call identifies + // (1) types that contain themselves and (2) types that contain a different + // recursive type. It is only necessary to throw an error on those that + // contain themselves. For case 2, there must be an inner type that will be + // caught by case 1. + match rty.is_representable(tcx, sp) { + Representability::SelfRecursive => { + let item_def_id = tcx.map.local_def_id(item_id); + traits::recursive_type_with_infinite_size_error(tcx, item_def_id).emit(); + return false + } + Representability::Representable | Representability::ContainsRecursive => (), + } + return true +} + +pub fn check_simd(tcx: &TyCtxt, sp: Span, id: ast::NodeId) { + let t = tcx.node_id_to_type(id); + match t.sty { + ty::TyStruct(def, substs) => { + let fields = &def.struct_variant().fields; + if fields.is_empty() { + span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty"); + return; + } + let e = fields[0].ty(tcx, substs); + if !fields.iter().all(|f| f.ty(tcx, substs) == e) { + span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous"); + return; + } + match e.sty { + ty::TyParam(_) => { /* struct(T, T, T, T) is ok */ } + _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ } + _ => { + span_err!(tcx.sess, sp, E0077, + "SIMD vector element type should be machine type"); + return; + } + } + } + _ => () + } +} + +pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + sp: Span, + vs: &'tcx [hir::Variant], + id: ast::NodeId) { + fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + vs: &'tcx [hir::Variant], + id: ast::NodeId, + hint: attr::ReprAttr) { + #![allow(trivial_numeric_casts)] + + let rty = ccx.tcx.node_id_to_type(id); + let mut disr_vals: Vec = Vec::new(); + + let tables = RefCell::new(ty::Tables::empty()); + let inh = static_inherited_fields(ccx, &tables); + let fcx = FnCtxt::new(ccx, &inh, ty::FnConverging(rty), id); + + let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx); + for v in vs { + if let Some(ref e) = v.node.disr_expr { + fcx.check_const_with_ty(e.span, e, repr_type_ty); + } + } + + let def_id = ccx.tcx.map.local_def_id(id); + + let variants = &ccx.tcx.lookup_adt_def(def_id).variants; + for (v, variant) in vs.iter().zip(variants.iter()) { + let current_disr_val = variant.disr_val; + + // Check for duplicate discriminant values + match disr_vals.iter().position(|&x| x == current_disr_val) { + Some(i) => { + let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0081, + "discriminant value `{}` already exists", disr_vals[i]); + let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap(); + span_note!(&mut err, ccx.tcx.map.span(variant_i_node_id), + "conflicting discriminant here"); + err.emit(); + } + None => {} + } + disr_vals.push(current_disr_val); + } + } + + let def_id = ccx.tcx.map.local_def_id(id); + let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny); + + if hint != attr::ReprAny && vs.is_empty() { + span_err!(ccx.tcx.sess, sp, E0084, + "unsupported representation for zero-variant enum"); + } + + do_check(ccx, vs, id, hint); + + check_representable(ccx.tcx, sp, id, "enum"); +} + impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { - fn tcx(&self) -> &TyCtxt<'tcx> { self.ccx.tcx } + fn tcx(&self) -> &TyCtxt<'tcx> { self.infcx().tcx } fn get_item_type_scheme(&self, _: Span, id: DefId) -> Result, ErrorReported> @@ -1131,7 +1309,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { assoc_name: ast::Name) -> bool { - let trait_def = self.ccx.tcx.lookup_trait_def(trait_def_id); + let trait_def = self.tcx().lookup_trait_def(trait_def_id); trait_def.associated_type_names.contains(&assoc_name) } @@ -1187,8 +1365,81 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } } +impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> { + fn object_lifetime_default(&self, span: Span) -> Option { + Some(self.base_object_lifetime_default(span)) + } + + fn base_object_lifetime_default(&self, span: Span) -> ty::Region { + // RFC #599 specifies that object lifetime defaults take + // precedence over other defaults. But within a fn body we + // don't have a *default* region, rather we use inference to + // find the *correct* region, which is strictly more general + // (and anyway, within a fn body the right region may not even + // be something the user can write explicitly, since it might + // be some expression). + self.infcx().next_region_var(infer::MiscVariable(span)) + } + + fn anon_regions(&self, span: Span, count: usize) + -> Result, Option>> { + Ok((0..count).map(|_| { + self.infcx().next_region_var(infer::MiscVariable(span)) + }).collect()) + } +} + +/// Whether `autoderef` requires types to resolve. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum UnresolvedTypeAction { + /// Produce an error and return `TyError` whenever a type cannot + /// be resolved (i.e. it is `TyInfer`). + Error, + /// Go on without emitting any errors, and return the unresolved + /// type. Useful for probing, e.g. in coercions. + Ignore +} + +/// Controls whether the arguments are tupled. This is used for the call +/// operator. +/// +/// Tupling means that all call-side arguments are packed into a tuple and +/// passed as a single parameter. For example, if tupling is enabled, this +/// function: +/// +/// fn f(x: (isize, isize)) +/// +/// Can be called as: +/// +/// f(1, 2); +/// +/// Instead of: +/// +/// f((1, 2)); +#[derive(Clone, Eq, PartialEq)] +enum TupleArgumentsFlag { + DontTupleArguments, + TupleArguments, +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - fn tcx(&self) -> &TyCtxt<'tcx> { self.ccx.tcx } + pub fn new(ccx: &'a CrateCtxt<'a, 'tcx>, + inh: &'a Inherited<'a, 'tcx>, + rty: ty::FnOutput<'tcx>, + body_id: ast::NodeId) + -> FnCtxt<'a, 'tcx> { + FnCtxt { + body_id: body_id, + writeback_errors: Cell::new(false), + err_count_on_creation: ccx.tcx.sess.err_count(), + ret_ty: rty, + ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, 0)), + inh: inh, + ccx: ccx + } + } + + pub fn tcx(&self) -> &TyCtxt<'tcx> { self.infcx().tcx } pub fn infcx(&self) -> &InferCtxt<'a,'tcx> { &self.inh.infcx @@ -1203,7 +1454,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn err_count_since_creation(&self) -> usize { - self.ccx.tcx.sess.err_count() - self.err_count_on_creation + self.tcx().sess.err_count() - self.err_count_on_creation } /// Resolves type variables in `ty` if possible. Unlike the infcx @@ -1714,7 +1965,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for ty in &self.infcx().unsolved_variables() { if let ty::TyInfer(_) = self.infcx().shallow_resolve(ty).sty { debug!("default_type_parameters: defaulting `{:?}` to error", ty); - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.err); + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.err); } } return; @@ -1725,18 +1976,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.infcx().type_var_diverges(resolved) { debug!("default_type_parameters: defaulting `{:?}` to `()` because it diverges", resolved); - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); } else { match self.infcx().type_is_unconstrained_numeric(resolved) { UnconstrainedInt => { debug!("default_type_parameters: defaulting `{:?}` to `i32`", resolved); - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.i32) }, UnconstrainedFloat => { debug!("default_type_parameters: defaulting `{:?}` to `f32`", resolved); - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.f64) } Neither => { } } @@ -1799,7 +2050,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for ty in &unsolved_variables { let resolved = self.infcx().resolve_type_vars_if_possible(ty); if self.infcx().type_var_diverges(resolved) { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); } else { match self.infcx().type_is_unconstrained_numeric(resolved) { UnconstrainedInt | UnconstrainedFloat => { @@ -1856,14 +2107,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let _ = self.infcx().commit_if_ok(|_: &infer::CombinedSnapshot| { for ty in &unbound_tyvars { if self.infcx().type_var_diverges(ty) { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); } else { match self.infcx().type_is_unconstrained_numeric(ty) { UnconstrainedInt => { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.i32) }, UnconstrainedFloat => { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.f64) } Neither => { if let Some(default) = default_map.get(ty) { @@ -1952,14 +2203,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // reporting for more then one conflict. for ty in &unbound_tyvars { if self.infcx().type_var_diverges(ty) { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().mk_nil()); } else { match self.infcx().type_is_unconstrained_numeric(ty) { UnconstrainedInt => { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.i32) + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.i32) }, UnconstrainedFloat => { - demand::eqtype(self, codemap::DUMMY_SP, *ty, self.tcx().types.f64) + self.demand_eqtype(codemap::DUMMY_SP, *ty, self.tcx().types.f64) }, Neither => { if let Some(default) = default_map.get(ty) { @@ -2014,56 +2265,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); } } } -} - -impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> { - fn object_lifetime_default(&self, span: Span) -> Option { - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, span: Span) -> ty::Region { - // RFC #599 specifies that object lifetime defaults take - // precedence over other defaults. But within a fn body we - // don't have a *default* region, rather we use inference to - // find the *correct* region, which is strictly more general - // (and anyway, within a fn body the right region may not even - // be something the user can write explicitly, since it might - // be some expression). - self.infcx().next_region_var(infer::MiscVariable(span)) - } - - fn anon_regions(&self, span: Span, count: usize) - -> Result, Option>> { - Ok((0..count).map(|_| { - self.infcx().next_region_var(infer::MiscVariable(span)) - }).collect()) - } -} - -/// Whether `autoderef` requires types to resolve. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum UnresolvedTypeAction { - /// Produce an error and return `TyError` whenever a type cannot - /// be resolved (i.e. it is `TyInfer`). - Error, - /// Go on without emitting any errors, and return the unresolved - /// type. Useful for probing, e.g. in coercions. - Ignore -} /// Executes an autoderef loop for the type `t`. At each step, invokes `should_stop` to decide /// whether to terminate the loop. Returns the final type and number of derefs that it performed. /// /// 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, 'b, 'tcx, E, I, T, F>(fcx: &FnCtxt<'a, 'tcx>, - sp: Span, - base_ty: Ty<'tcx>, - maybe_exprs: E, - unresolved_type_action: UnresolvedTypeAction, - mut lvalue_pref: LvaluePreference, - mut should_stop: F) - -> (Ty<'tcx>, usize, Option) +/// inserting an AutoAdjustment record into the `self` using one of the suitable methods. +pub fn autoderef<'b, E, I, T, F>(&self, + sp: Span, + base_ty: Ty<'tcx>, + maybe_exprs: E, + unresolved_type_action: UnresolvedTypeAction, + mut lvalue_pref: LvaluePreference, + mut should_stop: F) + -> (Ty<'tcx>, usize, Option) // FIXME(eddyb) use copyable iterators when that becomes ergonomic. where E: Fn() -> I, I: IntoIterator, @@ -2073,17 +2288,17 @@ pub fn autoderef<'a, 'b, 'tcx, E, I, T, F>(fcx: &FnCtxt<'a, 'tcx>, base_ty, lvalue_pref); let mut t = base_ty; - for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() { + for autoderefs in 0..self.tcx().sess.recursion_limit.get() { let resolved_t = match unresolved_type_action { UnresolvedTypeAction::Error => { - structurally_resolved_type(fcx, sp, t) + self.structurally_resolved_type(sp, t) } UnresolvedTypeAction::Ignore => { // We can continue even when the type cannot be resolved // (i.e. it is an inference variable) because `Ty::builtin_deref` // and `try_overloaded_deref` both simply return `None` // in such a case without producing spurious errors. - fcx.infcx().resolve_type_vars_if_possible(&t) + self.infcx().resolve_type_vars_if_possible(&t) } }; if resolved_t.references_error() { @@ -2110,13 +2325,13 @@ pub fn autoderef<'a, 'b, 'tcx, E, I, T, F>(fcx: &FnCtxt<'a, 'tcx>, // complex mess that is begging for a proper MIR. let mt = if let Some(mt) = resolved_t.builtin_deref(false, lvalue_pref) { mt - } else if let Some(method) = try_overloaded_deref(fcx, sp, None, - resolved_t, lvalue_pref) { + } else if let Some(method) = self.try_overloaded_deref(sp, None, + resolved_t, lvalue_pref) { for expr in maybe_exprs() { let method_call = MethodCall::autoderef(expr.id, autoderefs as u32); - fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); + self.inh.tables.borrow_mut().method_map.insert(method_call, method); } - make_overloaded_lvalue_return_type(fcx, method) + self.make_overloaded_lvalue_return_type(method) } else { return (resolved_t, autoderefs, None); }; @@ -2128,35 +2343,35 @@ pub fn autoderef<'a, 'b, 'tcx, E, I, T, F>(fcx: &FnCtxt<'a, 'tcx>, } // We've reached the recursion limit, error gracefully. - span_err!(fcx.tcx().sess, sp, E0055, + span_err!(self.tcx().sess, sp, E0055, "reached the recursion limit while auto-dereferencing {:?}", base_ty); - (fcx.tcx().types.err, 0, None) + (self.tcx().types.err, 0, None) } -fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - base_expr: Option<&hir::Expr>, - base_ty: Ty<'tcx>, - lvalue_pref: LvaluePreference) - -> Option> +fn try_overloaded_deref(&self, + span: Span, + base_expr: Option<&hir::Expr>, + base_ty: Ty<'tcx>, + lvalue_pref: LvaluePreference) + -> Option> { // Try DerefMut first, if preferred. - let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) { + let method = match (lvalue_pref, self.tcx().lang_items.deref_mut_trait()) { (PreferMutLvalue, Some(trait_did)) => { - method::lookup_in_trait(fcx, span, base_expr, - token::intern("deref_mut"), trait_did, - base_ty, None) + self.lookup_method_in_trait(span, base_expr, + token::intern("deref_mut"), trait_did, + base_ty, None) } _ => None }; // Otherwise, fall back to Deref. - let method = match (method, fcx.tcx().lang_items.deref_trait()) { + let method = match (method, self.tcx().lang_items.deref_trait()) { (None, Some(trait_did)) => { - method::lookup_in_trait(fcx, span, base_expr, - token::intern("deref"), trait_did, - base_ty, None) + self.lookup_method_in_trait(span, base_expr, + token::intern("deref"), trait_did, + base_ty, None) } (method, _) => method }; @@ -2167,40 +2382,39 @@ fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// 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`. -fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - method: MethodCallee<'tcx>) - -> ty::TypeAndMut<'tcx> +fn make_overloaded_lvalue_return_type(&self, + method: MethodCallee<'tcx>) + -> ty::TypeAndMut<'tcx> { // extract method return type, which will be &T; // all LB regions should have been instantiated during method lookup let ret_ty = method.ty.fn_ret(); - let ret_ty = fcx.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap(); + let ret_ty = self.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap(); // method returns &T, but the type as visible to user is T, so deref ret_ty.builtin_deref(true, NoPreference).unwrap() } -fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &hir::Expr, - base_expr: &'tcx hir::Expr, - base_ty: Ty<'tcx>, - idx_ty: Ty<'tcx>, - lvalue_pref: LvaluePreference) - -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> +fn lookup_indexing(&self, + expr: &hir::Expr, + base_expr: &'tcx hir::Expr, + base_ty: Ty<'tcx>, + idx_ty: Ty<'tcx>, + lvalue_pref: LvaluePreference) + -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { // FIXME(#18741) -- this is almost but not quite the same as the // autoderef that normal method probing does. They could likely be // consolidated. - let (ty, autoderefs, final_mt) = autoderef(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, - adj_ty, idx, false, lvalue_pref, idx_ty) + let (ty, autoderefs, final_mt) = self.autoderef(base_expr.span, + base_ty, + || Some(base_expr), + UnresolvedTypeAction::Error, + lvalue_pref, + |adj_ty, idx| { + self.try_index_step(MethodCall::expr(expr.id), expr, base_expr, + adj_ty, idx, false, lvalue_pref, idx_ty) }); if final_mt.is_some() { @@ -2210,9 +2424,9 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // After we have fully autoderef'd, if the resulting type is [T; n], then // do a final unsized coercion to yield [T]. if let ty::TyArray(element_ty, _) = ty.sty { - let adjusted_ty = fcx.tcx().mk_slice(element_ty); - try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr, - adjusted_ty, autoderefs, true, lvalue_pref, idx_ty) + let adjusted_ty = self.tcx().mk_slice(element_ty); + self.try_index_step(MethodCall::expr(expr.id), expr, base_expr, + adjusted_ty, autoderefs, true, lvalue_pref, idx_ty) } else { None } @@ -2222,18 +2436,18 @@ 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>, - method_call: MethodCall, - expr: &hir::Expr, - base_expr: &'tcx hir::Expr, - adjusted_ty: Ty<'tcx>, - autoderefs: usize, - unsize: bool, - lvalue_pref: LvaluePreference, - index_ty: Ty<'tcx>) - -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> +fn try_index_step(&self, + method_call: MethodCall, + expr: &hir::Expr, + base_expr: &'tcx hir::Expr, + adjusted_ty: Ty<'tcx>, + autoderefs: usize, + unsize: bool, + lvalue_pref: LvaluePreference, + index_ty: Ty<'tcx>) + -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { - let tcx = fcx.tcx(); + let tcx = self.tcx(); debug!("try_index_step(expr={:?}, base_expr.id={:?}, adjusted_ty={:?}, \ autoderefs={}, unsize={}, index_ty={:?})", expr, @@ -2243,7 +2457,7 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, unsize, index_ty); - let input_ty = fcx.infcx().next_ty_var(); + let input_ty = self.infcx().next_ty_var(); // First, try built-in indexing. match (adjusted_ty.builtin_index(), &index_ty.sty) { @@ -2251,7 +2465,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); + self.write_autoderef_adjustment(base_expr.id, autoderefs); return Some((tcx.types.usize, ty)); } _ => {} @@ -2260,15 +2474,14 @@ 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, - expr.span, - Some(&base_expr), - token::intern("index_mut"), - trait_did, - autoderefs, - unsize, - adjusted_ty, - Some(vec![input_ty])) + self.lookup_method_in_trait_adjusted(expr.span, + Some(&base_expr), + token::intern("index_mut"), + trait_did, + autoderefs, + unsize, + adjusted_ty, + Some(vec![input_ty])) } _ => None, }; @@ -2276,15 +2489,14 @@ 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, - expr.span, - Some(&base_expr), - token::intern("index"), - trait_did, - autoderefs, - unsize, - adjusted_ty, - Some(vec![input_ty])) + self.lookup_method_in_trait_adjusted(expr.span, + Some(&base_expr), + token::intern("index"), + trait_did, + autoderefs, + unsize, + adjusted_ty, + Some(vec![input_ty])) } (method, _) => method, }; @@ -2294,51 +2506,39 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // If some lookup succeeded, install method in table method.map(|method| { debug!("try_index_step: success, using overloaded indexing"); - fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); - (input_ty, make_overloaded_lvalue_return_type(fcx, method).ty) + self.inh.tables.borrow_mut().method_map.insert(method_call, method); + (input_ty, self.make_overloaded_lvalue_return_type(method).ty) }) } -fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - sp: Span, - method_fn_ty: Ty<'tcx>, - callee_expr: &'tcx hir::Expr, - args_no_rcvr: &'tcx [P], - tuple_arguments: TupleArgumentsFlag, - expected: Expectation<'tcx>) - -> ty::FnOutput<'tcx> { +fn check_method_argument_types(&self, + sp: Span, + method_fn_ty: Ty<'tcx>, + callee_expr: &'tcx hir::Expr, + args_no_rcvr: &'tcx [P], + tuple_arguments: TupleArgumentsFlag, + expected: Expectation<'tcx>) + -> ty::FnOutput<'tcx> { if method_fn_ty.references_error() { - let err_inputs = err_args(fcx, args_no_rcvr.len()); + let err_inputs = self.err_args(args_no_rcvr.len()); let err_inputs = match tuple_arguments { DontTupleArguments => err_inputs, - TupleArguments => vec![fcx.tcx().mk_tup(err_inputs)], + TupleArguments => vec![self.tcx().mk_tup(err_inputs)], }; - check_argument_types(fcx, - sp, - &err_inputs[..], - &[], - args_no_rcvr, - false, - tuple_arguments); - ty::FnConverging(fcx.tcx().types.err) + self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr, + false, tuple_arguments); + ty::FnConverging(self.tcx().types.err) } else { match method_fn_ty.sty { ty::TyFnDef(_, _, ref fty) => { // HACK(eddyb) ignore self in the definition (see above). - let expected_arg_tys = expected_types_for_fn_args(fcx, - sp, - expected, - fty.sig.0.output, - &fty.sig.0.inputs[1..]); - check_argument_types(fcx, - sp, - &fty.sig.0.inputs[1..], - &expected_arg_tys[..], - args_no_rcvr, - fty.sig.0.variadic, - tuple_arguments); + let expected_arg_tys = self.expected_types_for_fn_args(sp, expected, + fty.sig.0.output, + &fty.sig.0.inputs[1..]); + self.check_argument_types(sp, &fty.sig.0.inputs[1..], &expected_arg_tys[..], + args_no_rcvr, fty.sig.0.variadic, tuple_arguments); fty.sig.0.output } _ => { @@ -2350,14 +2550,14 @@ 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>, - sp: Span, - fn_inputs: &[Ty<'tcx>], - expected_arg_tys: &[Ty<'tcx>], - args: &'tcx [P], - variadic: bool, - tuple_arguments: TupleArgumentsFlag) { - let tcx = fcx.ccx.tcx; +fn check_argument_types(&self, + sp: Span, + fn_inputs: &[Ty<'tcx>], + expected_arg_tys: &[Ty<'tcx>], + args: &'tcx [P], + variadic: bool, + tuple_arguments: TupleArgumentsFlag) { + let tcx = self.tcx(); // Grab the argument types, supplying fresh type variables // if the wrong number of arguments were supplied @@ -2370,13 +2570,13 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // All the input types from the fn signature must outlive the call // so as to validate implied bounds. for &fn_input_ty in fn_inputs { - fcx.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation); + self.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation); } 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 = self.structurally_resolved_type(sp, fn_inputs[0]); match tuple_type.sty { ty::TyTuple(ref arg_types) => { if arg_types.len() != args.len() { @@ -2387,7 +2587,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, args.len(), if args.len() == 1 {" was"} else {"s were"}); expected_arg_tys = &[]; - err_args(fcx, args.len()) + self.err_args(args.len()) } else { expected_arg_tys = match expected_arg_tys.get(0) { Some(&ty) => match ty.sty { @@ -2404,7 +2604,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, "cannot use call notation; the first type parameter \ for the function trait is neither a tuple nor unit"); expected_arg_tys = &[]; - err_args(fcx, args.len()) + self.err_args(args.len()) } } } else if expected_arg_count == supplied_arg_count { @@ -2421,7 +2621,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, supplied_arg_count, if supplied_arg_count == 1 {" was"} else {"s were"}); expected_arg_tys = &[]; - err_args(fcx, supplied_arg_count) + self.err_args(supplied_arg_count) } } else { span_err!(tcx.sess, sp, E0061, @@ -2431,11 +2631,11 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, supplied_arg_count, if supplied_arg_count == 1 {" was"} else {"s were"}); expected_arg_tys = &[]; - err_args(fcx, supplied_arg_count) + self.err_args(supplied_arg_count) }; debug!("check_argument_types: formal_tys={:?}", - formal_tys.iter().map(|t| fcx.infcx().ty_to_string(*t)).collect::>()); + formal_tys.iter().map(|t| self.infcx().ty_to_string(*t)).collect::>()); // Check the arguments. // We do this in a pretty awful way: first we typecheck any arguments @@ -2454,7 +2654,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 { - fcx.select_obligations_where_possible(); + self.select_obligations_where_possible(); } // For variadic functions, we don't have a declared type for all of @@ -2469,8 +2669,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }; for (i, arg) in args.iter().take(t).enumerate() { if any_diverges && !warned { - fcx.ccx - .tcx + self.tcx() .sess .add_lint(lint::builtin::UNREACHABLE_CODE, arg.id, @@ -2490,30 +2689,29 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // The special-cased logic below has three functions: // 1. Provide as good of an expected type as possible. let expected = expected_arg_tys.get(i).map(|&ty| { - Expectation::rvalue_hint(fcx, ty) + Expectation::rvalue_hint(self, ty) }); - check_expr_with_expectation(fcx, &arg, + self.check_expr_with_expectation(&arg, expected.unwrap_or(ExpectHasType(formal_ty))); // 2. Coerce to the most detailed type that could be coerced // to, which is `expected_ty` if `rvalue_hint` returns an // `ExpectHasType(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); + let coerce_ty = expected.and_then(|e| e.only_has_type(self)); + self.demand_coerce(&arg, coerce_ty.unwrap_or(formal_ty)); // 3. Relate the expected type and the formal one, // if the expected type was used for the coercion. - coerce_ty.map(|ty| demand::suptype(fcx, arg.span, formal_ty, ty)); + coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty)); } - if let Some(&arg_ty) = fcx.inh.tables.borrow().node_types.get(&arg.id) { - any_diverges = any_diverges || fcx.infcx().type_var_diverges(arg_ty); + if let Some(&arg_ty) = self.inh.tables.borrow().node_types.get(&arg.id) { + any_diverges = any_diverges || self.infcx().type_var_diverges(arg_ty); } } if any_diverges && !warned { - let parent = fcx.ccx.tcx.map.get_parent_node(args[0].id); - fcx.ccx - .tcx + let parent = self.tcx().map.get_parent_node(args[0].id); + self.tcx() .sess .add_lint(lint::builtin::UNREACHABLE_CODE, parent, @@ -2528,39 +2726,38 @@ 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); + self.check_expr(&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 arg_ty = self.structurally_resolved_type(arg.span, + self.expr_ty(&arg)); match arg_ty.sty { ty::TyFloat(ast::FloatTy::F32) => { - fcx.type_error_message(arg.span, - |t| { + self.type_error_message(arg.span, |t| { format!("can't pass an `{}` to variadic \ function, cast to `c_double`", t) }, arg_ty, None); } ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => { - fcx.type_error_message(arg.span, |t| { + self.type_error_message(arg.span, |t| { format!("can't pass `{}` to variadic \ function, cast to `c_int`", t) }, arg_ty, None); } ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => { - fcx.type_error_message(arg.span, |t| { + self.type_error_message(arg.span, |t| { format!("can't pass `{}` to variadic \ function, cast to `c_uint`", t) }, arg_ty, None); } ty::TyFnDef(_, _, f) => { - let ptr_ty = fcx.tcx().mk_ty(ty::TyFnPtr(f)); - let ptr_ty = fcx.infcx().resolve_type_vars_if_possible(&ptr_ty); - fcx.type_error_message(arg.span, - |t| { + let ptr_ty = self.tcx().mk_ty(ty::TyFnPtr(f)); + let ptr_ty = self.infcx().resolve_type_vars_if_possible(&ptr_ty); + self.type_error_message(arg.span, + |t| { format!("can't pass `{}` to variadic \ function, cast to `{}`", t, ptr_ty) }, arg_ty, None); @@ -2571,26 +2768,26 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } -fn err_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, len: usize) -> Vec> { - (0..len).map(|_| fcx.tcx().types.err).collect() +fn err_args(&self, len: usize) -> Vec> { + (0..len).map(|_| self.tcx().types.err).collect() } -fn write_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - call_expr: &hir::Expr, - output: ty::FnOutput<'tcx>) { - fcx.write_ty(call_expr.id, match output { +fn write_call(&self, + call_expr: &hir::Expr, + output: ty::FnOutput<'tcx>) { + self.write_ty(call_expr.id, match output { ty::FnConverging(output_ty) => output_ty, - ty::FnDiverging => fcx.infcx().next_diverging_ty_var() + ty::FnDiverging => self.infcx().next_diverging_ty_var() }); } // AST fragment checking -fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - lit: &ast::Lit, - expected: Expectation<'tcx>) - -> Ty<'tcx> +fn check_lit(&self, + lit: &ast::Lit, + expected: Expectation<'tcx>) + -> Ty<'tcx> { - let tcx = fcx.ccx.tcx; + let tcx = self.tcx(); match lit.node { ast::LitKind::Str(..) => tcx.mk_static_str(), @@ -2603,7 +2800,7 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t), ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t), ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { - let opt_ty = expected.to_option(fcx).and_then(|ty| { + let opt_ty = expected.to_option(self).and_then(|ty| { match ty.sty { ty::TyInt(_) | ty::TyUint(_) => Some(ty), ty::TyChar => Some(tcx.types.u8), @@ -2613,73 +2810,73 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } }); opt_ty.unwrap_or_else( - || tcx.mk_int_var(fcx.infcx().next_int_var_id())) + || tcx.mk_int_var(self.infcx().next_int_var_id())) } ast::LitKind::Float(_, t) => tcx.mk_mach_float(t), ast::LitKind::FloatUnsuffixed(_) => { - let opt_ty = expected.to_option(fcx).and_then(|ty| { + let opt_ty = expected.to_option(self).and_then(|ty| { match ty.sty { ty::TyFloat(_) => Some(ty), _ => None } }); opt_ty.unwrap_or_else( - || tcx.mk_float_var(fcx.infcx().next_float_var_id())) + || tcx.mk_float_var(self.infcx().next_float_var_id())) } ast::LitKind::Bool(_) => tcx.types.bool } } -fn check_expr_eq_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, +fn check_expr_eq_type(&self, + expr: &'tcx hir::Expr, + expected: Ty<'tcx>) { + self.check_expr_with_hint(expr, expected); + self.demand_eqtype(expr.span, expected, self.expr_ty(expr)); +} + +pub fn check_expr_has_type(&self, + expr: &'tcx hir::Expr, + expected: Ty<'tcx>) { + self.check_expr_with_hint(expr, expected); + self.demand_suptype(expr.span, expected, self.expr_ty(expr)); +} + +fn check_expr_coercable_to_type(&self, expr: &'tcx hir::Expr, expected: Ty<'tcx>) { - check_expr_with_hint(fcx, expr, expected); - demand::eqtype(fcx, expr.span, expected, fcx.expr_ty(expr)); + self.check_expr_with_hint(expr, expected); + self.demand_coerce(expr, expected); } -pub fn check_expr_has_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - expected: Ty<'tcx>) { - check_expr_with_hint(fcx, expr, expected); - demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr)); +fn check_expr_with_hint(&self, expr: &'tcx hir::Expr, + expected: Ty<'tcx>) { + self.check_expr_with_expectation(expr, ExpectHasType(expected)) } -fn check_expr_coercable_to_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - expected: Ty<'tcx>) { - check_expr_with_hint(fcx, expr, expected); - demand::coerce(fcx, expr.span, expected, expr); +fn check_expr_with_expectation(&self, + expr: &'tcx hir::Expr, + expected: Expectation<'tcx>) { + self.check_expr_with_expectation_and_lvalue_pref(expr, expected, NoPreference) } -fn check_expr_with_hint<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, - expected: Ty<'tcx>) { - check_expr_with_expectation(fcx, expr, ExpectHasType(expected)) +fn check_expr(&self, expr: &'tcx hir::Expr) { + self.check_expr_with_expectation(expr, NoExpectation) } -fn check_expr_with_expectation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - expected: Expectation<'tcx>) { - check_expr_with_expectation_and_lvalue_pref(fcx, expr, expected, NoPreference) -} - -fn check_expr<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx hir::Expr) { - check_expr_with_expectation(fcx, expr, NoExpectation) -} - -fn check_expr_with_lvalue_pref<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx hir::Expr, - lvalue_pref: LvaluePreference) { - check_expr_with_expectation_and_lvalue_pref(fcx, expr, NoExpectation, lvalue_pref) +fn check_expr_with_lvalue_pref(&self, expr: &'tcx hir::Expr, + lvalue_pref: LvaluePreference) { + self.check_expr_with_expectation_and_lvalue_pref(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: DefId) - -> TypeAndSubsts<'tcx> { - let tcx = fcx.tcx(); +pub fn impl_self_ty(&self, + span: Span, // (potential) receiver for this impl + did: DefId) + -> TypeAndSubsts<'tcx> { + let tcx = self.tcx(); let ity = tcx.lookup_item_type(did); let (tps, rps, raw_ty) = @@ -2689,55 +2886,33 @@ pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, debug!("impl_self_ty: tps={:?} rps={:?} raw_ty={:?}", tps, rps, raw_ty); - let rps = fcx.inh.infcx.region_vars_for_defs(span, rps); + let rps = self.inh.infcx.region_vars_for_defs(span, rps); let mut substs = subst::Substs::new( VecPerParamSpace::empty(), VecPerParamSpace::new(rps, Vec::new(), Vec::new())); - fcx.inh.infcx.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps); - let substd_ty = fcx.instantiate_type_scheme(span, &substs, &raw_ty); + self.inh.infcx.type_vars_for_defs(span, ParamSpace::TypeSpace, &mut substs, tps); + let substd_ty = self.instantiate_type_scheme(span, &substs, &raw_ty); TypeAndSubsts { substs: substs, ty: substd_ty } } -/// Controls whether the arguments are tupled. This is used for the call -/// operator. -/// -/// Tupling means that all call-side arguments are packed into a tuple and -/// passed as a single parameter. For example, if tupling is enabled, this -/// function: -/// -/// fn f(x: (isize, isize)) -/// -/// Can be called as: -/// -/// f(1, 2); -/// -/// Instead of: -/// -/// f((1, 2)); -#[derive(Clone, Eq, PartialEq)] -enum TupleArgumentsFlag { - DontTupleArguments, - TupleArguments, -} - /// 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>, - call_span: Span, - expected_ret: Expectation<'tcx>, - formal_ret: ty::FnOutput<'tcx>, - formal_args: &[Ty<'tcx>]) - -> Vec> { - let expected_args = expected_ret.only_has_type(fcx).and_then(|ret_ty| { +fn expected_types_for_fn_args(&self, + call_span: Span, + expected_ret: Expectation<'tcx>, + formal_ret: ty::FnOutput<'tcx>, + formal_args: &[Ty<'tcx>]) + -> Vec> { + let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| { if let ty::FnConverging(formal_ret_ty) = formal_ret { - fcx.infcx().commit_regions_if_ok(|| { + self.infcx().commit_regions_if_ok(|| { // Attempt to apply a subtyping relationship between the formal // return type (likely containing type variables if the function // is polymorphic) and the expected return type. // No argument expectations are produced if unification fails. let origin = TypeOrigin::Misc(call_span); - let ures = fcx.infcx().sub_types(false, origin, formal_ret_ty, ret_ty); + let ures = self.infcx().sub_types(false, origin, formal_ret_ty, ret_ty); // FIXME(#15760) can't use try! here, FromError doesn't default // to identity so the resulting type is not constrained. match ures { @@ -2749,7 +2924,7 @@ fn expected_types_for_fn_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Record all the argument types, with the substitutions // produced from the above subtyping unification. Ok(formal_args.iter().map(|ty| { - fcx.infcx().resolve_type_vars_if_possible(ty) + self.infcx().resolve_type_vars_if_possible(ty) }).collect()) }).ok() } else { @@ -2762,115 +2937,92 @@ fn expected_types_for_fn_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expected_args } -/// Invariant: -/// If an expression has any sub-expressions that result in a type error, -/// inspecting that expression's type with `ty.references_error()` will return -/// true. Likewise, if an expression is known to diverge, inspecting its -/// type with `ty::type_is_bot` will return true (n.b.: since Rust is -/// strict, _|_ can appear in the type of an expression that does not, -/// itself, diverge: for example, fn() -> _|_.) -/// Note that inspecting a type's structure *directly* may expose the fact -/// that there are actually multiple representations for `TyError`, so avoid -/// that when err needs to be handled differently. -fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - expected: Expectation<'tcx>, - lvalue_pref: LvaluePreference) { - debug!(">> typechecking: expr={:?} expected={:?}", - expr, expected); - // Checks a method call. - fn check_method_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - method_name: Spanned, - args: &'tcx [P], - tps: &[P], - expected: Expectation<'tcx>, - lvalue_pref: LvaluePreference) { + fn check_method_call(&self, + expr: &'tcx hir::Expr, + method_name: Spanned, + args: &'tcx [P], + tps: &[P], + expected: Expectation<'tcx>, + lvalue_pref: LvaluePreference) { let rcvr = &args[0]; - check_expr_with_lvalue_pref(fcx, &rcvr, lvalue_pref); + self.check_expr_with_lvalue_pref(&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_t = self.structurally_resolved_type(expr.span, self.expr_ty(&rcvr)); - let tps = tps.iter().map(|ast_ty| fcx.to_ty(&ast_ty)).collect::>(); - let fn_ty = match method::lookup(fcx, - method_name.span, - method_name.node, - expr_t, - tps, - expr, - rcvr) { + let tps = tps.iter().map(|ast_ty| self.to_ty(&ast_ty)).collect::>(); + let fn_ty = match self.lookup_method(method_name.span, + method_name.node, + expr_t, + tps, + expr, + rcvr) { Ok(method) => { let method_ty = method.ty; let method_call = MethodCall::expr(expr.id); - fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); + self.inh.tables.borrow_mut().method_map.insert(method_call, method); method_ty } Err(error) => { if method_name.node != keywords::Invalid.name() { - method::report_error(fcx, method_name.span, expr_t, - method_name.node, Some(rcvr), error); + self.report_method_error(method_name.span, expr_t, + method_name.node, Some(rcvr), error); } - fcx.write_error(expr.id); - fcx.tcx().types.err + self.write_error(expr.id); + self.tcx().types.err } }; // Call the generic checker. - let ret_ty = check_method_argument_types(fcx, - method_name.span, - fn_ty, - expr, - &args[1..], - DontTupleArguments, - expected); + let ret_ty = self.check_method_argument_types(method_name.span, fn_ty, + expr, &args[1..], + DontTupleArguments, + expected); - write_call(fcx, expr, ret_ty); + self.write_call(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>, - cond_expr: &'tcx hir::Expr, - then_blk: &'tcx hir::Block, - opt_else_expr: Option<&'tcx hir::Expr>, - id: ast::NodeId, - sp: Span, - expected: Expectation<'tcx>) { - check_expr_has_type(fcx, cond_expr, fcx.tcx().types.bool); + fn check_then_else(&self, + cond_expr: &'tcx hir::Expr, + then_blk: &'tcx hir::Block, + opt_else_expr: Option<&'tcx hir::Expr>, + id: ast::NodeId, + sp: Span, + expected: Expectation<'tcx>) { + self.check_expr_has_type(cond_expr, self.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); + let expected = expected.adjust_for_branches(self); + self.check_block_with_expected(then_blk, expected); + let then_ty = self.node_ty(then_blk.id); - let unit = fcx.tcx().mk_nil(); + let unit = self.tcx().mk_nil(); let (origin, expected, found, result) = if let Some(else_expr) = opt_else_expr { - check_expr_with_expectation(fcx, else_expr, expected); - let else_ty = fcx.expr_ty(else_expr); + self.check_expr_with_expectation(else_expr, expected); + let else_ty = self.expr_ty(else_expr); let origin = TypeOrigin::IfExpression(sp); // Only try to coerce-unify if we have a then expression // to assign coercions to, otherwise it's () or diverging. let result = if let Some(ref then) = then_blk.expr { - let res = coercion::try_find_lub(fcx, origin, || Some(&**then), - then_ty, else_expr); + let res = self.try_find_coercion_lub(origin, || Some(&**then), + then_ty, else_expr); // In case we did perform an adjustment, we have to update // the type of the block, because old trans still uses it. - let adj = fcx.inh.tables.borrow().adjustments.get(&then.id).cloned(); + let adj = self.inh.tables.borrow().adjustments.get(&then.id).cloned(); if res.is_ok() && adj.is_some() { - fcx.write_ty(then_blk.id, fcx.adjust_expr_ty(then, adj.as_ref())); + self.write_ty(then_blk.id, self.adjust_expr_ty(then, adj.as_ref())); } res } else { - fcx.infcx().commit_if_ok(|_| { + self.infcx().commit_if_ok(|_| { let trace = TypeTrace::types(origin, true, then_ty, else_ty); - fcx.infcx().lub(true, trace, &then_ty, &else_ty) + self.infcx().lub(true, trace, &then_ty, &else_ty) .map(|InferOk { value, obligations }| { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); @@ -2882,7 +3034,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } else { let origin = TypeOrigin::IfExpressionWithNoElse(sp); (origin, unit, then_ty, - fcx.infcx().eq_types(true, origin, unit, then_ty) + self.infcx().eq_types(true, origin, unit, then_ty) .map(|InferOk { obligations, .. }| { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); @@ -2892,42 +3044,42 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let if_ty = match result { Ok(ty) => { - if fcx.expr_ty(cond_expr).references_error() { - fcx.tcx().types.err + if self.expr_ty(cond_expr).references_error() { + self.tcx().types.err } else { ty } } Err(e) => { - fcx.infcx().report_mismatched_types(origin, expected, found, e); - fcx.tcx().types.err + self.infcx().report_mismatched_types(origin, expected, found, e); + self.tcx().types.err } }; - fcx.write_ty(id, if_ty); + self.write_ty(id, if_ty); } // Check field access expressions - fn check_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, - expr: &'tcx hir::Expr, - lvalue_pref: LvaluePreference, - base: &'tcx hir::Expr, - field: &Spanned) { - check_expr_with_lvalue_pref(fcx, base, lvalue_pref); - let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base)); + fn check_field(&self, + expr: &'tcx hir::Expr, + lvalue_pref: LvaluePreference, + base: &'tcx hir::Expr, + field: &Spanned) { + self.check_expr_with_lvalue_pref(base, lvalue_pref); + let expr_t = self.structurally_resolved_type(expr.span, + self.expr_ty(base)); let mut private_candidate = None; - let (_, autoderefs, field_ty) = autoderef(fcx, - expr.span, - expr_t, - || Some(base), - UnresolvedTypeAction::Error, - lvalue_pref, - |base_t, _| { + let (_, autoderefs, field_ty) = self.autoderef(expr.span, + expr_t, + || Some(base), + UnresolvedTypeAction::Error, + lvalue_pref, + |base_t, _| { if let ty::TyStruct(base_def, substs) = base_t.sty { debug!("struct named {:?}", base_t); if let Some(field) = base_def.struct_variant().find_field_named(field.node) { - let field_ty = fcx.field_ty(expr.span, field, substs); - if field.vis.is_accessible_from(fcx.body_id, &fcx.tcx().map) { + let field_ty = self.field_ty(expr.span, field, substs); + if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { return Some(field_ty); } private_candidate = Some((base_def.did, field_ty)); @@ -2937,68 +3089,59 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }); match field_ty { Some(field_ty) => { - fcx.write_ty(expr.id, field_ty); - fcx.write_autoderef_adjustment(base.id, autoderefs); + self.write_ty(expr.id, field_ty); + self.write_autoderef_adjustment(base.id, autoderefs); return; } None => {} } if let Some((did, field_ty)) = private_candidate { - let struct_path = fcx.tcx().item_path_str(did); + let struct_path = self.tcx().item_path_str(did); let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path); - fcx.tcx().sess.span_err(expr.span, &msg); - fcx.write_ty(expr.id, field_ty); + self.tcx().sess.span_err(expr.span, &msg); + self.write_ty(expr.id, field_ty); } else if field.node == keywords::Invalid.name() { - fcx.write_error(expr.id); - } else if method::exists(fcx, field.span, field.node, expr_t, expr.id) { - fcx.type_error_struct(field.span, - |actual| { - format!("attempted to take value of method `{}` on type \ - `{}`", field.node, actual) - }, - expr_t, None) + self.write_error(expr.id); + } else if self.method_exists(field.span, field.node, expr_t, expr.id) { + self.type_error_struct(field.span, |actual| { + format!("attempted to take value of method `{}` on type \ + `{}`", field.node, actual) + }, expr_t, None) .help( "maybe a `()` to call it is missing? \ If not, try an anonymous function") .emit(); - fcx.write_error(expr.id); + self.write_error(expr.id); } else { - let mut err = fcx.type_error_struct( - expr.span, - |actual| { - format!("attempted access of field `{}` on \ - type `{}`, but no field with that \ - name was found", - field.node, - actual) - }, - expr_t, None); + let mut err = self.type_error_struct(expr.span, |actual| { + format!("attempted access of field `{}` on type `{}`, \ + but no field with that name was found", + field.node, actual) + }, expr_t, None); if let ty::TyStruct(def, _) = expr_t.sty { - suggest_field_names(&mut err, def.struct_variant(), field, vec![]); + Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]); } err.emit(); - fcx.write_error(expr.id); + self.write_error(expr.id); } } // displays hints about the closest matches in field names - fn suggest_field_names<'tcx>(err: &mut DiagnosticBuilder, - variant: ty::VariantDef<'tcx>, - field: &Spanned, - skip : Vec) { + fn suggest_field_names(err: &mut DiagnosticBuilder, + variant: ty::VariantDef<'tcx>, + field: &Spanned, + skip : Vec) { let name = field.node.as_str(); - let names = variant.fields - .iter() - .filter_map(|ref field| { - // ignore already set fields and private fields from non-local crates - if skip.iter().any(|x| *x == field.name.as_str()) || - (variant.did.krate != LOCAL_CRATE && field.vis != Visibility::Public) { - None - } else { - Some(&field.name) - } - }); + let names = variant.fields.iter().filter_map(|field| { + // ignore already set fields and private fields from non-local crates + if skip.iter().any(|x| *x == field.name.as_str()) || + (variant.did.krate != LOCAL_CRATE && field.vis != Visibility::Public) { + None + } else { + Some(&field.name) + } + }); // only find fits with at least one matching letter if let Some(name) = find_best_match_for_name(names, &name, Some(name.len())) { @@ -3008,22 +3151,22 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } // Check tuple index expressions - fn check_tup_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, - expr: &'tcx hir::Expr, - lvalue_pref: LvaluePreference, - base: &'tcx hir::Expr, - idx: codemap::Spanned) { - check_expr_with_lvalue_pref(fcx, base, lvalue_pref); - let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base)); + fn check_tup_field(&self, + expr: &'tcx hir::Expr, + lvalue_pref: LvaluePreference, + base: &'tcx hir::Expr, + idx: codemap::Spanned) { + self.check_expr_with_lvalue_pref(base, lvalue_pref); + let expr_t = self.structurally_resolved_type(expr.span, + self.expr_ty(base)); let mut private_candidate = None; let mut tuple_like = false; - let (_, autoderefs, field_ty) = autoderef(fcx, - expr.span, - expr_t, - || Some(base), - UnresolvedTypeAction::Error, - lvalue_pref, - |base_t, _| { + let (_, autoderefs, field_ty) = self.autoderef(expr.span, + expr_t, + || Some(base), + UnresolvedTypeAction::Error, + lvalue_pref, + |base_t, _| { let (base_def, substs) = match base_t.sty { ty::TyStruct(base_def, substs) => (base_def, substs), ty::TyTuple(ref v) => { @@ -3038,8 +3181,8 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, debug!("tuple struct named {:?}", base_t); if let Some(field) = base_def.struct_variant().fields.get(idx.node) { - let field_ty = fcx.field_ty(expr.span, field, substs); - if field.vis.is_accessible_from(fcx.body_id, &fcx.tcx().map) { + let field_ty = self.field_ty(expr.span, field, substs); + if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { return Some(field_ty); } private_candidate = Some((base_def.did, field_ty)); @@ -3048,22 +3191,22 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }); match field_ty { Some(field_ty) => { - fcx.write_ty(expr.id, field_ty); - fcx.write_autoderef_adjustment(base.id, autoderefs); + self.write_ty(expr.id, field_ty); + self.write_autoderef_adjustment(base.id, autoderefs); return; } None => {} } if let Some((did, field_ty)) = private_candidate { - let struct_path = fcx.tcx().item_path_str(did); + let struct_path = self.tcx().item_path_str(did); let msg = format!("field `{}` of struct `{}` is private", idx.node, struct_path); - fcx.tcx().sess.span_err(expr.span, &msg); - fcx.write_ty(expr.id, field_ty); + self.tcx().sess.span_err(expr.span, &msg); + self.write_ty(expr.id, field_ty); return; } - fcx.type_error_message( + self.type_error_message( expr.span, |actual| { if tuple_like { @@ -3080,15 +3223,15 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }, expr_t, None); - fcx.write_error(expr.id); + self.write_error(expr.id); } - fn report_unknown_field<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - ty: Ty<'tcx>, - variant: ty::VariantDef<'tcx>, - field: &hir::Field, - skip_fields: &[hir::Field]) { - let mut err = fcx.type_error_struct( + fn report_unknown_field(&self, + ty: Ty<'tcx>, + variant: ty::VariantDef<'tcx>, + field: &hir::Field, + skip_fields: &[hir::Field]) { + let mut err = self.type_error_struct( field.name.span, |actual| if let ty::TyEnum(..) = ty.sty { format!("struct variant `{}::{}` has no field named `{}`", @@ -3101,17 +3244,17 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, None); // prevent all specified fields from being suggested let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str()); - suggest_field_names(&mut err, variant, &field.name, skip_fields.collect()); + Self::suggest_field_names(&mut err, variant, &field.name, skip_fields.collect()); err.emit(); } - fn check_expr_struct_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - adt_ty: Ty<'tcx>, - span: Span, - variant: ty::VariantDef<'tcx>, - ast_fields: &'tcx [hir::Field], - check_completeness: bool) { - let tcx = fcx.ccx.tcx; + fn check_expr_struct_fields(&self, + adt_ty: Ty<'tcx>, + span: Span, + variant: ty::VariantDef<'tcx>, + ast_fields: &'tcx [hir::Field], + check_completeness: bool) { + let tcx = self.tcx(); let substs = match adt_ty.sty { ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields") @@ -3129,22 +3272,22 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let expected_field_type; if let Some(v_field) = remaining_fields.remove(&field.name.node) { - expected_field_type = fcx.field_ty(field.span, v_field, substs); + expected_field_type = self.field_ty(field.span, v_field, substs); } else { error_happened = true; expected_field_type = tcx.types.err; if let Some(_) = variant.find_field_named(field.name.node) { - span_err!(fcx.tcx().sess, field.name.span, E0062, + span_err!(self.tcx().sess, field.name.span, E0062, "field `{}` specified more than once", field.name.node); } else { - report_unknown_field(fcx, adt_ty, variant, field, ast_fields); + self.report_unknown_field(adt_ty, variant, field, ast_fields); } } // 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); + self.check_expr_coercable_to_type(&field.expr, expected_field_type); } // Make sure the programmer specified all the fields. @@ -3164,61 +3307,61 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } - fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, - id: ast::NodeId, - fields: &'tcx [hir::Field], - base_expr: &'tcx Option>) { + fn check_struct_fields_on_error(&self, + id: ast::NodeId, + fields: &'tcx [hir::Field], + base_expr: &'tcx Option>) { // Make sure to still write the types // otherwise we might ICE - fcx.write_error(id); + self.write_error(id); for field in fields { - check_expr(fcx, &field.expr); + self.check_expr(&field.expr); } match *base_expr { - Some(ref base) => check_expr(fcx, &base), + Some(ref base) => self.check_expr(&base), None => {} } } - fn check_expr_struct<'a, 'tcx>(fcx: &FnCtxt<'a,'tcx>, - expr: &hir::Expr, - path: &hir::Path, - fields: &'tcx [hir::Field], - base_expr: &'tcx Option>) + fn check_expr_struct(&self, + expr: &hir::Expr, + path: &hir::Path, + fields: &'tcx [hir::Field], + base_expr: &'tcx Option>) { - let tcx = fcx.tcx(); + let tcx = self.tcx(); // Find the relevant variant let def = lookup_full_def(tcx, path.span, expr.id); if def == Def::Err { - fcx.infcx().set_tainted_by_errors(); - check_struct_fields_on_error(fcx, expr.id, fields, base_expr); + self.infcx().set_tainted_by_errors(); + self.check_struct_fields_on_error(expr.id, fields, base_expr); return; } - let variant = match fcx.def_struct_variant(def, path.span) { + let variant = match self.def_struct_variant(def, path.span) { Some((_, variant)) => variant, None => { - span_err!(fcx.tcx().sess, path.span, E0071, + span_err!(self.tcx().sess, path.span, E0071, "`{}` does not name a structure", pprust::path_to_string(path)); - check_struct_fields_on_error(fcx, expr.id, fields, base_expr); + self.check_struct_fields_on_error(expr.id, fields, base_expr); return; } }; - let expr_ty = fcx.instantiate_type(def.def_id(), path); - fcx.write_ty(expr.id, expr_ty); + let expr_ty = self.instantiate_type(def.def_id(), path); + self.write_ty(expr.id, expr_ty); - check_expr_struct_fields(fcx, expr_ty, expr.span, variant, fields, - base_expr.is_none()); + self.check_expr_struct_fields(expr_ty, expr.span, variant, fields, + base_expr.is_none()); if let &Some(ref base_expr) = base_expr { - check_expr_has_type(fcx, base_expr, expr_ty); + self.check_expr_has_type(base_expr, expr_ty); match expr_ty.sty { ty::TyStruct(adt, substs) => { - fcx.inh.tables.borrow_mut().fru_field_types.insert( + self.inh.tables.borrow_mut().fru_field_types.insert( expr.id, adt.struct_variant().fields.iter().map(|f| { - fcx.normalize_associated_types_in( + self.normalize_associated_types_in( expr.span, &f.ty(tcx, substs) ) }).collect() @@ -3232,32 +3375,48 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } - type ExprCheckerWithTy = fn(&FnCtxt, &hir::Expr, Ty); - let tcx = fcx.ccx.tcx; +/// Invariant: +/// If an expression has any sub-expressions that result in a type error, +/// inspecting that expression's type with `ty.references_error()` will return +/// true. Likewise, if an expression is known to diverge, inspecting its +/// type with `ty::type_is_bot` will return true (n.b.: since Rust is +/// strict, _|_ can appear in the type of an expression that does not, +/// itself, diverge: for example, fn() -> _|_.) +/// Note that inspecting a type's structure *directly* may expose the fact +/// that there are actually multiple representations for `TyError`, so avoid +/// that when err needs to be handled differently. +fn check_expr_with_expectation_and_lvalue_pref(&self, + expr: &'tcx hir::Expr, + expected: Expectation<'tcx>, + lvalue_pref: LvaluePreference) { + debug!(">> typechecking: expr={:?} expected={:?}", + expr, expected); + + let tcx = self.tcx(); let id = expr.id; match expr.node { hir::ExprBox(ref subexpr) => { - let expected_inner = expected.to_option(fcx).map_or(NoExpectation, |ty| { + let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| { match ty.sty { - ty::TyBox(ty) => Expectation::rvalue_hint(fcx, ty), + ty::TyBox(ty) => Expectation::rvalue_hint(self, ty), _ => NoExpectation } }); - check_expr_with_expectation(fcx, subexpr, expected_inner); - let referent_ty = fcx.expr_ty(&subexpr); - fcx.write_ty(id, tcx.mk_box(referent_ty)); + self.check_expr_with_expectation(subexpr, expected_inner); + let referent_ty = self.expr_ty(&subexpr); + self.write_ty(id, tcx.mk_box(referent_ty)); } hir::ExprLit(ref lit) => { - let typ = check_lit(fcx, &lit, expected); - fcx.write_ty(id, typ); + let typ = self.check_lit(&lit, expected); + self.write_ty(id, typ); } hir::ExprBinary(op, ref lhs, ref rhs) => { - op::check_binop(fcx, expr, op, lhs, rhs); + self.check_binop(expr, op, lhs, rhs); } hir::ExprAssignOp(op, ref lhs, ref rhs) => { - op::check_binop_assign(fcx, expr, op, lhs, rhs); + self.check_binop_assign(expr, op, lhs, rhs); } hir::ExprUnary(unop, ref oprnd) => { let expected_inner = match unop { @@ -3272,24 +3431,25 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, hir::UnDeref => lvalue_pref, _ => NoPreference }; - check_expr_with_expectation_and_lvalue_pref( - fcx, &oprnd, expected_inner, lvalue_pref); - let mut oprnd_t = fcx.expr_ty(&oprnd); + self.check_expr_with_expectation_and_lvalue_pref(&oprnd, + expected_inner, + lvalue_pref); + let mut oprnd_t = self.expr_ty(&oprnd); if !oprnd_t.references_error() { match unop { hir::UnDeref => { - oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t); + oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) { oprnd_t = mt.ty; - } else if let Some(method) = try_overloaded_deref( - fcx, expr.span, Some(&oprnd), oprnd_t, lvalue_pref) { - oprnd_t = make_overloaded_lvalue_return_type(fcx, method).ty; - fcx.inh.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id), - method); + } else if let Some(method) = self.try_overloaded_deref( + expr.span, Some(&oprnd), oprnd_t, lvalue_pref) { + oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; + self.inh.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id), + method); } else { - fcx.type_error_message(expr.span, |actual| { + self.type_error_message(expr.span, |actual| { format!("type `{}` cannot be \ dereferenced", actual) }, oprnd_t, None); @@ -3297,50 +3457,47 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } hir::UnNot => { - oprnd_t = structurally_resolved_type(fcx, oprnd.span, - oprnd_t); + oprnd_t = self.structurally_resolved_type(oprnd.span, + oprnd_t); if !(oprnd_t.is_integral() || oprnd_t.sty == ty::TyBool) { - oprnd_t = op::check_user_unop(fcx, "!", "not", - tcx.lang_items.not_trait(), - expr, &oprnd, oprnd_t, unop); + oprnd_t = self.check_user_unop("!", "not", + tcx.lang_items.not_trait(), + expr, &oprnd, oprnd_t, unop); } } hir::UnNeg => { - oprnd_t = structurally_resolved_type(fcx, oprnd.span, - oprnd_t); + oprnd_t = self.structurally_resolved_type(oprnd.span, + oprnd_t); if !(oprnd_t.is_integral() || oprnd_t.is_fp()) { - oprnd_t = op::check_user_unop(fcx, "-", "neg", - tcx.lang_items.neg_trait(), - expr, &oprnd, oprnd_t, unop); + oprnd_t = self.check_user_unop("-", "neg", + tcx.lang_items.neg_trait(), + expr, &oprnd, oprnd_t, unop); } } } } - fcx.write_ty(id, oprnd_t); + self.write_ty(id, oprnd_t); } hir::ExprAddrOf(mutbl, ref oprnd) => { - let hint = expected.only_has_type(fcx).map_or(NoExpectation, |ty| { + let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| { match ty.sty { ty::TyRef(_, ref mt) | ty::TyRawPtr(ref mt) => { - if fcx.tcx().expr_is_lval(&oprnd) { + if self.tcx().expr_is_lval(&oprnd) { // Lvalues may legitimately have unsized types. // For example, dereferences of a fat pointer and // the last field of a struct can be unsized. ExpectHasType(mt.ty) } else { - Expectation::rvalue_hint(fcx, mt.ty) + Expectation::rvalue_hint(self, mt.ty) } } _ => NoExpectation } }); let lvalue_pref = LvaluePreference::from_mutbl(mutbl); - check_expr_with_expectation_and_lvalue_pref(fcx, - &oprnd, - hint, - lvalue_pref); + self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref); - let tm = ty::TypeAndMut { ty: fcx.expr_ty(&oprnd), mutbl: mutbl }; + let tm = ty::TypeAndMut { ty: self.expr_ty(&oprnd), mutbl: mutbl }; let oprnd_t = if tm.ty.references_error() { tcx.types.err } else { @@ -3357,14 +3514,14 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Finally, borrowck is charged with guaranteeing that the // value whose address was taken can actually be made to live // as long as it needs to live. - let region = fcx.infcx().next_region_var(infer::AddrOfRegion(expr.span)); + let region = self.infcx().next_region_var(infer::AddrOfRegion(expr.span)); tcx.mk_ref(tcx.mk_region(region), tm) }; - fcx.write_ty(id, oprnd_t); + self.write_ty(id, oprnd_t); } hir::ExprPath(ref maybe_qself, ref path) => { let opt_self_ty = maybe_qself.as_ref().map(|qself| { - fcx.to_ty(&qself.ty) + self.to_ty(&qself.ty) }); let path_res = if let Some(&d) = tcx.def_map.borrow().get(&id) { @@ -3380,213 +3537,206 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }; if let Some((opt_ty, segments, def)) = - resolve_ty_and_def_ufcs(fcx, path_res, opt_self_ty, path, - expr.span, expr.id) { + self.resolve_ty_and_def_ufcs(path_res, opt_self_ty, path, + expr.span, expr.id) { if def != Def::Err { - let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, - expr.span, - def); - instantiate_path(fcx, - segments, - scheme, - &predicates, - opt_ty, - def, - expr.span, - id); + let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span, + def); + self.instantiate_path(segments, scheme, &predicates, + opt_ty, def, expr.span, id); } else { - fcx.infcx().set_tainted_by_errors(); - fcx.write_ty(id, fcx.tcx().types.err); + self.infcx().set_tainted_by_errors(); + self.write_ty(id, self.tcx().types.err); } } // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. - fcx.opt_node_ty_substs(expr.id, |item_substs| { - fcx.add_wf_bounds(&item_substs.substs, expr); + self.opt_node_ty_substs(expr.id, |item_substs| { + self.add_wf_bounds(&item_substs.substs, expr); }); } hir::ExprInlineAsm(_, ref outputs, ref inputs) => { for output in outputs { - check_expr(fcx, output); + self.check_expr(output); } for input in inputs { - check_expr(fcx, input); + self.check_expr(input); } - fcx.write_nil(id); + self.write_nil(id); } - hir::ExprBreak(_) => { fcx.write_ty(id, fcx.infcx().next_diverging_ty_var()); } - hir::ExprAgain(_) => { fcx.write_ty(id, fcx.infcx().next_diverging_ty_var()); } + hir::ExprBreak(_) => { self.write_ty(id, self.infcx().next_diverging_ty_var()); } + hir::ExprAgain(_) => { self.write_ty(id, self.infcx().next_diverging_ty_var()); } hir::ExprRet(ref expr_opt) => { - match fcx.ret_ty { + match self.ret_ty { ty::FnConverging(result_type) => { match *expr_opt { None => - if let Err(_) = fcx.mk_eqty(false, TypeOrigin::Misc(expr.span), - result_type, fcx.tcx().mk_nil()) { + if let Err(_) = self.mk_eqty(false, TypeOrigin::Misc(expr.span), + result_type, self.tcx().mk_nil()) { span_err!(tcx.sess, expr.span, E0069, "`return;` in a function whose return type is \ not `()`"); }, Some(ref e) => { - check_expr_coercable_to_type(fcx, &e, result_type); + self.check_expr_coercable_to_type(&e, result_type); } } } ty::FnDiverging => { if let Some(ref e) = *expr_opt { - check_expr(fcx, &e); + self.check_expr(&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()); + self.write_ty(id, self.infcx().next_diverging_ty_var()); } hir::ExprAssign(ref lhs, ref rhs) => { - check_expr_with_lvalue_pref(fcx, &lhs, PreferMutLvalue); + self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue); - let tcx = fcx.tcx(); + let tcx = self.tcx(); if !tcx.expr_is_lval(&lhs) { span_err!(tcx.sess, expr.span, E0070, "invalid 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 = self.expr_ty(&lhs); + self.check_expr_coercable_to_type(&rhs, lhs_ty); + let rhs_ty = self.expr_ty(&rhs); - fcx.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized); + self.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized); if lhs_ty.references_error() || rhs_ty.references_error() { - fcx.write_error(id); + self.write_error(id); } else { - fcx.write_nil(id); + self.write_nil(id); } } hir::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), - id, expr.span, expected); + self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e), + id, expr.span, expected); } hir::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); + self.check_expr_has_type(&cond, tcx.types.bool); + self.check_block_no_value(&body); + let cond_ty = self.expr_ty(&cond); + let body_ty = self.node_ty(body.id); if cond_ty.references_error() || body_ty.references_error() { - fcx.write_error(id); + self.write_error(id); } else { - fcx.write_nil(id); + self.write_nil(id); } } hir::ExprLoop(ref body, _) => { - check_block_no_value(fcx, &body); + self.check_block_no_value(&body); if !may_break(tcx, expr.id, &body) { - fcx.write_ty(id, fcx.infcx().next_diverging_ty_var()); + self.write_ty(id, self.infcx().next_diverging_ty_var()); } else { - fcx.write_nil(id); + self.write_nil(id); } } hir::ExprMatch(ref discrim, ref arms, match_src) => { - _match::check_match(fcx, expr, &discrim, arms, expected, match_src); + self.check_match(expr, &discrim, arms, expected, match_src); } hir::ExprClosure(capture, ref decl, ref body, _) => { - closure::check_expr_closure(fcx, expr, capture, &decl, &body, expected); + self.check_expr_closure(expr, capture, &decl, &body, expected); } hir::ExprBlock(ref b) => { - check_block_with_expected(fcx, &b, expected); - fcx.write_ty(id, fcx.node_ty(b.id)); + self.check_block_with_expected(&b, expected); + self.write_ty(id, self.node_ty(b.id)); } hir::ExprCall(ref callee, ref args) => { - callee::check_call(fcx, expr, &callee, &args[..], expected); + self.check_call(expr, &callee, &args[..], expected); // we must check that return type of called functions is WF: - let ret_ty = fcx.expr_ty(expr); - fcx.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation); + let ret_ty = self.expr_ty(expr); + self.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation); } hir::ExprMethodCall(name, ref tps, ref args) => { - check_method_call(fcx, expr, name, &args[..], &tps[..], expected, lvalue_pref); - let arg_tys = args.iter().map(|a| fcx.expr_ty(&a)); + self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref); + let arg_tys = args.iter().map(|a| self.expr_ty(&a)); let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error()); if args_err { - fcx.write_error(id); + self.write_error(id); } } hir::ExprCast(ref e, ref t) => { if let hir::TyFixedLengthVec(_, ref count_expr) = t.node { - check_expr_with_hint(fcx, &count_expr, tcx.types.usize); + self.check_expr_with_hint(&count_expr, tcx.types.usize); } // Find the type of `e`. Supply hints based on the type we are casting to, // if appropriate. - let t_cast = fcx.to_ty(t); - let t_cast = fcx.infcx().resolve_type_vars_if_possible(&t_cast); - check_expr_with_expectation(fcx, e, ExpectCastableToType(t_cast)); - let t_expr = fcx.expr_ty(e); - let t_cast = fcx.infcx().resolve_type_vars_if_possible(&t_cast); + let t_cast = self.to_ty(t); + let t_cast = self.infcx().resolve_type_vars_if_possible(&t_cast); + self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); + let t_expr = self.expr_ty(e); + let t_cast = self.infcx().resolve_type_vars_if_possible(&t_cast); // Eagerly check for some obvious errors. if t_expr.references_error() || t_cast.references_error() { - fcx.write_error(id); + self.write_error(id); } else { // Write a type for the whole expression, assuming everything is going // to work out Ok. - fcx.write_ty(id, t_cast); + self.write_ty(id, t_cast); // Defer other checks until we're done type checking. - let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new(fcx, e, t_expr, t_cast, t.span, expr.span) { + let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut(); + match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { Ok(cast_check) => { deferred_cast_checks.push(cast_check); } Err(ErrorReported) => { - fcx.write_error(id); + self.write_error(id); } } } } hir::ExprType(ref e, ref t) => { - let typ = fcx.to_ty(&t); - check_expr_eq_type(fcx, &e, typ); - fcx.write_ty(id, typ); + let typ = self.to_ty(&t); + self.check_expr_eq_type(&e, typ); + self.write_ty(id, typ); } hir::ExprVec(ref args) => { - let uty = expected.to_option(fcx).and_then(|uty| { + let uty = expected.to_option(self).and_then(|uty| { match uty.sty { ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty), _ => None } }); - let mut unified = fcx.infcx().next_ty_var(); + let mut unified = self.infcx().next_ty_var(); let coerce_to = uty.unwrap_or(unified); for (i, e) in args.iter().enumerate() { - check_expr_with_hint(fcx, e, coerce_to); - let e_ty = fcx.expr_ty(e); + self.check_expr_with_hint(e, coerce_to); + let e_ty = self.expr_ty(e); let origin = TypeOrigin::Misc(e.span); // Special-case the first element, as it has no "previous expressions". let result = if i == 0 { - coercion::try(fcx, e, coerce_to) + self.try_coerce(e, coerce_to) } else { let prev_elems = || args[..i].iter().map(|e| &**e); - coercion::try_find_lub(fcx, origin, prev_elems, unified, e) + self.try_find_coercion_lub(origin, prev_elems, unified, e) }; match result { Ok(ty) => unified = ty, Err(e) => { - fcx.infcx().report_mismatched_types(origin, unified, e_ty, e); + self.infcx().report_mismatched_types(origin, unified, e_ty, e); } } } - fcx.write_ty(id, tcx.mk_array(unified, args.len())); + self.write_ty(id, tcx.mk_array(unified, args.len())); } hir::ExprRepeat(ref element, ref count_expr) => { - check_expr_has_type(fcx, &count_expr, tcx.types.usize); - let count = eval_repeat_count(fcx.tcx(), &count_expr); + self.check_expr_has_type(&count_expr, tcx.types.usize); + let count = eval_repeat_count(self.tcx(), &count_expr); let uty = match expected { ExpectHasType(uty) => { @@ -3600,35 +3750,31 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let (element_ty, t) = match uty { Some(uty) => { - check_expr_coercable_to_type(fcx, &element, uty); + self.check_expr_coercable_to_type(&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) + let t: Ty = self.infcx().next_ty_var(); + self.check_expr_has_type(&element, t); + (self.expr_ty(&element), t) } }; if count > 1 { // For [foo, ..n] where n > 1, `foo` must have // Copy type: - fcx.require_type_meets( - t, - expr.span, - traits::RepeatVec, - ty::BoundCopy); + self.require_type_meets(t, expr.span, traits::RepeatVec, ty::BoundCopy); } if element_ty.references_error() { - fcx.write_error(id); + self.write_error(id); } else { let t = tcx.mk_array(t, count); - fcx.write_ty(id, t); + self.write_ty(id, t); } } hir::ExprTup(ref elts) => { - let flds = expected.only_has_type(fcx).and_then(|ty| { + let flds = expected.only_has_type(self).and_then(|ty| { match ty.sty { ty::TyTuple(ref flds) => Some(&flds[..]), _ => None @@ -3640,57 +3786,57 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(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); + self.check_expr_coercable_to_type(&e, ety); ety } _ => { - check_expr_with_expectation(fcx, &e, NoExpectation); - fcx.expr_ty(&e) + self.check_expr_with_expectation(&e, NoExpectation); + self.expr_ty(&e) } }; err_field = err_field || t.references_error(); t }).collect(); if err_field { - fcx.write_error(id); + self.write_error(id); } else { let typ = tcx.mk_tup(elt_ts); - fcx.write_ty(id, typ); + self.write_ty(id, typ); } } hir::ExprStruct(ref path, ref fields, ref base_expr) => { - check_expr_struct(fcx, expr, path, fields, base_expr); + self.check_expr_struct(expr, path, fields, base_expr); - fcx.require_expr_have_sized_type(expr, traits::StructInitializerSized); + self.require_expr_have_sized_type(expr, traits::StructInitializerSized); } hir::ExprField(ref base, ref field) => { - check_field(fcx, expr, lvalue_pref, &base, field); + self.check_field(expr, lvalue_pref, &base, field); } hir::ExprTupField(ref base, idx) => { - check_tup_field(fcx, expr, lvalue_pref, &base, idx); + self.check_tup_field(expr, lvalue_pref, &base, idx); } hir::ExprIndex(ref base, ref idx) => { - check_expr_with_lvalue_pref(fcx, &base, lvalue_pref); - check_expr(fcx, &idx); + self.check_expr_with_lvalue_pref(&base, lvalue_pref); + self.check_expr(&idx); - let base_t = fcx.expr_ty(&base); - let idx_t = fcx.expr_ty(&idx); + let base_t = self.expr_ty(&base); + let idx_t = self.expr_ty(&idx); if base_t.references_error() { - fcx.write_ty(id, base_t); + self.write_ty(id, base_t); } else if idx_t.references_error() { - fcx.write_ty(id, idx_t); + self.write_ty(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 = self.structurally_resolved_type(expr.span, base_t); + match self.lookup_indexing(expr, base, base_t, idx_t, lvalue_pref) { Some((index_ty, element_ty)) => { - let idx_expr_ty = fcx.expr_ty(idx); - demand::eqtype(fcx, expr.span, index_ty, idx_expr_ty); - fcx.write_ty(id, element_ty); + let idx_expr_ty = self.expr_ty(idx); + self.demand_eqtype(expr.span, index_ty, idx_expr_ty); + self.write_ty(id, element_ty); } None => { - check_expr_has_type(fcx, &idx, fcx.tcx().types.err); - let mut err = fcx.type_error_struct( + self.check_expr_has_type(&idx, self.tcx().types.err); + let mut err = self.type_error_struct( expr.span, |actual| { format!("cannot index a value of type `{}`", @@ -3705,7 +3851,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // fixed expression: if let hir::ExprLit(ref lit) = idx.node { if let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node { - let snip = fcx.tcx().sess.codemap().span_to_snippet(base.span); + let snip = tcx.sess.codemap().span_to_snippet(base.span); if let Ok(snip) = snip { err.span_suggestion(expr.span, "to access tuple elements, use tuple \ @@ -3721,7 +3867,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } err.emit(); - fcx.write_ty(id, fcx.tcx().types.err); + self.write_ty(id, self.tcx().types.err); } } } @@ -3731,19 +3877,17 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, debug!("type of expr({}) {} is...", expr.id, pprust::expr_to_string(expr)); debug!("... {:?}, expected is {:?}", - fcx.expr_ty(expr), + self.expr_ty(expr), expected); } -pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, - path_res: def::PathResolution, - opt_self_ty: Option>, - path: &'a hir::Path, - span: Span, - node_id: ast::NodeId) - -> Option<(Option>, - &'a [hir::PathSegment], - Def)> +pub fn resolve_ty_and_def_ufcs<'b>(&self, + path_res: def::PathResolution, + opt_self_ty: Option>, + path: &'b hir::Path, + span: Span, + node_id: ast::NodeId) + -> Option<(Option>, &'b [hir::PathSegment], Def)> { // If fully resolved already, we don't have to do anything. @@ -3753,7 +3897,7 @@ 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.split_last().unwrap().1; let base_ty_end = path.segments.len() - path_res.depth; - let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, span, + let ty = astconv::finish_resolving_def_to_ty(self, self, span, PathParamMode::Optional, &mut def, opt_self_ty, @@ -3761,7 +3905,7 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, &ty_segments[base_ty_end..]); let item_segment = path.segments.last().unwrap(); let item_name = item_segment.identifier.name; - let def = match method::resolve_ufcs(fcx, span, item_name, ty, node_id) { + let def = match self.resolve_ufcs(span, item_name, ty, node_id) { Ok(def) => Some(def), Err(error) => { let def = match error { @@ -3769,7 +3913,7 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, _ => None, }; if item_name != keywords::Invalid.name() { - method::report_error(fcx, span, ty, item_name, None, error); + self.report_method_error(span, ty, item_name, None, error); } def } @@ -3777,94 +3921,25 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, if let Some(def) = def { // Write back the new resolution. - fcx.ccx.tcx.def_map.borrow_mut().insert(node_id, def::PathResolution { + self.tcx().def_map.borrow_mut().insert(node_id, def::PathResolution { base_def: def, depth: 0, }); Some((Some(ty), slice::ref_slice(item_segment), def)) } else { - fcx.write_error(node_id); + self.write_error(node_id); None } } } -impl<'tcx> Expectation<'tcx> { - /// Provide an expectation for an rvalue expression given an *optional* - /// hint, which is not required for type safety (the resulting type might - /// be checked higher up, as is the case with `&expr` and `box expr`), but - /// is useful in determining the concrete type. - /// - /// The primary use case is where the expected type is a fat pointer, - /// like `&[isize]`. For example, consider the following statement: - /// - /// let x: &[isize] = &[1, 2, 3]; - /// - /// In this case, the expected type for the `&[1, 2, 3]` expression is - /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the - /// expectation `ExpectHasType([isize])`, that would be too strong -- - /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`. - /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced - /// to the type `&[isize]`. Therefore, we propagate this more limited hint, - /// which still is useful, because it informs integer literals and the like. - /// See the test case `test/run-pass/coerce-expect-unsized.rs` and #20169 - /// for examples of where this comes up,. - fn rvalue_hint<'a>(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> { - match fcx.tcx().struct_tail(ty).sty { - ty::TySlice(_) | ty::TyStr | ty::TyTrait(..) => { - ExpectRvalueLikeUnsized(ty) - } - _ => ExpectHasType(ty) - } - } - - // 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> { - match self { - NoExpectation => { - NoExpectation - } - ExpectCastableToType(t) => { - ExpectCastableToType( - fcx.infcx().resolve_type_vars_if_possible(&t)) - } - ExpectHasType(t) => { - ExpectHasType( - fcx.infcx().resolve_type_vars_if_possible(&t)) - } - ExpectRvalueLikeUnsized(t) => { - ExpectRvalueLikeUnsized( - fcx.infcx().resolve_type_vars_if_possible(&t)) - } - } - } - - fn to_option<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { - match self.resolve(fcx) { - NoExpectation => None, - ExpectCastableToType(ty) | - ExpectHasType(ty) | - ExpectRvalueLikeUnsized(ty) => Some(ty), - } - } - - fn only_has_type<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { - match self.resolve(fcx) { - ExpectHasType(ty) => Some(ty), - _ => None - } - } -} - -pub fn check_decl_initializer<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, - local: &'tcx hir::Local, - init: &'tcx hir::Expr) +pub fn check_decl_initializer(&self, + local: &'tcx hir::Local, + init: &'tcx hir::Expr) { - let ref_bindings = fcx.tcx().pat_contains_ref_binding(&local.pat); + let ref_bindings = self.tcx().pat_contains_ref_binding(&local.pat); - let local_ty = fcx.local_ty(init.span, local.id); + let local_ty = self.local_ty(init.span, local.id); if let Some(m) = ref_bindings { // Somewhat subtle: if we have a `ref` binding in the pattern, // we want to avoid introducing coercions for the RHS. This is @@ -3874,40 +3949,40 @@ 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_with_lvalue_pref(fcx, init, LvaluePreference::from_mutbl(m)); - let init_ty = fcx.expr_ty(init); - demand::eqtype(fcx, init.span, init_ty, local_ty); + self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m)); + let init_ty = self.expr_ty(init); + self.demand_eqtype(init.span, init_ty, local_ty); } else { - check_expr_coercable_to_type(fcx, init, local_ty) + self.check_expr_coercable_to_type(init, local_ty) }; } -pub fn check_decl_local<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, local: &'tcx hir::Local) { - let tcx = fcx.ccx.tcx; +pub fn check_decl_local(&self, local: &'tcx hir::Local) { + let tcx = self.tcx(); - let t = fcx.local_ty(local.span, local.id); - fcx.write_ty(local.id, t); + let t = self.local_ty(local.span, local.id); + self.write_ty(local.id, t); if let Some(ref init) = local.init { - check_decl_initializer(fcx, local, &init); - let init_ty = fcx.expr_ty(&init); + self.check_decl_initializer(local, &init); + let init_ty = self.expr_ty(&init); if init_ty.references_error() { - fcx.write_ty(local.id, init_ty); + self.write_ty(local.id, init_ty); } } - let pcx = pat_ctxt { - fcx: fcx, + let pcx = PatCtxt { + fcx: self, 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); + pcx.check_pat(&local.pat, t); + let pat_ty = self.node_ty(local.pat.id); if pat_ty.references_error() { - fcx.write_ty(local.id, pat_ty); + self.write_ty(local.id, pat_ty); } } -pub fn check_stmt<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, stmt: &'tcx hir::Stmt) { +pub fn check_stmt(&self, stmt: &'tcx hir::Stmt) { let node_id; let mut saw_bot = false; let mut saw_err = false; @@ -3916,9 +3991,9 @@ pub fn check_stmt<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, stmt: &'tcx hir::Stmt) { node_id = id; match decl.node { hir::DeclLocal(ref l) => { - check_decl_local(fcx, &l); - let l_t = fcx.node_ty(l.id); - saw_bot = saw_bot || fcx.infcx().type_var_diverges(l_t); + self.check_decl_local(&l); + let l_t = self.node_ty(l.id); + saw_bot = saw_bot || self.infcx().type_var_diverges(l_t); saw_err = saw_err || l_t.references_error(); } hir::DeclItem(_) => {/* ignore for now */ } @@ -3927,46 +4002,46 @@ pub fn check_stmt<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, stmt: &'tcx hir::Stmt) { hir::StmtExpr(ref expr, id) => { node_id = id; // Check with expected type of () - check_expr_has_type(fcx, &expr, fcx.tcx().mk_nil()); - let expr_ty = fcx.expr_ty(&expr); - saw_bot = saw_bot || fcx.infcx().type_var_diverges(expr_ty); + self.check_expr_has_type(&expr, self.tcx().mk_nil()); + let expr_ty = self.expr_ty(&expr); + saw_bot = saw_bot || self.infcx().type_var_diverges(expr_ty); saw_err = saw_err || expr_ty.references_error(); } hir::StmtSemi(ref expr, id) => { node_id = id; - check_expr(fcx, &expr); - let expr_ty = fcx.expr_ty(&expr); - saw_bot |= fcx.infcx().type_var_diverges(expr_ty); + self.check_expr(&expr); + let expr_ty = self.expr_ty(&expr); + saw_bot |= self.infcx().type_var_diverges(expr_ty); saw_err |= expr_ty.references_error(); } } if saw_bot { - fcx.write_ty(node_id, fcx.infcx().next_diverging_ty_var()); + self.write_ty(node_id, self.infcx().next_diverging_ty_var()); } else if saw_err { - fcx.write_error(node_id); + self.write_error(node_id); } else { - fcx.write_nil(node_id) + self.write_nil(node_id) } } -pub fn check_block_no_value<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, blk: &'tcx hir::Block) { - check_block_with_expected(fcx, blk, ExpectHasType(fcx.tcx().mk_nil())); - let blkty = fcx.node_ty(blk.id); +pub fn check_block_no_value(&self, blk: &'tcx hir::Block) { + self.check_block_with_expected(blk, ExpectHasType(self.tcx().mk_nil())); + let blkty = self.node_ty(blk.id); if blkty.references_error() { - fcx.write_error(blk.id); + self.write_error(blk.id); } else { - let nilty = fcx.tcx().mk_nil(); - demand::suptype(fcx, blk.span, nilty, blkty); + let nilty = self.tcx().mk_nil(); + self.demand_suptype(blk.span, nilty, blkty); } } -fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - blk: &'tcx hir::Block, - expected: Expectation<'tcx>) { +fn check_block_with_expected(&self, + blk: &'tcx hir::Block, + expected: Expectation<'tcx>) { let prev = { - let mut fcx_ps = fcx.ps.borrow_mut(); + let mut fcx_ps = self.ps.borrow_mut(); let unsafety_state = fcx_ps.recurse(blk); replace(&mut *fcx_ps, unsafety_state) }; @@ -3975,9 +4050,9 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let mut any_diverges = false; let mut any_err = false; for s in &blk.stmts { - check_stmt(fcx, s); + self.check_stmt(s); let s_id = s.node.id(); - let s_ty = fcx.node_ty(s_id); + let s_ty = self.node_ty(s_id); if any_diverges && !warned && match s.node { hir::StmtDecl(ref decl, _) => { match decl.node { @@ -3987,8 +4062,7 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } hir::StmtExpr(_, _) | hir::StmtSemi(_, _) => true, } { - fcx.ccx - .tcx + self.tcx() .sess .add_lint(lint::builtin::UNREACHABLE_CODE, s_id, @@ -3996,21 +4070,20 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, "unreachable statement".to_string()); warned = true; } - any_diverges = any_diverges || fcx.infcx().type_var_diverges(s_ty); + any_diverges = any_diverges || self.infcx().type_var_diverges(s_ty); any_err = any_err || s_ty.references_error(); } match blk.expr { None => if any_err { - fcx.write_error(blk.id); + self.write_error(blk.id); } else if any_diverges { - fcx.write_ty(blk.id, fcx.infcx().next_diverging_ty_var()); + self.write_ty(blk.id, self.infcx().next_diverging_ty_var()); } else { - fcx.write_nil(blk.id); + self.write_nil(blk.id); }, Some(ref e) => { if any_diverges && !warned { - fcx.ccx - .tcx + self.tcx() .sess .add_lint(lint::builtin::UNREACHABLE_CODE, e.id, @@ -4019,202 +4092,66 @@ 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); + self.check_expr_coercable_to_type(&e, ety); ety } _ => { - check_expr_with_expectation(fcx, &e, expected); - fcx.expr_ty(&e) + self.check_expr_with_expectation(&e, expected); + self.expr_ty(&e) } }; if any_err { - fcx.write_error(blk.id); + self.write_error(blk.id); } else if any_diverges { - fcx.write_ty(blk.id, fcx.infcx().next_diverging_ty_var()); + self.write_ty(blk.id, self.infcx().next_diverging_ty_var()); } else { - fcx.write_ty(blk.id, ety); + self.write_ty(blk.id, ety); } } }; - *fcx.ps.borrow_mut() = prev; + *self.ps.borrow_mut() = prev; } -/// Checks a constant appearing in a type. At the moment this is just the -/// length expression in a fixed-length vector, but someday it might be -/// extended to type-level numeric literals. -fn check_const_in_type<'a,'tcx>(ccx: &'a CrateCtxt<'a,'tcx>, - expr: &'tcx hir::Expr, - expected_type: Ty<'tcx>) { - let tables = RefCell::new(ty::Tables::empty()); - let inh = static_inherited_fields(ccx, &tables); - let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(expected_type), expr.id); - check_const_with_ty(&fcx, expr.span, expr, expected_type); -} -fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - sp: Span, - e: &'tcx hir::Expr, - id: ast::NodeId) { - let tables = RefCell::new(ty::Tables::empty()); - let inh = static_inherited_fields(ccx, &tables); - let rty = ccx.tcx.node_id_to_type(id); - let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id); - let declty = fcx.ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty; - check_const_with_ty(&fcx, sp, e, declty); -} - -fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - _: Span, - e: &'tcx hir::Expr, - declty: Ty<'tcx>) { +fn check_const_with_ty(&self, + _: Span, + e: &'tcx hir::Expr, + declty: Ty<'tcx>) { // Gather locals in statics (because of block expressions). // This is technically unnecessary because locals in static items are forbidden, // but prevents type checking from blowing up before const checking can properly // emit an error. - GatherLocalsVisitor { fcx: fcx }.visit_expr(e); + GatherLocalsVisitor { fcx: self }.visit_expr(e); - check_expr_with_hint(fcx, e, declty); - demand::coerce(fcx, e.span, declty, e); + self.check_expr_coercable_to_type(e, declty); - fcx.select_all_obligations_and_apply_defaults(); - upvar::closure_analyze_const(&fcx, e); - fcx.select_obligations_where_possible(); - fcx.check_casts(); - fcx.select_all_obligations_or_error(); + self.select_all_obligations_and_apply_defaults(); + self.closure_analyze_const(e); + self.select_obligations_where_possible(); + self.check_casts(); + self.select_all_obligations_or_error(); - regionck::regionck_expr(fcx, e); - writeback::resolve_type_vars_in_expr(fcx, e); -} - -/// Checks whether a type can be represented in memory. In particular, it -/// identifies types that contain themselves without indirection through a -/// pointer, which would mean their size is unbounded. -pub fn check_representable(tcx: &TyCtxt, - sp: Span, - item_id: ast::NodeId, - _designation: &str) -> bool { - let rty = tcx.node_id_to_type(item_id); - - // Check that it is possible to represent this type. This call identifies - // (1) types that contain themselves and (2) types that contain a different - // recursive type. It is only necessary to throw an error on those that - // contain themselves. For case 2, there must be an inner type that will be - // caught by case 1. - match rty.is_representable(tcx, sp) { - Representability::SelfRecursive => { - let item_def_id = tcx.map.local_def_id(item_id); - traits::recursive_type_with_infinite_size_error(tcx, item_def_id).emit(); - return false - } - Representability::Representable | Representability::ContainsRecursive => (), - } - return true -} - -pub fn check_simd(tcx: &TyCtxt, sp: Span, id: ast::NodeId) { - let t = tcx.node_id_to_type(id); - match t.sty { - ty::TyStruct(def, substs) => { - let fields = &def.struct_variant().fields; - if fields.is_empty() { - span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty"); - return; - } - let e = fields[0].ty(tcx, substs); - if !fields.iter().all(|f| f.ty(tcx, substs) == e) { - span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous"); - return; - } - match e.sty { - ty::TyParam(_) => { /* struct(T, T, T, T) is ok */ } - _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ } - _ => { - span_err!(tcx.sess, sp, E0077, - "SIMD vector element type should be machine type"); - return; - } - } - } - _ => () - } -} - -pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - sp: Span, - vs: &'tcx [hir::Variant], - id: ast::NodeId) { - fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - vs: &'tcx [hir::Variant], - id: ast::NodeId, - hint: attr::ReprAttr) { - #![allow(trivial_numeric_casts)] - - let rty = ccx.tcx.node_id_to_type(id); - let mut disr_vals: Vec = Vec::new(); - - let tables = RefCell::new(ty::Tables::empty()); - let inh = static_inherited_fields(ccx, &tables); - let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), id); - - let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(&ccx.tcx); - for v in vs { - if let Some(ref e) = v.node.disr_expr { - check_const_with_ty(&fcx, e.span, e, repr_type_ty); - } - } - - let def_id = ccx.tcx.map.local_def_id(id); - - let variants = &ccx.tcx.lookup_adt_def(def_id).variants; - for (v, variant) in vs.iter().zip(variants.iter()) { - let current_disr_val = variant.disr_val; - - // Check for duplicate discriminant values - match disr_vals.iter().position(|&x| x == current_disr_val) { - Some(i) => { - let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0081, - "discriminant value `{}` already exists", disr_vals[i]); - let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap(); - span_note!(&mut err, ccx.tcx.map.span(variant_i_node_id), - "conflicting discriminant here"); - err.emit(); - } - None => {} - } - disr_vals.push(current_disr_val); - } - } - - let def_id = ccx.tcx.map.local_def_id(id); - let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny); - - if hint != attr::ReprAny && vs.is_empty() { - span_err!(ccx.tcx.sess, sp, E0084, - "unsupported representation for zero-variant enum"); - } - - do_check(ccx, vs, id, hint); - - check_representable(ccx.tcx, sp, id, "enum"); + self.regionck_expr(e); + self.resolve_type_vars_in_expr(e); } // 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>, - sp: Span, - defn: Def) - -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) { +fn type_scheme_and_predicates_for_def(&self, + sp: Span, + defn: Def) + -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) { match defn { Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => { - let typ = fcx.local_ty(sp, nid); + let typ = self.local_ty(sp, nid); (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ }, ty::GenericPredicates::empty()) } Def::Fn(id) | Def::Method(id) | Def::Static(id, _) | Def::Variant(_, id) | Def::Struct(id) | Def::Const(id) | Def::AssociatedConst(id) => { - (fcx.tcx().lookup_item_type(id), fcx.tcx().lookup_predicates(id)) + (self.tcx().lookup_item_type(id), self.tcx().lookup_predicates(id)) } Def::Trait(_) | Def::Enum(..) | @@ -4234,14 +4171,14 @@ 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: &[hir::PathSegment], - type_scheme: TypeScheme<'tcx>, - type_predicates: &ty::GenericPredicates<'tcx>, - opt_self_ty: Option>, - def: Def, - span: Span, - node_id: ast::NodeId) { +pub fn instantiate_path(&self, + segments: &[hir::PathSegment], + type_scheme: TypeScheme<'tcx>, + type_predicates: &ty::GenericPredicates<'tcx>, + opt_self_ty: Option>, + def: Def, + span: Span, + node_id: ast::NodeId) { debug!("instantiate_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})", segments, def, @@ -4348,10 +4285,10 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Case 3. Reference to a method. Def::Method(def_id) => { - let container = fcx.tcx().impl_or_trait_item(def_id).container(); + let container = self.tcx().impl_or_trait_item(def_id).container(); match container { ty::TraitContainer(trait_did) => { - callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did) + callee::check_legal_trait_for_method_call(self.ccx, span, trait_did) } ty::ImplContainer(_) => {} } @@ -4369,10 +4306,10 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } Def::AssociatedConst(def_id) => { - let container = fcx.tcx().impl_or_trait_item(def_id).container(); + let container = self.tcx().impl_or_trait_item(def_id).container(); match container { ty::TraitContainer(trait_did) => { - callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did) + callee::check_legal_trait_for_method_call(self.ccx, span, trait_did) } ty::ImplContainer(_) => {} } @@ -4401,7 +4338,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } Def::Err => { - fcx.infcx().set_tainted_by_errors(); + self.infcx().set_tainted_by_errors(); segment_spaces = vec![None; segments.len()]; } } @@ -4424,21 +4361,16 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // provided (if any) into their appropriate spaces. We'll also report // errors if type parameters are provided in an inappropriate place. let mut substs = Substs::empty(); - for (opt_space, segment) in segment_spaces.iter().zip(segments) { - match *opt_space { - None => { - prohibit_type_params(fcx.tcx(), slice::ref_slice(segment)); - } - - Some(space) => { - push_explicit_parameters_from_segment_to_substs(fcx, - space, - span, - type_defs, - region_defs, - segment, - &mut substs); - } + for (&opt_space, segment) in segment_spaces.iter().zip(segments) { + if let Some(space) = opt_space { + self.push_explicit_parameters_from_segment_to_substs(space, + span, + type_defs, + region_defs, + segment, + &mut substs); + } else { + prohibit_type_params(self.tcx(), slice::ref_slice(segment)); } } if let Some(self_ty) = opt_self_ty { @@ -4454,11 +4386,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // to add defaults. If the user provided *too many* types, that's // a problem. for &space in &[subst::SelfSpace, subst::TypeSpace, subst::FnSpace] { - adjust_type_parameters(fcx, span, space, type_defs, - require_type_space, &mut substs); + self.adjust_type_parameters(span, space, type_defs, + require_type_space, &mut substs); assert_eq!(substs.types.len(space), type_defs.len(space)); - adjust_region_parameters(fcx, span, space, region_defs, &mut substs); + self.adjust_region_parameters(span, space, region_defs, &mut substs); assert_eq!(substs.regions.len(space), region_defs.len(space)); } @@ -4469,14 +4401,14 @@ 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( - traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def.def_id())), + let bounds = self.instantiate_bounds(span, &substs, &type_predicates); + self.add_obligations_for_parameters( + traits::ObligationCause::new(span, self.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); + let ty_substituted = self.instantiate_type_scheme(span, &substs, &type_scheme.ty); if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated { @@ -4484,14 +4416,14 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // is inherent, there is no `Self` parameter, instead, the impl needs // type parameters, which we can infer by unifying the provided `Self` // with the substituted impl type. - let impl_scheme = fcx.tcx().lookup_item_type(impl_def_id); + let impl_scheme = self.tcx().lookup_item_type(impl_def_id); assert_eq!(substs.types.len(subst::TypeSpace), impl_scheme.generics.types.len(subst::TypeSpace)); 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); - if fcx.mk_subty(false, TypeOrigin::Misc(span), self_ty, impl_ty).is_err() { + let impl_ty = self.instantiate_type_scheme(span, &substs, &impl_scheme.ty); + if self.mk_subty(false, TypeOrigin::Misc(span), self_ty, impl_ty).is_err() { span_bug!(span, "instantiate_path: (UFCS) {:?} was a subtype of {:?} but now is not?", self_ty, @@ -4502,9 +4434,9 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, debug!("instantiate_path: type of {:?} is {:?}", node_id, ty_substituted); - fcx.write_ty(node_id, ty_substituted); - fcx.write_substs(node_id, ty::ItemSubsts { substs: substs }); - return; + self.write_ty(node_id, ty_substituted); + self.write_substs(node_id, ty::ItemSubsts { substs: substs }); +} /// Finds the parameters that the user provided and adds them to `substs`. If too many /// parameters are provided, then reports an error and clears the output vector. @@ -4515,8 +4447,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// Note that we *do not* check for *too few* parameters here. Due to the presence of defaults /// 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>( - fcx: &FnCtxt<'a, 'tcx>, + fn push_explicit_parameters_from_segment_to_substs(&self, space: subst::ParamSpace, span: Span, type_defs: &VecPerParamSpace>, @@ -4526,21 +4457,20 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, { match segment.parameters { hir::AngleBracketedParameters(ref data) => { - push_explicit_angle_bracketed_parameters_from_segment_to_substs( - fcx, space, type_defs, region_defs, data, substs); + self.push_explicit_angle_bracketed_parameters_from_segment_to_substs( + space, type_defs, region_defs, data, substs); } hir::ParenthesizedParameters(ref data) => { - span_err!(fcx.tcx().sess, span, E0238, + span_err!(self.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); + self.push_explicit_parenthesized_parameters_from_segment_to_substs( + space, span, type_defs, data, substs); } } } - fn push_explicit_angle_bracketed_parameters_from_segment_to_substs<'a, 'tcx>( - fcx: &FnCtxt<'a, 'tcx>, + fn push_explicit_angle_bracketed_parameters_from_segment_to_substs(&self, space: subst::ParamSpace, type_defs: &VecPerParamSpace>, region_defs: &VecPerParamSpace, @@ -4551,11 +4481,11 @@ 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 t = self.to_ty(&typ); if i < type_count { substs.types.push(space, t); } else if i == type_count { - span_err!(fcx.tcx().sess, typ.span, E0087, + span_err!(self.tcx().sess, typ.span, E0087, "too many type parameters provided: \ expected at most {} parameter{}, \ found {} parameter{}", @@ -4570,7 +4500,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } if !data.bindings.is_empty() { - span_err!(fcx.tcx().sess, data.bindings[0].span, E0182, + span_err!(self.tcx().sess, data.bindings[0].span, E0182, "unexpected binding of associated item in expression path \ (only allowed in type paths)"); } @@ -4579,11 +4509,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let region_count = region_defs.len(space); assert_eq!(substs.regions.len(space), 0); for (i, lifetime) in data.lifetimes.iter().enumerate() { - let r = ast_region_to_region(fcx.tcx(), lifetime); + let r = ast_region_to_region(self.tcx(), lifetime); if i < region_count { substs.regions.push(space, r); } else if i == region_count { - span_err!(fcx.tcx().sess, lifetime.span, E0088, + span_err!(self.tcx().sess, lifetime.span, E0088, "too many lifetime parameters provided: \ expected {} parameter{}, found {} parameter{}", region_count, @@ -4603,8 +4533,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// roughly the same thing as `Foo<(A,B),C>`. One important /// 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>( - fcx: &FnCtxt<'a, 'tcx>, + fn push_explicit_parenthesized_parameters_from_segment_to_substs(&self, space: subst::ParamSpace, span: Span, type_defs: &VecPerParamSpace>, @@ -4613,34 +4542,33 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, { let type_count = type_defs.len(space); if type_count < 2 { - span_err!(fcx.tcx().sess, span, E0167, + span_err!(self.tcx().sess, span, E0167, "parenthesized form always supplies 2 type parameters, \ but only {} parameter(s) were expected", type_count); } let input_tys: Vec = - data.inputs.iter().map(|ty| fcx.to_ty(&ty)).collect(); + data.inputs.iter().map(|ty| self.to_ty(&ty)).collect(); - let tuple_ty = fcx.tcx().mk_tup(input_tys); + let tuple_ty = self.tcx().mk_tup(input_tys); if type_count >= 1 { substs.types.push(space, tuple_ty); } let output_ty: Option = - data.output.as_ref().map(|ty| fcx.to_ty(&ty)); + data.output.as_ref().map(|ty| self.to_ty(&ty)); let output_ty = - output_ty.unwrap_or(fcx.tcx().mk_nil()); + output_ty.unwrap_or(self.tcx().mk_nil()); if type_count >= 2 { substs.types.push(space, output_ty); } } - fn adjust_type_parameters<'a, 'tcx>( - fcx: &FnCtxt<'a, 'tcx>, + fn adjust_type_parameters(&self, span: Span, space: ParamSpace, defs: &VecPerParamSpace>, @@ -4669,7 +4597,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // everything. if provided_len == 0 && !(require_type_space && space == subst::TypeSpace) { substs.types.replace(space, Vec::new()); - fcx.infcx().type_vars_for_defs(span, space, substs, &desired[..]); + self.infcx().type_vars_for_defs(span, space, substs, &desired[..]); return; } @@ -4678,14 +4606,14 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if provided_len < required_len { let qualifier = if desired.len() != required_len { "at least " } else { "" }; - span_err!(fcx.tcx().sess, span, E0089, + span_err!(self.tcx().sess, span, E0089, "too few type parameters provided: expected {}{} parameter{}, \ found {} parameter{}", qualifier, required_len, if required_len == 1 {""} else {"s"}, provided_len, if provided_len == 1 {""} else {"s"}); - substs.types.replace(space, vec![fcx.tcx().types.err; desired.len()]); + substs.types.replace(space, vec![self.tcx().types.err; desired.len()]); return; } @@ -4698,7 +4626,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // partial substitution that we have built up. for i in provided_len..desired.len() { let default = desired[i].default.unwrap(); - let default = default.subst_spanned(fcx.tcx(), substs, Some(span)); + let default = default.subst_spanned(self.tcx(), substs, Some(span)); substs.types.push(space, default); } assert_eq!(substs.types.len(space), desired.len()); @@ -4706,8 +4634,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, debug!("Final substs: {:?}", substs); } - fn adjust_region_parameters( - fcx: &FnCtxt, + fn adjust_region_parameters(&self, span: Span, space: ParamSpace, defs: &VecPerParamSpace, @@ -4723,7 +4650,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if provided_len == 0 { substs.regions.replace( space, - fcx.infcx().region_vars_for_defs(span, desired)); + self.infcx().region_vars_for_defs(span, desired)); return; } @@ -4734,7 +4661,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Otherwise, too few were provided. Report an error and then // use inference variables. - span_err!(fcx.tcx().sess, span, E0090, + span_err!(self.tcx().sess, span, E0090, "too few lifetime parameters provided: expected {} parameter{}, \ found {} parameter{}", desired.len(), @@ -4744,32 +4671,29 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, substs.regions.replace( space, - fcx.infcx().region_vars_for_defs(span, desired)); + self.infcx().region_vars_for_defs(span, desired)); } -} -fn structurally_resolve_type_or_else<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, - sp: Span, - ty: Ty<'tcx>, - f: F) -> Ty<'tcx> +fn structurally_resolve_type_or_else(&self, 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 = self.resolve_type_vars_if_possible(ty); if ty.is_ty_var() { let alternative = f(); // If not, error. if alternative.is_ty_var() || alternative.references_error() { - if !fcx.infcx().is_tainted_by_errors() { - fcx.type_error_message(sp, |_actual| { + if !self.infcx().is_tainted_by_errors() { + self.type_error_message(sp, |_actual| { "the type of this value must be known in this context".to_string() }, ty, None); } - demand::suptype(fcx, sp, fcx.tcx().types.err, ty); - ty = fcx.tcx().types.err; + self.demand_suptype(sp, self.tcx().types.err, ty); + ty = self.tcx().types.err; } else { - demand::suptype(fcx, sp, alternative, ty); + self.demand_suptype(sp, alternative, ty); ty = alternative; } } @@ -4779,15 +4703,12 @@ 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> -{ - structurally_resolve_type_or_else(fcx, sp, ty, || { - fcx.tcx().types.err +pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + self.structurally_resolve_type_or_else(sp, ty, || { + self.tcx().types.err }) } +} // Returns true if b contains a break that can exit from b pub fn may_break(tcx: &TyCtxt, id: ast::NodeId, b: &hir::Block) -> bool { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index debf9258757..d86813e2807 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -10,55 +10,49 @@ //! Code related to processing overloaded binary and unary operators. -use super::{ - check_expr, - check_expr_coercable_to_type, - check_expr_with_lvalue_pref, - demand, - method, - FnCtxt, -}; +use super::FnCtxt; use hir::def_id::DefId; use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue}; use syntax::ast; use syntax::parse::token; use rustc::hir; +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Check a `a = b` -pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, - expr: &'tcx hir::Expr, - op: hir::BinOp, - lhs_expr: &'tcx hir::Expr, - rhs_expr: &'tcx hir::Expr) +pub fn check_binop_assign(&self, + expr: &'tcx hir::Expr, + op: hir::BinOp, + lhs_expr: &'tcx hir::Expr, + rhs_expr: &'tcx hir::Expr) { - check_expr_with_lvalue_pref(fcx, lhs_expr, PreferMutLvalue); + self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue); - let lhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr)); + let lhs_ty = self.resolve_type_vars_if_possible(self.expr_ty(lhs_expr)); let (rhs_ty, return_ty) = - check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes); - let rhs_ty = fcx.resolve_type_vars_if_possible(rhs_ty); + self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes); + let rhs_ty = self.resolve_type_vars_if_possible(rhs_ty); if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) { - enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); - fcx.write_nil(expr.id); + self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); + self.write_nil(expr.id); } else { - fcx.write_ty(expr.id, return_ty); + self.write_ty(expr.id, return_ty); } - let tcx = fcx.tcx(); + let tcx = self.tcx(); if !tcx.expr_is_lval(lhs_expr) { span_err!(tcx.sess, lhs_expr.span, E0067, "invalid left-hand side expression"); } } /// Check a potentially overloaded binary operator. -pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - op: hir::BinOp, - lhs_expr: &'tcx hir::Expr, - rhs_expr: &'tcx hir::Expr) +pub fn check_binop(&self, + expr: &'tcx hir::Expr, + op: hir::BinOp, + lhs_expr: &'tcx hir::Expr, + rhs_expr: &'tcx hir::Expr) { - let tcx = fcx.ccx.tcx; + let tcx = self.tcx(); debug!("check_binop(expr.id={}, expr={:?}, op={:?}, lhs_expr={:?}, rhs_expr={:?})", expr.id, @@ -67,22 +61,22 @@ pub fn check_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, lhs_expr, rhs_expr); - check_expr(fcx, lhs_expr); - let lhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr)); + self.check_expr(lhs_expr); + let lhs_ty = self.resolve_type_vars_if_possible(self.expr_ty(lhs_expr)); match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { // && and || are a simple case. - demand::suptype(fcx, lhs_expr.span, tcx.mk_bool(), lhs_ty); - check_expr_coercable_to_type(fcx, rhs_expr, tcx.mk_bool()); - fcx.write_ty(expr.id, tcx.mk_bool()); + self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty); + self.check_expr_coercable_to_type(rhs_expr, tcx.mk_bool()); + self.write_ty(expr.id, tcx.mk_bool()); } _ => { // 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, IsAssign::No); + self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::No); // Supply type inference hints if relevant. Probably these // hints should be enforced during select as part of the @@ -96,36 +90,36 @@ 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 = self.resolve_type_vars_if_possible(rhs_ty); if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) { let builtin_return_ty = - enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); - demand::suptype(fcx, expr.span, builtin_return_ty, return_ty); + self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); + self.demand_suptype(expr.span, builtin_return_ty, return_ty); } - fcx.write_ty(expr.id, return_ty); + self.write_ty(expr.id, return_ty); } } } -fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - lhs_expr: &'tcx hir::Expr, - lhs_ty: Ty<'tcx>, - rhs_expr: &'tcx hir::Expr, - rhs_ty: Ty<'tcx>, - op: hir::BinOp) - -> Ty<'tcx> +fn enforce_builtin_binop_types(&self, + lhs_expr: &'tcx hir::Expr, + lhs_ty: Ty<'tcx>, + rhs_expr: &'tcx hir::Expr, + rhs_ty: Ty<'tcx>, + op: hir::BinOp) + -> Ty<'tcx> { debug_assert!(is_builtin_binop(lhs_ty, rhs_ty, op)); - let tcx = fcx.tcx(); + let tcx = self.tcx(); match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { - demand::suptype(fcx, lhs_expr.span, tcx.mk_bool(), lhs_ty); - demand::suptype(fcx, rhs_expr.span, tcx.mk_bool(), rhs_ty); + self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty); + self.demand_suptype(rhs_expr.span, tcx.mk_bool(), rhs_ty); tcx.mk_bool() } @@ -137,33 +131,33 @@ fn enforce_builtin_binop_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, BinOpCategory::Math | BinOpCategory::Bitwise => { // both LHS and RHS and result will have the same type - demand::suptype(fcx, rhs_expr.span, lhs_ty, rhs_ty); + self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty); lhs_ty } BinOpCategory::Comparison => { // both LHS and RHS and result will have the same type - demand::suptype(fcx, rhs_expr.span, lhs_ty, rhs_ty); + self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty); tcx.mk_bool() } } } -fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - lhs_expr: &'tcx hir::Expr, - lhs_ty: Ty<'tcx>, - rhs_expr: &'tcx hir::Expr, - op: hir::BinOp, - is_assign: IsAssign) - -> (Ty<'tcx>, Ty<'tcx>) +fn check_overloaded_binop(&self, + expr: &'tcx hir::Expr, + lhs_expr: &'tcx hir::Expr, + lhs_ty: Ty<'tcx>, + rhs_expr: &'tcx hir::Expr, + op: hir::BinOp, + is_assign: IsAssign) + -> (Ty<'tcx>, Ty<'tcx>) { debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?}, is_assign={:?})", expr.id, lhs_ty, is_assign); - let (name, trait_def_id) = name_and_trait_def_id(fcx, op, is_assign); + let (name, trait_def_id) = self.name_and_trait_def_id(op, is_assign); // NB: As we have not yet type-checked the RHS, we don't have the // type at hand. Make a variable to represent it. The whole reason @@ -171,22 +165,22 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // using this variable as the expected type, which sometimes lets // us do better coercions than we would be able to do otherwise, // particularly for things like `String + &String`. - let rhs_ty_var = fcx.infcx().next_ty_var(); + let rhs_ty_var = self.infcx().next_ty_var(); - let return_ty = match lookup_op_method(fcx, expr, lhs_ty, vec![rhs_ty_var], - token::intern(name), trait_def_id, - lhs_expr) { + let return_ty = match self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var], + token::intern(name), trait_def_id, + lhs_expr) { Ok(return_ty) => return_ty, Err(()) => { // error types are considered "builtin" if !lhs_ty.references_error() { if let IsAssign::Yes = is_assign { - span_err!(fcx.tcx().sess, lhs_expr.span, E0368, + span_err!(self.tcx().sess, lhs_expr.span, E0368, "binary assignment operation `{}=` cannot be applied to type `{}`", op.node.as_str(), lhs_ty); } else { - let mut err = struct_span_err!(fcx.tcx().sess, lhs_expr.span, E0369, + let mut err = struct_span_err!(self.tcx().sess, lhs_expr.span, E0369, "binary operation `{}` cannot be applied to type `{}`", op.node.as_str(), lhs_ty); @@ -214,46 +208,46 @@ fn check_overloaded_binop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, err.emit(); } } - fcx.tcx().types.err + self.tcx().types.err } }; // see `NB` above - check_expr_coercable_to_type(fcx, rhs_expr, rhs_ty_var); + self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); (rhs_ty_var, return_ty) } -pub fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - op_str: &str, - mname: &str, - trait_did: Option, - ex: &'tcx hir::Expr, - operand_expr: &'tcx hir::Expr, - operand_ty: Ty<'tcx>, - op: hir::UnOp) - -> Ty<'tcx> +pub fn check_user_unop(&self, + op_str: &str, + mname: &str, + trait_did: Option, + ex: &'tcx hir::Expr, + operand_expr: &'tcx hir::Expr, + operand_ty: Ty<'tcx>, + op: hir::UnOp) + -> Ty<'tcx> { assert!(op.is_by_value()); - match lookup_op_method(fcx, ex, operand_ty, vec![], - token::intern(mname), trait_did, - operand_expr) { + match self.lookup_op_method(ex, operand_ty, vec![], + token::intern(mname), trait_did, + operand_expr) { Ok(t) => t, Err(()) => { - fcx.type_error_message(ex.span, |actual| { + self.type_error_message(ex.span, |actual| { format!("cannot apply unary operator `{}` to type `{}`", op_str, actual) }, operand_ty, None); - fcx.tcx().types.err + self.tcx().types.err } } } -fn name_and_trait_def_id(fcx: &FnCtxt, +fn name_and_trait_def_id(&self, op: hir::BinOp, is_assign: IsAssign) -> (&'static str, Option) { - let lang = &fcx.tcx().lang_items; + let lang = &self.tcx().lang_items; if let IsAssign::Yes = is_assign { match op.node { @@ -299,14 +293,14 @@ fn name_and_trait_def_id(fcx: &FnCtxt, } } -fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - lhs_ty: Ty<'tcx>, - other_tys: Vec>, - opname: ast::Name, - trait_did: Option, - lhs_expr: &'a hir::Expr) - -> Result,()> +fn lookup_op_method(&self, + expr: &'tcx hir::Expr, + lhs_ty: Ty<'tcx>, + other_tys: Vec>, + opname: ast::Name, + trait_did: Option, + lhs_expr: &'a hir::Expr) + -> Result,()> { debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, trait_did={:?}, lhs_expr={:?})", expr, @@ -317,15 +311,14 @@ 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, - expr.span, - Some(lhs_expr), - opname, - trait_did, - 0, - false, - lhs_ty, - Some(other_tys)) + self.lookup_method_in_trait_adjusted(expr.span, + Some(lhs_expr), + opname, + trait_did, + 0, + false, + lhs_ty, + Some(other_tys)) } None => None }; @@ -336,18 +329,19 @@ 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 = ::rustc::ty::MethodCall::expr(expr.id); - fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); + self.inh.tables.borrow_mut().method_map.insert(method_call, method); // extract return type for method; all late bound regions // should have been instantiated by now let ret_ty = method_ty.fn_ret(); - Ok(fcx.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap()) + Ok(self.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap()) } None => { Err(()) } } } +} // Binary operator categories. These categories summarize the behavior // with respect to the builtin operationrs supported. @@ -428,11 +422,7 @@ enum IsAssign { /// Reason #2 is the killer. I tried for a while to always use /// overloaded logic and just check the types in constants/trans after /// the fact, and it worked fine, except for SIMD types. -nmatsakis -fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, - rhs: Ty<'tcx>, - op: hir::BinOp) - -> bool -{ +fn is_builtin_binop(lhs: Ty, rhs: Ty, op: hir::BinOp) -> bool { match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { true diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index bda4c422880..76c387ccc2c 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -112,9 +112,10 @@ macro_rules! ignore_err { /////////////////////////////////////////////////////////////////////////// // PUBLIC ENTRY POINTS -pub fn regionck_expr(fcx: &FnCtxt, e: &hir::Expr) { - let mut rcx = Rcx::new(fcx, RepeatingScope(e.id), e.id, Subject(e.id)); - if fcx.err_count_since_creation() == 0 { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { +pub fn regionck_expr(&self, e: &hir::Expr) { + let mut rcx = Rcx::new(self, RepeatingScope(e.id), e.id, Subject(e.id)); + if self.err_count_since_creation() == 0 { // regionck assumes typeck succeeded rcx.visit_expr(e); rcx.visit_region_obligations(e.id); @@ -124,43 +125,44 @@ pub fn regionck_expr(fcx: &FnCtxt, e: &hir::Expr) { /// Region checking during the WF phase for items. `wf_tys` are the /// types from which we should derive implied bounds, if any. -pub fn regionck_item<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, - item_id: ast::NodeId, - span: Span, - wf_tys: &[Ty<'tcx>]) { +pub fn regionck_item(&self, + item_id: ast::NodeId, + span: Span, + wf_tys: &[Ty<'tcx>]) { debug!("regionck_item(item.id={:?}, wf_tys={:?}", item_id, wf_tys); - let mut rcx = Rcx::new(fcx, RepeatingScope(item_id), item_id, Subject(item_id)); - let tcx = fcx.tcx(); - rcx.free_region_map - .relate_free_regions_from_predicates(tcx, &fcx.infcx().parameter_environment.caller_bounds); + let mut rcx = Rcx::new(self, RepeatingScope(item_id), item_id, Subject(item_id)); + let tcx = self.tcx(); + rcx.free_region_map.relate_free_regions_from_predicates(tcx, + &self.infcx().parameter_environment.caller_bounds); rcx.relate_free_regions(wf_tys, item_id, span); rcx.visit_region_obligations(item_id); rcx.resolve_regions_and_report_errors(); } -pub fn regionck_fn(fcx: &FnCtxt, +pub fn regionck_fn(&self, fn_id: ast::NodeId, fn_span: Span, decl: &hir::FnDecl, blk: &hir::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(self, RepeatingScope(blk.id), blk.id, Subject(fn_id)); - if fcx.err_count_since_creation() == 0 { + if self.err_count_since_creation() == 0 { // regionck assumes typeck succeeded rcx.visit_fn_body(fn_id, decl, blk, fn_span); } - let tcx = fcx.tcx(); - rcx.free_region_map - .relate_free_regions_from_predicates(tcx, &fcx.infcx().parameter_environment.caller_bounds); + let tcx = self.tcx(); + rcx.free_region_map.relate_free_regions_from_predicates(tcx, + &self.infcx().parameter_environment.caller_bounds); rcx.resolve_regions_and_report_errors(); // For the top-level fn, store the free-region-map. We don't store // any map for closures; they just share the same map as the // function that created them. - fcx.tcx().store_free_region_map(fn_id, rcx.free_region_map); + self.tcx().store_free_region_map(fn_id, rcx.free_region_map); +} } /////////////////////////////////////////////////////////////////////////// @@ -207,7 +209,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { } pub fn tcx(&self) -> &'a TyCtxt<'tcx> { - self.fcx.ccx.tcx + self.fcx.tcx() } pub fn infcx(&self) -> &InferCtxt<'a,'tcx> { diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index c39e992eb36..629b3035404 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -42,7 +42,6 @@ use super::FnCtxt; -use check::demand; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; @@ -57,34 +56,30 @@ use rustc::hir::intravisit::{self, Visitor}; /////////////////////////////////////////////////////////////////////////// // PUBLIC ENTRY POINTS -pub fn closure_analyze_fn(fcx: &FnCtxt, - _id: ast::NodeId, - _decl: &hir::FnDecl, - body: &hir::Block) -{ - let mut seed = SeedBorrowKind::new(fcx); +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { +pub fn closure_analyze_fn(&self, body: &hir::Block) { + let mut seed = SeedBorrowKind::new(self); 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(self, &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!(self.inh.deferred_call_resolutions.borrow().is_empty()); } -pub fn closure_analyze_const(fcx: &FnCtxt, - body: &hir::Expr) -{ - let mut seed = SeedBorrowKind::new(fcx); +pub fn closure_analyze_const(&self, body: &hir::Expr) { + let mut seed = SeedBorrowKind::new(self); seed.visit_expr(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(self, &closures_with_inferred_kinds); adjust.visit_expr(body); // it's our job to process these. - assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty()); + assert!(self.inh.deferred_call_resolutions.borrow().is_empty()); +} } /////////////////////////////////////////////////////////////////////////// @@ -221,7 +216,7 @@ impl<'a,'tcx> AdjustBorrowKind<'a,'tcx> { debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}", id, closure_substs, final_upvar_tys); for (&upvar_ty, final_upvar_ty) in closure_substs.upvar_tys.iter().zip(final_upvar_tys) { - demand::eqtype(self.fcx, span, final_upvar_ty, upvar_ty); + self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty); } // Now we must process and remove any deferred resolutions, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 17856dc4255..9e8cfa42f4e 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck}; +use check::{FnCtxt, Inherited}; use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; use hir::def_id::DefId; @@ -108,14 +108,14 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } hir::ItemStruct(ref struct_def, ref ast_generics) => { self.check_type_defn(item, |fcx| { - vec![struct_variant(fcx, struct_def)] + vec![fcx.struct_variant(struct_def)] }); self.check_variances_for_type_defn(item, ast_generics); } hir::ItemEnum(ref enum_def, ref ast_generics) => { self.check_type_defn(item, |fcx| { - enum_variants(fcx, enum_def) + fcx.enum_variants(enum_def) }); self.check_variances_for_type_defn(item, ast_generics); @@ -137,7 +137,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let (mut implied_bounds, self_ty) = match item.container() { ty::TraitContainer(_) => (vec![], fcx.tcx().mk_self_type()), - ty::ImplContainer(def_id) => (impl_implied_bounds(fcx, def_id, span), + ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span), fcx.tcx().lookup_item_type(def_id).ty) }; @@ -182,10 +182,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let param_env = ty::ParameterEnvironment::for_item(ccx.tcx, id); let tables = RefCell::new(ty::Tables::empty()); let inh = Inherited::new(ccx.tcx, &tables, param_env); - let fcx = blank_fn_ctxt(ccx, &inh, ty::FnDiverging, id); + let fcx = FnCtxt::new(ccx, &inh, ty::FnDiverging, id); let wf_tys = f(&fcx, self); fcx.select_all_obligations_or_error(); - regionck::regionck_item(&fcx, id, span, &wf_tys); + fcx.regionck_item(id, span, &wf_tys); } /// In a type definition, we check that to ensure that the types of the fields are well-formed. @@ -229,7 +229,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { { let trait_def_id = self.tcx().map.local_def_id(item.id); - if self.ccx.tcx.trait_has_default_impl(trait_def_id) { + if self.tcx().trait_has_default_impl(trait_def_id) { if !items.is_empty() { error_380(self.ccx, item.span); } @@ -327,7 +327,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); this.check_where_clauses(fcx, item.span, &predicates); - impl_implied_bounds(fcx, fcx.tcx().map.local_def_id(item.id), item.span) + fcx.impl_implied_bounds(fcx.tcx().map.local_def_id(item.id), item.span) }); } @@ -554,55 +554,48 @@ struct AdtField<'tcx> { span: Span, } -fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - struct_def: &hir::VariantData) - -> AdtVariant<'tcx> { +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { +fn struct_variant(&self, struct_def: &hir::VariantData) -> AdtVariant<'tcx> { let fields = struct_def.fields().iter() .map(|field| { - let field_ty = fcx.tcx().node_id_to_type(field.id); - let field_ty = fcx.instantiate_type_scheme(field.span, - &fcx.inh - .infcx - .parameter_environment - .free_substs, - &field_ty); + let field_ty = self.tcx().node_id_to_type(field.id); + let field_ty = self.instantiate_type_scheme(field.span, + &self.infcx() + .parameter_environment + .free_substs, + &field_ty); AdtField { ty: field_ty, span: field.span } }) .collect(); AdtVariant { fields: fields } } -fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - enum_def: &hir::EnumDef) - -> Vec> { +fn enum_variants(&self, enum_def: &hir::EnumDef) -> Vec> { enum_def.variants.iter() - .map(|variant| struct_variant(fcx, &variant.node.data)) + .map(|variant| self.struct_variant(&variant.node.data)) .collect() } -fn impl_implied_bounds<'fcx,'tcx>(fcx: &FnCtxt<'fcx, 'tcx>, - impl_def_id: DefId, - span: Span) - -> Vec> -{ - let free_substs = &fcx.inh.infcx.parameter_environment.free_substs; - match fcx.tcx().impl_trait_ref(impl_def_id) { +fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec> { + let free_substs = &self.inh.infcx.parameter_environment.free_substs; + match self.tcx().impl_trait_ref(impl_def_id) { Some(ref trait_ref) => { // Trait impl: take implied bounds from all types that // appear in the trait reference. - let trait_ref = fcx.instantiate_type_scheme(span, free_substs, trait_ref); + let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref); trait_ref.substs.types.as_slice().to_vec() } None => { // Inherent impl: take implied bounds from the self type. - let self_ty = fcx.tcx().lookup_item_type(impl_def_id).ty; - let self_ty = fcx.instantiate_type_scheme(span, free_substs, &self_ty); + let self_ty = self.tcx().lookup_item_type(impl_def_id).ty; + let self_ty = self.instantiate_type_scheme(span, free_substs, &self_ty); vec![self_ty] } } } +} fn error_192(ccx: &CrateCtxt, span: Span) { span_err!(ccx.tcx.sess, span, E0192, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index a7039dcd91c..f8e4cb0eb65 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -34,9 +34,10 @@ use rustc::hir; /////////////////////////////////////////////////////////////////////////// // Entry point functions -pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &hir::Expr) { - assert_eq!(fcx.writeback_errors.get(), false); - let mut wbcx = WritebackCx::new(fcx); +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { +pub fn resolve_type_vars_in_expr(&self, e: &hir::Expr) { + assert_eq!(self.writeback_errors.get(), false); + let mut wbcx = WritebackCx::new(self); wbcx.visit_expr(e); wbcx.visit_upvar_borrow_map(); wbcx.visit_closures(); @@ -44,18 +45,16 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &hir::Expr) { wbcx.visit_fru_field_types(); } -pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, - decl: &hir::FnDecl, - blk: &hir::Block) { - assert_eq!(fcx.writeback_errors.get(), false); - let mut wbcx = WritebackCx::new(fcx); +pub fn resolve_type_vars_in_fn(&self, decl: &hir::FnDecl, blk: &hir::Block) { + assert_eq!(self.writeback_errors.get(), false); + let mut wbcx = WritebackCx::new(self); wbcx.visit_block(blk); for arg in &decl.inputs { wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id); wbcx.visit_pat(&arg.pat); // Privacy needs the type for the whole pattern, not just each binding - if !pat_util::pat_is_binding(&fcx.tcx().def_map.borrow(), &arg.pat) { + if !pat_util::pat_is_binding(&self.tcx().def_map.borrow(), &arg.pat) { wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.pat.id); } @@ -65,6 +64,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, wbcx.visit_liberated_fn_sigs(); wbcx.visit_fru_field_types(); } +} /////////////////////////////////////////////////////////////////////////// // The Writerback context. This visitor walks the AST, checking the