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