mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
typeck: Turn everything operating on FnCtxt into a method.
This commit is contained in:
parent
ef2f5f6d8e
commit
d7ee56e862
@ -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;
|
||||
|
@ -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<SomeTrait>", 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<hir::FieldPat>],
|
||||
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<hir::FieldPat>],
|
||||
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<hir::Pat>]>,
|
||||
expected: Ty<'tcx>,
|
||||
is_tuple_struct_pat: bool)
|
||||
fn check_pat_enum(&self,
|
||||
pat: &hir::Pat,
|
||||
path: &hir::Path,
|
||||
subpats: Option<&'tcx [P<hir::Pat>]>,
|
||||
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<hir::FieldPat>],
|
||||
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<hir::FieldPat>],
|
||||
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>,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<hir::Expr>],
|
||||
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<CallStep<'tcx>>
|
||||
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<hir::Expr>],
|
||||
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<CallStep<'tcx>>
|
||||
{
|
||||
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<ty::MethodCallee<'tcx>>
|
||||
fn try_overloaded_call_traits(&self,
|
||||
call_expr: &hir::Expr,
|
||||
callee_expr: &hir::Expr,
|
||||
adjusted_ty: Ty<'tcx>,
|
||||
autoderefs: usize)
|
||||
-> Option<ty::MethodCallee<'tcx>>
|
||||
{
|
||||
// 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<hir::Expr>],
|
||||
expected: Expectation<'tcx>)
|
||||
fn confirm_builtin_call(&self,
|
||||
call_expr: &hir::Expr,
|
||||
callee_ty: Ty<'tcx>,
|
||||
arg_exprs: &'tcx [P<hir::Expr>],
|
||||
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<hir::Expr>],
|
||||
expected: Expectation<'tcx>,
|
||||
fn_sig: ty::FnSig<'tcx>)
|
||||
fn confirm_deferred_closure_call(&self,
|
||||
call_expr: &hir::Expr,
|
||||
arg_exprs: &'tcx [P<hir::Expr>],
|
||||
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<hir::Expr>],
|
||||
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<hir::Expr>],
|
||||
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!(
|
||||
|
@ -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<UnsizeKind<'tcx>> {
|
||||
fn unsize_kind(&self, t: Ty<'tcx>) -> Option<UnsizeKind<'tcx>> {
|
||||
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<CastCheck<'tcx>, 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<CastCheck<'tcx>, 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<CastKind, CastError> {
|
||||
fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
|
||||
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<CastKind, CastError>
|
||||
fn check_ptr_ptr_cast(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_expr: &'tcx ty::TypeAndMut<'tcx>,
|
||||
m_cast: &'tcx ty::TypeAndMut<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
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<CastKind, CastError>
|
||||
fn check_fptr_ptr_cast(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_cast: &'tcx ty::TypeAndMut<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
// 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<CastKind, CastError>
|
||||
fn check_ptr_addr_cast(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_expr: &'tcx ty::TypeAndMut<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
// 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<CastKind, CastError>
|
||||
fn check_ref_cast(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_expr: &'tcx ty::TypeAndMut<'tcx>,
|
||||
m_cast: &'tcx ty::TypeAndMut<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
// 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<CastKind, CastError>
|
||||
fn check_addr_ptr_cast(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_cast: &'tcx ty::TypeAndMut<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
// 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()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<ty::ClosureKind>,
|
||||
decl: &'tcx hir::FnDecl,
|
||||
body: &'tcx hir::Block,
|
||||
expected_sig: Option<ty::FnSig<'tcx>>) {
|
||||
let expr_def_id = fcx.tcx().map.local_def_id(expr.id);
|
||||
fn check_closure(&self,
|
||||
expr: &hir::Expr,
|
||||
opt_kind: Option<ty::ClosureKind>,
|
||||
decl: &'tcx hir::FnDecl,
|
||||
body: &'tcx hir::Block,
|
||||
expected_sig: Option<ty::FnSig<'tcx>>) {
|
||||
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<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
|
||||
{
|
||||
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<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
|
||||
{
|
||||
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<ty::ClosureKind>,
|
||||
cur: ty::ClosureKind)
|
||||
-> Option<ty::ClosureKind>
|
||||
{
|
||||
match best {
|
||||
None => Some(cur),
|
||||
Some(best) => Some(cmp::min(best, cur))
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a projection like "<F as Fn(X)>::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<ty::FnSig<'tcx>>
|
||||
{
|
||||
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<ty::PolyTraitRef<'tcx>>
|
||||
{
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Item=&'b hir::Expr> {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<'tcx>>)
|
||||
-> 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<'tcx>>)
|
||||
-> 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<Object>`
|
||||
// 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);
|
||||
|
@ -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<ty::Ty<'tcx>>,
|
||||
call_expr: &'tcx hir::Expr,
|
||||
self_expr: &'tcx hir::Expr)
|
||||
-> Result<ty::MethodCallee<'tcx>, MethodError<'tcx>>
|
||||
pub fn lookup_method(&self,
|
||||
span: Span,
|
||||
method_name: ast::Name,
|
||||
self_ty: ty::Ty<'tcx>,
|
||||
supplied_method_types: Vec<ty::Ty<'tcx>>,
|
||||
call_expr: &'tcx hir::Expr,
|
||||
self_expr: &'tcx hir::Expr)
|
||||
-> Result<ty::MethodCallee<'tcx>, 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<Vec<ty::Ty<'tcx>>>)
|
||||
-> Option<ty::MethodCallee<'tcx>>
|
||||
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<Vec<ty::Ty<'tcx>>>)
|
||||
-> Option<ty::MethodCallee<'tcx>>
|
||||
{
|
||||
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<Vec<ty::Ty<'tcx>>>)
|
||||
-> Option<ty::MethodCallee<'tcx>>
|
||||
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<Vec<ty::Ty<'tcx>>>)
|
||||
-> Option<ty::MethodCallee<'tcx>>
|
||||
{
|
||||
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<Def, MethodError<'tcx>>
|
||||
pub fn resolve_ufcs(&self,
|
||||
span: Span,
|
||||
method_name: ast::Name,
|
||||
self_ty: ty::Ty<'tcx>,
|
||||
expr_id: ast::NodeId)
|
||||
-> Result<Def, MethodError<'tcx>>
|
||||
{
|
||||
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<ty::ImplOrTraitItem<'tcx>>
|
||||
pub fn trait_item(&self,
|
||||
trait_def_id: DefId,
|
||||
item_name: ast::Name)
|
||||
-> Option<ty::ImplOrTraitItem<'tcx>>
|
||||
{
|
||||
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<ty::ImplOrTraitItem<'tcx>>
|
||||
pub fn impl_item(&self,
|
||||
impl_def_id: DefId,
|
||||
item_name: ast::Name)
|
||||
-> Option<ty::ImplOrTraitItem<'tcx>>
|
||||
{
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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<Vec<CandidateStep<'tcx>>> {
|
||||
fn create_steps(&self,
|
||||
span: Span,
|
||||
self_ty: Ty<'tcx>)
|
||||
-> Option<Vec<CandidateStep<'tcx>>> {
|
||||
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<ty::ImplOrTraitItem<'tcx>>
|
||||
{
|
||||
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<ty::ImplOrTraitItem<'tcx>>
|
||||
{
|
||||
super::trait_item(self.fcx, trait_def_id, self.item_name)
|
||||
self.fcx.trait_item(trait_def_id, self.item_name)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<CandidateSource>| {
|
||||
|
||||
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::<Vec<_>>()
|
||||
.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<CandidateSource>) {
|
||||
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::<Vec<_>>()
|
||||
.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<TraitInfo>;
|
||||
|
||||
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<DefId>)
|
||||
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<DefId>)
|
||||
{
|
||||
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::<Vec<_>>();
|
||||
|
||||
@ -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<TraitInfo>;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TraitInfo {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 <op>= 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<DefId>,
|
||||
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<DefId>,
|
||||
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<DefId>) {
|
||||
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<Ty<'tcx>>,
|
||||
opname: ast::Name,
|
||||
trait_did: Option<DefId>,
|
||||
lhs_expr: &'a hir::Expr)
|
||||
-> Result<Ty<'tcx>,()>
|
||||
fn lookup_op_method(&self,
|
||||
expr: &'tcx hir::Expr,
|
||||
lhs_ty: Ty<'tcx>,
|
||||
other_tys: Vec<Ty<'tcx>>,
|
||||
opname: ast::Name,
|
||||
trait_did: Option<DefId>,
|
||||
lhs_expr: &'a hir::Expr)
|
||||
-> Result<Ty<'tcx>,()>
|
||||
{
|
||||
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
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
|
@ -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<AdtVariant<'tcx>> {
|
||||
fn enum_variants(&self, enum_def: &hir::EnumDef) -> Vec<AdtVariant<'tcx>> {
|
||||
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<Ty<'tcx>>
|
||||
{
|
||||
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<Ty<'tcx>> {
|
||||
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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user