Merge branch 'master' into mb/36812_ICHFunctionInterfaces
This commit is contained in:
commit
6f6429609a
@ -96,6 +96,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
ExprKind::LogicalOp { .. } |
|
||||
ExprKind::Box { .. } |
|
||||
ExprKind::Cast { .. } |
|
||||
ExprKind::Use { .. } |
|
||||
ExprKind::NeverToAny { .. } |
|
||||
ExprKind::ReifyFnPointer { .. } |
|
||||
ExprKind::UnsafeFnPointer { .. } |
|
||||
|
@ -115,6 +115,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let source = unpack!(block = this.as_operand(block, source));
|
||||
block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
|
||||
}
|
||||
ExprKind::Use { source } => {
|
||||
let source = unpack!(block = this.as_operand(block, source));
|
||||
block.and(Rvalue::Use(source))
|
||||
}
|
||||
ExprKind::ReifyFnPointer { source } => {
|
||||
let source = unpack!(block = this.as_operand(block, source));
|
||||
block.and(Rvalue::Cast(CastKind::ReifyFnPointer, source, expr.ty))
|
||||
|
@ -68,6 +68,7 @@ impl Category {
|
||||
ExprKind::Binary { .. } |
|
||||
ExprKind::Box { .. } |
|
||||
ExprKind::Cast { .. } |
|
||||
ExprKind::Use { .. } |
|
||||
ExprKind::ReifyFnPointer { .. } |
|
||||
ExprKind::UnsafeFnPointer { .. } |
|
||||
ExprKind::Unsize { .. } |
|
||||
|
@ -249,6 +249,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
ExprKind::Binary { .. } |
|
||||
ExprKind::Box { .. } |
|
||||
ExprKind::Cast { .. } |
|
||||
ExprKind::Use { .. } |
|
||||
ExprKind::ReifyFnPointer { .. } |
|
||||
ExprKind::UnsafeFnPointer { .. } |
|
||||
ExprKind::Unsize { .. } |
|
||||
|
@ -600,8 +600,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
// Check to see if this cast is a "coercion cast", where the cast is actually done
|
||||
// using a coercion (or is a no-op).
|
||||
if let Some(&TyCastKind::CoercionCast) = cx.tcx.cast_kinds.borrow().get(&source.id) {
|
||||
// Skip the actual cast itexpr, as it's now a no-op.
|
||||
return source.make_mirror(cx);
|
||||
// Convert the lexpr to a vexpr.
|
||||
ExprKind::Use { source: source.to_ref() }
|
||||
} else {
|
||||
ExprKind::Cast { source: source.to_ref() }
|
||||
}
|
||||
|
@ -139,6 +139,9 @@ pub enum ExprKind<'tcx> {
|
||||
Cast {
|
||||
source: ExprRef<'tcx>,
|
||||
},
|
||||
Use {
|
||||
source: ExprRef<'tcx>,
|
||||
}, // Use a lexpr to get a vexpr.
|
||||
NeverToAny {
|
||||
source: ExprRef<'tcx>,
|
||||
},
|
||||
|
@ -308,7 +308,16 @@ pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
_ => bug!("compare_scalar_types: must be a comparison operator"),
|
||||
}
|
||||
}
|
||||
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyBool | ty::TyUint(_) | ty::TyChar => {
|
||||
ty::TyBool => {
|
||||
// FIXME(#36856) -- using `from_immediate` forces these booleans into `i8`,
|
||||
// which works around some LLVM bugs
|
||||
ICmp(bcx,
|
||||
bin_op_to_icmp_predicate(op, false),
|
||||
from_immediate(bcx, lhs),
|
||||
from_immediate(bcx, rhs),
|
||||
debug_loc)
|
||||
}
|
||||
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyUint(_) | ty::TyChar => {
|
||||
ICmp(bcx,
|
||||
bin_op_to_icmp_predicate(op, false),
|
||||
lhs,
|
||||
|
@ -23,7 +23,7 @@ use rustc::hir;
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
struct ConfirmContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a>{
|
||||
struct ConfirmContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
|
||||
span: Span,
|
||||
self_expr: &'gcx hir::Expr,
|
||||
@ -55,8 +55,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
unadjusted_self_ty: Ty<'tcx>,
|
||||
pick: probe::Pick<'tcx>,
|
||||
supplied_method_types: Vec<Ty<'tcx>>)
|
||||
-> ty::MethodCallee<'tcx>
|
||||
{
|
||||
-> ty::MethodCallee<'tcx> {
|
||||
debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
|
||||
unadjusted_self_ty,
|
||||
pick,
|
||||
@ -72,17 +71,20 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
span: Span,
|
||||
self_expr: &'gcx hir::Expr,
|
||||
call_expr: &'gcx hir::Expr)
|
||||
-> ConfirmContext<'a, 'gcx, 'tcx>
|
||||
{
|
||||
ConfirmContext { fcx: fcx, span: span, self_expr: self_expr, call_expr: call_expr }
|
||||
-> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
ConfirmContext {
|
||||
fcx: fcx,
|
||||
span: span,
|
||||
self_expr: self_expr,
|
||||
call_expr: call_expr,
|
||||
}
|
||||
}
|
||||
|
||||
fn confirm(&mut self,
|
||||
unadjusted_self_ty: Ty<'tcx>,
|
||||
pick: probe::Pick<'tcx>,
|
||||
supplied_method_types: Vec<Ty<'tcx>>)
|
||||
-> ty::MethodCallee<'tcx>
|
||||
{
|
||||
-> ty::MethodCallee<'tcx> {
|
||||
// Adjust the self expression the user provided and obtain the adjusted type.
|
||||
let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick);
|
||||
|
||||
@ -91,18 +93,13 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
// Create substitutions for the method's type parameters.
|
||||
let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick);
|
||||
let all_substs =
|
||||
self.instantiate_method_substs(
|
||||
&pick,
|
||||
supplied_method_types,
|
||||
rcvr_substs);
|
||||
let all_substs = self.instantiate_method_substs(&pick, supplied_method_types, rcvr_substs);
|
||||
|
||||
debug!("all_substs={:?}", all_substs);
|
||||
|
||||
// Create the final signature for the method, replacing late-bound regions.
|
||||
let InstantiatedMethodSig {
|
||||
method_sig, method_predicates
|
||||
} = self.instantiate_method_sig(&pick, all_substs);
|
||||
let InstantiatedMethodSig { method_sig, method_predicates } =
|
||||
self.instantiate_method_sig(&pick, all_substs);
|
||||
let method_self_ty = method_sig.inputs[0];
|
||||
|
||||
// Unify the (adjusted) self type with what the method expects.
|
||||
@ -111,12 +108,13 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
// Create the method type
|
||||
let def_id = pick.item.def_id();
|
||||
let method_ty = pick.item.as_opt_method().unwrap();
|
||||
let fty = self.tcx.mk_fn_def(def_id, all_substs,
|
||||
let fty = self.tcx.mk_fn_def(def_id,
|
||||
all_substs,
|
||||
self.tcx.mk_bare_fn(ty::BareFnTy {
|
||||
sig: ty::Binder(method_sig),
|
||||
unsafety: method_ty.fty.unsafety,
|
||||
abi: method_ty.fty.abi.clone(),
|
||||
}));
|
||||
sig: ty::Binder(method_sig),
|
||||
unsafety: method_ty.fty.unsafety,
|
||||
abi: method_ty.fty.abi.clone(),
|
||||
}));
|
||||
|
||||
// Add any trait/regions obligations specified on the method's type parameters.
|
||||
self.add_obligations(fty, all_substs, &method_predicates);
|
||||
@ -125,7 +123,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
let callee = ty::MethodCallee {
|
||||
def_id: def_id,
|
||||
ty: fty,
|
||||
substs: all_substs
|
||||
substs: all_substs,
|
||||
};
|
||||
|
||||
if let Some(hir::MutMutable) = pick.autoref {
|
||||
@ -141,14 +139,12 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
fn adjust_self_ty(&mut self,
|
||||
unadjusted_self_ty: Ty<'tcx>,
|
||||
pick: &probe::Pick<'tcx>)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
-> Ty<'tcx> {
|
||||
let (autoref, unsize) = if let Some(mutbl) = pick.autoref {
|
||||
let region = self.next_region_var(infer::Autoref(self.span));
|
||||
let autoref = AutoPtr(region, mutbl);
|
||||
(Some(autoref), pick.unsize.map(|target| {
|
||||
target.adjust_for_autoref(self.tcx, Some(autoref))
|
||||
}))
|
||||
(Some(autoref),
|
||||
pick.unsize.map(|target| target.adjust_for_autoref(self.tcx, Some(autoref))))
|
||||
} else {
|
||||
// No unsizing should be performed without autoref (at
|
||||
// least during method dispach). This is because we
|
||||
@ -168,11 +164,12 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
autoderef.finalize(LvaluePreference::NoPreference, Some(self.self_expr));
|
||||
|
||||
// Write out the final adjustment.
|
||||
self.write_adjustment(self.self_expr.id, AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: pick.autoderefs,
|
||||
autoref: autoref,
|
||||
unsize: unsize
|
||||
}));
|
||||
self.write_adjustment(self.self_expr.id,
|
||||
AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: pick.autoderefs,
|
||||
autoref: autoref,
|
||||
unsize: unsize,
|
||||
}));
|
||||
|
||||
if let Some(target) = unsize {
|
||||
target
|
||||
@ -193,13 +190,13 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
fn fresh_receiver_substs(&mut self,
|
||||
self_ty: Ty<'tcx>,
|
||||
pick: &probe::Pick<'tcx>)
|
||||
-> &'tcx Substs<'tcx>
|
||||
{
|
||||
-> &'tcx Substs<'tcx> {
|
||||
match pick.kind {
|
||||
probe::InherentImplPick => {
|
||||
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);
|
||||
"impl {:?} is not an inherent impl",
|
||||
impl_def_id);
|
||||
self.impl_self_ty(self.span, impl_def_id).substs
|
||||
}
|
||||
|
||||
@ -216,10 +213,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
// argument type), but those cases have already
|
||||
// been ruled out when we deemed the trait to be
|
||||
// "object safe".
|
||||
let original_poly_trait_ref =
|
||||
principal.with_self_ty(this.tcx, object_ty);
|
||||
let upcast_poly_trait_ref =
|
||||
this.upcast(original_poly_trait_ref, trait_def_id);
|
||||
let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty);
|
||||
let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id);
|
||||
let upcast_trait_ref =
|
||||
this.replace_late_bound_regions_with_fresh_var(&upcast_poly_trait_ref);
|
||||
debug!("original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
|
||||
@ -242,10 +237,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
// the impl ([$A,$B,$C]) not the receiver type ([$C]).
|
||||
let impl_polytype = self.impl_self_ty(self.span, impl_def_id);
|
||||
let impl_trait_ref =
|
||||
self.instantiate_type_scheme(
|
||||
self.span,
|
||||
impl_polytype.substs,
|
||||
&self.tcx.impl_trait_ref(impl_def_id).unwrap());
|
||||
self.instantiate_type_scheme(self.span,
|
||||
impl_polytype.substs,
|
||||
&self.tcx.impl_trait_ref(impl_def_id).unwrap());
|
||||
impl_trait_ref.substs
|
||||
}
|
||||
|
||||
@ -268,12 +262,11 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_existential_trait_ref<R, F>(&mut self,
|
||||
self_ty: Ty<'tcx>,
|
||||
mut closure: F) -> R
|
||||
fn extract_existential_trait_ref<R, F>(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R
|
||||
where F: FnMut(&mut ConfirmContext<'a, 'gcx, 'tcx>,
|
||||
Ty<'tcx>,
|
||||
ty::PolyExistentialTraitRef<'tcx>) -> R,
|
||||
ty::PolyExistentialTraitRef<'tcx>)
|
||||
-> R
|
||||
{
|
||||
// If we specified that this is an object method, then the
|
||||
// self-type ought to be something that can be dereferenced to
|
||||
@ -281,7 +274,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
// etc).
|
||||
|
||||
// FIXME: this feels, like, super dubious
|
||||
self.fcx.autoderef(self.span, self_ty)
|
||||
self.fcx
|
||||
.autoderef(self.span, self_ty)
|
||||
.filter_map(|(ty, _)| {
|
||||
match ty.sty {
|
||||
ty::TyTrait(ref data) => Some(closure(self, ty, data.principal)),
|
||||
@ -290,10 +284,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
})
|
||||
.next()
|
||||
.unwrap_or_else(|| {
|
||||
span_bug!(
|
||||
self.span,
|
||||
"self-type `{}` for ObjectPick never dereferenced to an object",
|
||||
self_ty)
|
||||
span_bug!(self.span,
|
||||
"self-type `{}` for ObjectPick never dereferenced to an object",
|
||||
self_ty)
|
||||
})
|
||||
}
|
||||
|
||||
@ -301,8 +294,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
pick: &probe::Pick<'tcx>,
|
||||
mut supplied_method_types: Vec<Ty<'tcx>>,
|
||||
substs: &Substs<'tcx>)
|
||||
-> &'tcx Substs<'tcx>
|
||||
{
|
||||
-> &'tcx Substs<'tcx> {
|
||||
// Determine the values for the generic parameters of the method.
|
||||
// If they were not explicitly supplied, just construct fresh
|
||||
// variables.
|
||||
@ -312,23 +304,24 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
if num_supplied_types > 0 && num_supplied_types != num_method_types {
|
||||
if num_method_types == 0 {
|
||||
struct_span_err!(self.tcx.sess, self.span, E0035,
|
||||
struct_span_err!(self.tcx.sess,
|
||||
self.span,
|
||||
E0035,
|
||||
"does not take type parameters")
|
||||
.span_label(self.span, &"called with unneeded type parameters")
|
||||
.emit();
|
||||
} else {
|
||||
struct_span_err!(self.tcx.sess, self.span, E0036,
|
||||
"incorrect number of type parameters given for this method: \
|
||||
expected {}, found {}",
|
||||
num_method_types, num_supplied_types)
|
||||
struct_span_err!(self.tcx.sess,
|
||||
self.span,
|
||||
E0036,
|
||||
"incorrect number of type parameters given for this method: \
|
||||
expected {}, found {}",
|
||||
num_method_types,
|
||||
num_supplied_types)
|
||||
.span_label(self.span,
|
||||
&format!("Passed {} type argument{}, expected {}",
|
||||
num_supplied_types,
|
||||
if num_supplied_types != 1 {
|
||||
"s"
|
||||
} else {
|
||||
""
|
||||
},
|
||||
if num_supplied_types != 1 { "s" } else { "" },
|
||||
num_method_types))
|
||||
.emit();
|
||||
}
|
||||
@ -340,14 +333,17 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
//
|
||||
// FIXME -- permit users to manually specify lifetimes
|
||||
let supplied_start = substs.params().len() + method.generics.regions.len();
|
||||
Substs::for_item(self.tcx, method.def_id, |def, _| {
|
||||
Substs::for_item(self.tcx,
|
||||
method.def_id,
|
||||
|def, _| {
|
||||
let i = def.index as usize;
|
||||
if i < substs.params().len() {
|
||||
substs.region_at(i)
|
||||
} else {
|
||||
self.region_var_for_def(self.span, def)
|
||||
}
|
||||
}, |def, cur_substs| {
|
||||
},
|
||||
|def, cur_substs| {
|
||||
let i = def.index as usize;
|
||||
if i < substs.params().len() {
|
||||
substs.type_at(i)
|
||||
@ -359,21 +355,17 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
fn unify_receivers(&mut self,
|
||||
self_ty: Ty<'tcx>,
|
||||
method_self_ty: Ty<'tcx>)
|
||||
{
|
||||
match self.sub_types(false, TypeOrigin::Misc(self.span),
|
||||
self_ty, method_self_ty) {
|
||||
fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) {
|
||||
match self.sub_types(false, TypeOrigin::Misc(self.span), self_ty, method_self_ty) {
|
||||
Ok(InferOk { obligations, .. }) => {
|
||||
// FIXME(#32730) propagate obligations
|
||||
assert!(obligations.is_empty());
|
||||
}
|
||||
Err(_) => {
|
||||
span_bug!(
|
||||
self.span,
|
||||
"{} was a subtype of {} but now is not?",
|
||||
self_ty, method_self_ty);
|
||||
span_bug!(self.span,
|
||||
"{} was a subtype of {} but now is not?",
|
||||
self_ty,
|
||||
method_self_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -384,8 +376,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
fn instantiate_method_sig(&mut self,
|
||||
pick: &probe::Pick<'tcx>,
|
||||
all_substs: &'tcx Substs<'tcx>)
|
||||
-> InstantiatedMethodSig<'tcx>
|
||||
{
|
||||
-> InstantiatedMethodSig<'tcx> {
|
||||
debug!("instantiate_method_sig(pick={:?}, all_substs={:?})",
|
||||
pick,
|
||||
all_substs);
|
||||
@ -393,13 +384,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
// Instantiate the bounds on the method with the
|
||||
// type/early-bound-regions substitutions performed. There can
|
||||
// be no late-bound regions appearing here.
|
||||
let method_predicates = pick.item.as_opt_method().unwrap()
|
||||
.predicates.instantiate(self.tcx, all_substs);
|
||||
let method_predicates = self.normalize_associated_types_in(self.span,
|
||||
&method_predicates);
|
||||
let method_predicates = pick.item
|
||||
.as_opt_method()
|
||||
.unwrap()
|
||||
.predicates
|
||||
.instantiate(self.tcx, all_substs);
|
||||
let method_predicates = self.normalize_associated_types_in(self.span, &method_predicates);
|
||||
|
||||
debug!("method_predicates after subst = {:?}",
|
||||
method_predicates);
|
||||
debug!("method_predicates after subst = {:?}", method_predicates);
|
||||
|
||||
// Instantiate late-bound regions and substitute the trait
|
||||
// parameters into the method type to get the actual method type.
|
||||
@ -407,14 +399,16 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
// NB: Instantiate late-bound regions first so that
|
||||
// `instantiate_type_scheme` can normalize associated types that
|
||||
// may reference those regions.
|
||||
let method_sig = self.replace_late_bound_regions_with_fresh_var(
|
||||
&pick.item.as_opt_method().unwrap().fty.sig);
|
||||
let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.item
|
||||
.as_opt_method()
|
||||
.unwrap()
|
||||
.fty
|
||||
.sig);
|
||||
debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
|
||||
method_sig);
|
||||
|
||||
let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig);
|
||||
debug!("type scheme substituted, method_sig={:?}",
|
||||
method_sig);
|
||||
debug!("type scheme substituted, method_sig={:?}", method_sig);
|
||||
|
||||
InstantiatedMethodSig {
|
||||
method_sig: method_sig,
|
||||
@ -431,9 +425,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
all_substs,
|
||||
method_predicates);
|
||||
|
||||
self.add_obligations_for_parameters(
|
||||
traits::ObligationCause::misc(self.span, self.body_id),
|
||||
method_predicates);
|
||||
self.add_obligations_for_parameters(traits::ObligationCause::misc(self.span, self.body_id),
|
||||
method_predicates);
|
||||
|
||||
// this is a projection from a trait reference, so we have to
|
||||
// make sure that the trait reference inputs are well-formed.
|
||||
@ -472,21 +465,24 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
for (i, &expr) in exprs.iter().rev().enumerate() {
|
||||
// Count autoderefs.
|
||||
let autoderef_count = match self.tables
|
||||
.borrow()
|
||||
.adjustments
|
||||
.get(&expr.id) {
|
||||
.borrow()
|
||||
.adjustments
|
||||
.get(&expr.id) {
|
||||
Some(&AdjustDerefRef(ref adj)) => adj.autoderefs,
|
||||
Some(_) | None => 0,
|
||||
};
|
||||
|
||||
debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?} \
|
||||
autoderef_count={}",
|
||||
i, expr, autoderef_count);
|
||||
i,
|
||||
expr,
|
||||
autoderef_count);
|
||||
|
||||
if autoderef_count > 0 {
|
||||
let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id));
|
||||
autoderef.nth(autoderef_count).unwrap_or_else(|| {
|
||||
span_bug!(expr.span, "expr was deref-able {} times but now isn't?",
|
||||
span_bug!(expr.span,
|
||||
"expr was deref-able {} times but now isn't?",
|
||||
autoderef_count);
|
||||
});
|
||||
autoderef.finalize(PreferMutLvalue, Some(expr));
|
||||
@ -508,29 +504,30 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
// (ab)use the normal type checking paths.
|
||||
let adj = self.tables.borrow().adjustments.get(&base_expr.id).cloned();
|
||||
let (autoderefs, unsize) = match adj {
|
||||
Some(AdjustDerefRef(adr)) => match adr.autoref {
|
||||
None => {
|
||||
assert!(adr.unsize.is_none());
|
||||
(adr.autoderefs, None)
|
||||
Some(AdjustDerefRef(adr)) => {
|
||||
match adr.autoref {
|
||||
None => {
|
||||
assert!(adr.unsize.is_none());
|
||||
(adr.autoderefs, None)
|
||||
}
|
||||
Some(AutoPtr(..)) => {
|
||||
(adr.autoderefs,
|
||||
adr.unsize.map(|target| {
|
||||
target.builtin_deref(false, NoPreference)
|
||||
.expect("fixup: AutoPtr is not &T")
|
||||
.ty
|
||||
}))
|
||||
}
|
||||
Some(_) => {
|
||||
span_bug!(base_expr.span,
|
||||
"unexpected adjustment autoref {:?}",
|
||||
adr);
|
||||
}
|
||||
}
|
||||
Some(AutoPtr(..)) => {
|
||||
(adr.autoderefs, adr.unsize.map(|target| {
|
||||
target.builtin_deref(false, NoPreference)
|
||||
.expect("fixup: AutoPtr is not &T").ty
|
||||
}))
|
||||
}
|
||||
Some(_) => {
|
||||
span_bug!(
|
||||
base_expr.span,
|
||||
"unexpected adjustment autoref {:?}",
|
||||
adr);
|
||||
}
|
||||
},
|
||||
}
|
||||
None => (0, None),
|
||||
Some(_) => {
|
||||
span_bug!(
|
||||
base_expr.span,
|
||||
"unexpected adjustment type");
|
||||
span_bug!(base_expr.span, "unexpected adjustment type");
|
||||
}
|
||||
};
|
||||
|
||||
@ -538,23 +535,23 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
(target, true)
|
||||
} else {
|
||||
(self.adjust_expr_ty(base_expr,
|
||||
Some(&AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: None,
|
||||
unsize: None
|
||||
}))), false)
|
||||
Some(&AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: None,
|
||||
unsize: None,
|
||||
}))),
|
||||
false)
|
||||
};
|
||||
let index_expr_ty = self.node_ty(index_expr.id);
|
||||
|
||||
let result = self.try_index_step(
|
||||
ty::MethodCall::expr(expr.id),
|
||||
expr,
|
||||
&base_expr,
|
||||
adjusted_base_ty,
|
||||
autoderefs,
|
||||
unsize,
|
||||
PreferMutLvalue,
|
||||
index_expr_ty);
|
||||
let result = self.try_index_step(ty::MethodCall::expr(expr.id),
|
||||
expr,
|
||||
&base_expr,
|
||||
adjusted_base_ty,
|
||||
autoderefs,
|
||||
unsize,
|
||||
PreferMutLvalue,
|
||||
index_expr_ty);
|
||||
|
||||
if let Some((input_ty, return_ty)) = result {
|
||||
self.demand_suptype(index_expr.span, input_ty, index_expr_ty);
|
||||
@ -569,9 +566,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
let method_call = ty::MethodCall::expr(expr.id);
|
||||
if self.tables.borrow().method_map.contains_key(&method_call) {
|
||||
let method = self.try_overloaded_deref(expr.span,
|
||||
Some(&base_expr),
|
||||
self.node_ty(base_expr.id),
|
||||
PreferMutLvalue);
|
||||
Some(&base_expr),
|
||||
self.node_ty(base_expr.id),
|
||||
PreferMutLvalue);
|
||||
let method = method.expect("re-trying deref failed");
|
||||
self.tables.borrow_mut().method_map.insert(method_call, method);
|
||||
}
|
||||
@ -597,28 +594,27 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
fn upcast(&mut self,
|
||||
source_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
target_trait_def_id: DefId)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
let upcast_trait_refs = self.tcx.upcast_choices(source_trait_ref.clone(),
|
||||
target_trait_def_id);
|
||||
-> ty::PolyTraitRef<'tcx> {
|
||||
let upcast_trait_refs = self.tcx
|
||||
.upcast_choices(source_trait_ref.clone(), target_trait_def_id);
|
||||
|
||||
// must be exactly one trait ref or we'd get an ambig error etc
|
||||
if upcast_trait_refs.len() != 1 {
|
||||
span_bug!(
|
||||
self.span,
|
||||
"cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
|
||||
source_trait_ref,
|
||||
target_trait_def_id,
|
||||
upcast_trait_refs);
|
||||
span_bug!(self.span,
|
||||
"cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
|
||||
source_trait_ref,
|
||||
target_trait_def_id,
|
||||
upcast_trait_refs);
|
||||
}
|
||||
|
||||
upcast_trait_refs.into_iter().next().unwrap()
|
||||
}
|
||||
|
||||
fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &ty::Binder<T>) -> T
|
||||
where T : TypeFoldable<'tcx>
|
||||
where T: TypeFoldable<'tcx>
|
||||
{
|
||||
self.fcx.replace_late_bound_regions_with_fresh_var(
|
||||
self.span, infer::FnCall, value).0
|
||||
self.fcx
|
||||
.replace_late_bound_regions_with_fresh_var(self.span, infer::FnCall, value)
|
||||
.0
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,8 @@ pub enum MethodError<'tcx> {
|
||||
Ambiguity(Vec<CandidateSource>),
|
||||
|
||||
// Using a `Fn`/`FnMut`/etc method on a raw closure type before we have inferred its kind.
|
||||
ClosureAmbiguity(/* DefId of fn trait */ DefId),
|
||||
ClosureAmbiguity(// DefId of fn trait
|
||||
DefId),
|
||||
|
||||
// Found an applicable method, but it is not visible.
|
||||
PrivateMatch(Def),
|
||||
@ -53,19 +54,20 @@ pub struct NoMatchData<'tcx> {
|
||||
pub static_candidates: Vec<CandidateSource>,
|
||||
pub unsatisfied_predicates: Vec<TraitRef<'tcx>>,
|
||||
pub out_of_scope_traits: Vec<DefId>,
|
||||
pub mode: probe::Mode
|
||||
pub mode: probe::Mode,
|
||||
}
|
||||
|
||||
impl<'tcx> NoMatchData<'tcx> {
|
||||
pub fn new(static_candidates: Vec<CandidateSource>,
|
||||
unsatisfied_predicates: Vec<TraitRef<'tcx>>,
|
||||
out_of_scope_traits: Vec<DefId>,
|
||||
mode: probe::Mode) -> Self {
|
||||
mode: probe::Mode)
|
||||
-> Self {
|
||||
NoMatchData {
|
||||
static_candidates: static_candidates,
|
||||
unsatisfied_predicates: unsatisfied_predicates,
|
||||
out_of_scope_traits: out_of_scope_traits,
|
||||
mode: mode
|
||||
mode: mode,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,7 +77,8 @@ impl<'tcx> NoMatchData<'tcx> {
|
||||
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub enum CandidateSource {
|
||||
ImplSource(DefId),
|
||||
TraitSource(/* trait id */ DefId),
|
||||
TraitSource(// trait id
|
||||
DefId),
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
@ -86,8 +89,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
self_ty: ty::Ty<'tcx>,
|
||||
call_expr_id: ast::NodeId,
|
||||
allow_private: bool)
|
||||
-> bool
|
||||
{
|
||||
-> bool {
|
||||
let mode = probe::Mode::MethodCall;
|
||||
match self.probe_method(span, mode, method_name, self_ty, call_expr_id) {
|
||||
Ok(..) => true,
|
||||
@ -119,8 +121,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
supplied_method_types: Vec<ty::Ty<'tcx>>,
|
||||
call_expr: &'gcx hir::Expr,
|
||||
self_expr: &'gcx hir::Expr)
|
||||
-> Result<ty::MethodCallee<'tcx>, MethodError<'tcx>>
|
||||
{
|
||||
-> Result<ty::MethodCallee<'tcx>, MethodError<'tcx>> {
|
||||
debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
|
||||
method_name,
|
||||
self_ty,
|
||||
@ -135,7 +136,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
self.tcx.used_trait_imports.borrow_mut().insert(import_id);
|
||||
}
|
||||
|
||||
Ok(self.confirm_method(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_method_in_trait(&self,
|
||||
@ -145,10 +151,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
trait_def_id: DefId,
|
||||
self_ty: ty::Ty<'tcx>,
|
||||
opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
|
||||
-> Option<ty::MethodCallee<'tcx>>
|
||||
{
|
||||
self.lookup_method_in_trait_adjusted(span, self_expr, m_name, trait_def_id,
|
||||
0, false, self_ty, opt_input_types)
|
||||
-> Option<ty::MethodCallee<'tcx>> {
|
||||
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.
|
||||
@ -171,8 +182,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
unsize: bool,
|
||||
self_ty: ty::Ty<'tcx>,
|
||||
opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
|
||||
-> Option<ty::MethodCallee<'tcx>>
|
||||
{
|
||||
-> Option<ty::MethodCallee<'tcx>> {
|
||||
debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, \
|
||||
m_name={}, trait_def_id={:?})",
|
||||
self_ty,
|
||||
@ -188,9 +198,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
assert!(trait_def.generics.regions.is_empty());
|
||||
|
||||
// Construct a trait-reference `self_ty : Trait<input_tys>`
|
||||
let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| {
|
||||
self.region_var_for_def(span, def)
|
||||
}, |def, substs| {
|
||||
let substs = Substs::for_item(self.tcx,
|
||||
trait_def_id,
|
||||
|def, _| self.region_var_for_def(span, def),
|
||||
|def, substs| {
|
||||
if def.index == 0 {
|
||||
self_ty
|
||||
} else if let Some(ref input_types) = opt_input_types {
|
||||
@ -204,9 +215,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
// Construct an obligation
|
||||
let poly_trait_ref = trait_ref.to_poly_trait_ref();
|
||||
let obligation = traits::Obligation::misc(span,
|
||||
self.body_id,
|
||||
poly_trait_ref.to_predicate());
|
||||
let obligation =
|
||||
traits::Obligation::misc(span, self.body_id, poly_trait_ref.to_predicate());
|
||||
|
||||
// Now we want to know if this can be matched
|
||||
let mut selcx = traits::SelectionContext::new(self);
|
||||
@ -224,7 +234,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
assert_eq!(method_ty.generics.regions.len(), 0);
|
||||
|
||||
debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}",
|
||||
method_item, method_ty);
|
||||
method_item,
|
||||
method_ty);
|
||||
|
||||
// Instantiate late-bound regions and substitute the trait
|
||||
// parameters into the method type to get the actual method type.
|
||||
@ -232,18 +243,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// NB: Instantiate late-bound regions first so that
|
||||
// `instantiate_type_scheme` can normalize associated types that
|
||||
// may reference those regions.
|
||||
let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
|
||||
infer::FnCall,
|
||||
&method_ty.fty.sig).0;
|
||||
let fn_sig =
|
||||
self.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,
|
||||
let fty = tcx.mk_fn_def(def_id,
|
||||
trait_ref.substs,
|
||||
tcx.mk_bare_fn(ty::BareFnTy {
|
||||
sig: ty::Binder(fn_sig),
|
||||
unsafety: method_ty.fty.unsafety,
|
||||
abi: method_ty.fty.abi.clone(),
|
||||
}));
|
||||
sig: ty::Binder(fn_sig),
|
||||
unsafety: method_ty.fty.unsafety,
|
||||
abi: method_ty.fty.abi.clone(),
|
||||
}));
|
||||
|
||||
debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}",
|
||||
fty,
|
||||
@ -259,9 +271,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// any late-bound regions appearing in its bounds.
|
||||
let method_bounds = self.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates);
|
||||
assert!(!method_bounds.has_escaping_regions());
|
||||
self.add_obligations_for_parameters(
|
||||
traits::ObligationCause::misc(span, self.body_id),
|
||||
&method_bounds);
|
||||
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.
|
||||
self.register_wf_obligation(fty, span, traits::MiscObligation);
|
||||
@ -273,12 +284,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
// Insert any adjustments needed (always an autoref of some mutability).
|
||||
match self_expr {
|
||||
None => { }
|
||||
None => {}
|
||||
|
||||
Some(self_expr) => {
|
||||
debug!("lookup_in_trait_adjusted: inserting adjustment if needed \
|
||||
(self-id={}, autoderefs={}, unsize={}, explicit_self={:?})",
|
||||
self_expr.id, autoderefs, unsize,
|
||||
self_expr.id,
|
||||
autoderefs,
|
||||
unsize,
|
||||
method_ty.explicit_self);
|
||||
|
||||
match method_ty.explicit_self {
|
||||
@ -294,31 +307,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
match transformed_self_ty.sty {
|
||||
ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => {
|
||||
self.write_adjustment(self_expr.id,
|
||||
AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: Some(AutoPtr(region, mutbl)),
|
||||
unsize: if unsize {
|
||||
Some(transformed_self_ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}));
|
||||
AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: autoderefs,
|
||||
autoref: Some(AutoPtr(region, mutbl)),
|
||||
unsize: if unsize {
|
||||
Some(transformed_self_ty)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
_ => {
|
||||
span_bug!(
|
||||
span,
|
||||
"trait method is &self but first arg is: {}",
|
||||
transformed_self_ty);
|
||||
span_bug!(span,
|
||||
"trait method is &self but first arg is: {}",
|
||||
transformed_self_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
span_bug!(
|
||||
span,
|
||||
"unexpected explicit self type in operator method: {:?}",
|
||||
method_ty.explicit_self);
|
||||
span_bug!(span,
|
||||
"unexpected explicit self type in operator method: {:?}",
|
||||
method_ty.explicit_self);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -327,7 +338,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let callee = ty::MethodCallee {
|
||||
def_id: def_id,
|
||||
ty: fty,
|
||||
substs: trait_ref.substs
|
||||
substs: trait_ref.substs,
|
||||
};
|
||||
|
||||
debug!("callee = {:?}", callee);
|
||||
@ -340,8 +351,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
method_name: ast::Name,
|
||||
self_ty: ty::Ty<'tcx>,
|
||||
expr_id: ast::NodeId)
|
||||
-> Result<Def, MethodError<'tcx>>
|
||||
{
|
||||
-> Result<Def, MethodError<'tcx>> {
|
||||
let mode = probe::Mode::Path;
|
||||
let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?;
|
||||
|
||||
@ -364,9 +374,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
pub fn impl_or_trait_item(&self,
|
||||
def_id: DefId,
|
||||
item_name: ast::Name)
|
||||
-> Option<ty::ImplOrTraitItem<'tcx>>
|
||||
{
|
||||
self.tcx.impl_or_trait_items(def_id)
|
||||
-> Option<ty::ImplOrTraitItem<'tcx>> {
|
||||
self.tcx
|
||||
.impl_or_trait_items(def_id)
|
||||
.iter()
|
||||
.map(|&did| self.tcx.impl_or_trait_item(did))
|
||||
.find(|m| m.name() == item_name)
|
||||
|
@ -13,7 +13,7 @@ use super::NoMatchData;
|
||||
use super::{CandidateSource, ImplSource, TraitSource};
|
||||
use super::suggest;
|
||||
|
||||
use check::{FnCtxt};
|
||||
use check::FnCtxt;
|
||||
use hir::def_id::DefId;
|
||||
use hir::def::Def;
|
||||
use rustc::ty::subst::{Subst, Substs};
|
||||
@ -31,7 +31,7 @@ use std::rc::Rc;
|
||||
use self::CandidateKind::*;
|
||||
pub use self::PickKind::*;
|
||||
|
||||
struct ProbeContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
|
||||
span: Span,
|
||||
mode: Mode,
|
||||
@ -52,7 +52,7 @@ struct ProbeContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
|
||||
/// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
|
||||
/// for error reporting
|
||||
unsatisfied_predicates: Vec<TraitRef<'tcx>>
|
||||
unsatisfied_predicates: Vec<TraitRef<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> {
|
||||
@ -66,7 +66,7 @@ impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> {
|
||||
struct CandidateStep<'tcx> {
|
||||
self_ty: Ty<'tcx>,
|
||||
autoderefs: usize,
|
||||
unsize: bool
|
||||
unsize: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -80,12 +80,17 @@ struct Candidate<'tcx> {
|
||||
#[derive(Debug)]
|
||||
enum CandidateKind<'tcx> {
|
||||
InherentImplCandidate(&'tcx Substs<'tcx>,
|
||||
/* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>),
|
||||
ExtensionImplCandidate(/* Impl */ DefId, &'tcx Substs<'tcx>,
|
||||
/* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>),
|
||||
// Normalize obligations
|
||||
Vec<traits::PredicateObligation<'tcx>>),
|
||||
ExtensionImplCandidate(// Impl
|
||||
DefId,
|
||||
&'tcx Substs<'tcx>,
|
||||
// Normalize obligations
|
||||
Vec<traits::PredicateObligation<'tcx>>),
|
||||
ObjectCandidate,
|
||||
TraitCandidate,
|
||||
WhereClauseCandidate(/* Trait */ ty::PolyTraitRef<'tcx>),
|
||||
WhereClauseCandidate(// Trait
|
||||
ty::PolyTraitRef<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -115,10 +120,12 @@ pub struct Pick<'tcx> {
|
||||
#[derive(Clone,Debug)]
|
||||
pub enum PickKind<'tcx> {
|
||||
InherentImplPick,
|
||||
ExtensionImplPick(/* Impl */ DefId),
|
||||
ExtensionImplPick(// Impl
|
||||
DefId),
|
||||
ObjectPick,
|
||||
TraitPick,
|
||||
WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>),
|
||||
WhereClausePick(// Trait
|
||||
ty::PolyTraitRef<'tcx>),
|
||||
}
|
||||
|
||||
pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError<'tcx>>;
|
||||
@ -132,7 +139,7 @@ pub enum Mode {
|
||||
// An expression of the form `Type::item` or `<T>::item`.
|
||||
// No autoderefs are performed, lookup is done based on the type each
|
||||
// implementation is for, and static methods are included.
|
||||
Path
|
||||
Path,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
@ -142,8 +149,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
item_name: ast::Name,
|
||||
self_ty: Ty<'tcx>,
|
||||
scope_expr_id: ast::NodeId)
|
||||
-> PickResult<'tcx>
|
||||
{
|
||||
-> PickResult<'tcx> {
|
||||
debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})",
|
||||
self_ty,
|
||||
item_name,
|
||||
@ -159,31 +165,38 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let steps = if mode == Mode::MethodCall {
|
||||
match self.create_steps(span, self_ty) {
|
||||
Some(steps) => steps,
|
||||
None =>return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), Vec::new(),
|
||||
Vec::new(), mode))),
|
||||
None => {
|
||||
return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(),
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
mode)))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vec![CandidateStep {
|
||||
self_ty: self_ty,
|
||||
autoderefs: 0,
|
||||
unsize: false
|
||||
}]
|
||||
self_ty: self_ty,
|
||||
autoderefs: 0,
|
||||
unsize: false,
|
||||
}]
|
||||
};
|
||||
|
||||
// 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(self.tcx, step.self_ty, true) {
|
||||
None => { break; }
|
||||
Some(simplified_type) => { simplified_steps.push(simplified_type); }
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
Some(simplified_type) => {
|
||||
simplified_steps.push(simplified_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
let opt_simplified_steps =
|
||||
if simplified_steps.len() < steps.len() {
|
||||
None // failed to convert at least one of the steps
|
||||
} else {
|
||||
Some(simplified_steps)
|
||||
};
|
||||
let opt_simplified_steps = if simplified_steps.len() < steps.len() {
|
||||
None // failed to convert at least one of the steps
|
||||
} else {
|
||||
Some(simplified_steps)
|
||||
};
|
||||
|
||||
debug!("ProbeContext: steps for self_ty={:?} are {:?}",
|
||||
self_ty,
|
||||
@ -192,31 +205,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// this creates one big transaction so that all type variables etc
|
||||
// that we create during the probe process are removed later
|
||||
self.probe(|_| {
|
||||
let mut probe_cx = ProbeContext::new(self,
|
||||
span,
|
||||
mode,
|
||||
item_name,
|
||||
steps,
|
||||
opt_simplified_steps);
|
||||
let mut probe_cx =
|
||||
ProbeContext::new(self, span, mode, item_name, steps, opt_simplified_steps);
|
||||
probe_cx.assemble_inherent_candidates();
|
||||
probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?;
|
||||
probe_cx.pick()
|
||||
})
|
||||
}
|
||||
|
||||
fn create_steps(&self,
|
||||
span: Span,
|
||||
self_ty: Ty<'tcx>)
|
||||
-> Option<Vec<CandidateStep<'tcx>>>
|
||||
{
|
||||
fn create_steps(&self, span: Span, self_ty: Ty<'tcx>) -> Option<Vec<CandidateStep<'tcx>>> {
|
||||
// FIXME: we don't need to create the entire steps in one pass
|
||||
|
||||
let mut autoderef = self.autoderef(span, self_ty);
|
||||
let mut steps: Vec<_> = autoderef.by_ref().map(|(ty, d)| CandidateStep {
|
||||
self_ty: ty,
|
||||
autoderefs: d,
|
||||
unsize: false
|
||||
}).collect();
|
||||
let mut steps: Vec<_> = autoderef.by_ref()
|
||||
.map(|(ty, d)| {
|
||||
CandidateStep {
|
||||
self_ty: ty,
|
||||
autoderefs: d,
|
||||
unsize: false,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let final_ty = autoderef.unambiguous_final_ty();
|
||||
match final_ty.sty {
|
||||
@ -226,7 +235,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
steps.push(CandidateStep {
|
||||
self_ty: self.tcx.mk_slice(elem_ty),
|
||||
autoderefs: dereferences,
|
||||
unsize: true
|
||||
unsize: true,
|
||||
});
|
||||
}
|
||||
ty::TyError => return None,
|
||||
@ -246,8 +255,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
item_name: ast::Name,
|
||||
steps: Vec<CandidateStep<'tcx>>,
|
||||
opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>)
|
||||
-> ProbeContext<'a, 'gcx, 'tcx>
|
||||
{
|
||||
-> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
ProbeContext {
|
||||
fcx: fcx,
|
||||
span: span,
|
||||
@ -284,8 +292,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
fn assemble_probe(&mut self, self_ty: Ty<'tcx>) {
|
||||
debug!("assemble_probe: self_ty={:?}",
|
||||
self_ty);
|
||||
debug!("assemble_probe: self_ty={:?}", self_ty);
|
||||
|
||||
match self_ty.sty {
|
||||
ty::TyTrait(box ref data) => {
|
||||
@ -371,8 +378,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
let lang_def_id = self.tcx.lang_items.f64_impl();
|
||||
self.assemble_inherent_impl_for_primitive(lang_def_id);
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -405,7 +411,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
let item = match self.impl_or_trait_item(impl_def_id) {
|
||||
Some(m) => m,
|
||||
None => { return; } // No method with correct name on this impl
|
||||
None => {
|
||||
return;
|
||||
} // No method with correct name on this impl
|
||||
};
|
||||
|
||||
if !self.has_applicable_self(&item) {
|
||||
@ -415,7 +423,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
if !item.vis().is_accessible_from(self.body_id, &self.tcx.map) {
|
||||
self.private_candidate = Some(item.def());
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
|
||||
@ -458,9 +466,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
self.elaborate_bounds(&[trait_ref], |this, new_trait_ref, item| {
|
||||
let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
|
||||
|
||||
let xform_self_ty = this.xform_self_ty(&item,
|
||||
new_trait_ref.self_ty(),
|
||||
new_trait_ref.substs);
|
||||
let xform_self_ty =
|
||||
this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
|
||||
|
||||
this.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
@ -476,8 +483,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
param_ty: ty::ParamTy) {
|
||||
// FIXME -- Do we want to commit to this behavior for param bounds?
|
||||
|
||||
let bounds: Vec<_> =
|
||||
self.parameter_environment.caller_bounds
|
||||
let bounds: Vec<_> = self.parameter_environment
|
||||
.caller_bounds
|
||||
.iter()
|
||||
.filter_map(|predicate| {
|
||||
match *predicate {
|
||||
@ -486,7 +493,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
ty::TyParam(ref p) if *p == param_ty => {
|
||||
Some(trait_predicate.to_poly_trait_ref())
|
||||
}
|
||||
_ => None
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
ty::Predicate::Equate(..) |
|
||||
@ -495,21 +502,15 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
ty::Predicate::WellFormed(..) |
|
||||
ty::Predicate::ObjectSafe(..) |
|
||||
ty::Predicate::ClosureKind(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
None
|
||||
}
|
||||
ty::Predicate::TypeOutlives(..) => None,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.elaborate_bounds(&bounds, |this, poly_trait_ref, item| {
|
||||
let trait_ref =
|
||||
this.erase_late_bound_regions(&poly_trait_ref);
|
||||
let trait_ref = this.erase_late_bound_regions(&poly_trait_ref);
|
||||
|
||||
let xform_self_ty =
|
||||
this.xform_self_ty(&item,
|
||||
trait_ref.self_ty(),
|
||||
trait_ref.substs);
|
||||
let xform_self_ty = this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs);
|
||||
|
||||
if let Some(ref m) = item.as_opt_method() {
|
||||
debug!("found match: trait_ref={:?} substs={:?} m={:?}",
|
||||
@ -540,16 +541,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
// Do a search through a list of bounds, using a callback to actually
|
||||
// create the candidates.
|
||||
fn elaborate_bounds<F>(
|
||||
&mut self,
|
||||
bounds: &[ty::PolyTraitRef<'tcx>],
|
||||
mut mk_cand: F,
|
||||
) where
|
||||
F: for<'b> FnMut(
|
||||
&mut ProbeContext<'b, 'gcx, 'tcx>,
|
||||
ty::PolyTraitRef<'tcx>,
|
||||
ty::ImplOrTraitItem<'tcx>,
|
||||
),
|
||||
fn elaborate_bounds<F>(&mut self, bounds: &[ty::PolyTraitRef<'tcx>], mut mk_cand: F)
|
||||
where F: for<'b> FnMut(&mut ProbeContext<'b, 'gcx, 'tcx>,
|
||||
ty::PolyTraitRef<'tcx>,
|
||||
ty::ImplOrTraitItem<'tcx>)
|
||||
{
|
||||
debug!("elaborate_bounds(bounds={:?})", bounds);
|
||||
|
||||
@ -557,7 +552,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
|
||||
let item = match self.impl_or_trait_item(bound_trait_ref.def_id()) {
|
||||
Some(v) => v,
|
||||
None => { continue; }
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if !self.has_applicable_self(&item) {
|
||||
@ -570,8 +567,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn assemble_extension_candidates_for_traits_in_scope(&mut self,
|
||||
expr_id: ast::NodeId)
|
||||
-> Result<(), MethodError<'tcx>>
|
||||
{
|
||||
-> Result<(), MethodError<'tcx>> {
|
||||
let mut duplicates = FnvHashSet();
|
||||
let opt_applicable_traits = self.tcx.trait_map.get(&expr_id);
|
||||
if let Some(applicable_traits) = opt_applicable_traits {
|
||||
@ -600,20 +596,19 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn assemble_extension_candidates_for_trait(&mut self,
|
||||
trait_def_id: DefId)
|
||||
-> Result<(), MethodError<'tcx>>
|
||||
{
|
||||
-> Result<(), MethodError<'tcx>> {
|
||||
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})",
|
||||
trait_def_id);
|
||||
|
||||
// Check whether `trait_def_id` defines a method with suitable name:
|
||||
let trait_items =
|
||||
self.tcx.trait_items(trait_def_id);
|
||||
let maybe_item =
|
||||
trait_items.iter()
|
||||
.find(|item| item.name() == self.item_name);
|
||||
let trait_items = self.tcx.trait_items(trait_def_id);
|
||||
let maybe_item = trait_items.iter()
|
||||
.find(|item| item.name() == self.item_name);
|
||||
let item = match maybe_item {
|
||||
Some(i) => i,
|
||||
None => { return Ok(()); }
|
||||
None => {
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
// Check whether `trait_def_id` defines a method with suitable name:
|
||||
@ -636,8 +631,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn assemble_extension_candidates_for_trait_impls(&mut self,
|
||||
trait_def_id: DefId,
|
||||
item: ty::ImplOrTraitItem<'tcx>)
|
||||
{
|
||||
item: ty::ImplOrTraitItem<'tcx>) {
|
||||
let trait_def = self.tcx.lookup_trait_def(trait_def_id);
|
||||
|
||||
// FIXME(arielb1): can we use for_each_relevant_impl here?
|
||||
@ -655,8 +649,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
debug!("impl_substs={:?}", impl_substs);
|
||||
|
||||
let impl_trait_ref =
|
||||
self.tcx.impl_trait_ref(impl_def_id)
|
||||
let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id)
|
||||
.unwrap() // we know this is a trait impl
|
||||
.subst(self.tcx, impl_substs);
|
||||
|
||||
@ -664,9 +657,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
// Determine the receiver type that the method itself expects.
|
||||
let xform_self_ty =
|
||||
self.xform_self_ty(&item,
|
||||
impl_trait_ref.self_ty(),
|
||||
impl_trait_ref.substs);
|
||||
self.xform_self_ty(&item, impl_trait_ref.self_ty(), impl_trait_ref.substs);
|
||||
|
||||
// Normalize the receiver. We can't use normalize_associated_types_in
|
||||
// as it will pollute the fcx's fulfillment context after this probe
|
||||
@ -690,14 +681,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
fn impl_can_possibly_match(&self, impl_def_id: DefId) -> bool {
|
||||
let simplified_steps = match self.opt_simplified_steps {
|
||||
Some(ref simplified_steps) => simplified_steps,
|
||||
None => { return true; }
|
||||
None => {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
let impl_type = self.tcx.lookup_item_type(impl_def_id);
|
||||
let impl_simplified_type =
|
||||
match ty::fast_reject::simplify_type(self.tcx, impl_type.ty, false) {
|
||||
Some(simplified_type) => simplified_type,
|
||||
None => { return true; }
|
||||
None => {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
simplified_steps.contains(&impl_simplified_type)
|
||||
@ -706,8 +701,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
fn assemble_closure_candidates(&mut self,
|
||||
trait_def_id: DefId,
|
||||
item: ty::ImplOrTraitItem<'tcx>)
|
||||
-> Result<(), MethodError<'tcx>>
|
||||
{
|
||||
-> Result<(), MethodError<'tcx>> {
|
||||
// Check if this is one of the Fn,FnMut,FnOnce traits.
|
||||
let tcx = self.tcx;
|
||||
let kind = if Some(trait_def_id) == tcx.lang_items.fn_trait() {
|
||||
@ -746,9 +740,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
// for the purposes of our method lookup, we only take
|
||||
// receiver type into account, so we can just substitute
|
||||
// fresh types here to use during substitution and subtyping.
|
||||
let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| {
|
||||
self.region_var_for_def(self.span, def)
|
||||
}, |def, substs| {
|
||||
let substs = Substs::for_item(self.tcx,
|
||||
trait_def_id,
|
||||
|def, _| self.region_var_for_def(self.span, def),
|
||||
|def, substs| {
|
||||
if def.index == 0 {
|
||||
step.self_ty
|
||||
} else {
|
||||
@ -756,9 +751,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
});
|
||||
|
||||
let xform_self_ty = self.xform_self_ty(&item,
|
||||
step.self_ty,
|
||||
substs);
|
||||
let xform_self_ty = self.xform_self_ty(&item, step.self_ty, substs);
|
||||
self.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
item: item.clone(),
|
||||
@ -772,8 +765,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn assemble_projection_candidates(&mut self,
|
||||
trait_def_id: DefId,
|
||||
item: ty::ImplOrTraitItem<'tcx>)
|
||||
{
|
||||
item: ty::ImplOrTraitItem<'tcx>) {
|
||||
debug!("assemble_projection_candidates(\
|
||||
trait_def_id={:?}, \
|
||||
item={:?})",
|
||||
@ -781,39 +773,35 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
item);
|
||||
|
||||
for step in self.steps.iter() {
|
||||
debug!("assemble_projection_candidates: step={:?}",
|
||||
step);
|
||||
debug!("assemble_projection_candidates: step={:?}", step);
|
||||
|
||||
let (def_id, substs) = match step.self_ty.sty {
|
||||
ty::TyProjection(ref data) => {
|
||||
(data.trait_ref.def_id, data.trait_ref.substs)
|
||||
}
|
||||
ty::TyProjection(ref data) => (data.trait_ref.def_id, data.trait_ref.substs),
|
||||
ty::TyAnon(def_id, substs) => (def_id, substs),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
debug!("assemble_projection_candidates: def_id={:?} substs={:?}",
|
||||
def_id, substs);
|
||||
def_id,
|
||||
substs);
|
||||
|
||||
let trait_predicates = self.tcx.lookup_predicates(def_id);
|
||||
let bounds = trait_predicates.instantiate(self.tcx, substs);
|
||||
let predicates = bounds.predicates;
|
||||
debug!("assemble_projection_candidates: predicates={:?}",
|
||||
predicates);
|
||||
for poly_bound in
|
||||
traits::elaborate_predicates(self.tcx, predicates)
|
||||
for poly_bound in traits::elaborate_predicates(self.tcx, predicates)
|
||||
.filter_map(|p| p.to_opt_poly_trait_ref())
|
||||
.filter(|b| b.def_id() == trait_def_id)
|
||||
{
|
||||
.filter(|b| b.def_id() == trait_def_id) {
|
||||
let bound = self.erase_late_bound_regions(&poly_bound);
|
||||
|
||||
debug!("assemble_projection_candidates: def_id={:?} substs={:?} bound={:?}",
|
||||
def_id, substs, bound);
|
||||
def_id,
|
||||
substs,
|
||||
bound);
|
||||
|
||||
if self.can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
|
||||
let xform_self_ty = self.xform_self_ty(&item,
|
||||
bound.self_ty(),
|
||||
bound.substs);
|
||||
let xform_self_ty = self.xform_self_ty(&item, bound.self_ty(), bound.substs);
|
||||
|
||||
debug!("assemble_projection_candidates: bound={:?} xform_self_ty={:?}",
|
||||
bound,
|
||||
@ -832,20 +820,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn assemble_where_clause_candidates(&mut self,
|
||||
trait_def_id: DefId,
|
||||
item: ty::ImplOrTraitItem<'tcx>)
|
||||
{
|
||||
item: ty::ImplOrTraitItem<'tcx>) {
|
||||
debug!("assemble_where_clause_candidates(trait_def_id={:?})",
|
||||
trait_def_id);
|
||||
|
||||
let caller_predicates = self.parameter_environment.caller_bounds.clone();
|
||||
for poly_bound in traits::elaborate_predicates(self.tcx, caller_predicates)
|
||||
.filter_map(|p| p.to_opt_poly_trait_ref())
|
||||
.filter(|b| b.def_id() == trait_def_id)
|
||||
{
|
||||
.filter_map(|p| p.to_opt_poly_trait_ref())
|
||||
.filter(|b| b.def_id() == trait_def_id) {
|
||||
let bound = self.erase_late_bound_regions(&poly_bound);
|
||||
let xform_self_ty = self.xform_self_ty(&item,
|
||||
bound.self_ty(),
|
||||
bound.substs);
|
||||
let xform_self_ty = self.xform_self_ty(&item, bound.self_ty(), bound.substs);
|
||||
|
||||
debug!("assemble_where_clause_candidates: bound={:?} xform_self_ty={:?}",
|
||||
bound,
|
||||
@ -882,19 +866,24 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
let out_of_scope_traits = match self.pick_core() {
|
||||
Some(Ok(p)) => vec![p.item.container().id()],
|
||||
Some(Err(MethodError::Ambiguity(v))) => v.into_iter().map(|source| {
|
||||
match source {
|
||||
TraitSource(id) => id,
|
||||
ImplSource(impl_id) => {
|
||||
match tcx.trait_id_of_impl(impl_id) {
|
||||
Some(id) => id,
|
||||
None =>
|
||||
span_bug!(span,
|
||||
"found inherent method when looking at traits")
|
||||
Some(Err(MethodError::Ambiguity(v))) => {
|
||||
v.into_iter()
|
||||
.map(|source| {
|
||||
match source {
|
||||
TraitSource(id) => id,
|
||||
ImplSource(impl_id) => {
|
||||
match tcx.trait_id_of_impl(impl_id) {
|
||||
Some(id) => id,
|
||||
None => {
|
||||
span_bug!(span,
|
||||
"found inherent method when looking at traits")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}).collect(),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
Some(Err(MethodError::NoMatch(NoMatchData { out_of_scope_traits: others, .. }))) => {
|
||||
assert!(others.is_empty());
|
||||
vec![]
|
||||
@ -910,8 +899,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
return Err(MethodError::PrivateMatch(def));
|
||||
}
|
||||
|
||||
Err(MethodError::NoMatch(NoMatchData::new(static_candidates, unsatisfied_predicates,
|
||||
out_of_scope_traits, self.mode)))
|
||||
Err(MethodError::NoMatch(NoMatchData::new(static_candidates,
|
||||
unsatisfied_predicates,
|
||||
out_of_scope_traits,
|
||||
self.mode)))
|
||||
}
|
||||
|
||||
fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
|
||||
@ -935,41 +926,35 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
self.pick_autorefd_method(step)
|
||||
}
|
||||
|
||||
fn pick_by_value_method(&mut self,
|
||||
step: &CandidateStep<'tcx>)
|
||||
-> Option<PickResult<'tcx>>
|
||||
{
|
||||
/*!
|
||||
* For each type `T` in the step list, this attempts to find a
|
||||
* method where the (transformed) self type is exactly `T`. We
|
||||
* do however do one transformation on the adjustment: if we
|
||||
* are passing a region pointer in, we will potentially
|
||||
* *reborrow* it to a shorter lifetime. This allows us to
|
||||
* transparently pass `&mut` pointers, in particular, without
|
||||
* consuming them for their entire lifetime.
|
||||
*/
|
||||
fn pick_by_value_method(&mut self, step: &CandidateStep<'tcx>) -> Option<PickResult<'tcx>> {
|
||||
//! For each type `T` in the step list, this attempts to find a
|
||||
//! method where the (transformed) self type is exactly `T`. We
|
||||
//! do however do one transformation on the adjustment: if we
|
||||
//! are passing a region pointer in, we will potentially
|
||||
//! *reborrow* it to a shorter lifetime. This allows us to
|
||||
//! transparently pass `&mut` pointers, in particular, without
|
||||
//! consuming them for their entire lifetime.
|
||||
|
||||
if step.unsize {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.pick_method(step.self_ty).map(|r| r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
self.pick_method(step.self_ty).map(|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
|
||||
// Insert a `&*` or `&mut *` if this is a reference type:
|
||||
if let ty::TyRef(_, mt) = step.self_ty.sty {
|
||||
pick.autoderefs += 1;
|
||||
pick.autoref = Some(mt.mutbl);
|
||||
}
|
||||
// Insert a `&*` or `&mut *` if this is a reference type:
|
||||
if let ty::TyRef(_, mt) = step.self_ty.sty {
|
||||
pick.autoderefs += 1;
|
||||
pick.autoref = Some(mt.mutbl);
|
||||
}
|
||||
|
||||
pick
|
||||
}))
|
||||
pick
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn pick_autorefd_method(&mut self,
|
||||
step: &CandidateStep<'tcx>)
|
||||
-> Option<PickResult<'tcx>>
|
||||
{
|
||||
fn pick_autorefd_method(&mut self, step: &CandidateStep<'tcx>) -> Option<PickResult<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// In general, during probing we erase regions. See
|
||||
@ -977,22 +962,28 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
let region = tcx.mk_region(ty::ReErased);
|
||||
|
||||
// Search through mutabilities in order to find one where pick works:
|
||||
[hir::MutImmutable, hir::MutMutable].iter().filter_map(|&m| {
|
||||
let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut {
|
||||
ty: step.self_ty,
|
||||
mutbl: m
|
||||
});
|
||||
self.pick_method(autoref_ty).map(|r| r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref = Some(m);
|
||||
pick.unsize = if step.unsize {
|
||||
Some(step.self_ty)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
pick
|
||||
}))
|
||||
}).nth(0)
|
||||
[hir::MutImmutable, hir::MutMutable]
|
||||
.iter()
|
||||
.filter_map(|&m| {
|
||||
let autoref_ty = tcx.mk_ref(region,
|
||||
ty::TypeAndMut {
|
||||
ty: step.self_ty,
|
||||
mutbl: m,
|
||||
});
|
||||
self.pick_method(autoref_ty).map(|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref = Some(m);
|
||||
pick.unsize = if step.unsize {
|
||||
Some(step.self_ty)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
pick
|
||||
})
|
||||
})
|
||||
})
|
||||
.nth(0)
|
||||
}
|
||||
|
||||
fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
|
||||
@ -1008,7 +999,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
debug!("searching extension candidates");
|
||||
let res = self.consider_candidates(self_ty, &self.extension_candidates,
|
||||
let res = self.consider_candidates(self_ty,
|
||||
&self.extension_candidates,
|
||||
&mut possibly_unsatisfied_predicates);
|
||||
if let None = res {
|
||||
self.unsatisfied_predicates.extend(possibly_unsatisfied_predicates);
|
||||
@ -1021,18 +1013,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
probes: &[Candidate<'tcx>],
|
||||
possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>)
|
||||
-> Option<PickResult<'tcx>> {
|
||||
let mut applicable_candidates: Vec<_> =
|
||||
probes.iter()
|
||||
.filter(|&probe| self.consider_probe(self_ty,
|
||||
probe,possibly_unsatisfied_predicates))
|
||||
.collect();
|
||||
let mut applicable_candidates: Vec<_> = probes.iter()
|
||||
.filter(|&probe| self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates))
|
||||
.collect();
|
||||
|
||||
debug!("applicable_candidates: {:?}", applicable_candidates);
|
||||
|
||||
if applicable_candidates.len() > 1 {
|
||||
match self.collapse_candidates_to_trait_pick(&applicable_candidates[..]) {
|
||||
Some(pick) => { return Some(Ok(pick)); }
|
||||
None => { }
|
||||
Some(pick) => {
|
||||
return Some(Ok(pick));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1041,21 +1033,22 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
return Some(Err(MethodError::Ambiguity(sources)));
|
||||
}
|
||||
|
||||
applicable_candidates.pop().map(|probe| {
|
||||
Ok(probe.to_unadjusted_pick())
|
||||
})
|
||||
applicable_candidates.pop().map(|probe| Ok(probe.to_unadjusted_pick()))
|
||||
}
|
||||
|
||||
fn consider_probe(&self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>,
|
||||
possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>) -> bool {
|
||||
debug!("consider_probe: self_ty={:?} probe={:?}",
|
||||
self_ty,
|
||||
probe);
|
||||
fn consider_probe(&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
probe: &Candidate<'tcx>,
|
||||
possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>)
|
||||
-> bool {
|
||||
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
|
||||
|
||||
self.probe(|_| {
|
||||
// First check that the self type can be related.
|
||||
match self.sub_types(false, TypeOrigin::Misc(DUMMY_SP),
|
||||
self_ty, probe.xform_self_ty) {
|
||||
match self.sub_types(false,
|
||||
TypeOrigin::Misc(DUMMY_SP),
|
||||
self_ty,
|
||||
probe.xform_self_ty) {
|
||||
Ok(InferOk { obligations, .. }) => {
|
||||
// FIXME(#32730) propagate obligations
|
||||
assert!(obligations.is_empty())
|
||||
@ -1093,14 +1086,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
// Check whether the impl imposes obligations we have to worry about.
|
||||
let impl_bounds = self.tcx.lookup_predicates(impl_def_id);
|
||||
let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
|
||||
let traits::Normalized { value: impl_bounds,
|
||||
obligations: norm_obligations } =
|
||||
let traits::Normalized { value: impl_bounds, obligations: norm_obligations } =
|
||||
traits::normalize(selcx, cause.clone(), &impl_bounds);
|
||||
|
||||
// Convert the bounds into obligations.
|
||||
let obligations =
|
||||
traits::predicates_for_generics(cause.clone(),
|
||||
&impl_bounds);
|
||||
let obligations = traits::predicates_for_generics(cause.clone(), &impl_bounds);
|
||||
debug!("impl_obligations={:?}", obligations);
|
||||
|
||||
// Evaluate those obligations to see if they might possibly hold.
|
||||
@ -1136,14 +1126,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
///
|
||||
/// Now imagine the receiver is `Vec<_>`. It doesn't really matter at this time which impl we
|
||||
/// use, so it's ok to just commit to "using the method from the trait Foo".
|
||||
fn collapse_candidates_to_trait_pick(&self,
|
||||
probes: &[&Candidate<'tcx>])
|
||||
-> Option<Pick<'tcx>> {
|
||||
fn collapse_candidates_to_trait_pick(&self, probes: &[&Candidate<'tcx>]) -> Option<Pick<'tcx>> {
|
||||
// Do all probes correspond to the same trait?
|
||||
let container = probes[0].item.container();
|
||||
match container {
|
||||
ty::TraitContainer(_) => {}
|
||||
ty::ImplContainer(_) => return None
|
||||
ty::ImplContainer(_) => return None,
|
||||
}
|
||||
if probes[1..].iter().any(|p| p.item.container() != container) {
|
||||
return None;
|
||||
@ -1156,7 +1144,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
import_id: probes[0].import_id,
|
||||
autoderefs: 0,
|
||||
autoref: None,
|
||||
unsize: None
|
||||
unsize: None,
|
||||
})
|
||||
}
|
||||
|
||||
@ -1165,13 +1153,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool {
|
||||
// "fast track" -- check for usage of sugar
|
||||
match *item {
|
||||
ty::ImplOrTraitItem::MethodTraitItem(ref method) =>
|
||||
ty::ImplOrTraitItem::MethodTraitItem(ref method) => {
|
||||
match method.explicit_self {
|
||||
ty::ExplicitSelfCategory::Static => self.mode == Mode::Path,
|
||||
ty::ExplicitSelfCategory::ByValue |
|
||||
ty::ExplicitSelfCategory::ByReference(..) |
|
||||
ty::ExplicitSelfCategory::ByBox => true,
|
||||
},
|
||||
}
|
||||
}
|
||||
ty::ImplOrTraitItem::ConstTraitItem(..) => self.mode == Mode::Path,
|
||||
_ => false,
|
||||
}
|
||||
@ -1191,11 +1180,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
item: &ty::ImplOrTraitItem<'tcx>,
|
||||
impl_ty: Ty<'tcx>,
|
||||
substs: &Substs<'tcx>)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
-> Ty<'tcx> {
|
||||
match item.as_opt_method() {
|
||||
Some(ref method) => self.xform_method_self_ty(method, impl_ty,
|
||||
substs),
|
||||
Some(ref method) => self.xform_method_self_ty(method, impl_ty, substs),
|
||||
None => impl_ty,
|
||||
}
|
||||
}
|
||||
@ -1204,8 +1191,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
method: &Rc<ty::Method<'tcx>>,
|
||||
impl_ty: Ty<'tcx>,
|
||||
substs: &Substs<'tcx>)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
-> Ty<'tcx> {
|
||||
debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})",
|
||||
impl_ty,
|
||||
method.fty.sig.0.inputs.get(0),
|
||||
@ -1218,8 +1204,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
// are given do not include type/lifetime parameters for the
|
||||
// method yet. So create fresh variables here for those too,
|
||||
// if there are any.
|
||||
assert_eq!(substs.types().count(), method.generics.parent_types as usize);
|
||||
assert_eq!(substs.regions().count(), method.generics.parent_regions as usize);
|
||||
assert_eq!(substs.types().count(),
|
||||
method.generics.parent_types as usize);
|
||||
assert_eq!(substs.regions().count(),
|
||||
method.generics.parent_regions as usize);
|
||||
|
||||
if self.mode == Mode::Path {
|
||||
return impl_ty;
|
||||
@ -1233,7 +1221,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
if method.generics.types.is_empty() && method.generics.regions.is_empty() {
|
||||
xform_self_ty.subst(self.tcx, substs)
|
||||
} else {
|
||||
let substs = Substs::for_item(self.tcx, method.def_id, |def, _| {
|
||||
let substs = Substs::for_item(self.tcx,
|
||||
method.def_id,
|
||||
|def, _| {
|
||||
let i = def.index as usize;
|
||||
if i < substs.params().len() {
|
||||
substs.region_at(i)
|
||||
@ -1242,7 +1232,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
// `impl_self_ty()` for an explanation.
|
||||
self.tcx.mk_region(ty::ReErased)
|
||||
}
|
||||
}, |def, cur_substs| {
|
||||
},
|
||||
|def, cur_substs| {
|
||||
let i = def.index as usize;
|
||||
if i < substs.params().len() {
|
||||
substs.type_at(i)
|
||||
@ -1255,13 +1246,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
/// Get the type of an impl and generate substitutions with placeholders.
|
||||
fn impl_ty_and_substs(&self,
|
||||
impl_def_id: DefId)
|
||||
-> (Ty<'tcx>, &'tcx Substs<'tcx>)
|
||||
{
|
||||
fn impl_ty_and_substs(&self, impl_def_id: DefId) -> (Ty<'tcx>, &'tcx Substs<'tcx>) {
|
||||
let impl_ty = self.tcx.lookup_item_type(impl_def_id).ty;
|
||||
|
||||
let substs = Substs::for_item(self.tcx, impl_def_id,
|
||||
let substs = Substs::for_item(self.tcx,
|
||||
impl_def_id,
|
||||
|_, _| self.tcx.mk_region(ty::ReErased),
|
||||
|_, _| self.next_ty_var());
|
||||
|
||||
@ -1287,16 +1276,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
/// and/or tracking the substitution and
|
||||
/// so forth.
|
||||
fn erase_late_bound_regions<T>(&self, value: &ty::Binder<T>) -> T
|
||||
where T : TypeFoldable<'tcx>
|
||||
where T: TypeFoldable<'tcx>
|
||||
{
|
||||
self.tcx.erase_late_bound_regions(value)
|
||||
}
|
||||
|
||||
/// Find item with name `item_name` defined in impl/trait `def_id`
|
||||
/// and return it, or `None`, if no such item was defined there.
|
||||
fn impl_or_trait_item(&self, def_id: DefId)
|
||||
-> Option<ty::ImplOrTraitItem<'tcx>>
|
||||
{
|
||||
fn impl_or_trait_item(&self, def_id: DefId) -> Option<ty::ImplOrTraitItem<'tcx>> {
|
||||
self.fcx.impl_or_trait_item(def_id, self.item_name)
|
||||
}
|
||||
}
|
||||
@ -1307,9 +1294,7 @@ impl<'tcx> Candidate<'tcx> {
|
||||
item: self.item.clone(),
|
||||
kind: match self.kind {
|
||||
InherentImplCandidate(..) => InherentImplPick,
|
||||
ExtensionImplCandidate(def_id, ..) => {
|
||||
ExtensionImplPick(def_id)
|
||||
}
|
||||
ExtensionImplCandidate(def_id, ..) => ExtensionImplPick(def_id),
|
||||
ObjectCandidate => ObjectPick,
|
||||
TraitCandidate => TraitPick,
|
||||
WhereClauseCandidate(ref trait_ref) => {
|
||||
@ -1326,15 +1311,13 @@ impl<'tcx> Candidate<'tcx> {
|
||||
import_id: self.import_id,
|
||||
autoderefs: 0,
|
||||
autoref: None,
|
||||
unsize: None
|
||||
unsize: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_source(&self) -> CandidateSource {
|
||||
match self.kind {
|
||||
InherentImplCandidate(..) => {
|
||||
ImplSource(self.item.container().id())
|
||||
}
|
||||
InherentImplCandidate(..) => ImplSource(self.item.container().id()),
|
||||
ExtensionImplCandidate(def_id, ..) => ImplSource(def_id),
|
||||
ObjectCandidate |
|
||||
TraitCandidate |
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
use CrateCtxt;
|
||||
|
||||
use check::{FnCtxt};
|
||||
use check::FnCtxt;
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
|
||||
use hir::def::Def;
|
||||
@ -21,7 +21,7 @@ use hir::def_id::{CRATE_DEF_INDEX, DefId};
|
||||
use middle::lang_items::FnOnceTraitLangItem;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::traits::{Obligation, SelectionContext};
|
||||
use util::nodemap::{FnvHashSet};
|
||||
use util::nodemap::FnvHashSet;
|
||||
|
||||
use syntax::ast;
|
||||
use errors::DiagnosticBuilder;
|
||||
@ -43,25 +43,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
match ty.sty {
|
||||
// Not all of these (e.g. unsafe fns) implement FnOnce
|
||||
// so we look for these beforehand
|
||||
ty::TyClosure(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => true,
|
||||
ty::TyClosure(..) |
|
||||
ty::TyFnDef(..) |
|
||||
ty::TyFnPtr(_) => true,
|
||||
// If it's not a simple function, look for things which implement FnOnce
|
||||
_ => {
|
||||
let fn_once = match tcx.lang_items.require(FnOnceTraitLangItem) {
|
||||
Ok(fn_once) => fn_once,
|
||||
Err(..) => return false
|
||||
Err(..) => return false,
|
||||
};
|
||||
|
||||
self.autoderef(span, ty).any(|(ty, _)| self.probe(|_| {
|
||||
let fn_once_substs =
|
||||
Substs::new_trait(tcx, ty, &[self.next_ty_var()]);
|
||||
let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
|
||||
let poly_trait_ref = trait_ref.to_poly_trait_ref();
|
||||
let obligation = Obligation::misc(span,
|
||||
self.body_id,
|
||||
poly_trait_ref
|
||||
.to_predicate());
|
||||
SelectionContext::new(self).evaluate_obligation(&obligation)
|
||||
}))
|
||||
self.autoderef(span, ty).any(|(ty, _)| {
|
||||
self.probe(|_| {
|
||||
let fn_once_substs = Substs::new_trait(tcx, ty, &[self.next_ty_var()]);
|
||||
let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
|
||||
let poly_trait_ref = trait_ref.to_poly_trait_ref();
|
||||
let obligation =
|
||||
Obligation::misc(span, self.body_id, poly_trait_ref.to_predicate());
|
||||
SelectionContext::new(self).evaluate_obligation(&obligation)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -71,15 +72,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
item_name: ast::Name,
|
||||
rcvr_expr: Option<&hir::Expr>,
|
||||
error: MethodError<'tcx>)
|
||||
{
|
||||
error: MethodError<'tcx>) {
|
||||
// avoid suggestions when we don't know what's going on.
|
||||
if rcvr_ty.references_error() {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
let report_candidates = |err: &mut DiagnosticBuilder,
|
||||
mut sources: Vec<CandidateSource>| {
|
||||
let report_candidates = |err: &mut DiagnosticBuilder, mut sources: Vec<CandidateSource>| {
|
||||
|
||||
sources.sort();
|
||||
sources.dedup();
|
||||
@ -93,15 +92,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// the impl, if local to crate (item may be defaulted), else nothing.
|
||||
let item = self.impl_or_trait_item(impl_did, item_name)
|
||||
.or_else(|| {
|
||||
self.impl_or_trait_item(
|
||||
self.tcx.impl_trait_ref(impl_did).unwrap().def_id,
|
||||
self.impl_or_trait_item(self.tcx
|
||||
.impl_trait_ref(impl_did)
|
||||
.unwrap()
|
||||
.def_id,
|
||||
|
||||
item_name
|
||||
)
|
||||
}).unwrap();
|
||||
let note_span = self.tcx.map.span_if_local(item.def_id()).or_else(|| {
|
||||
self.tcx.map.span_if_local(impl_did)
|
||||
});
|
||||
item_name)
|
||||
})
|
||||
.unwrap();
|
||||
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 = self.impl_self_ty(span, impl_did).ty;
|
||||
|
||||
@ -128,7 +130,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
CandidateSource::TraitSource(trait_did) => {
|
||||
let item = self.impl_or_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,
|
||||
span_note!(err,
|
||||
item_span,
|
||||
"candidate #{} is defined in the trait `{}`",
|
||||
idx + 1,
|
||||
self.tcx.item_path_str(trait_did));
|
||||
@ -144,20 +147,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
MethodError::NoMatch(NoMatchData { static_candidates: static_sources,
|
||||
unsatisfied_predicates,
|
||||
out_of_scope_traits,
|
||||
mode, .. }) => {
|
||||
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);
|
||||
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);
|
||||
|
||||
// If the method name is the name of a field with a function or closure type,
|
||||
// give a helping note that it has to be called as (x.f)(...).
|
||||
@ -165,27 +170,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
for (ty, _) in self.autoderef(span, rcvr_ty) {
|
||||
match ty.sty {
|
||||
ty::TyAdt(def, substs) if !def.is_enum() => {
|
||||
if let Some(field) = def.struct_variant().
|
||||
find_field_named(item_name) {
|
||||
if let Some(field) = def.struct_variant()
|
||||
.find_field_named(item_name) {
|
||||
let snippet = tcx.sess.codemap().span_to_snippet(expr.span);
|
||||
let expr_string = match snippet {
|
||||
Ok(expr_string) => expr_string,
|
||||
_ => "s".into() // Default to a generic placeholder for the
|
||||
// expression when we can't generate a
|
||||
// string snippet
|
||||
_ => "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));
|
||||
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));
|
||||
err.span_note(span,
|
||||
&format!("did you mean to write `{0}.{1}`?",
|
||||
expr_string,
|
||||
item_name));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -204,10 +212,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
if let Some(expr) = rcvr_expr {
|
||||
if let Ok (expr_string) = tcx.sess.codemap().span_to_snippet(expr.span) {
|
||||
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() {
|
||||
} else if let Expr_::ExprPath(_, path) = expr.node.clone() {
|
||||
if let Some(segment) = path.segments.last() {
|
||||
report_function!(expr.span, segment.name);
|
||||
}
|
||||
@ -216,34 +223,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
if !static_sources.is_empty() {
|
||||
err.note(
|
||||
"found the following associated functions; to be used as \
|
||||
methods, functions must have a `self` parameter");
|
||||
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))
|
||||
.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));
|
||||
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);
|
||||
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,
|
||||
let mut err = struct_span_err!(self.sess(),
|
||||
span,
|
||||
E0034,
|
||||
"multiple applicable items in scope");
|
||||
err.span_label(span, &format!("multiple `{}` found", item_name));
|
||||
|
||||
@ -255,11 +264,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
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));
|
||||
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))
|
||||
msg,
|
||||
pprust::expr_to_string(callee))
|
||||
} else {
|
||||
msg
|
||||
};
|
||||
@ -279,18 +289,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
item_name: ast::Name,
|
||||
rcvr_expr: Option<&hir::Expr>,
|
||||
valid_out_of_scope_traits: Vec<DefId>)
|
||||
{
|
||||
valid_out_of_scope_traits: Vec<DefId>) {
|
||||
if !valid_out_of_scope_traits.is_empty() {
|
||||
let mut candidates = valid_out_of_scope_traits;
|
||||
candidates.sort();
|
||||
candidates.dedup();
|
||||
let msg = format!(
|
||||
"items from traits can only be used if the trait is in scope; \
|
||||
the following {traits_are} implemented but not in scope, \
|
||||
perhaps add a `use` for {one_of_them}:",
|
||||
traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"},
|
||||
one_of_them = if candidates.len() == 1 {"it"} else {"one of them"});
|
||||
let msg = format!("items from traits can only be used if the trait is in scope; the \
|
||||
following {traits_are} implemented but not in scope, perhaps add \
|
||||
a `use` for {one_of_them}:",
|
||||
traits_are = if candidates.len() == 1 {
|
||||
"trait is"
|
||||
} else {
|
||||
"traits are"
|
||||
},
|
||||
one_of_them = if candidates.len() == 1 {
|
||||
"it"
|
||||
} else {
|
||||
"one of them"
|
||||
});
|
||||
|
||||
err.help(&msg[..]);
|
||||
|
||||
@ -303,7 +319,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
if candidates.len() > limit {
|
||||
err.note(&format!("and {} others", candidates.len() - limit));
|
||||
}
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
let type_is_local = self.type_derefs_to_local(span, rcvr_ty, rcvr_expr);
|
||||
@ -319,8 +335,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// this isn't perfect (that is, there are cases when
|
||||
// implementing a trait would be legal but is rejected
|
||||
// here).
|
||||
(type_is_local || info.def_id.is_local())
|
||||
&& self.impl_or_trait_item(info.def_id, item_name).is_some()
|
||||
(type_is_local || info.def_id.is_local()) &&
|
||||
self.impl_or_trait_item(info.def_id, item_name).is_some()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@ -332,13 +348,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// FIXME #21673 this help message could be tuned to the case
|
||||
// of a type parameter: suggest adding a trait bound rather
|
||||
// than implementing.
|
||||
let msg = format!(
|
||||
"items from traits can only be used if the trait is implemented and in scope; \
|
||||
the following {traits_define} an item `{name}`, \
|
||||
perhaps you need to implement {one_of_them}:",
|
||||
traits_define = if candidates.len() == 1 {"trait defines"} else {"traits define"},
|
||||
one_of_them = if candidates.len() == 1 {"it"} else {"one of them"},
|
||||
name = item_name);
|
||||
let msg = format!("items from traits can only be used if the trait is implemented \
|
||||
and in scope; the following {traits_define} an item `{name}`, \
|
||||
perhaps you need to implement {one_of_them}:",
|
||||
traits_define = if candidates.len() == 1 {
|
||||
"trait defines"
|
||||
} else {
|
||||
"traits define"
|
||||
},
|
||||
one_of_them = if candidates.len() == 1 {
|
||||
"it"
|
||||
} else {
|
||||
"one of them"
|
||||
},
|
||||
name = item_name);
|
||||
|
||||
err.help(&msg[..]);
|
||||
|
||||
@ -355,7 +378,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
fn type_derefs_to_local(&self,
|
||||
span: Span,
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
rcvr_expr: Option<&hir::Expr>) -> bool {
|
||||
rcvr_expr: Option<&hir::Expr>)
|
||||
-> bool {
|
||||
fn is_local(ty: Ty) -> bool {
|
||||
match ty.sty {
|
||||
ty::TyAdt(def, _) => def.did.is_local(),
|
||||
@ -368,7 +392,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// non-local (there are "edge" cases, e.g. (LocalType,), but
|
||||
// the noise from these sort of types is usually just really
|
||||
// annoying, rather than any sort of help).
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -391,9 +415,7 @@ pub struct TraitInfo {
|
||||
|
||||
impl TraitInfo {
|
||||
fn new(def_id: DefId) -> TraitInfo {
|
||||
TraitInfo {
|
||||
def_id: def_id,
|
||||
}
|
||||
TraitInfo { def_id: def_id }
|
||||
}
|
||||
}
|
||||
impl PartialEq for TraitInfo {
|
||||
@ -403,7 +425,9 @@ impl PartialEq for TraitInfo {
|
||||
}
|
||||
impl Eq for TraitInfo {}
|
||||
impl PartialOrd for TraitInfo {
|
||||
fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> { Some(self.cmp(other)) }
|
||||
fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
impl Ord for TraitInfo {
|
||||
fn cmp(&self, other: &TraitInfo) -> Ordering {
|
||||
@ -426,7 +450,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
|
||||
// Crate-local:
|
||||
//
|
||||
// meh.
|
||||
struct Visitor<'a, 'tcx:'a> {
|
||||
struct Visitor<'a, 'tcx: 'a> {
|
||||
map: &'a hir_map::Map<'tcx>,
|
||||
traits: &'a mut AllTraitsVec,
|
||||
}
|
||||
@ -443,7 +467,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
|
||||
}
|
||||
ccx.tcx.map.krate().visit_all_items(&mut Visitor {
|
||||
map: &ccx.tcx.map,
|
||||
traits: &mut traits
|
||||
traits: &mut traits,
|
||||
});
|
||||
|
||||
// Cross-crate:
|
||||
@ -469,7 +493,10 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
|
||||
}
|
||||
}
|
||||
for cnum in ccx.tcx.sess.cstore.crates() {
|
||||
let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
|
||||
let def_id = DefId {
|
||||
krate: cnum,
|
||||
index: CRATE_DEF_INDEX,
|
||||
};
|
||||
handle_external_def(ccx, &mut traits, &mut external_mods, Def::Mod(def_id));
|
||||
}
|
||||
|
||||
@ -480,13 +507,13 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
|
||||
assert!(borrow.is_some());
|
||||
AllTraits {
|
||||
borrow: borrow,
|
||||
idx: 0
|
||||
idx: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AllTraits<'a> {
|
||||
borrow: cell::Ref<'a, Option<AllTraitsVec>>,
|
||||
idx: usize
|
||||
idx: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for AllTraits<'a> {
|
||||
|
@ -140,7 +140,7 @@ pub mod os {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "haiku")]
|
||||
mod os {
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "haiku";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
@ -151,7 +151,7 @@ mod os {
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))]
|
||||
mod os {
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "emscripten";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
@ -162,7 +162,7 @@ mod os {
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))]
|
||||
mod os {
|
||||
pub mod os {
|
||||
pub const FAMILY: &'static str = "unix";
|
||||
pub const OS: &'static str = "emscripten";
|
||||
pub const DLL_PREFIX: &'static str = "lib";
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 755bc3db4ff795865ea31b5b4f38ac920d8acacb
|
||||
Subproject commit 4f994850808a572e2cc8d43f968893c8e942e9bf
|
24
src/test/run-pass/issue-36856.rs
Normal file
24
src/test/run-pass/issue-36856.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Regression test for #36856.
|
||||
|
||||
// compile-flags:-g
|
||||
|
||||
fn g() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let a = !g();
|
||||
if a != !g() {
|
||||
panic!();
|
||||
}
|
||||
}
|
35
src/test/run-pass/issue-36936.rs
Normal file
35
src/test/run-pass/issue-36936.rs
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// check that casts are not being treated as lexprs.
|
||||
|
||||
fn main() {
|
||||
let mut a = 0i32;
|
||||
let b = &(a as i32);
|
||||
a = 1;
|
||||
assert_ne!(&a as *const i32, b as *const i32);
|
||||
assert_eq!(*b, 0);
|
||||
|
||||
assert_eq!(issue_36936(), 1);
|
||||
}
|
||||
|
||||
|
||||
struct A(u32);
|
||||
|
||||
impl Drop for A {
|
||||
fn drop(&mut self) {
|
||||
self.0 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fn issue_36936() -> u32 {
|
||||
let a = &(A(1) as A);
|
||||
a.0
|
||||
}
|
Loading…
Reference in New Issue
Block a user