|
2 | 2 | #![allow(rustc::untranslatable_diagnostic)]
|
3 | 3 | use std::num::NonZero;
|
4 | 4 |
|
5 |
| -use crate::errors::RequestedLevel; |
| 5 | +use crate::builtin::TypeAliasBounds; |
6 | 6 | use crate::fluent_generated as fluent;
|
| 7 | +use crate::{builtin::ShorthandAssocTyCollector, errors::RequestedLevel}; |
7 | 8 | use rustc_errors::{
|
8 | 9 | codes::*, Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString,
|
9 | 10 | ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp,
|
@@ -265,97 +266,72 @@ pub struct BuiltinUnreachablePub<'a> {
|
265 | 266 | pub help: Option<()>,
|
266 | 267 | }
|
267 | 268 |
|
268 |
| -#[derive(LintDiagnostic)] |
269 |
| -pub enum BuiltinTypeAliasBounds<'a, 'hir> { |
270 |
| - #[diag(lint_builtin_type_alias_bounds_where_clause)] |
271 |
| - #[note(lint_builtin_type_alias_bounds_limitation_note)] |
272 |
| - WhereClause { |
273 |
| - #[label(lint_builtin_type_alias_bounds_label)] |
274 |
| - label: Span, |
275 |
| - #[help(lint_builtin_type_alias_bounds_enable_feat_help)] |
276 |
| - enable_feat_help: Option<()>, |
277 |
| - #[suggestion(code = "")] |
278 |
| - suggestion: (Span, Applicability), |
279 |
| - #[subdiagnostic] |
280 |
| - qualify_assoc_tys_sugg: Option<TypeAliasBoundsQualifyAssocTysSugg<'a, 'hir>>, |
281 |
| - }, |
282 |
| - #[diag(lint_builtin_type_alias_bounds_param_bounds)] |
283 |
| - #[note(lint_builtin_type_alias_bounds_limitation_note)] |
284 |
| - ParamBounds { |
285 |
| - #[label(lint_builtin_type_alias_bounds_label)] |
286 |
| - label: Span, |
287 |
| - #[help(lint_builtin_type_alias_bounds_enable_feat_help)] |
288 |
| - enable_feat_help: Option<()>, |
289 |
| - #[subdiagnostic] |
290 |
| - suggestion: BuiltinTypeAliasParamBoundsSuggestion, |
291 |
| - #[subdiagnostic] |
292 |
| - qualify_assoc_tys_sugg: Option<TypeAliasBoundsQualifyAssocTysSugg<'a, 'hir>>, |
293 |
| - }, |
294 |
| -} |
295 |
| - |
296 |
| -pub struct BuiltinTypeAliasParamBoundsSuggestion { |
| 269 | +pub struct BuiltinTypeAliasBounds<'a, 'hir> { |
| 270 | + pub in_where_clause: bool, |
| 271 | + pub label: Span, |
| 272 | + pub enable_feat_help: bool, |
297 | 273 | pub suggestions: Vec<(Span, String)>,
|
298 |
| - pub applicability: Applicability, |
| 274 | + pub preds: &'hir [hir::WherePredicate<'hir>], |
| 275 | + pub ty: Option<&'a hir::Ty<'hir>>, |
299 | 276 | }
|
300 | 277 |
|
301 |
| -impl Subdiagnostic for BuiltinTypeAliasParamBoundsSuggestion { |
302 |
| - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( |
303 |
| - self, |
304 |
| - diag: &mut Diag<'_, G>, |
305 |
| - _f: &F, |
306 |
| - ) { |
307 |
| - diag.arg("count", self.suggestions.len()); |
308 |
| - diag.multipart_suggestion(fluent::lint_suggestion, self.suggestions, self.applicability); |
309 |
| - } |
310 |
| -} |
311 |
| - |
312 |
| -pub struct TypeAliasBoundsQualifyAssocTysSugg<'a, 'hir> { |
313 |
| - pub ty: &'a hir::Ty<'hir>, |
314 |
| -} |
| 278 | +impl<'a> LintDiagnostic<'a, ()> for BuiltinTypeAliasBounds<'_, '_> { |
| 279 | + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { |
| 280 | + diag.primary_message(if self.in_where_clause { |
| 281 | + fluent::lint_builtin_type_alias_bounds_where_clause |
| 282 | + } else { |
| 283 | + fluent::lint_builtin_type_alias_bounds_param_bounds |
| 284 | + }); |
| 285 | + diag.span_label(self.label, fluent::lint_builtin_type_alias_bounds_label); |
| 286 | + diag.note(fluent::lint_builtin_type_alias_bounds_limitation_note); |
| 287 | + if self.enable_feat_help { |
| 288 | + diag.help(fluent::lint_builtin_type_alias_bounds_enable_feat_help); |
| 289 | + } |
315 | 290 |
|
316 |
| -impl<'a, 'hir> Subdiagnostic for TypeAliasBoundsQualifyAssocTysSugg<'a, 'hir> { |
317 |
| - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( |
318 |
| - self, |
319 |
| - diag: &mut Diag<'_, G>, |
320 |
| - _f: &F, |
321 |
| - ) { |
322 | 291 | // We perform the walk in here instead of in `<TypeAliasBounds as LateLintPass>` to
|
323 | 292 | // avoid doing throwaway work in case the lint ends up getting suppressed.
|
324 |
| - |
325 |
| - use hir::intravisit::Visitor; |
326 |
| - struct ProbeShorthandAssocTys<'a, 'b, G: EmissionGuarantee> { |
327 |
| - diag: &'a mut Diag<'b, G>, |
| 293 | + let mut collector = ShorthandAssocTyCollector { qselves: Vec::new() }; |
| 294 | + if let Some(ty) = self.ty { |
| 295 | + hir::intravisit::Visitor::visit_ty(&mut collector, ty); |
328 | 296 | }
|
329 |
| - impl<'a, 'b, G: EmissionGuarantee> Visitor<'_> for ProbeShorthandAssocTys<'a, 'b, G> { |
330 |
| - fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, _: Span) { |
331 |
| - // Look for "type-parameter shorthand-associated-types". I.e., paths of the |
332 |
| - // form `T::Assoc` with `T` type param. These are reliant on trait bounds. |
333 |
| - // Suggest fully qualifying them via `<T as /* Trait */>::Assoc`. |
334 |
| - // |
335 |
| - // Instead of attempting to figure out the necessary trait ref, just use a |
336 |
| - // placeholder. Since we don't record type-dependent resolutions for non-body |
337 |
| - // items like type aliases, we can't simply deduce the corresp. trait from |
338 |
| - // the HIR path alone without rerunning parts of HIR ty lowering here |
339 |
| - // (namely `probe_single_ty_param_bound_for_assoc_ty`) which is infeasible. |
340 |
| - // |
341 |
| - // (We could employ some simple heuristics but that's likely not worth it). |
342 |
| - if let hir::QPath::TypeRelative(qself, _) = qpath |
343 |
| - && let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = qself.kind |
344 |
| - && let hir::def::Res::Def(hir::def::DefKind::TyParam, _) = path.res |
345 |
| - { |
346 |
| - self.diag.multipart_suggestion( |
347 |
| - fluent::lint_builtin_type_alias_bounds_qualify_assoc_tys_sugg, |
348 |
| - vec![ |
349 |
| - (qself.span.shrink_to_lo(), "<".into()), |
350 |
| - (qself.span.shrink_to_hi(), " as /* Trait */>".into()), |
351 |
| - ], |
352 |
| - Applicability::HasPlaceholders, |
353 |
| - ); |
354 |
| - } |
355 |
| - hir::intravisit::walk_qpath(self, qpath, id) |
356 |
| - } |
| 297 | + |
| 298 | + let affect_object_lifetime_defaults = self |
| 299 | + .preds |
| 300 | + .iter() |
| 301 | + .filter(|pred| pred.in_where_clause() == self.in_where_clause) |
| 302 | + .any(|pred| TypeAliasBounds::affects_object_lifetime_defaults(pred)); |
| 303 | + |
| 304 | + // If there are any shorthand assoc tys, then the bounds can't be removed automatically. |
| 305 | + // The user first needs to fully qualify the assoc tys. |
| 306 | + let applicability = if !collector.qselves.is_empty() || affect_object_lifetime_defaults { |
| 307 | + Applicability::MaybeIncorrect |
| 308 | + } else { |
| 309 | + Applicability::MachineApplicable |
| 310 | + }; |
| 311 | + |
| 312 | + diag.arg("count", self.suggestions.len()); |
| 313 | + diag.multipart_suggestion(fluent::lint_suggestion, self.suggestions, applicability); |
| 314 | + |
| 315 | + // Suggest fully qualifying paths of the form `T::Assoc` with `T` type param via |
| 316 | + // `<T as /* Trait */>::Assoc` to remove their reliance on any type param bounds. |
| 317 | + // |
| 318 | + // Instead of attempting to figure out the necessary trait ref, just use a |
| 319 | + // placeholder. Since we don't record type-dependent resolutions for non-body |
| 320 | + // items like type aliases, we can't simply deduce the corresp. trait from |
| 321 | + // the HIR path alone without rerunning parts of HIR ty lowering here |
| 322 | + // (namely `probe_single_ty_param_bound_for_assoc_ty`) which is infeasible. |
| 323 | + // |
| 324 | + // (We could employ some simple heuristics but that's likely not worth it). |
| 325 | + for qself in collector.qselves { |
| 326 | + diag.multipart_suggestion( |
| 327 | + fluent::lint_builtin_type_alias_bounds_qualify_assoc_tys_sugg, |
| 328 | + vec![ |
| 329 | + (qself.shrink_to_lo(), "<".into()), |
| 330 | + (qself.shrink_to_hi(), " as /* Trait */>".into()), |
| 331 | + ], |
| 332 | + Applicability::HasPlaceholders, |
| 333 | + ); |
357 | 334 | }
|
358 |
| - ProbeShorthandAssocTys { diag }.visit_ty(self.ty); |
359 | 335 | }
|
360 | 336 | }
|
361 | 337 |
|
|
0 commit comments