diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 6bbe40950b75..3e7cc0b1e3e9 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1367,7 +1367,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, - err: TypeError<'tcx>) -> DiagnosticBuilder<'tcx> { + err: TypeError<'tcx>) + -> DiagnosticBuilder<'tcx> { let trace = TypeTrace::types(cause, true, expected, actual); self.report_and_explain_type_error(trace, &err) } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index c09fde04ba4c..17d1bd777973 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -81,7 +81,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn format_method_suggestion(&self, method: &AssociatedItem) -> String { format!(".{}({})", method.name, - if self.has_not_input_arg(method) { + if self.has_no_input_arg(method) { "" } else { "..." @@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn get_best_match(&self, methods: &[AssociatedItem]) -> String { let no_argument_methods: Vec<_> = methods.iter() - .filter(|ref x| self.has_not_input_arg(&*x)) + .filter(|ref x| self.has_no_input_arg(&*x)) .map(|x| x.clone()) .collect(); if no_argument_methods.len() > 0 { @@ -110,7 +110,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // This function checks if the method isn't static and takes other arguments than `self`. - fn has_not_input_arg(&self, method: &AssociatedItem) -> bool { + fn has_no_input_arg(&self, method: &AssociatedItem) -> bool { match method.def() { Def::Method(def_id) => { match self.tcx.item_type(def_id).sty { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index d2089fb49152..b11f6e837d20 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -37,6 +37,22 @@ pub enum LookingFor<'tcx> { ReturnType(Ty<'tcx>), } +impl<'tcx> LookingFor<'tcx> { + pub fn is_method_name(&self) -> bool { + match *self { + LookingFor::MethodName(_) => true, + _ => false, + } + } + + pub fn is_return_type(&self) -> bool { + match *self { + LookingFor::ReturnType(_) => true, + _ => false, + } + } +} + struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, span: Span, @@ -468,44 +484,81 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { debug!("assemble_inherent_impl_probe {:?}", impl_def_id); - let item = match self.impl_or_trait_item(impl_def_id) { - Some(m) => m, - None => { + let items = self.impl_or_trait_item(impl_def_id); + if items.len() < 1 { + return // No method with correct name on this impl + } + + if self.looking_for.is_method_name() { + let item = items[0]; + + if !self.has_applicable_self(&item) { + // No receiver declared. Not a candidate. + return self.record_static_candidate(ImplSource(impl_def_id)); + } + + if !item.vis.is_accessible_from(self.body_id, &self.tcx.map) { + self.private_candidate = Some(item.def()); return; - } // No method with correct name on this impl - }; + } - if !self.has_applicable_self(&item) { - // No receiver declared. Not a candidate. - return self.record_static_candidate(ImplSource(impl_def_id)); + let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); + let impl_ty = impl_ty.subst(self.tcx, impl_substs); + + // Determine the receiver type that the method itself expects. + let xform_self_ty = self.xform_self_ty(&item, impl_ty, impl_substs); + + // We can't use normalize_associated_types_in as it will pollute the + // fcx's fulfillment context after this probe is over. + let cause = traits::ObligationCause::misc(self.span, self.body_id); + let mut selcx = &mut traits::SelectionContext::new(self.fcx); + let traits::Normalized { value: xform_self_ty, obligations } = + traits::normalize(selcx, cause, &xform_self_ty); + debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}", + xform_self_ty); + + self.inherent_candidates.push(Candidate { + xform_self_ty: xform_self_ty, + item: item, + kind: InherentImplCandidate(impl_substs, obligations), + import_id: self.import_id, + }); + } else { + for item in items { + if !self.has_applicable_self(&item) { + // No receiver declared. Not a candidate. + self.record_static_candidate(ImplSource(impl_def_id)); + continue + } + + if !item.vis.is_accessible_from(self.body_id, &self.tcx.map) { + self.private_candidate = Some(item.def()); + continue + } + + let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); + let impl_ty = impl_ty.subst(self.tcx, impl_substs); + + // Determine the receiver type that the method itself expects. + let xform_self_ty = self.xform_self_ty(&item, impl_ty, impl_substs); + + // We can't use normalize_associated_types_in as it will pollute the + // fcx's fulfillment context after this probe is over. + let cause = traits::ObligationCause::misc(self.span, self.body_id); + let mut selcx = &mut traits::SelectionContext::new(self.fcx); + let traits::Normalized { value: xform_self_ty, obligations } = + traits::normalize(selcx, cause, &xform_self_ty); + debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}", + xform_self_ty); + + self.inherent_candidates.push(Candidate { + xform_self_ty: xform_self_ty, + item: item, + kind: InherentImplCandidate(impl_substs, obligations), + import_id: self.import_id, + }); + } } - - if !item.vis.is_accessible_from(self.body_id, &self.tcx.map) { - self.private_candidate = Some(item.def()); - return; - } - - let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); - let impl_ty = impl_ty.subst(self.tcx, impl_substs); - - // Determine the receiver type that the method itself expects. - let xform_self_ty = self.xform_self_ty(&item, impl_ty, impl_substs); - - // We can't use normalize_associated_types_in as it will pollute the - // fcx's fulfillment context after this probe is over. - let cause = traits::ObligationCause::misc(self.span, self.body_id); - let mut selcx = &mut traits::SelectionContext::new(self.fcx); - let traits::Normalized { value: xform_self_ty, obligations } = - traits::normalize(selcx, cause, &xform_self_ty); - debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}", - xform_self_ty); - - self.inherent_candidates.push(Candidate { - xform_self_ty: xform_self_ty, - item: item, - kind: InherentImplCandidate(impl_substs, obligations), - import_id: self.import_id, - }); } fn assemble_inherent_candidates_from_object(&mut self, @@ -598,12 +651,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let tcx = self.tcx; for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { - let item = match self.impl_or_trait_item(bound_trait_ref.def_id()) { - Some(v) => v, - None => { - continue; - } - }; + let items = self.impl_or_trait_item(bound_trait_ref.def_id()); + if items.len() < 1 { + continue + } + let item = items[0]; if !self.has_applicable_self(&item) { self.record_static_candidate(TraitSource(bound_trait_ref.def_id())); @@ -665,12 +717,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id); - let item = match self.impl_or_trait_item(trait_def_id) { - Some(i) => i, - None => { - return Ok(()); - } - }; + let items = self.impl_or_trait_item(trait_def_id); + if items.len() < 1 { + return Ok(()); + } + let item = items[0]; // Check whether `trait_def_id` defines a method with suitable name: if !self.has_applicable_self(&item) { @@ -1351,16 +1402,17 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } /// Find the method with the appropriate name (or return type, as the case may be). - fn impl_or_trait_item(&self, def_id: DefId) -> Option { + fn impl_or_trait_item(&self, def_id: DefId) -> Vec { match self.looking_for { LookingFor::MethodName(name) => { - self.fcx.associated_item(def_id, name) + self.fcx.associated_item(def_id, name).map_or(Vec::new(), |x| vec![x]) } LookingFor::ReturnType(return_ty) => { self.tcx .associated_items(def_id) .map(|did| self.tcx.associated_item(did.def_id)) - .find(|m| self.matches_return_type(m, return_ty)) + .filter(|m| self.matches_return_type(m, return_ty)) + .collect() } } }