1
Fork 0

Auto merge of #36736 - srinivasreddy:method, r=nrc

run rustfmt on librustc_typeck/check/method  folder
This commit is contained in:
bors 2016-10-05 05:53:01 -07:00 committed by GitHub
commit fd1ea1330e
4 changed files with 564 additions and 548 deletions

View file

@ -23,7 +23,7 @@ use rustc::hir;
use std::ops::Deref; 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>, fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
span: Span, span: Span,
self_expr: &'gcx hir::Expr, self_expr: &'gcx hir::Expr,
@ -55,8 +55,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
unadjusted_self_ty: Ty<'tcx>, unadjusted_self_ty: Ty<'tcx>,
pick: probe::Pick<'tcx>, pick: probe::Pick<'tcx>,
supplied_method_types: Vec<Ty<'tcx>>) supplied_method_types: Vec<Ty<'tcx>>)
-> ty::MethodCallee<'tcx> -> ty::MethodCallee<'tcx> {
{
debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})", debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
unadjusted_self_ty, unadjusted_self_ty,
pick, pick,
@ -72,17 +71,20 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
span: Span, span: Span,
self_expr: &'gcx hir::Expr, self_expr: &'gcx hir::Expr,
call_expr: &'gcx hir::Expr) call_expr: &'gcx hir::Expr)
-> ConfirmContext<'a, 'gcx, 'tcx> -> ConfirmContext<'a, 'gcx, 'tcx> {
{ ConfirmContext {
ConfirmContext { fcx: fcx, span: span, self_expr: self_expr, call_expr: call_expr } fcx: fcx,
span: span,
self_expr: self_expr,
call_expr: call_expr,
}
} }
fn confirm(&mut self, fn confirm(&mut self,
unadjusted_self_ty: Ty<'tcx>, unadjusted_self_ty: Ty<'tcx>,
pick: probe::Pick<'tcx>, pick: probe::Pick<'tcx>,
supplied_method_types: Vec<Ty<'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. // Adjust the self expression the user provided and obtain the adjusted type.
let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick); let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick);
@ -91,18 +93,13 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
// Create substitutions for the method's type parameters. // Create substitutions for the method's type parameters.
let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick); let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick);
let all_substs = let all_substs = self.instantiate_method_substs(&pick, supplied_method_types, rcvr_substs);
self.instantiate_method_substs(
&pick,
supplied_method_types,
rcvr_substs);
debug!("all_substs={:?}", all_substs); debug!("all_substs={:?}", all_substs);
// Create the final signature for the method, replacing late-bound regions. // Create the final signature for the method, replacing late-bound regions.
let InstantiatedMethodSig { let InstantiatedMethodSig { method_sig, method_predicates } =
method_sig, method_predicates self.instantiate_method_sig(&pick, all_substs);
} = self.instantiate_method_sig(&pick, all_substs);
let method_self_ty = method_sig.inputs[0]; let method_self_ty = method_sig.inputs[0];
// Unify the (adjusted) self type with what the method expects. // 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 // Create the method type
let def_id = pick.item.def_id(); let def_id = pick.item.def_id();
let method_ty = pick.item.as_opt_method().unwrap(); 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 { self.tcx.mk_bare_fn(ty::BareFnTy {
sig: ty::Binder(method_sig), sig: ty::Binder(method_sig),
unsafety: method_ty.fty.unsafety, unsafety: method_ty.fty.unsafety,
abi: method_ty.fty.abi.clone(), abi: method_ty.fty.abi.clone(),
})); }));
// Add any trait/regions obligations specified on the method's type parameters. // Add any trait/regions obligations specified on the method's type parameters.
self.add_obligations(fty, all_substs, &method_predicates); self.add_obligations(fty, all_substs, &method_predicates);
@ -125,7 +123,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
let callee = ty::MethodCallee { let callee = ty::MethodCallee {
def_id: def_id, def_id: def_id,
ty: fty, ty: fty,
substs: all_substs substs: all_substs,
}; };
if let Some(hir::MutMutable) = pick.autoref { 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, fn adjust_self_ty(&mut self,
unadjusted_self_ty: Ty<'tcx>, unadjusted_self_ty: Ty<'tcx>,
pick: &probe::Pick<'tcx>) pick: &probe::Pick<'tcx>)
-> Ty<'tcx> -> Ty<'tcx> {
{
let (autoref, unsize) = if let Some(mutbl) = pick.autoref { let (autoref, unsize) = if let Some(mutbl) = pick.autoref {
let region = self.next_region_var(infer::Autoref(self.span)); let region = self.next_region_var(infer::Autoref(self.span));
let autoref = AutoPtr(region, mutbl); let autoref = AutoPtr(region, mutbl);
(Some(autoref), pick.unsize.map(|target| { (Some(autoref),
target.adjust_for_autoref(self.tcx, Some(autoref)) pick.unsize.map(|target| target.adjust_for_autoref(self.tcx, Some(autoref))))
}))
} else { } else {
// No unsizing should be performed without autoref (at // No unsizing should be performed without autoref (at
// least during method dispach). This is because we // 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)); autoderef.finalize(LvaluePreference::NoPreference, Some(self.self_expr));
// Write out the final adjustment. // Write out the final adjustment.
self.write_adjustment(self.self_expr.id, AdjustDerefRef(AutoDerefRef { self.write_adjustment(self.self_expr.id,
autoderefs: pick.autoderefs, AdjustDerefRef(AutoDerefRef {
autoref: autoref, autoderefs: pick.autoderefs,
unsize: unsize autoref: autoref,
})); unsize: unsize,
}));
if let Some(target) = unsize { if let Some(target) = unsize {
target target
@ -193,13 +190,13 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
fn fresh_receiver_substs(&mut self, fn fresh_receiver_substs(&mut self,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
pick: &probe::Pick<'tcx>) pick: &probe::Pick<'tcx>)
-> &'tcx Substs<'tcx> -> &'tcx Substs<'tcx> {
{
match pick.kind { match pick.kind {
probe::InherentImplPick => { probe::InherentImplPick => {
let impl_def_id = pick.item.container().id(); let impl_def_id = pick.item.container().id();
assert!(self.tcx.impl_trait_ref(impl_def_id).is_none(), 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 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 // argument type), but those cases have already
// been ruled out when we deemed the trait to be // been ruled out when we deemed the trait to be
// "object safe". // "object safe".
let original_poly_trait_ref = let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty);
principal.with_self_ty(this.tcx, object_ty); let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id);
let upcast_poly_trait_ref =
this.upcast(original_poly_trait_ref, trait_def_id);
let upcast_trait_ref = let upcast_trait_ref =
this.replace_late_bound_regions_with_fresh_var(&upcast_poly_trait_ref); this.replace_late_bound_regions_with_fresh_var(&upcast_poly_trait_ref);
debug!("original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}", 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]). // the impl ([$A,$B,$C]) not the receiver type ([$C]).
let impl_polytype = self.impl_self_ty(self.span, impl_def_id); let impl_polytype = self.impl_self_ty(self.span, impl_def_id);
let impl_trait_ref = let impl_trait_ref =
self.instantiate_type_scheme( self.instantiate_type_scheme(self.span,
self.span, impl_polytype.substs,
impl_polytype.substs, &self.tcx.impl_trait_ref(impl_def_id).unwrap());
&self.tcx.impl_trait_ref(impl_def_id).unwrap());
impl_trait_ref.substs 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, fn extract_existential_trait_ref<R, F>(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R
self_ty: Ty<'tcx>,
mut closure: F) -> R
where F: FnMut(&mut ConfirmContext<'a, 'gcx, 'tcx>, where F: FnMut(&mut ConfirmContext<'a, 'gcx, 'tcx>,
Ty<'tcx>, Ty<'tcx>,
ty::PolyExistentialTraitRef<'tcx>) -> R, ty::PolyExistentialTraitRef<'tcx>)
-> R
{ {
// If we specified that this is an object method, then the // If we specified that this is an object method, then the
// self-type ought to be something that can be dereferenced to // self-type ought to be something that can be dereferenced to
@ -281,7 +274,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
// etc). // etc).
// FIXME: this feels, like, super dubious // FIXME: this feels, like, super dubious
self.fcx.autoderef(self.span, self_ty) self.fcx
.autoderef(self.span, self_ty)
.filter_map(|(ty, _)| { .filter_map(|(ty, _)| {
match ty.sty { match ty.sty {
ty::TyTrait(ref data) => Some(closure(self, ty, data.principal)), ty::TyTrait(ref data) => Some(closure(self, ty, data.principal)),
@ -290,10 +284,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
}) })
.next() .next()
.unwrap_or_else(|| { .unwrap_or_else(|| {
span_bug!( span_bug!(self.span,
self.span, "self-type `{}` for ObjectPick never dereferenced to an object",
"self-type `{}` for ObjectPick never dereferenced to an object", self_ty)
self_ty)
}) })
} }
@ -301,8 +294,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
pick: &probe::Pick<'tcx>, pick: &probe::Pick<'tcx>,
mut supplied_method_types: Vec<Ty<'tcx>>, mut supplied_method_types: Vec<Ty<'tcx>>,
substs: &Substs<'tcx>) substs: &Substs<'tcx>)
-> &'tcx Substs<'tcx> -> &'tcx Substs<'tcx> {
{
// Determine the values for the generic parameters of the method. // Determine the values for the generic parameters of the method.
// If they were not explicitly supplied, just construct fresh // If they were not explicitly supplied, just construct fresh
// variables. // 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_supplied_types > 0 && num_supplied_types != num_method_types {
if num_method_types == 0 { 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") "does not take type parameters")
.span_label(self.span, &"called with unneeded type parameters") .span_label(self.span, &"called with unneeded type parameters")
.emit(); .emit();
} else { } else {
struct_span_err!(self.tcx.sess, self.span, E0036, struct_span_err!(self.tcx.sess,
"incorrect number of type parameters given for this method: \ self.span,
expected {}, found {}", E0036,
num_method_types, num_supplied_types) "incorrect number of type parameters given for this method: \
expected {}, found {}",
num_method_types,
num_supplied_types)
.span_label(self.span, .span_label(self.span,
&format!("Passed {} type argument{}, expected {}", &format!("Passed {} type argument{}, expected {}",
num_supplied_types, num_supplied_types,
if num_supplied_types != 1 { if num_supplied_types != 1 { "s" } else { "" },
"s"
} else {
""
},
num_method_types)) num_method_types))
.emit(); .emit();
} }
@ -340,14 +333,17 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
// //
// FIXME -- permit users to manually specify lifetimes // FIXME -- permit users to manually specify lifetimes
let supplied_start = substs.params().len() + method.generics.regions.len(); 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; let i = def.index as usize;
if i < substs.params().len() { if i < substs.params().len() {
substs.region_at(i) substs.region_at(i)
} else { } else {
self.region_var_for_def(self.span, def) self.region_var_for_def(self.span, def)
} }
}, |def, cur_substs| { },
|def, cur_substs| {
let i = def.index as usize; let i = def.index as usize;
if i < substs.params().len() { if i < substs.params().len() {
substs.type_at(i) substs.type_at(i)
@ -359,21 +355,17 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
}) })
} }
fn unify_receivers(&mut self, fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) {
self_ty: Ty<'tcx>, match self.sub_types(false, TypeOrigin::Misc(self.span), self_ty, method_self_ty) {
method_self_ty: Ty<'tcx>)
{
match self.sub_types(false, TypeOrigin::Misc(self.span),
self_ty, method_self_ty) {
Ok(InferOk { obligations, .. }) => { Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations // FIXME(#32730) propagate obligations
assert!(obligations.is_empty()); assert!(obligations.is_empty());
} }
Err(_) => { Err(_) => {
span_bug!( span_bug!(self.span,
self.span, "{} was a subtype of {} but now is not?",
"{} was a subtype of {} but now is not?", self_ty,
self_ty, method_self_ty); method_self_ty);
} }
} }
} }
@ -384,8 +376,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
fn instantiate_method_sig(&mut self, fn instantiate_method_sig(&mut self,
pick: &probe::Pick<'tcx>, pick: &probe::Pick<'tcx>,
all_substs: &'tcx Substs<'tcx>) all_substs: &'tcx Substs<'tcx>)
-> InstantiatedMethodSig<'tcx> -> InstantiatedMethodSig<'tcx> {
{
debug!("instantiate_method_sig(pick={:?}, all_substs={:?})", debug!("instantiate_method_sig(pick={:?}, all_substs={:?})",
pick, pick,
all_substs); all_substs);
@ -393,13 +384,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
// Instantiate the bounds on the method with the // Instantiate the bounds on the method with the
// type/early-bound-regions substitutions performed. There can // type/early-bound-regions substitutions performed. There can
// be no late-bound regions appearing here. // be no late-bound regions appearing here.
let method_predicates = pick.item.as_opt_method().unwrap() let method_predicates = pick.item
.predicates.instantiate(self.tcx, all_substs); .as_opt_method()
let method_predicates = self.normalize_associated_types_in(self.span, .unwrap()
&method_predicates); .predicates
.instantiate(self.tcx, all_substs);
let method_predicates = self.normalize_associated_types_in(self.span, &method_predicates);
debug!("method_predicates after subst = {:?}", debug!("method_predicates after subst = {:?}", method_predicates);
method_predicates);
// Instantiate late-bound regions and substitute the trait // Instantiate late-bound regions and substitute the trait
// parameters into the method type to get the actual method type. // 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 // NB: Instantiate late-bound regions first so that
// `instantiate_type_scheme` can normalize associated types that // `instantiate_type_scheme` can normalize associated types that
// may reference those regions. // may reference those regions.
let method_sig = self.replace_late_bound_regions_with_fresh_var( let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.item
&pick.item.as_opt_method().unwrap().fty.sig); .as_opt_method()
.unwrap()
.fty
.sig);
debug!("late-bound lifetimes from method instantiated, method_sig={:?}", debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
method_sig); method_sig);
let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig); let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig);
debug!("type scheme substituted, method_sig={:?}", debug!("type scheme substituted, method_sig={:?}", method_sig);
method_sig);
InstantiatedMethodSig { InstantiatedMethodSig {
method_sig: method_sig, method_sig: method_sig,
@ -431,9 +425,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
all_substs, all_substs,
method_predicates); method_predicates);
self.add_obligations_for_parameters( self.add_obligations_for_parameters(traits::ObligationCause::misc(self.span, self.body_id),
traits::ObligationCause::misc(self.span, self.body_id), method_predicates);
method_predicates);
// this is a projection from a trait reference, so we have to // this is a projection from a trait reference, so we have to
// make sure that the trait reference inputs are well-formed. // 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() { for (i, &expr) in exprs.iter().rev().enumerate() {
// Count autoderefs. // Count autoderefs.
let autoderef_count = match self.tables let autoderef_count = match self.tables
.borrow() .borrow()
.adjustments .adjustments
.get(&expr.id) { .get(&expr.id) {
Some(&AdjustDerefRef(ref adj)) => adj.autoderefs, Some(&AdjustDerefRef(ref adj)) => adj.autoderefs,
Some(_) | None => 0, Some(_) | None => 0,
}; };
debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?} \ debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?} \
autoderef_count={}", autoderef_count={}",
i, expr, autoderef_count); i,
expr,
autoderef_count);
if autoderef_count > 0 { if autoderef_count > 0 {
let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id)); let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id));
autoderef.nth(autoderef_count).unwrap_or_else(|| { 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_count);
}); });
autoderef.finalize(PreferMutLvalue, Some(expr)); autoderef.finalize(PreferMutLvalue, Some(expr));
@ -508,29 +504,30 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
// (ab)use the normal type checking paths. // (ab)use the normal type checking paths.
let adj = self.tables.borrow().adjustments.get(&base_expr.id).cloned(); let adj = self.tables.borrow().adjustments.get(&base_expr.id).cloned();
let (autoderefs, unsize) = match adj { let (autoderefs, unsize) = match adj {
Some(AdjustDerefRef(adr)) => match adr.autoref { Some(AdjustDerefRef(adr)) => {
None => { match adr.autoref {
assert!(adr.unsize.is_none()); None => {
(adr.autoderefs, 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), None => (0, None),
Some(_) => { Some(_) => {
span_bug!( span_bug!(base_expr.span, "unexpected adjustment type");
base_expr.span,
"unexpected adjustment type");
} }
}; };
@ -538,23 +535,23 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
(target, true) (target, true)
} else { } else {
(self.adjust_expr_ty(base_expr, (self.adjust_expr_ty(base_expr,
Some(&AdjustDerefRef(AutoDerefRef { Some(&AdjustDerefRef(AutoDerefRef {
autoderefs: autoderefs, autoderefs: autoderefs,
autoref: None, autoref: None,
unsize: None unsize: None,
}))), false) }))),
false)
}; };
let index_expr_ty = self.node_ty(index_expr.id); let index_expr_ty = self.node_ty(index_expr.id);
let result = self.try_index_step( let result = self.try_index_step(ty::MethodCall::expr(expr.id),
ty::MethodCall::expr(expr.id), expr,
expr, &base_expr,
&base_expr, adjusted_base_ty,
adjusted_base_ty, autoderefs,
autoderefs, unsize,
unsize, PreferMutLvalue,
PreferMutLvalue, index_expr_ty);
index_expr_ty);
if let Some((input_ty, return_ty)) = result { if let Some((input_ty, return_ty)) = result {
self.demand_suptype(index_expr.span, input_ty, index_expr_ty); 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); let method_call = ty::MethodCall::expr(expr.id);
if self.tables.borrow().method_map.contains_key(&method_call) { if self.tables.borrow().method_map.contains_key(&method_call) {
let method = self.try_overloaded_deref(expr.span, let method = self.try_overloaded_deref(expr.span,
Some(&base_expr), Some(&base_expr),
self.node_ty(base_expr.id), self.node_ty(base_expr.id),
PreferMutLvalue); PreferMutLvalue);
let method = method.expect("re-trying deref failed"); let method = method.expect("re-trying deref failed");
self.tables.borrow_mut().method_map.insert(method_call, method); 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, fn upcast(&mut self,
source_trait_ref: ty::PolyTraitRef<'tcx>, source_trait_ref: ty::PolyTraitRef<'tcx>,
target_trait_def_id: DefId) target_trait_def_id: DefId)
-> ty::PolyTraitRef<'tcx> -> ty::PolyTraitRef<'tcx> {
{ let upcast_trait_refs = self.tcx
let upcast_trait_refs = self.tcx.upcast_choices(source_trait_ref.clone(), .upcast_choices(source_trait_ref.clone(), target_trait_def_id);
target_trait_def_id);
// must be exactly one trait ref or we'd get an ambig error etc // must be exactly one trait ref or we'd get an ambig error etc
if upcast_trait_refs.len() != 1 { if upcast_trait_refs.len() != 1 {
span_bug!( span_bug!(self.span,
self.span, "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
"cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`", source_trait_ref,
source_trait_ref, target_trait_def_id,
target_trait_def_id, upcast_trait_refs);
upcast_trait_refs);
} }
upcast_trait_refs.into_iter().next().unwrap() upcast_trait_refs.into_iter().next().unwrap()
} }
fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &ty::Binder<T>) -> T 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.fcx
self.span, infer::FnCall, value).0 .replace_late_bound_regions_with_fresh_var(self.span, infer::FnCall, value)
.0
} }
} }

View file

@ -41,7 +41,8 @@ pub enum MethodError<'tcx> {
Ambiguity(Vec<CandidateSource>), Ambiguity(Vec<CandidateSource>),
// Using a `Fn`/`FnMut`/etc method on a raw closure type before we have inferred its kind. // 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. // Found an applicable method, but it is not visible.
PrivateMatch(Def), PrivateMatch(Def),
@ -53,19 +54,20 @@ pub struct NoMatchData<'tcx> {
pub static_candidates: Vec<CandidateSource>, pub static_candidates: Vec<CandidateSource>,
pub unsatisfied_predicates: Vec<TraitRef<'tcx>>, pub unsatisfied_predicates: Vec<TraitRef<'tcx>>,
pub out_of_scope_traits: Vec<DefId>, pub out_of_scope_traits: Vec<DefId>,
pub mode: probe::Mode pub mode: probe::Mode,
} }
impl<'tcx> NoMatchData<'tcx> { impl<'tcx> NoMatchData<'tcx> {
pub fn new(static_candidates: Vec<CandidateSource>, pub fn new(static_candidates: Vec<CandidateSource>,
unsatisfied_predicates: Vec<TraitRef<'tcx>>, unsatisfied_predicates: Vec<TraitRef<'tcx>>,
out_of_scope_traits: Vec<DefId>, out_of_scope_traits: Vec<DefId>,
mode: probe::Mode) -> Self { mode: probe::Mode)
-> Self {
NoMatchData { NoMatchData {
static_candidates: static_candidates, static_candidates: static_candidates,
unsatisfied_predicates: unsatisfied_predicates, unsatisfied_predicates: unsatisfied_predicates,
out_of_scope_traits: out_of_scope_traits, 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)] #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum CandidateSource { pub enum CandidateSource {
ImplSource(DefId), ImplSource(DefId),
TraitSource(/* trait id */ DefId), TraitSource(// trait id
DefId),
} }
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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>, self_ty: ty::Ty<'tcx>,
call_expr_id: ast::NodeId, call_expr_id: ast::NodeId,
allow_private: bool) allow_private: bool)
-> bool -> bool {
{
let mode = probe::Mode::MethodCall; let mode = probe::Mode::MethodCall;
match self.probe_method(span, mode, method_name, self_ty, call_expr_id) { match self.probe_method(span, mode, method_name, self_ty, call_expr_id) {
Ok(..) => true, Ok(..) => true,
@ -119,8 +121,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
supplied_method_types: Vec<ty::Ty<'tcx>>, supplied_method_types: Vec<ty::Ty<'tcx>>,
call_expr: &'gcx hir::Expr, call_expr: &'gcx hir::Expr,
self_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={:?})", debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
method_name, method_name,
self_ty, self_ty,
@ -135,7 +136,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.tcx.used_trait_imports.borrow_mut().insert(import_id); 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, pub fn lookup_method_in_trait(&self,
@ -145,10 +151,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
trait_def_id: DefId, trait_def_id: DefId,
self_ty: ty::Ty<'tcx>, self_ty: ty::Ty<'tcx>,
opt_input_types: Option<Vec<ty::Ty<'tcx>>>) opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
-> Option<ty::MethodCallee<'tcx>> -> Option<ty::MethodCallee<'tcx>> {
{ self.lookup_method_in_trait_adjusted(span,
self.lookup_method_in_trait_adjusted(span, self_expr, m_name, trait_def_id, self_expr,
0, false, self_ty, opt_input_types) m_name,
trait_def_id,
0,
false,
self_ty,
opt_input_types)
} }
/// `lookup_in_trait_adjusted` is used for overloaded operators. /// `lookup_in_trait_adjusted` is used for overloaded operators.
@ -171,8 +182,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
unsize: bool, unsize: bool,
self_ty: ty::Ty<'tcx>, self_ty: ty::Ty<'tcx>,
opt_input_types: Option<Vec<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={:?}, \ debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, \
m_name={}, trait_def_id={:?})", m_name={}, trait_def_id={:?})",
self_ty, self_ty,
@ -188,9 +198,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
assert!(trait_def.generics.regions.is_empty()); assert!(trait_def.generics.regions.is_empty());
// Construct a trait-reference `self_ty : Trait<input_tys>` // Construct a trait-reference `self_ty : Trait<input_tys>`
let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| { let substs = Substs::for_item(self.tcx,
self.region_var_for_def(span, def) trait_def_id,
}, |def, substs| { |def, _| self.region_var_for_def(span, def),
|def, substs| {
if def.index == 0 { if def.index == 0 {
self_ty self_ty
} else if let Some(ref input_types) = opt_input_types { } 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 // Construct an obligation
let poly_trait_ref = trait_ref.to_poly_trait_ref(); let poly_trait_ref = trait_ref.to_poly_trait_ref();
let obligation = traits::Obligation::misc(span, let obligation =
self.body_id, traits::Obligation::misc(span, self.body_id, poly_trait_ref.to_predicate());
poly_trait_ref.to_predicate());
// Now we want to know if this can be matched // Now we want to know if this can be matched
let mut selcx = traits::SelectionContext::new(self); 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); assert_eq!(method_ty.generics.regions.len(), 0);
debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}", 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 // Instantiate late-bound regions and substitute the trait
// parameters into the method type to get the actual method type. // 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 // NB: Instantiate late-bound regions first so that
// `instantiate_type_scheme` can normalize associated types that // `instantiate_type_scheme` can normalize associated types that
// may reference those regions. // may reference those regions.
let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, let fn_sig =
infer::FnCall, self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &method_ty.fty.sig)
&method_ty.fty.sig).0; .0;
let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
let transformed_self_ty = fn_sig.inputs[0]; let transformed_self_ty = fn_sig.inputs[0];
let def_id = method_item.def_id(); 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 { tcx.mk_bare_fn(ty::BareFnTy {
sig: ty::Binder(fn_sig), sig: ty::Binder(fn_sig),
unsafety: method_ty.fty.unsafety, unsafety: method_ty.fty.unsafety,
abi: method_ty.fty.abi.clone(), abi: method_ty.fty.abi.clone(),
})); }));
debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}", debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}",
fty, fty,
@ -259,9 +271,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// any late-bound regions appearing in its bounds. // any late-bound regions appearing in its bounds.
let method_bounds = self.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()); assert!(!method_bounds.has_escaping_regions());
self.add_obligations_for_parameters( self.add_obligations_for_parameters(traits::ObligationCause::misc(span, self.body_id),
traits::ObligationCause::misc(span, self.body_id), &method_bounds);
&method_bounds);
// Also register an obligation for the method type being well-formed. // Also register an obligation for the method type being well-formed.
self.register_wf_obligation(fty, span, traits::MiscObligation); 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). // Insert any adjustments needed (always an autoref of some mutability).
match self_expr { match self_expr {
None => { } None => {}
Some(self_expr) => { Some(self_expr) => {
debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ debug!("lookup_in_trait_adjusted: inserting adjustment if needed \
(self-id={}, autoderefs={}, unsize={}, explicit_self={:?})", (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})",
self_expr.id, autoderefs, unsize, self_expr.id,
autoderefs,
unsize,
method_ty.explicit_self); method_ty.explicit_self);
match 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 { match transformed_self_ty.sty {
ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => { ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => {
self.write_adjustment(self_expr.id, self.write_adjustment(self_expr.id,
AdjustDerefRef(AutoDerefRef { AdjustDerefRef(AutoDerefRef {
autoderefs: autoderefs, autoderefs: autoderefs,
autoref: Some(AutoPtr(region, mutbl)), autoref: Some(AutoPtr(region, mutbl)),
unsize: if unsize { unsize: if unsize {
Some(transformed_self_ty) Some(transformed_self_ty)
} else { } else {
None None
} },
})); }));
} }
_ => { _ => {
span_bug!( span_bug!(span,
span, "trait method is &self but first arg is: {}",
"trait method is &self but first arg is: {}", transformed_self_ty);
transformed_self_ty);
} }
} }
} }
_ => { _ => {
span_bug!( span_bug!(span,
span, "unexpected explicit self type in operator method: {:?}",
"unexpected explicit self type in operator method: {:?}", method_ty.explicit_self);
method_ty.explicit_self);
} }
} }
} }
@ -327,7 +338,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let callee = ty::MethodCallee { let callee = ty::MethodCallee {
def_id: def_id, def_id: def_id,
ty: fty, ty: fty,
substs: trait_ref.substs substs: trait_ref.substs,
}; };
debug!("callee = {:?}", callee); debug!("callee = {:?}", callee);
@ -340,8 +351,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
method_name: ast::Name, method_name: ast::Name,
self_ty: ty::Ty<'tcx>, self_ty: ty::Ty<'tcx>,
expr_id: ast::NodeId) expr_id: ast::NodeId)
-> Result<Def, MethodError<'tcx>> -> Result<Def, MethodError<'tcx>> {
{
let mode = probe::Mode::Path; let mode = probe::Mode::Path;
let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?; 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, pub fn impl_or_trait_item(&self,
def_id: DefId, def_id: DefId,
item_name: ast::Name) item_name: ast::Name)
-> Option<ty::ImplOrTraitItem<'tcx>> -> Option<ty::ImplOrTraitItem<'tcx>> {
{ self.tcx
self.tcx.impl_or_trait_items(def_id) .impl_or_trait_items(def_id)
.iter() .iter()
.map(|&did| self.tcx.impl_or_trait_item(did)) .map(|&did| self.tcx.impl_or_trait_item(did))
.find(|m| m.name() == item_name) .find(|m| m.name() == item_name)

View file

@ -13,7 +13,7 @@ use super::NoMatchData;
use super::{CandidateSource, ImplSource, TraitSource}; use super::{CandidateSource, ImplSource, TraitSource};
use super::suggest; use super::suggest;
use check::{FnCtxt}; use check::FnCtxt;
use hir::def_id::DefId; use hir::def_id::DefId;
use hir::def::Def; use hir::def::Def;
use rustc::ty::subst::{Subst, Substs}; use rustc::ty::subst::{Subst, Substs};
@ -31,7 +31,7 @@ use std::rc::Rc;
use self::CandidateKind::*; use self::CandidateKind::*;
pub use self::PickKind::*; 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>, fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
span: Span, span: Span,
mode: Mode, 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 /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
/// for error reporting /// for error reporting
unsatisfied_predicates: Vec<TraitRef<'tcx>> unsatisfied_predicates: Vec<TraitRef<'tcx>>,
} }
impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, '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> { struct CandidateStep<'tcx> {
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
autoderefs: usize, autoderefs: usize,
unsize: bool unsize: bool,
} }
#[derive(Debug)] #[derive(Debug)]
@ -80,12 +80,17 @@ struct Candidate<'tcx> {
#[derive(Debug)] #[derive(Debug)]
enum CandidateKind<'tcx> { enum CandidateKind<'tcx> {
InherentImplCandidate(&'tcx Substs<'tcx>, InherentImplCandidate(&'tcx Substs<'tcx>,
/* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>), // Normalize obligations
ExtensionImplCandidate(/* Impl */ DefId, &'tcx Substs<'tcx>, Vec<traits::PredicateObligation<'tcx>>),
/* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>), ExtensionImplCandidate(// Impl
DefId,
&'tcx Substs<'tcx>,
// Normalize obligations
Vec<traits::PredicateObligation<'tcx>>),
ObjectCandidate, ObjectCandidate,
TraitCandidate, TraitCandidate,
WhereClauseCandidate(/* Trait */ ty::PolyTraitRef<'tcx>), WhereClauseCandidate(// Trait
ty::PolyTraitRef<'tcx>),
} }
#[derive(Debug)] #[derive(Debug)]
@ -115,10 +120,12 @@ pub struct Pick<'tcx> {
#[derive(Clone,Debug)] #[derive(Clone,Debug)]
pub enum PickKind<'tcx> { pub enum PickKind<'tcx> {
InherentImplPick, InherentImplPick,
ExtensionImplPick(/* Impl */ DefId), ExtensionImplPick(// Impl
DefId),
ObjectPick, ObjectPick,
TraitPick, TraitPick,
WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>), WhereClausePick(// Trait
ty::PolyTraitRef<'tcx>),
} }
pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError<'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`. // An expression of the form `Type::item` or `<T>::item`.
// No autoderefs are performed, lookup is done based on the type each // No autoderefs are performed, lookup is done based on the type each
// implementation is for, and static methods are included. // implementation is for, and static methods are included.
Path Path,
} }
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
@ -142,8 +149,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
item_name: ast::Name, item_name: ast::Name,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
scope_expr_id: ast::NodeId) scope_expr_id: ast::NodeId)
-> PickResult<'tcx> -> PickResult<'tcx> {
{
debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})", debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})",
self_ty, self_ty,
item_name, item_name,
@ -159,31 +165,38 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let steps = if mode == Mode::MethodCall { let steps = if mode == Mode::MethodCall {
match self.create_steps(span, self_ty) { match self.create_steps(span, self_ty) {
Some(steps) => steps, Some(steps) => steps,
None =>return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), Vec::new(), None => {
Vec::new(), mode))), return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(),
Vec::new(),
Vec::new(),
mode)))
}
} }
} else { } else {
vec![CandidateStep { vec![CandidateStep {
self_ty: self_ty, self_ty: self_ty,
autoderefs: 0, autoderefs: 0,
unsize: false unsize: false,
}] }]
}; };
// Create a list of simplified self types, if we can. // Create a list of simplified self types, if we can.
let mut simplified_steps = Vec::new(); let mut simplified_steps = Vec::new();
for step in &steps { for step in &steps {
match ty::fast_reject::simplify_type(self.tcx, step.self_ty, true) { match ty::fast_reject::simplify_type(self.tcx, step.self_ty, true) {
None => { break; } None => {
Some(simplified_type) => { simplified_steps.push(simplified_type); } break;
}
Some(simplified_type) => {
simplified_steps.push(simplified_type);
}
} }
} }
let opt_simplified_steps = let opt_simplified_steps = if simplified_steps.len() < steps.len() {
if simplified_steps.len() < steps.len() { None // failed to convert at least one of the steps
None // failed to convert at least one of the steps } else {
} else { Some(simplified_steps)
Some(simplified_steps) };
};
debug!("ProbeContext: steps for self_ty={:?} are {:?}", debug!("ProbeContext: steps for self_ty={:?} are {:?}",
self_ty, 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 // this creates one big transaction so that all type variables etc
// that we create during the probe process are removed later // that we create during the probe process are removed later
self.probe(|_| { self.probe(|_| {
let mut probe_cx = ProbeContext::new(self, let mut probe_cx =
span, ProbeContext::new(self, span, mode, item_name, steps, opt_simplified_steps);
mode,
item_name,
steps,
opt_simplified_steps);
probe_cx.assemble_inherent_candidates(); probe_cx.assemble_inherent_candidates();
probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?; probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?;
probe_cx.pick() probe_cx.pick()
}) })
} }
fn create_steps(&self, fn create_steps(&self, span: Span, self_ty: Ty<'tcx>) -> Option<Vec<CandidateStep<'tcx>>> {
span: Span,
self_ty: Ty<'tcx>)
-> Option<Vec<CandidateStep<'tcx>>>
{
// FIXME: we don't need to create the entire steps in one pass // FIXME: we don't need to create the entire steps in one pass
let mut autoderef = self.autoderef(span, self_ty); let mut autoderef = self.autoderef(span, self_ty);
let mut steps: Vec<_> = autoderef.by_ref().map(|(ty, d)| CandidateStep { let mut steps: Vec<_> = autoderef.by_ref()
self_ty: ty, .map(|(ty, d)| {
autoderefs: d, CandidateStep {
unsize: false self_ty: ty,
}).collect(); autoderefs: d,
unsize: false,
}
})
.collect();
let final_ty = autoderef.unambiguous_final_ty(); let final_ty = autoderef.unambiguous_final_ty();
match final_ty.sty { match final_ty.sty {
@ -226,7 +235,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
steps.push(CandidateStep { steps.push(CandidateStep {
self_ty: self.tcx.mk_slice(elem_ty), self_ty: self.tcx.mk_slice(elem_ty),
autoderefs: dereferences, autoderefs: dereferences,
unsize: true unsize: true,
}); });
} }
ty::TyError => return None, ty::TyError => return None,
@ -246,8 +255,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
item_name: ast::Name, item_name: ast::Name,
steps: Vec<CandidateStep<'tcx>>, steps: Vec<CandidateStep<'tcx>>,
opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>) opt_simplified_steps: Option<Vec<ty::fast_reject::SimplifiedType>>)
-> ProbeContext<'a, 'gcx, 'tcx> -> ProbeContext<'a, 'gcx, 'tcx> {
{
ProbeContext { ProbeContext {
fcx: fcx, fcx: fcx,
span: span, span: span,
@ -284,8 +292,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
} }
fn assemble_probe(&mut self, self_ty: Ty<'tcx>) { fn assemble_probe(&mut self, self_ty: Ty<'tcx>) {
debug!("assemble_probe: self_ty={:?}", debug!("assemble_probe: self_ty={:?}", self_ty);
self_ty);
match self_ty.sty { match self_ty.sty {
ty::TyTrait(box ref data) => { 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(); let lang_def_id = self.tcx.lang_items.f64_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id); self.assemble_inherent_impl_for_primitive(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) { let item = match self.impl_or_trait_item(impl_def_id) {
Some(m) => m, 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) { 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) { if !item.vis().is_accessible_from(self.body_id, &self.tcx.map) {
self.private_candidate = Some(item.def()); self.private_candidate = Some(item.def());
return return;
} }
let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); 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| { self.elaborate_bounds(&[trait_ref], |this, new_trait_ref, item| {
let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref); let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
let xform_self_ty = this.xform_self_ty(&item, let xform_self_ty =
new_trait_ref.self_ty(), this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs);
new_trait_ref.substs);
this.inherent_candidates.push(Candidate { this.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty, xform_self_ty: xform_self_ty,
@ -476,8 +483,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
param_ty: ty::ParamTy) { param_ty: ty::ParamTy) {
// FIXME -- Do we want to commit to this behavior for param bounds? // FIXME -- Do we want to commit to this behavior for param bounds?
let bounds: Vec<_> = let bounds: Vec<_> = self.parameter_environment
self.parameter_environment.caller_bounds .caller_bounds
.iter() .iter()
.filter_map(|predicate| { .filter_map(|predicate| {
match *predicate { match *predicate {
@ -486,7 +493,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
ty::TyParam(ref p) if *p == param_ty => { ty::TyParam(ref p) if *p == param_ty => {
Some(trait_predicate.to_poly_trait_ref()) Some(trait_predicate.to_poly_trait_ref())
} }
_ => None _ => None,
} }
} }
ty::Predicate::Equate(..) | ty::Predicate::Equate(..) |
@ -495,21 +502,15 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
ty::Predicate::WellFormed(..) | ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) | ty::Predicate::ObjectSafe(..) |
ty::Predicate::ClosureKind(..) | ty::Predicate::ClosureKind(..) |
ty::Predicate::TypeOutlives(..) => { ty::Predicate::TypeOutlives(..) => None,
None
}
} }
}) })
.collect(); .collect();
self.elaborate_bounds(&bounds, |this, poly_trait_ref, item| { self.elaborate_bounds(&bounds, |this, poly_trait_ref, item| {
let trait_ref = let trait_ref = this.erase_late_bound_regions(&poly_trait_ref);
this.erase_late_bound_regions(&poly_trait_ref);
let xform_self_ty = let xform_self_ty = this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs);
this.xform_self_ty(&item,
trait_ref.self_ty(),
trait_ref.substs);
if let Some(ref m) = item.as_opt_method() { if let Some(ref m) = item.as_opt_method() {
debug!("found match: trait_ref={:?} substs={:?} m={:?}", 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 // Do a search through a list of bounds, using a callback to actually
// create the candidates. // create the candidates.
fn elaborate_bounds<F>( fn elaborate_bounds<F>(&mut self, bounds: &[ty::PolyTraitRef<'tcx>], mut mk_cand: F)
&mut self, where F: for<'b> FnMut(&mut ProbeContext<'b, 'gcx, 'tcx>,
bounds: &[ty::PolyTraitRef<'tcx>], ty::PolyTraitRef<'tcx>,
mut mk_cand: F, ty::ImplOrTraitItem<'tcx>)
) where
F: for<'b> FnMut(
&mut ProbeContext<'b, 'gcx, 'tcx>,
ty::PolyTraitRef<'tcx>,
ty::ImplOrTraitItem<'tcx>,
),
{ {
debug!("elaborate_bounds(bounds={:?})", bounds); 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) { for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
let item = match self.impl_or_trait_item(bound_trait_ref.def_id()) { let item = match self.impl_or_trait_item(bound_trait_ref.def_id()) {
Some(v) => v, Some(v) => v,
None => { continue; } None => {
continue;
}
}; };
if !self.has_applicable_self(&item) { 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, fn assemble_extension_candidates_for_traits_in_scope(&mut self,
expr_id: ast::NodeId) expr_id: ast::NodeId)
-> Result<(), MethodError<'tcx>> -> Result<(), MethodError<'tcx>> {
{
let mut duplicates = FnvHashSet(); let mut duplicates = FnvHashSet();
let opt_applicable_traits = self.tcx.trait_map.get(&expr_id); let opt_applicable_traits = self.tcx.trait_map.get(&expr_id);
if let Some(applicable_traits) = opt_applicable_traits { 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, fn assemble_extension_candidates_for_trait(&mut self,
trait_def_id: DefId) trait_def_id: DefId)
-> Result<(), MethodError<'tcx>> -> Result<(), MethodError<'tcx>> {
{
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})",
trait_def_id); trait_def_id);
// Check whether `trait_def_id` defines a method with suitable name: // Check whether `trait_def_id` defines a method with suitable name:
let trait_items = let trait_items = self.tcx.trait_items(trait_def_id);
self.tcx.trait_items(trait_def_id); let maybe_item = trait_items.iter()
let maybe_item = .find(|item| item.name() == self.item_name);
trait_items.iter()
.find(|item| item.name() == self.item_name);
let item = match maybe_item { let item = match maybe_item {
Some(i) => i, Some(i) => i,
None => { return Ok(()); } None => {
return Ok(());
}
}; };
// Check whether `trait_def_id` defines a method with suitable name: // 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, fn assemble_extension_candidates_for_trait_impls(&mut self,
trait_def_id: DefId, trait_def_id: DefId,
item: ty::ImplOrTraitItem<'tcx>) item: ty::ImplOrTraitItem<'tcx>) {
{
let trait_def = self.tcx.lookup_trait_def(trait_def_id); let trait_def = self.tcx.lookup_trait_def(trait_def_id);
// FIXME(arielb1): can we use for_each_relevant_impl here? // 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); debug!("impl_substs={:?}", impl_substs);
let impl_trait_ref = let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id)
self.tcx.impl_trait_ref(impl_def_id)
.unwrap() // we know this is a trait impl .unwrap() // we know this is a trait impl
.subst(self.tcx, impl_substs); .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. // Determine the receiver type that the method itself expects.
let xform_self_ty = let xform_self_ty =
self.xform_self_ty(&item, self.xform_self_ty(&item, impl_trait_ref.self_ty(), impl_trait_ref.substs);
impl_trait_ref.self_ty(),
impl_trait_ref.substs);
// Normalize the receiver. We can't use normalize_associated_types_in // Normalize the receiver. We can't use normalize_associated_types_in
// as it will pollute the fcx's fulfillment context after this probe // 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 { fn impl_can_possibly_match(&self, impl_def_id: DefId) -> bool {
let simplified_steps = match self.opt_simplified_steps { let simplified_steps = match self.opt_simplified_steps {
Some(ref simplified_steps) => 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_type = self.tcx.lookup_item_type(impl_def_id);
let impl_simplified_type = let impl_simplified_type =
match ty::fast_reject::simplify_type(self.tcx, impl_type.ty, false) { match ty::fast_reject::simplify_type(self.tcx, impl_type.ty, false) {
Some(simplified_type) => simplified_type, Some(simplified_type) => simplified_type,
None => { return true; } None => {
return true;
}
}; };
simplified_steps.contains(&impl_simplified_type) simplified_steps.contains(&impl_simplified_type)
@ -706,8 +701,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
fn assemble_closure_candidates(&mut self, fn assemble_closure_candidates(&mut self,
trait_def_id: DefId, trait_def_id: DefId,
item: ty::ImplOrTraitItem<'tcx>) item: ty::ImplOrTraitItem<'tcx>)
-> Result<(), MethodError<'tcx>> -> Result<(), MethodError<'tcx>> {
{
// Check if this is one of the Fn,FnMut,FnOnce traits. // Check if this is one of the Fn,FnMut,FnOnce traits.
let tcx = self.tcx; let tcx = self.tcx;
let kind = if Some(trait_def_id) == tcx.lang_items.fn_trait() { 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 // for the purposes of our method lookup, we only take
// receiver type into account, so we can just substitute // receiver type into account, so we can just substitute
// fresh types here to use during substitution and subtyping. // fresh types here to use during substitution and subtyping.
let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| { let substs = Substs::for_item(self.tcx,
self.region_var_for_def(self.span, def) trait_def_id,
}, |def, substs| { |def, _| self.region_var_for_def(self.span, def),
|def, substs| {
if def.index == 0 { if def.index == 0 {
step.self_ty step.self_ty
} else { } else {
@ -756,9 +751,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
} }
}); });
let xform_self_ty = self.xform_self_ty(&item, let xform_self_ty = self.xform_self_ty(&item, step.self_ty, substs);
step.self_ty,
substs);
self.inherent_candidates.push(Candidate { self.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty, xform_self_ty: xform_self_ty,
item: item.clone(), item: item.clone(),
@ -772,8 +765,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
fn assemble_projection_candidates(&mut self, fn assemble_projection_candidates(&mut self,
trait_def_id: DefId, trait_def_id: DefId,
item: ty::ImplOrTraitItem<'tcx>) item: ty::ImplOrTraitItem<'tcx>) {
{
debug!("assemble_projection_candidates(\ debug!("assemble_projection_candidates(\
trait_def_id={:?}, \ trait_def_id={:?}, \
item={:?})", item={:?})",
@ -781,39 +773,35 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
item); item);
for step in self.steps.iter() { for step in self.steps.iter() {
debug!("assemble_projection_candidates: step={:?}", debug!("assemble_projection_candidates: step={:?}", step);
step);
let (def_id, substs) = match step.self_ty.sty { let (def_id, substs) = match step.self_ty.sty {
ty::TyProjection(ref data) => { ty::TyProjection(ref data) => (data.trait_ref.def_id, data.trait_ref.substs),
(data.trait_ref.def_id, data.trait_ref.substs)
}
ty::TyAnon(def_id, substs) => (def_id, substs), ty::TyAnon(def_id, substs) => (def_id, substs),
_ => continue, _ => continue,
}; };
debug!("assemble_projection_candidates: def_id={:?} substs={:?}", debug!("assemble_projection_candidates: def_id={:?} substs={:?}",
def_id, substs); def_id,
substs);
let trait_predicates = self.tcx.lookup_predicates(def_id); let trait_predicates = self.tcx.lookup_predicates(def_id);
let bounds = trait_predicates.instantiate(self.tcx, substs); let bounds = trait_predicates.instantiate(self.tcx, substs);
let predicates = bounds.predicates; let predicates = bounds.predicates;
debug!("assemble_projection_candidates: predicates={:?}", debug!("assemble_projection_candidates: predicates={:?}",
predicates); predicates);
for poly_bound in for poly_bound in traits::elaborate_predicates(self.tcx, predicates)
traits::elaborate_predicates(self.tcx, predicates)
.filter_map(|p| p.to_opt_poly_trait_ref()) .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); let bound = self.erase_late_bound_regions(&poly_bound);
debug!("assemble_projection_candidates: def_id={:?} substs={:?} 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() { if self.can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
let xform_self_ty = self.xform_self_ty(&item, let xform_self_ty = self.xform_self_ty(&item, bound.self_ty(), bound.substs);
bound.self_ty(),
bound.substs);
debug!("assemble_projection_candidates: bound={:?} xform_self_ty={:?}", debug!("assemble_projection_candidates: bound={:?} xform_self_ty={:?}",
bound, bound,
@ -832,20 +820,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
fn assemble_where_clause_candidates(&mut self, fn assemble_where_clause_candidates(&mut self,
trait_def_id: DefId, trait_def_id: DefId,
item: ty::ImplOrTraitItem<'tcx>) item: ty::ImplOrTraitItem<'tcx>) {
{
debug!("assemble_where_clause_candidates(trait_def_id={:?})", debug!("assemble_where_clause_candidates(trait_def_id={:?})",
trait_def_id); trait_def_id);
let caller_predicates = self.parameter_environment.caller_bounds.clone(); let caller_predicates = self.parameter_environment.caller_bounds.clone();
for poly_bound in traits::elaborate_predicates(self.tcx, caller_predicates) for poly_bound in traits::elaborate_predicates(self.tcx, caller_predicates)
.filter_map(|p| p.to_opt_poly_trait_ref()) .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); let bound = self.erase_late_bound_regions(&poly_bound);
let xform_self_ty = self.xform_self_ty(&item, let xform_self_ty = self.xform_self_ty(&item, bound.self_ty(), bound.substs);
bound.self_ty(),
bound.substs);
debug!("assemble_where_clause_candidates: bound={:?} xform_self_ty={:?}", debug!("assemble_where_clause_candidates: bound={:?} xform_self_ty={:?}",
bound, bound,
@ -882,19 +866,24 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
let out_of_scope_traits = match self.pick_core() { let out_of_scope_traits = match self.pick_core() {
Some(Ok(p)) => vec![p.item.container().id()], Some(Ok(p)) => vec![p.item.container().id()],
Some(Err(MethodError::Ambiguity(v))) => v.into_iter().map(|source| { Some(Err(MethodError::Ambiguity(v))) => {
match source { v.into_iter()
TraitSource(id) => id, .map(|source| {
ImplSource(impl_id) => { match source {
match tcx.trait_id_of_impl(impl_id) { TraitSource(id) => id,
Some(id) => id, ImplSource(impl_id) => {
None => match tcx.trait_id_of_impl(impl_id) {
span_bug!(span, Some(id) => id,
"found inherent method when looking at traits") None => {
span_bug!(span,
"found inherent method when looking at traits")
}
}
}
} }
} })
} .collect()
}).collect(), }
Some(Err(MethodError::NoMatch(NoMatchData { out_of_scope_traits: others, .. }))) => { Some(Err(MethodError::NoMatch(NoMatchData { out_of_scope_traits: others, .. }))) => {
assert!(others.is_empty()); assert!(others.is_empty());
vec![] vec![]
@ -910,8 +899,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
return Err(MethodError::PrivateMatch(def)); return Err(MethodError::PrivateMatch(def));
} }
Err(MethodError::NoMatch(NoMatchData::new(static_candidates, unsatisfied_predicates, Err(MethodError::NoMatch(NoMatchData::new(static_candidates,
out_of_scope_traits, self.mode))) unsatisfied_predicates,
out_of_scope_traits,
self.mode)))
} }
fn pick_core(&mut self) -> Option<PickResult<'tcx>> { 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) self.pick_autorefd_method(step)
} }
fn pick_by_value_method(&mut self, fn pick_by_value_method(&mut self, step: &CandidateStep<'tcx>) -> Option<PickResult<'tcx>> {
step: &CandidateStep<'tcx>) //! For each type `T` in the step list, this attempts to find a
-> Option<PickResult<'tcx>> //! 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
* For each type `T` in the step list, this attempts to find a //! *reborrow* it to a shorter lifetime. This allows us to
* method where the (transformed) self type is exactly `T`. We //! transparently pass `&mut` pointers, in particular, without
* do however do one transformation on the adjustment: if we //! consuming them for their entire lifetime.
* 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 { if step.unsize {
return None; return None;
} }
self.pick_method(step.self_ty).map(|r| r.map(|mut pick| { self.pick_method(step.self_ty).map(|r| {
pick.autoderefs = step.autoderefs; r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
// Insert a `&*` or `&mut *` if this is a reference type: // Insert a `&*` or `&mut *` if this is a reference type:
if let ty::TyRef(_, mt) = step.self_ty.sty { if let ty::TyRef(_, mt) = step.self_ty.sty {
pick.autoderefs += 1; pick.autoderefs += 1;
pick.autoref = Some(mt.mutbl); pick.autoref = Some(mt.mutbl);
} }
pick pick
})) })
})
} }
fn pick_autorefd_method(&mut self, fn pick_autorefd_method(&mut self, step: &CandidateStep<'tcx>) -> Option<PickResult<'tcx>> {
step: &CandidateStep<'tcx>)
-> Option<PickResult<'tcx>>
{
let tcx = self.tcx; let tcx = self.tcx;
// In general, during probing we erase regions. See // 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); let region = tcx.mk_region(ty::ReErased);
// Search through mutabilities in order to find one where pick works: // Search through mutabilities in order to find one where pick works:
[hir::MutImmutable, hir::MutMutable].iter().filter_map(|&m| { [hir::MutImmutable, hir::MutMutable]
let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { .iter()
ty: step.self_ty, .filter_map(|&m| {
mutbl: m let autoref_ty = tcx.mk_ref(region,
}); ty::TypeAndMut {
self.pick_method(autoref_ty).map(|r| r.map(|mut pick| { ty: step.self_ty,
pick.autoderefs = step.autoderefs; mutbl: m,
pick.autoref = Some(m); });
pick.unsize = if step.unsize { self.pick_method(autoref_ty).map(|r| {
Some(step.self_ty) r.map(|mut pick| {
} else { pick.autoderefs = step.autoderefs;
None pick.autoref = Some(m);
}; pick.unsize = if step.unsize {
pick Some(step.self_ty)
})) } else {
}).nth(0) None
};
pick
})
})
})
.nth(0)
} }
fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> { 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"); 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); &mut possibly_unsatisfied_predicates);
if let None = res { if let None = res {
self.unsatisfied_predicates.extend(possibly_unsatisfied_predicates); self.unsatisfied_predicates.extend(possibly_unsatisfied_predicates);
@ -1021,18 +1013,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
probes: &[Candidate<'tcx>], probes: &[Candidate<'tcx>],
possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>) possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>)
-> Option<PickResult<'tcx>> { -> Option<PickResult<'tcx>> {
let mut applicable_candidates: Vec<_> = let mut applicable_candidates: Vec<_> = probes.iter()
probes.iter() .filter(|&probe| self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates))
.filter(|&probe| self.consider_probe(self_ty, .collect();
probe,possibly_unsatisfied_predicates))
.collect();
debug!("applicable_candidates: {:?}", applicable_candidates); debug!("applicable_candidates: {:?}", applicable_candidates);
if applicable_candidates.len() > 1 { if applicable_candidates.len() > 1 {
match self.collapse_candidates_to_trait_pick(&applicable_candidates[..]) { match self.collapse_candidates_to_trait_pick(&applicable_candidates[..]) {
Some(pick) => { return Some(Ok(pick)); } Some(pick) => {
None => { } return Some(Ok(pick));
}
None => {}
} }
} }
@ -1041,21 +1033,22 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
return Some(Err(MethodError::Ambiguity(sources))); return Some(Err(MethodError::Ambiguity(sources)));
} }
applicable_candidates.pop().map(|probe| { applicable_candidates.pop().map(|probe| Ok(probe.to_unadjusted_pick()))
Ok(probe.to_unadjusted_pick())
})
} }
fn consider_probe(&self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>, fn consider_probe(&self,
possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>) -> bool { self_ty: Ty<'tcx>,
debug!("consider_probe: self_ty={:?} probe={:?}", probe: &Candidate<'tcx>,
self_ty, possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>)
probe); -> bool {
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
self.probe(|_| { self.probe(|_| {
// First check that the self type can be related. // First check that the self type can be related.
match self.sub_types(false, TypeOrigin::Misc(DUMMY_SP), match self.sub_types(false,
self_ty, probe.xform_self_ty) { TypeOrigin::Misc(DUMMY_SP),
self_ty,
probe.xform_self_ty) {
Ok(InferOk { obligations, .. }) => { Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations // FIXME(#32730) propagate obligations
assert!(obligations.is_empty()) 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. // Check whether the impl imposes obligations we have to worry about.
let impl_bounds = self.tcx.lookup_predicates(impl_def_id); let impl_bounds = self.tcx.lookup_predicates(impl_def_id);
let impl_bounds = impl_bounds.instantiate(self.tcx, substs); let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
let traits::Normalized { value: impl_bounds, let traits::Normalized { value: impl_bounds, obligations: norm_obligations } =
obligations: norm_obligations } =
traits::normalize(selcx, cause.clone(), &impl_bounds); traits::normalize(selcx, cause.clone(), &impl_bounds);
// Convert the bounds into obligations. // Convert the bounds into obligations.
let obligations = let obligations = traits::predicates_for_generics(cause.clone(), &impl_bounds);
traits::predicates_for_generics(cause.clone(),
&impl_bounds);
debug!("impl_obligations={:?}", obligations); debug!("impl_obligations={:?}", obligations);
// Evaluate those obligations to see if they might possibly hold. // 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 /// 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". /// use, so it's ok to just commit to "using the method from the trait Foo".
fn collapse_candidates_to_trait_pick(&self, fn collapse_candidates_to_trait_pick(&self, probes: &[&Candidate<'tcx>]) -> Option<Pick<'tcx>> {
probes: &[&Candidate<'tcx>])
-> Option<Pick<'tcx>> {
// Do all probes correspond to the same trait? // Do all probes correspond to the same trait?
let container = probes[0].item.container(); let container = probes[0].item.container();
match container { match container {
ty::TraitContainer(_) => {} ty::TraitContainer(_) => {}
ty::ImplContainer(_) => return None ty::ImplContainer(_) => return None,
} }
if probes[1..].iter().any(|p| p.item.container() != container) { if probes[1..].iter().any(|p| p.item.container() != container) {
return None; return None;
@ -1156,7 +1144,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
import_id: probes[0].import_id, import_id: probes[0].import_id,
autoderefs: 0, autoderefs: 0,
autoref: None, 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 { fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool {
// "fast track" -- check for usage of sugar // "fast track" -- check for usage of sugar
match *item { match *item {
ty::ImplOrTraitItem::MethodTraitItem(ref method) => ty::ImplOrTraitItem::MethodTraitItem(ref method) => {
match method.explicit_self { match method.explicit_self {
ty::ExplicitSelfCategory::Static => self.mode == Mode::Path, ty::ExplicitSelfCategory::Static => self.mode == Mode::Path,
ty::ExplicitSelfCategory::ByValue | ty::ExplicitSelfCategory::ByValue |
ty::ExplicitSelfCategory::ByReference(..) | ty::ExplicitSelfCategory::ByReference(..) |
ty::ExplicitSelfCategory::ByBox => true, ty::ExplicitSelfCategory::ByBox => true,
}, }
}
ty::ImplOrTraitItem::ConstTraitItem(..) => self.mode == Mode::Path, ty::ImplOrTraitItem::ConstTraitItem(..) => self.mode == Mode::Path,
_ => false, _ => false,
} }
@ -1191,11 +1180,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
item: &ty::ImplOrTraitItem<'tcx>, item: &ty::ImplOrTraitItem<'tcx>,
impl_ty: Ty<'tcx>, impl_ty: Ty<'tcx>,
substs: &Substs<'tcx>) substs: &Substs<'tcx>)
-> Ty<'tcx> -> Ty<'tcx> {
{
match item.as_opt_method() { match item.as_opt_method() {
Some(ref method) => self.xform_method_self_ty(method, impl_ty, Some(ref method) => self.xform_method_self_ty(method, impl_ty, substs),
substs),
None => impl_ty, None => impl_ty,
} }
} }
@ -1204,8 +1191,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
method: &Rc<ty::Method<'tcx>>, method: &Rc<ty::Method<'tcx>>,
impl_ty: Ty<'tcx>, impl_ty: Ty<'tcx>,
substs: &Substs<'tcx>) substs: &Substs<'tcx>)
-> Ty<'tcx> -> Ty<'tcx> {
{
debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})", debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})",
impl_ty, impl_ty,
method.fty.sig.0.inputs.get(0), 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 // are given do not include type/lifetime parameters for the
// method yet. So create fresh variables here for those too, // method yet. So create fresh variables here for those too,
// if there are any. // if there are any.
assert_eq!(substs.types().count(), method.generics.parent_types as usize); assert_eq!(substs.types().count(),
assert_eq!(substs.regions().count(), method.generics.parent_regions as usize); method.generics.parent_types as usize);
assert_eq!(substs.regions().count(),
method.generics.parent_regions as usize);
if self.mode == Mode::Path { if self.mode == Mode::Path {
return impl_ty; 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() { if method.generics.types.is_empty() && method.generics.regions.is_empty() {
xform_self_ty.subst(self.tcx, substs) xform_self_ty.subst(self.tcx, substs)
} else { } 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; let i = def.index as usize;
if i < substs.params().len() { if i < substs.params().len() {
substs.region_at(i) substs.region_at(i)
@ -1242,7 +1232,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
// `impl_self_ty()` for an explanation. // `impl_self_ty()` for an explanation.
self.tcx.mk_region(ty::ReErased) self.tcx.mk_region(ty::ReErased)
} }
}, |def, cur_substs| { },
|def, cur_substs| {
let i = def.index as usize; let i = def.index as usize;
if i < substs.params().len() { if i < substs.params().len() {
substs.type_at(i) 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. /// Get the type of an impl and generate substitutions with placeholders.
fn impl_ty_and_substs(&self, fn impl_ty_and_substs(&self, impl_def_id: DefId) -> (Ty<'tcx>, &'tcx Substs<'tcx>) {
impl_def_id: DefId)
-> (Ty<'tcx>, &'tcx Substs<'tcx>)
{
let impl_ty = self.tcx.lookup_item_type(impl_def_id).ty; 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.tcx.mk_region(ty::ReErased),
|_, _| self.next_ty_var()); |_, _| self.next_ty_var());
@ -1287,16 +1276,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
/// and/or tracking the substitution and /// and/or tracking the substitution and
/// so forth. /// so forth.
fn erase_late_bound_regions<T>(&self, value: &ty::Binder<T>) -> T 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) self.tcx.erase_late_bound_regions(value)
} }
/// Find item with name `item_name` defined in impl/trait `def_id` /// Find item with name `item_name` defined in impl/trait `def_id`
/// and return it, or `None`, if no such item was defined there. /// and return it, or `None`, if no such item was defined there.
fn impl_or_trait_item(&self, def_id: DefId) fn impl_or_trait_item(&self, def_id: DefId) -> Option<ty::ImplOrTraitItem<'tcx>> {
-> Option<ty::ImplOrTraitItem<'tcx>>
{
self.fcx.impl_or_trait_item(def_id, self.item_name) self.fcx.impl_or_trait_item(def_id, self.item_name)
} }
} }
@ -1307,9 +1294,7 @@ impl<'tcx> Candidate<'tcx> {
item: self.item.clone(), item: self.item.clone(),
kind: match self.kind { kind: match self.kind {
InherentImplCandidate(..) => InherentImplPick, InherentImplCandidate(..) => InherentImplPick,
ExtensionImplCandidate(def_id, ..) => { ExtensionImplCandidate(def_id, ..) => ExtensionImplPick(def_id),
ExtensionImplPick(def_id)
}
ObjectCandidate => ObjectPick, ObjectCandidate => ObjectPick,
TraitCandidate => TraitPick, TraitCandidate => TraitPick,
WhereClauseCandidate(ref trait_ref) => { WhereClauseCandidate(ref trait_ref) => {
@ -1326,15 +1311,13 @@ impl<'tcx> Candidate<'tcx> {
import_id: self.import_id, import_id: self.import_id,
autoderefs: 0, autoderefs: 0,
autoref: None, autoref: None,
unsize: None unsize: None,
} }
} }
fn to_source(&self) -> CandidateSource { fn to_source(&self) -> CandidateSource {
match self.kind { match self.kind {
InherentImplCandidate(..) => { InherentImplCandidate(..) => ImplSource(self.item.container().id()),
ImplSource(self.item.container().id())
}
ExtensionImplCandidate(def_id, ..) => ImplSource(def_id), ExtensionImplCandidate(def_id, ..) => ImplSource(def_id),
ObjectCandidate | ObjectCandidate |
TraitCandidate | TraitCandidate |

View file

@ -13,7 +13,7 @@
use CrateCtxt; use CrateCtxt;
use check::{FnCtxt}; use check::FnCtxt;
use rustc::hir::map as hir_map; use rustc::hir::map as hir_map;
use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable}; use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
use hir::def::Def; use hir::def::Def;
@ -21,7 +21,7 @@ use hir::def_id::{CRATE_DEF_INDEX, DefId};
use middle::lang_items::FnOnceTraitLangItem; use middle::lang_items::FnOnceTraitLangItem;
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
use rustc::traits::{Obligation, SelectionContext}; use rustc::traits::{Obligation, SelectionContext};
use util::nodemap::{FnvHashSet}; use util::nodemap::FnvHashSet;
use syntax::ast; use syntax::ast;
use errors::DiagnosticBuilder; use errors::DiagnosticBuilder;
@ -43,25 +43,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
match ty.sty { match ty.sty {
// Not all of these (e.g. unsafe fns) implement FnOnce // Not all of these (e.g. unsafe fns) implement FnOnce
// so we look for these beforehand // 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 // If it's not a simple function, look for things which implement FnOnce
_ => { _ => {
let fn_once = match tcx.lang_items.require(FnOnceTraitLangItem) { let fn_once = match tcx.lang_items.require(FnOnceTraitLangItem) {
Ok(fn_once) => fn_once, Ok(fn_once) => fn_once,
Err(..) => return false Err(..) => return false,
}; };
self.autoderef(span, ty).any(|(ty, _)| self.probe(|_| { self.autoderef(span, ty).any(|(ty, _)| {
let fn_once_substs = self.probe(|_| {
Substs::new_trait(tcx, ty, &[self.next_ty_var()]); 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 trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
let poly_trait_ref = trait_ref.to_poly_trait_ref(); let poly_trait_ref = trait_ref.to_poly_trait_ref();
let obligation = Obligation::misc(span, let obligation =
self.body_id, Obligation::misc(span, self.body_id, poly_trait_ref.to_predicate());
poly_trait_ref SelectionContext::new(self).evaluate_obligation(&obligation)
.to_predicate()); })
SelectionContext::new(self).evaluate_obligation(&obligation) })
}))
} }
} }
} }
@ -71,15 +72,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
rcvr_ty: Ty<'tcx>, rcvr_ty: Ty<'tcx>,
item_name: ast::Name, item_name: ast::Name,
rcvr_expr: Option<&hir::Expr>, rcvr_expr: Option<&hir::Expr>,
error: MethodError<'tcx>) error: MethodError<'tcx>) {
{
// avoid suggestions when we don't know what's going on. // avoid suggestions when we don't know what's going on.
if rcvr_ty.references_error() { if rcvr_ty.references_error() {
return return;
} }
let report_candidates = |err: &mut DiagnosticBuilder, let report_candidates = |err: &mut DiagnosticBuilder, mut sources: Vec<CandidateSource>| {
mut sources: Vec<CandidateSource>| {
sources.sort(); sources.sort();
sources.dedup(); 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. // the impl, if local to crate (item may be defaulted), else nothing.
let item = self.impl_or_trait_item(impl_did, item_name) let item = self.impl_or_trait_item(impl_did, item_name)
.or_else(|| { .or_else(|| {
self.impl_or_trait_item( self.impl_or_trait_item(self.tcx
self.tcx.impl_trait_ref(impl_did).unwrap().def_id, .impl_trait_ref(impl_did)
.unwrap()
.def_id,
item_name item_name)
) })
}).unwrap(); .unwrap();
let note_span = self.tcx.map.span_if_local(item.def_id()).or_else(|| { let note_span = self.tcx
self.tcx.map.span_if_local(impl_did) .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; 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) => { CandidateSource::TraitSource(trait_did) => {
let item = self.impl_or_trait_item(trait_did, item_name).unwrap(); 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); 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 `{}`", "candidate #{} is defined in the trait `{}`",
idx + 1, idx + 1,
self.tcx.item_path_str(trait_did)); 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, MethodError::NoMatch(NoMatchData { static_candidates: static_sources,
unsatisfied_predicates, unsatisfied_predicates,
out_of_scope_traits, out_of_scope_traits,
mode, .. }) => { mode,
.. }) => {
let tcx = self.tcx; let tcx = self.tcx;
let mut err = self.type_error_struct( let mut err = self.type_error_struct(span,
span, |actual| {
|actual| { format!("no {} named `{}` found for type `{}` in the current scope",
format!("no {} named `{}` found for type `{}` \ if mode == Mode::MethodCall {
in the current scope", "method"
if mode == Mode::MethodCall { "method" } } else {
else { "associated item" }, "associated item"
item_name, },
actual) item_name,
}, actual)
rcvr_ty); },
rcvr_ty);
// If the method name is the name of a field with a function or closure type, // 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)(...). // 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) { for (ty, _) in self.autoderef(span, rcvr_ty) {
match ty.sty { match ty.sty {
ty::TyAdt(def, substs) if !def.is_enum() => { ty::TyAdt(def, substs) if !def.is_enum() => {
if let Some(field) = def.struct_variant(). if let Some(field) = def.struct_variant()
find_field_named(item_name) { .find_field_named(item_name) {
let snippet = tcx.sess.codemap().span_to_snippet(expr.span); let snippet = tcx.sess.codemap().span_to_snippet(expr.span);
let expr_string = match snippet { let expr_string = match snippet {
Ok(expr_string) => expr_string, Ok(expr_string) => expr_string,
_ => "s".into() // Default to a generic placeholder for the _ => "s".into(), // Default to a generic placeholder for the
// expression when we can't generate a // expression when we can't generate a
// string snippet // string snippet
}; };
let field_ty = field.ty(tcx, substs); let field_ty = field.ty(tcx, substs);
if self.is_fn_ty(&field_ty, span) { if self.is_fn_ty(&field_ty, span) {
err.span_note(span, &format!( err.span_note(span,
"use `({0}.{1})(...)` if you meant to call the \ &format!("use `({0}.{1})(...)` if you \
function stored in the `{1}` field", meant to call the function \
expr_string, item_name)); stored in the `{1}` field",
expr_string,
item_name));
} else { } else {
err.span_note(span, &format!( err.span_note(span,
"did you mean to write `{0}.{1}`?", &format!("did you mean to write `{0}.{1}`?",
expr_string, item_name)); expr_string,
item_name));
} }
break; break;
} }
@ -204,10 +212,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} }
if let Some(expr) = rcvr_expr { 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); 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() { if let Some(segment) = path.segments.last() {
report_function!(expr.span, segment.name); report_function!(expr.span, segment.name);
} }
@ -216,34 +223,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} }
if !static_sources.is_empty() { if !static_sources.is_empty() {
err.note( err.note("found the following associated functions; to be used as methods, \
"found the following associated functions; to be used as \ functions must have a `self` parameter");
methods, functions must have a `self` parameter");
report_candidates(&mut err, static_sources); report_candidates(&mut err, static_sources);
} }
if !unsatisfied_predicates.is_empty() { if !unsatisfied_predicates.is_empty() {
let bound_list = unsatisfied_predicates.iter() let bound_list = unsatisfied_predicates.iter()
.map(|p| format!("`{} : {}`", .map(|p| format!("`{} : {}`", p.self_ty(), p))
p.self_ty(),
p))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", "); .join(", ");
err.note( err.note(&format!("the method `{}` exists but the following trait bounds \
&format!("the method `{}` exists but the \ were not satisfied: {}",
following trait bounds were not satisfied: {}", item_name,
item_name, bound_list));
bound_list));
} }
self.suggest_traits_to_import(&mut err, span, rcvr_ty, item_name, self.suggest_traits_to_import(&mut err,
rcvr_expr, out_of_scope_traits); span,
rcvr_ty,
item_name,
rcvr_expr,
out_of_scope_traits);
err.emit(); err.emit();
} }
MethodError::Ambiguity(sources) => { 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"); "multiple applicable items in scope");
err.span_label(span, &format!("multiple `{}` found", item_name)); 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 \ let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \
invoked on this closure as we have not yet inferred what \ invoked on this closure as we have not yet inferred what \
kind of closure it is", kind of closure it is",
item_name, item_name,
self.tcx.item_path_str(trait_def_id)); self.tcx.item_path_str(trait_def_id));
let msg = if let Some(callee) = rcvr_expr { let msg = if let Some(callee) = rcvr_expr {
format!("{}; use overloaded call notation instead (e.g., `{}()`)", format!("{}; use overloaded call notation instead (e.g., `{}()`)",
msg, pprust::expr_to_string(callee)) msg,
pprust::expr_to_string(callee))
} else { } else {
msg msg
}; };
@ -279,18 +289,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
rcvr_ty: Ty<'tcx>, rcvr_ty: Ty<'tcx>,
item_name: ast::Name, item_name: ast::Name,
rcvr_expr: Option<&hir::Expr>, 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() { if !valid_out_of_scope_traits.is_empty() {
let mut candidates = valid_out_of_scope_traits; let mut candidates = valid_out_of_scope_traits;
candidates.sort(); candidates.sort();
candidates.dedup(); candidates.dedup();
let msg = format!( let msg = format!("items from traits can only be used if the trait is in scope; the \
"items from traits can only be used if the trait is in scope; \ following {traits_are} implemented but not in scope, perhaps add \
the following {traits_are} implemented but not in scope, \ a `use` for {one_of_them}:",
perhaps add a `use` for {one_of_them}:", traits_are = if candidates.len() == 1 {
traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"}, "trait is"
one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}); } else {
"traits are"
},
one_of_them = if candidates.len() == 1 {
"it"
} else {
"one of them"
});
err.help(&msg[..]); err.help(&msg[..]);
@ -303,7 +319,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if candidates.len() > limit { if candidates.len() > limit {
err.note(&format!("and {} others", 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); 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 // this isn't perfect (that is, there are cases when
// implementing a trait would be legal but is rejected // implementing a trait would be legal but is rejected
// here). // here).
(type_is_local || info.def_id.is_local()) (type_is_local || info.def_id.is_local()) &&
&& self.impl_or_trait_item(info.def_id, item_name).is_some() self.impl_or_trait_item(info.def_id, item_name).is_some()
}) })
.collect::<Vec<_>>(); .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 // FIXME #21673 this help message could be tuned to the case
// of a type parameter: suggest adding a trait bound rather // of a type parameter: suggest adding a trait bound rather
// than implementing. // than implementing.
let msg = format!( let msg = format!("items from traits can only be used if the trait is implemented \
"items from traits can only be used if the trait is implemented and in scope; \ and in scope; the following {traits_define} an item `{name}`, \
the following {traits_define} an item `{name}`, \ perhaps you need to implement {one_of_them}:",
perhaps you need to implement {one_of_them}:", traits_define = if candidates.len() == 1 {
traits_define = if candidates.len() == 1 {"trait defines"} else {"traits define"}, "trait defines"
one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}, } else {
name = item_name); "traits define"
},
one_of_them = if candidates.len() == 1 {
"it"
} else {
"one of them"
},
name = item_name);
err.help(&msg[..]); err.help(&msg[..]);
@ -355,7 +378,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
fn type_derefs_to_local(&self, fn type_derefs_to_local(&self,
span: Span, span: Span,
rcvr_ty: Ty<'tcx>, rcvr_ty: Ty<'tcx>,
rcvr_expr: Option<&hir::Expr>) -> bool { rcvr_expr: Option<&hir::Expr>)
-> bool {
fn is_local(ty: Ty) -> bool { fn is_local(ty: Ty) -> bool {
match ty.sty { match ty.sty {
ty::TyAdt(def, _) => def.did.is_local(), 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 // non-local (there are "edge" cases, e.g. (LocalType,), but
// the noise from these sort of types is usually just really // the noise from these sort of types is usually just really
// annoying, rather than any sort of help). // annoying, rather than any sort of help).
_ => false _ => false,
} }
} }
@ -391,9 +415,7 @@ pub struct TraitInfo {
impl TraitInfo { impl TraitInfo {
fn new(def_id: DefId) -> TraitInfo { fn new(def_id: DefId) -> TraitInfo {
TraitInfo { TraitInfo { def_id: def_id }
def_id: def_id,
}
} }
} }
impl PartialEq for TraitInfo { impl PartialEq for TraitInfo {
@ -403,7 +425,9 @@ impl PartialEq for TraitInfo {
} }
impl Eq for TraitInfo {} impl Eq for TraitInfo {}
impl PartialOrd 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 { impl Ord for TraitInfo {
fn cmp(&self, other: &TraitInfo) -> Ordering { fn cmp(&self, other: &TraitInfo) -> Ordering {
@ -426,7 +450,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
// Crate-local: // Crate-local:
// //
// meh. // meh.
struct Visitor<'a, 'tcx:'a> { struct Visitor<'a, 'tcx: 'a> {
map: &'a hir_map::Map<'tcx>, map: &'a hir_map::Map<'tcx>,
traits: &'a mut AllTraitsVec, 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 { ccx.tcx.map.krate().visit_all_items(&mut Visitor {
map: &ccx.tcx.map, map: &ccx.tcx.map,
traits: &mut traits traits: &mut traits,
}); });
// Cross-crate: // Cross-crate:
@ -469,7 +493,10 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
} }
} }
for cnum in ccx.tcx.sess.cstore.crates() { 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)); 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()); assert!(borrow.is_some());
AllTraits { AllTraits {
borrow: borrow, borrow: borrow,
idx: 0 idx: 0,
} }
} }
pub struct AllTraits<'a> { pub struct AllTraits<'a> {
borrow: cell::Ref<'a, Option<AllTraitsVec>>, borrow: cell::Ref<'a, Option<AllTraitsVec>>,
idx: usize idx: usize,
} }
impl<'a> Iterator for AllTraits<'a> { impl<'a> Iterator for AllTraits<'a> {