rustc_trait_selection/error_reporting/infer/nice_region_error/
trait_impl_difference.rs1use rustc_errors::ErrorGuaranteed;
4use rustc_hir::def::{Namespace, Res};
5use rustc_hir::def_id::DefId;
6use rustc_hir::intravisit::{Visitor, walk_ty};
7use rustc_hir::{self as hir, AmbigArg};
8use rustc_infer::infer::SubregionOrigin;
9use rustc_middle::hir::nested_filter;
10use rustc_middle::traits::ObligationCauseCode;
11use rustc_middle::ty::error::ExpectedFound;
12use rustc_middle::ty::print::RegionHighlightMode;
13use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
14use rustc_span::{Ident, Span};
15use tracing::debug;
16
17use crate::diagnostics::{ConsiderBorrowingParamHelp, TraitImplDiff};
18use crate::error_reporting::infer::nice_region_error::NiceRegionError;
19use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted;
20use crate::infer::{RegionResolutionError, ValuePairs};
21
22impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
23 pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorGuaranteed> {
25 let error = self.error.as_ref()?;
26 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/822182db4c4a1827256881d8c7aa685f0bcf2b11/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs:26",
"rustc_trait_selection::error_reporting::infer::nice_region_error::trait_impl_difference",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/822182db4c4a1827256881d8c7aa685f0bcf2b11/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs"),
::tracing_core::__macro_support::Option::Some(26u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::infer::nice_region_error::trait_impl_difference"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("try_report_impl_not_conforming_to_trait {0:?}",
error) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("try_report_impl_not_conforming_to_trait {:?}", error);
27 if let RegionResolutionError::SubSupConflict(
28 _,
29 var_origin,
30 sub_origin,
31 _sub,
32 sup_origin,
33 _sup,
34 _,
35 ) = error.clone()
36 && let (SubregionOrigin::Subtype(sup_trace), SubregionOrigin::Subtype(sub_trace)) =
37 (&sup_origin, &sub_origin)
38 && let &ObligationCauseCode::CompareImplItem {
39 trait_item_def_id, impl_item_def_id, ..
40 } = sub_trace.cause.code()
41 && sub_trace.values == sup_trace.values
42 && let ValuePairs::PolySigs(ExpectedFound { expected, found }) = sub_trace.values
43 {
44 let guar = self.emit_err(
47 var_origin.span(),
48 expected,
49 found,
50 trait_item_def_id,
51 impl_item_def_id.into(),
52 );
53 return Some(guar);
54 }
55 None
56 }
57
58 fn emit_err(
59 &self,
60 sp: Span,
61 expected: ty::PolyFnSig<'tcx>,
62 found: ty::PolyFnSig<'tcx>,
63 trait_item_def_id: DefId,
64 impl_item_def_id: DefId,
65 ) -> ErrorGuaranteed {
66 let trait_sp = self.tcx().def_span(trait_item_def_id);
67
68 struct HighlightBuilder<'tcx> {
71 tcx: TyCtxt<'tcx>,
72 highlight: RegionHighlightMode<'tcx>,
73 counter: usize,
74 }
75
76 impl<'tcx> HighlightBuilder<'tcx> {
77 fn build(tcx: TyCtxt<'tcx>, sig: ty::PolyFnSig<'tcx>) -> RegionHighlightMode<'tcx> {
78 let mut builder =
79 HighlightBuilder { tcx, highlight: RegionHighlightMode::default(), counter: 1 };
80 sig.visit_with(&mut builder);
81 builder.highlight
82 }
83 }
84
85 impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HighlightBuilder<'tcx> {
86 fn visit_region(&mut self, r: ty::Region<'tcx>) {
87 if !r.is_named(self.tcx) && self.counter <= 3 {
88 self.highlight.highlighting_region(r, self.counter);
89 self.counter += 1;
90 }
91 }
92 }
93
94 let tcx = self.cx.tcx;
95 let mut expected_highlight = HighlightBuilder::build(tcx, expected);
96 let expected_short = Highlighted {
97 highlight: expected_highlight,
98 ns: Namespace::TypeNS,
99 tcx,
100 value: expected,
101 }
102 .to_string();
103 expected_highlight.keep_regions = false;
104 let expected = Highlighted {
105 highlight: expected_highlight,
106 ns: Namespace::TypeNS,
107 tcx,
108 value: expected,
109 }
110 .to_string();
111 let mut found_highlight = HighlightBuilder::build(tcx, found);
112 let found_short =
113 Highlighted { highlight: found_highlight, ns: Namespace::TypeNS, tcx, value: found }
114 .to_string();
115 found_highlight.keep_regions = false;
116 let found =
117 Highlighted { highlight: found_highlight, ns: Namespace::TypeNS, tcx, value: found }
118 .to_string();
119
120 let assoc_item = self.tcx().associated_item(trait_item_def_id);
122 let mut visitor =
123 TypeParamSpanVisitor { tcx: self.tcx(), types: ::alloc::vec::Vec::new()vec![], elided_lifetime_paths: ::alloc::vec::Vec::new()vec![] };
124 match assoc_item.kind {
125 ty::AssocKind::Fn { .. } => {
126 if let Some(hir_id) =
127 assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id))
128 && let Some(decl) = self.tcx().hir_fn_decl_by_hir_id(hir_id)
129 {
130 visitor.visit_fn_decl(decl);
131 }
132 }
133 _ => {}
134 }
135
136 let diag = TraitImplDiff {
137 sp,
138 trait_sp,
139 note: (),
140 param_help: ConsiderBorrowingParamHelp { spans: visitor.types.to_vec() },
141 rel_help: visitor.types.is_empty(),
142 expected,
143 found,
144 expected_short,
145 found_short,
146 trait_span: self.tcx().def_span(self.tcx().parent(trait_item_def_id)).shrink_to_lo(),
147 impl_span: self.tcx().def_span(self.tcx().parent(impl_item_def_id)).shrink_to_lo(),
148 };
149
150 let mut diag = self.tcx().dcx().create_err(diag);
151 const ELIDED_LIFETIME_NOTE_LIMIT: usize = 5;
153 let elided_lifetime_paths = visitor.elided_lifetime_paths;
154 let total_elided_lifetime_paths = elided_lifetime_paths.len();
155 let shown_elided_lifetime_paths = if tcx.sess.opts.verbose {
156 total_elided_lifetime_paths
157 } else {
158 ELIDED_LIFETIME_NOTE_LIMIT
159 };
160
161 for elided in elided_lifetime_paths.into_iter().take(shown_elided_lifetime_paths) {
162 diag.span_note(
163 elided.span,
164 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}` here is elided as `{1}`",
elided.ident, elided.shorthand))
})format!("`{}` here is elided as `{}`", elided.ident, elided.shorthand),
165 );
166 }
167 if total_elided_lifetime_paths > shown_elided_lifetime_paths {
168 diag.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("and {0} more elided lifetime{1} in type paths",
total_elided_lifetime_paths - shown_elided_lifetime_paths,
if total_elided_lifetime_paths - shown_elided_lifetime_paths
== 1 {
""
} else { "s" }))
})format!(
169 "and {} more elided lifetime{} in type paths",
170 total_elided_lifetime_paths - shown_elided_lifetime_paths,
171 if total_elided_lifetime_paths - shown_elided_lifetime_paths == 1 {
172 ""
173 } else {
174 "s"
175 },
176 ));
177 }
178 diag.emit_err()
179 }
180}
181
182#[derive(#[automatically_derived]
impl ::core::clone::Clone for ElidedLifetimeInPath {
#[inline]
fn clone(&self) -> Self {
ElidedLifetimeInPath {
span: ::core::clone::Clone::clone(&self.span),
ident: ::core::clone::Clone::clone(&self.ident),
shorthand: ::core::clone::Clone::clone(&self.shorthand),
}
}
}Clone)]
183struct ElidedLifetimeInPath {
184 span: Span,
185 ident: Ident,
186 shorthand: String,
187}
188
189struct TypeParamSpanVisitor<'tcx> {
190 tcx: TyCtxt<'tcx>,
191 types: Vec<Span>,
192 elided_lifetime_paths: Vec<ElidedLifetimeInPath>,
193}
194
195impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
196 type NestedFilter = nested_filter::OnlyBodies;
197
198 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
199 self.tcx
200 }
201
202 fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, _span: Span) {
203 fn record_elided_lifetimes(
204 tcx: TyCtxt<'_>,
205 elided_lifetime_paths: &mut Vec<ElidedLifetimeInPath>,
206 segment: &hir::PathSegment<'_>,
207 ) {
208 let Some(args) = segment.args else { return };
209 if args.parenthesized != hir::GenericArgsParentheses::No {
210 return;
212 }
213 let elided_count = args
214 .args
215 .iter()
216 .filter(|arg| {
217 let hir::GenericArg::Lifetime(l) = arg else { return false };
218 l.syntax == hir::LifetimeSyntax::Implicit
219 && #[allow(non_exhaustive_omitted_patterns)] match l.source {
hir::LifetimeSource::Path { .. } => true,
_ => false,
}matches!(l.source, hir::LifetimeSource::Path { .. })
220 })
221 .count();
222 if elided_count == 0
223 || elided_lifetime_paths.iter().any(|p| p.span == segment.ident.span)
224 {
225 return;
226 }
227
228 let sm = tcx.sess.source_map();
229 let mut parts = args
230 .args
231 .iter()
232 .map(|arg| match arg {
233 hir::GenericArg::Lifetime(l) => {
234 if l.syntax == hir::LifetimeSyntax::Implicit
235 && #[allow(non_exhaustive_omitted_patterns)] match l.source {
hir::LifetimeSource::Path { .. } => true,
_ => false,
}matches!(l.source, hir::LifetimeSource::Path { .. })
236 {
237 "'_".to_string()
238 } else {
239 sm.span_to_snippet(l.ident.span)
240 .unwrap_or_else(|_| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\'{0}", l.ident.name))
})format!("'{}", l.ident.name))
241 }
242 }
243 hir::GenericArg::Type(ty) => {
244 sm.span_to_snippet(ty.span).unwrap_or_else(|_| "..".to_string())
245 }
246 hir::GenericArg::Const(ct) => {
247 sm.span_to_snippet(ct.span).unwrap_or_else(|_| "..".to_string())
248 }
249 hir::GenericArg::Infer(_) => "_".to_string(),
250 })
251 .collect::<Vec<_>>();
252 parts.extend(args.constraints.iter().map(|constraint| {
253 sm.span_to_snippet(constraint.span)
254 .unwrap_or_else(|_| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} = ..", constraint.ident))
})format!("{} = ..", constraint.ident))
255 }));
256 let shorthand = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}<{1}>", segment.ident,
parts.join(", ")))
})format!("{}<{}>", segment.ident, parts.join(", "));
257
258 elided_lifetime_paths.push(ElidedLifetimeInPath {
259 span: segment.ident.span,
260 ident: segment.ident,
261 shorthand,
262 });
263 }
264
265 match qpath {
266 hir::QPath::Resolved(_, path) => {
267 for segment in path.segments {
268 record_elided_lifetimes(self.tcx, &mut self.elided_lifetime_paths, segment);
269 }
270 }
271 hir::QPath::TypeRelative(_, segment) => {
272 record_elided_lifetimes(self.tcx, &mut self.elided_lifetime_paths, segment);
273 }
274 }
275
276 hir::intravisit::walk_qpath(self, qpath, id);
277 }
278
279 fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) {
280 match arg.kind {
281 hir::TyKind::Ref(_, ref ty, _) => {
282 if let Some(ambig_ty) = ty.try_as_ambig_ty() {
284 walk_ty(self, ambig_ty);
285 }
286 return;
287 }
288 hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
289 [segment]
290 if #[allow(non_exhaustive_omitted_patterns)] match segment.res {
Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } |
Res::Def(hir::def::DefKind::TyParam, _) => true,
_ => false,
}matches!(
291 segment.res,
292 Res::SelfTyParam { .. }
293 | Res::SelfTyAlias { .. }
294 | Res::Def(hir::def::DefKind::TyParam, _)
295 ) =>
296 {
297 self.types.push(path.span);
298 }
299 _ => {}
300 },
301 _ => {}
302 }
303 hir::intravisit::walk_ty(self, arg);
304 }
305}