diff options
| author | 许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com> | 2023-06-10 17:06:26 +0800 |
|---|---|---|
| committer | 许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com> | 2023-06-15 18:19:09 +0800 |
| commit | 32ae8810fcc6d96a1e7e5447f5b35759ca338ed9 (patch) | |
| tree | 7ad52c891db2fdebfe29ac7207a201562443235c /compiler/rustc_resolve/src | |
| parent | 314c39d2ea07d8b50649149358ebeb1a6bd09179 (diff) | |
| download | rust-32ae8810fcc6d96a1e7e5447f5b35759ca338ed9.tar.gz rust-32ae8810fcc6d96a1e7e5447f5b35759ca338ed9.zip | |
Fix suggestion for E0404 not dealing with multiple generics
Diffstat (limited to 'compiler/rustc_resolve/src')
| -rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 92 |
1 files changed, 69 insertions, 23 deletions
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e4b01ef2b17..7284b33f09d 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -10,7 +10,7 @@ use rustc_ast::{ self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, MethodCall, NodeId, Path, Ty, TyKind, DUMMY_NODE_ID, }; -use rustc_ast_pretty::pprust::path_segment_to_string; +use rustc_ast_pretty::pprust::where_bound_predicate_to_string; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, @@ -1050,7 +1050,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { }; // Confirm that the target is an associated type. - let (ty, position, path) = if let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind { + let (ty, _, path) = if let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind { // use this to verify that ident is a type param. let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { return false; @@ -1079,7 +1079,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { return false; } if let ( - [ast::PathSegment { ident: constrain_ident, args: None, .. }], + [ast::PathSegment { args: None, .. }], [ast::GenericBound::Trait(poly_trait_ref, ast::TraitBoundModifier::None)], ) = (&type_param_path.segments[..], &bounds[..]) { @@ -1087,29 +1087,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { &poly_trait_ref.trait_ref.path.segments[..] { if ident.span == span { + let Some(new_where_bound_predicate) = mk_where_bound_predicate(path, poly_trait_ref, ty) else { return false; }; err.span_suggestion_verbose( *where_span, format!("constrain the associated type to `{}`", ident), - format!( - "{}: {}<{} = {}>", - self.r - .tcx - .sess - .source_map() - .span_to_snippet(ty.span) // Account for `<&'a T as Foo>::Bar`. - .unwrap_or_else(|_| constrain_ident.to_string()), - path.segments[..position] - .iter() - .map(|segment| path_segment_to_string(segment)) - .collect::<Vec<_>>() - .join("::"), - path.segments[position..] - .iter() - .map(|segment| path_segment_to_string(segment)) - .collect::<Vec<_>>() - .join("::"), - ident, - ), + where_bound_predicate_to_string(&new_where_bound_predicate), Applicability::MaybeIncorrect, ); } @@ -2605,6 +2587,70 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } +fn mk_where_bound_predicate( + path: &Path, + poly_trait_ref: &ast::PolyTraitRef, + ty: &ast::Ty, +) -> Option<ast::WhereBoundPredicate> { + use rustc_span::DUMMY_SP; + let modified_segments = { + let mut segments = path.segments.clone(); + let [preceding @ .., second_last, last] = segments.as_mut_slice() else { return None; }; + let mut segments = ThinVec::from(preceding); + + let added_constraint = ast::AngleBracketedArg::Constraint(ast::AssocConstraint { + id: DUMMY_NODE_ID, + ident: last.ident, + gen_args: None, + kind: ast::AssocConstraintKind::Equality { + term: ast::Term::Ty(ast::ptr::P(ast::Ty { + kind: ast::TyKind::Path(None, poly_trait_ref.trait_ref.path.clone()), + id: DUMMY_NODE_ID, + span: DUMMY_SP, + tokens: None, + })), + }, + span: DUMMY_SP, + }); + + match second_last.args.as_deref_mut() { + Some(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { args, .. })) => { + args.push(added_constraint); + } + Some(_) => return None, + None => { + second_last.args = + Some(ast::ptr::P(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { + args: ThinVec::from([added_constraint]), + span: DUMMY_SP, + }))); + } + } + + segments.push(second_last.clone()); + segments + }; + + let new_where_bound_predicate = ast::WhereBoundPredicate { + span: DUMMY_SP, + bound_generic_params: ThinVec::new(), + bounded_ty: ast::ptr::P(ty.clone()), + bounds: vec![ast::GenericBound::Trait( + ast::PolyTraitRef { + bound_generic_params: ThinVec::new(), + trait_ref: ast::TraitRef { + path: ast::Path { segments: modified_segments, span: DUMMY_SP, tokens: None }, + ref_id: DUMMY_NODE_ID, + }, + span: DUMMY_SP, + }, + ast::TraitBoundModifier::None, + )], + }; + + Some(new_where_bound_predicate) +} + /// Report lifetime/lifetime shadowing as an error. pub(super) fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) { let mut err = struct_span_err!( |
