From 83cc6204ec4b706eaf8183cac618715357d7cba1 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Nov 2022 14:37:33 +0000 Subject: [PATCH 1/7] Flip a boolean that was used wrongly (has no effect though) --- compiler/rustc_hir_typeck/src/method/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 4a8b774936543..e7e0a3a23a279 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -128,7 +128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { method_name.span, probe::Mode::MethodCall, method_name, - IsSuggestion(false), + IsSuggestion(true), self_ty, call_expr.hir_id, ProbeScope::TraitsInScope, From 44c4a7b6c4a57e5e925d2156737bf9f003f583b4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Nov 2022 14:43:51 +0000 Subject: [PATCH 2/7] Remove an unnecessary `resolve_vars_if_possible` --- compiler/rustc_hir_typeck/src/method/mod.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index e7e0a3a23a279..a067b0d6c1813 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -93,10 +93,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr_id: hir::HirId, allow_private: bool, ) -> bool { - let mode = probe::Mode::MethodCall; match self.probe_for_name( method_name.span, - mode, + probe::Mode::MethodCall, method_name, IsSuggestion(false), self_ty, @@ -253,11 +252,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr: &'tcx hir::Expr<'tcx>, scope: ProbeScope, ) -> probe::PickResult<'tcx> { - let mode = probe::Mode::MethodCall; - let self_ty = self.resolve_vars_if_possible(self_ty); self.probe_for_name( span, - mode, + probe::Mode::MethodCall, method_name, IsSuggestion(false), self_ty, From c3c3719fdd1146fcc014cafc0498aa308897e9ee Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Nov 2022 16:07:59 +0000 Subject: [PATCH 3/7] Remove some redundant span arguments --- compiler/rustc_hir_typeck/src/callee.rs | 1 - compiler/rustc_hir_typeck/src/method/mod.rs | 51 ++++++++----------- compiler/rustc_hir_typeck/src/method/probe.rs | 3 +- .../rustc_hir_typeck/src/method/suggest.rs | 34 ++++--------- 4 files changed, 32 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 2b019c8c9b7a5..ed2218b8746ee 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -504,7 +504,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // method lookup. let Ok(pick) = self .probe_for_name( - call_expr.span, Mode::MethodCall, segment.ident, IsSuggestion(true), diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index a067b0d6c1813..791a01ef74a2c 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -94,7 +94,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { allow_private: bool, ) -> bool { match self.probe_for_name( - method_name.span, probe::Mode::MethodCall, method_name, IsSuggestion(false), @@ -124,7 +123,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let params = self .probe_for_name( - method_name.span, probe::Mode::MethodCall, method_name, IsSuggestion(true), @@ -174,7 +172,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args: &'tcx [hir::Expr<'tcx>], ) -> Result, MethodError<'tcx>> { let pick = - self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?; + self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?; self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args); @@ -199,7 +197,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .mk_ref(*region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() }); // We probe again to see if there might be a borrow mutability discrepancy. match self.lookup_probe( - span, segment.ident, trait_type, call_expr, @@ -213,28 +210,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // We probe again, taking all traits into account (not only those in scope). - let mut candidates = match self.lookup_probe( - span, - segment.ident, - self_ty, - call_expr, - ProbeScope::AllTraits, - ) { - // If we find a different result the caller probably forgot to import a trait. - Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container_id(self.tcx)], - Err(Ambiguity(ref sources)) => sources - .iter() - .filter_map(|source| { - match *source { - // Note: this cannot come from an inherent impl, - // because the first probing succeeded. - CandidateSource::Impl(def) => self.tcx.trait_id_of_impl(def), - CandidateSource::Trait(_) => None, - } - }) - .collect(), - _ => Vec::new(), - }; + let mut candidates = + match self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::AllTraits) { + // If we find a different result the caller probably forgot to import a trait. + Ok(ref new_pick) if *new_pick != pick => { + vec![new_pick.item.container_id(self.tcx)] + } + Err(Ambiguity(ref sources)) => sources + .iter() + .filter_map(|source| { + match *source { + // Note: this cannot come from an inherent impl, + // because the first probing succeeded. + CandidateSource::Impl(def) => self.tcx.trait_id_of_impl(def), + CandidateSource::Trait(_) => None, + } + }) + .collect(), + _ => Vec::new(), + }; candidates.retain(|candidate| *candidate != self.tcx.parent(result.callee.def_id)); return Err(IllegalSizedBound(candidates, needs_mut, span)); @@ -246,14 +240,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self, call_expr))] pub fn lookup_probe( &self, - span: Span, method_name: Ident, self_ty: Ty<'tcx>, call_expr: &'tcx hir::Expr<'tcx>, scope: ProbeScope, ) -> probe::PickResult<'tcx> { self.probe_for_name( - span, probe::Mode::MethodCall, method_name, IsSuggestion(false), @@ -584,9 +576,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let pick = self.probe_for_name( - span, probe::Mode::Path, - method_name, + method_name.with_span_pos(span), IsSuggestion(false), self_ty, expr_id, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 3fcd073f59793..eaf1a963ca986 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -298,7 +298,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self))] pub fn probe_for_name( &self, - span: Span, mode: Mode, item_name: Ident, is_suggestion: IsSuggestion, @@ -307,7 +306,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { scope: ProbeScope, ) -> PickResult<'tcx> { self.probe_op( - span, + item_name.span, mode, Some(item_name), None, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index edfe12963dc63..19f56c738239b 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -376,7 +376,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .hir() .expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id)); let probe = self.lookup_probe( - span, item_name, output_ty, call_expr, @@ -914,7 +913,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - self.check_for_inner_self(&mut err, source, span, rcvr_ty, item_name); + self.check_for_inner_self(&mut err, source, rcvr_ty, item_name); bound_spans.sort(); bound_spans.dedup(); @@ -1321,7 +1320,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.bound_type_of(range_def_id).subst(self.tcx, &[actual.into()]); let pick = self.probe_for_name( - span, Mode::MethodCall, item_name, IsSuggestion(true), @@ -1500,7 +1498,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, &|_, field_ty| { self.lookup_probe( - span, item_name, field_ty, call_expr, @@ -1548,7 +1545,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, err: &mut Diagnostic, source: SelfSource<'tcx>, - span: Span, actual: Ty<'tcx>, item_name: Ident, ) { @@ -1571,15 +1567,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } - self.lookup_probe( - span, - item_name, - field_ty, - call_expr, - ProbeScope::TraitsInScope, - ) - .ok() - .map(|pick| (variant, field, pick)) + self.lookup_probe(item_name, field_ty, call_expr, ProbeScope::TraitsInScope) + .ok() + .map(|pick| (variant, field, pick)) }) .collect(); @@ -1644,12 +1634,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let [first] = ***substs else { return; }; let ty::GenericArgKind::Type(ty) = first.unpack() else { return; }; let Ok(pick) = self.lookup_probe( - span, - item_name, - ty, - call_expr, - ProbeScope::TraitsInScope, - ) else { return; }; + item_name, + ty, + call_expr, + ProbeScope::TraitsInScope, + ) else { return; }; let name = self.ty_to_value_string(actual); let inner_id = kind.did(); @@ -1899,7 +1888,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let SelfSource::QPath(ty) = self_source else { return; }; for (deref_ty, _) in self.autoderef(rustc_span::DUMMY_SP, rcvr_ty).skip(1) { if let Ok(pick) = self.probe_for_name( - ty.span, Mode::Path, item_name, IsSuggestion(true), @@ -2107,7 +2095,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "), (self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"), ] { - match self.lookup_probe(span, item_name, *rcvr_ty, rcvr, ProbeScope::AllTraits) { + match self.lookup_probe(item_name, *rcvr_ty, rcvr, ProbeScope::AllTraits) { Ok(pick) => { // If the method is defined for the receiver we have, it likely wasn't `use`d. // We point at the method, but we just skip the rest of the check for arbitrary @@ -2141,7 +2129,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ] { if let Some(new_rcvr_t) = *rcvr_ty && let Ok(pick) = self.lookup_probe( - span, item_name, new_rcvr_t, rcvr, @@ -2522,7 +2509,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: method_name.span, }; let probe = self.lookup_probe( - expr.span, new_name, self_ty, self_expr, From e694ef5f20992514b895493ccf9df0fd851bc715 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Nov 2022 16:39:21 +0000 Subject: [PATCH 4/7] Remove the fishy need for a PartialEq impl --- compiler/rustc_hir_typeck/src/method/mod.rs | 4 ++-- compiler/rustc_hir_typeck/src/method/probe.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 791a01ef74a2c..302aaaed34ab1 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -202,7 +202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr, ProbeScope::TraitsInScope, ) { - Ok(ref new_pick) if *new_pick != pick => { + Ok(ref new_pick) if new_pick.self_ty != pick.self_ty => { needs_mut = true; } _ => {} @@ -213,7 +213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut candidates = match self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::AllTraits) { // If we find a different result the caller probably forgot to import a trait. - Ok(ref new_pick) if *new_pick != pick => { + Ok(ref new_pick) if new_pick.self_ty != pick.self_ty => { vec![new_pick.item.container_id(self.tcx)] } Err(Ambiguity(ref sources)) => sources diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index eaf1a963ca986..2a1c374e0c232 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -193,7 +193,7 @@ impl AutorefOrPtrAdjustment { } } -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, Clone)] pub struct Pick<'tcx> { pub item: ty::AssocItem, pub kind: PickKind<'tcx>, From e65688386b933914374a4565d00c1aea6fc92a0b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Nov 2022 16:12:16 +0000 Subject: [PATCH 5/7] Pull the unstable name collision hint emission out of method probing --- compiler/rustc_hir_typeck/src/method/mod.rs | 15 ++- compiler/rustc_hir_typeck/src/method/probe.rs | 105 ++++++++---------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 302aaaed34ab1..1d13386c57afb 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -101,7 +101,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr_id, ProbeScope::TraitsInScope, ) { - Ok(..) => true, + Ok(pick) => { + pick.emit_unstable_name_collision_hint(self.tcx, method_name.span, call_expr_id); + true + } Err(NoMatch(..)) => false, Err(Ambiguity(..)) => true, Err(PrivateMatch(..)) => allow_private, @@ -245,14 +248,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr: &'tcx hir::Expr<'tcx>, scope: ProbeScope, ) -> probe::PickResult<'tcx> { - self.probe_for_name( + let pick = self.probe_for_name( probe::Mode::MethodCall, method_name, IsSuggestion(false), self_ty, call_expr.hir_id, scope, - ) + )?; + pick.emit_unstable_name_collision_hint(self.tcx, method_name.span, call_expr.hir_id); + Ok(pick) } pub(super) fn obligation_for_method( @@ -577,13 +582,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let pick = self.probe_for_name( probe::Mode::Path, - method_name.with_span_pos(span), + method_name, IsSuggestion(false), self_ty, expr_id, ProbeScope::TraitsInScope, )?; + pick.emit_unstable_name_collision_hint(self.tcx, span, expr_id); + self.lint_fully_qualified_call_from_2018( span, method_name, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 2a1c374e0c232..15481296d9bfd 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -83,8 +83,6 @@ struct ProbeContext<'a, 'tcx> { unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option>, Option>)>, - is_suggestion: IsSuggestion, - scope_expr_id: hir::HirId, } @@ -209,6 +207,9 @@ pub struct Pick<'tcx> { /// `*mut T`, convert it to `*const T`. pub autoref_or_ptr_adjustment: Option, pub self_ty: Ty<'tcx>, + + /// Unstable candidates alongside the stable ones. + unstable_candidates: Vec<(Candidate<'tcx>, Symbol)>, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -445,7 +446,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return_type, orig_values, steps.steps, - is_suggestion, scope_expr_id, ); @@ -540,7 +540,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { return_type: Option>, orig_steps_var_values: OriginalQueryValues<'tcx>, steps: &'tcx [CandidateStep<'tcx>], - is_suggestion: IsSuggestion, scope_expr_id: hir::HirId, ) -> ProbeContext<'a, 'tcx> { ProbeContext { @@ -558,7 +557,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { allow_similar_names: false, private_candidate: None, unsatisfied_predicates: Vec::new(), - is_suggestion, scope_expr_id, } } @@ -880,7 +878,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - pub fn matches_return_type( + fn matches_return_type( &self, method: &ty::AssocItem, self_ty: Option>, @@ -1051,26 +1049,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } fn pick_core(&mut self) -> Option> { - let mut unstable_candidates = Vec::new(); - let pick = self.pick_all_method(Some(&mut unstable_candidates)); + let pick = self.pick_all_method(Some(&mut vec![])); // In this case unstable picking is done by `pick_method`. if !self.tcx.sess.opts.unstable_opts.pick_stable_methods_before_any_unstable { return pick; } - match pick { - // Emit a lint if there are unstable candidates alongside the stable ones. - // - // We suppress warning if we're picking the method only because it is a - // suggestion. - Some(Ok(ref p)) if !self.is_suggestion.0 && !unstable_candidates.is_empty() => { - self.emit_unstable_name_collision_hint(p, &unstable_candidates); - pick - } - Some(_) => pick, - None => self.pick_all_method(None), + if pick.is_none() { + return self.pick_all_method(None); } + pick } fn pick_all_method( @@ -1215,7 +1204,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { debug!("pick_method_with_unstable(self_ty={})", self.ty_to_string(self_ty)); let mut possibly_unsatisfied_predicates = Vec::new(); - let mut unstable_candidates = Vec::new(); for (kind, candidates) in &[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)] @@ -1225,26 +1213,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self_ty, candidates.iter(), &mut possibly_unsatisfied_predicates, - Some(&mut unstable_candidates), + Some(&mut vec![]), ); - if let Some(pick) = res { - if !self.is_suggestion.0 && !unstable_candidates.is_empty() { - if let Ok(p) = &pick { - // Emit a lint if there are unstable candidates alongside the stable ones. - // - // We suppress warning if we're picking the method only because it is a - // suggestion. - self.emit_unstable_name_collision_hint(p, &unstable_candidates); - } - } - return Some(pick); + if res.is_some() { + return res; } } debug!("searching unstable candidates"); let res = self.consider_candidates( self_ty, - unstable_candidates.iter().map(|(c, _)| c), + self.inherent_candidates.iter().chain(&self.extension_candidates), &mut possibly_unsatisfied_predicates, None, ); @@ -1299,7 +1278,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { Option>, Option>, )>, - unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, + mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>, ) -> Option> where ProbesIter: Iterator> + Clone, @@ -1323,7 +1302,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - if let Some(uc) = unstable_candidates { + if let Some(uc) = &mut unstable_candidates { applicable_candidates.retain(|&(p, _)| { if let stability::EvalResult::Deny { feature, .. } = self.tcx.eval_stability(p.item.def_id, None, self.span, None) @@ -1342,30 +1321,37 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { applicable_candidates.pop().map(|(probe, status)| { if status == ProbeResult::Match { - Ok(probe.to_unadjusted_pick(self_ty)) + Ok(probe + .to_unadjusted_pick(self_ty, unstable_candidates.cloned().unwrap_or_default())) } else { Err(MethodError::BadReturnType) } }) } +} - fn emit_unstable_name_collision_hint( +impl<'tcx> Pick<'tcx> { + pub fn emit_unstable_name_collision_hint( &self, - stable_pick: &Pick<'_>, - unstable_candidates: &[(Candidate<'tcx>, Symbol)], + tcx: TyCtxt<'tcx>, + span: Span, + scope_expr_id: hir::HirId, ) { - let def_kind = stable_pick.item.kind.as_def_kind(); - self.tcx.struct_span_lint_hir( + if self.unstable_candidates.is_empty() { + return; + } + let def_kind = self.item.kind.as_def_kind(); + tcx.struct_span_lint_hir( lint::builtin::UNSTABLE_NAME_COLLISIONS, - self.scope_expr_id, - self.span, + scope_expr_id, + span, format!( "{} {} with this name may be added to the standard library in the future", def_kind.article(), - def_kind.descr(stable_pick.item.def_id), + def_kind.descr(self.item.def_id), ), |lint| { - match (stable_pick.item.kind, stable_pick.item.container) { + match (self.item.kind, self.item.container) { (ty::AssocKind::Fn, _) => { // FIXME: This should be a `span_suggestion` instead of `help` // However `self.span` only @@ -1374,31 +1360,31 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { lint.help(&format!( "call with fully qualified syntax `{}(...)` to keep using the current \ method", - self.tcx.def_path_str(stable_pick.item.def_id), + tcx.def_path_str(self.item.def_id), )); } (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => { - let def_id = stable_pick.item.container_id(self.tcx); + let def_id = self.item.container_id(tcx); lint.span_suggestion( - self.span, + span, "use the fully qualified path to the associated const", format!( "<{} as {}>::{}", - stable_pick.self_ty, - self.tcx.def_path_str(def_id), - stable_pick.item.name + self.self_ty, + tcx.def_path_str(def_id), + self.item.name ), Applicability::MachineApplicable, ); } _ => {} } - if self.tcx.sess.is_nightly_build() { - for (candidate, feature) in unstable_candidates { + if tcx.sess.is_nightly_build() { + for (candidate, feature) in &self.unstable_candidates { lint.help(&format!( "add `#![feature({})]` to the crate attributes to enable `{}`", feature, - self.tcx.def_path_str(candidate.item.def_id), + tcx.def_path_str(candidate.item.def_id), )); } } @@ -1407,7 +1393,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }, ); } +} +impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn select_trait_candidate( &self, trait_ref: ty::TraitRef<'tcx>, @@ -1666,6 +1654,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { autoderefs: 0, autoref_or_ptr_adjustment: None, self_ty, + unstable_candidates: vec![], }) } @@ -1685,7 +1674,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.return_type, self.orig_steps_var_values.clone(), steps, - IsSuggestion(true), self.scope_expr_id, ); pcx.allow_similar_names = true; @@ -1893,7 +1881,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } impl<'tcx> Candidate<'tcx> { - fn to_unadjusted_pick(&self, self_ty: Ty<'tcx>) -> Pick<'tcx> { + fn to_unadjusted_pick( + &self, + self_ty: Ty<'tcx>, + unstable_candidates: Vec<(Candidate<'tcx>, Symbol)>, + ) -> Pick<'tcx> { Pick { item: self.item, kind: match self.kind { @@ -1918,6 +1910,7 @@ impl<'tcx> Candidate<'tcx> { autoderefs: 0, autoref_or_ptr_adjustment: None, self_ty, + unstable_candidates, } } } From d06aac178358509cd7f416285e920f67bea1d64b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 14 Nov 2022 11:21:37 +0000 Subject: [PATCH 6/7] Expose the fallibilty of the unstable lint emission in the method name --- compiler/rustc_hir_typeck/src/method/mod.rs | 10 +++++++--- compiler/rustc_hir_typeck/src/method/probe.rs | 3 ++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 1d13386c57afb..1577eb666c847 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -102,7 +102,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ProbeScope::TraitsInScope, ) { Ok(pick) => { - pick.emit_unstable_name_collision_hint(self.tcx, method_name.span, call_expr_id); + pick.maybe_emit_unstable_name_collision_hint( + self.tcx, + method_name.span, + call_expr_id, + ); true } Err(NoMatch(..)) => false, @@ -256,7 +260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr.hir_id, scope, )?; - pick.emit_unstable_name_collision_hint(self.tcx, method_name.span, call_expr.hir_id); + pick.maybe_emit_unstable_name_collision_hint(self.tcx, method_name.span, call_expr.hir_id); Ok(pick) } @@ -589,7 +593,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ProbeScope::TraitsInScope, )?; - pick.emit_unstable_name_collision_hint(self.tcx, span, expr_id); + pick.maybe_emit_unstable_name_collision_hint(self.tcx, span, expr_id); self.lint_fully_qualified_call_from_2018( span, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 15481296d9bfd..6d46be40e6224 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1331,7 +1331,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } impl<'tcx> Pick<'tcx> { - pub fn emit_unstable_name_collision_hint( + /// In case there were unstable name collisions, emit them as a lint. + pub fn maybe_emit_unstable_name_collision_hint( &self, tcx: TyCtxt<'tcx>, span: Span, From e2fbd01ac3305fd9bfb5ee4f76c42f06df4e1f10 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 14 Nov 2022 11:20:25 +0000 Subject: [PATCH 7/7] Compare picks via `Self` type and associated item id --- compiler/rustc_hir_typeck/src/method/mod.rs | 4 +-- compiler/rustc_hir_typeck/src/method/probe.rs | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 1577eb666c847..3f390cba3e7c2 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -209,7 +209,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr, ProbeScope::TraitsInScope, ) { - Ok(ref new_pick) if new_pick.self_ty != pick.self_ty => { + Ok(ref new_pick) if pick.differs_from(new_pick) => { needs_mut = true; } _ => {} @@ -220,7 +220,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut candidates = match self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::AllTraits) { // If we find a different result the caller probably forgot to import a trait. - Ok(ref new_pick) if new_pick.self_ty != pick.self_ty => { + Ok(ref new_pick) if pick.differs_from(new_pick) => { vec![new_pick.item.container_id(self.tcx)] } Err(Ambiguity(ref sources)) => sources diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 6d46be40e6224..46a760851893d 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -17,6 +17,7 @@ use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::middle::stability; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; +use rustc_middle::ty::AssocItem; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; @@ -1331,6 +1332,31 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } impl<'tcx> Pick<'tcx> { + /// In case there were unstable name collisions, emit them as a lint. + /// Checks whether two picks do not refer to the same trait item for the same `Self` type. + /// Only useful for comparisons of picks in order to improve diagnostics. + /// Do not use for type checking. + pub fn differs_from(&self, other: &Self) -> bool { + let Self { + item: + AssocItem { + def_id, + name: _, + kind: _, + container: _, + trait_item_def_id: _, + fn_has_self_parameter: _, + }, + kind: _, + import_ids: _, + autoderefs: _, + autoref_or_ptr_adjustment: _, + self_ty, + unstable_candidates: _, + } = *self; + self_ty != other.self_ty || def_id != other.item.def_id + } + /// In case there were unstable name collisions, emit them as a lint. pub fn maybe_emit_unstable_name_collision_hint( &self,