@@ -403,6 +403,141 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
403403 } )
404404 }
405405
406+ pub ( super ) fn report_ambiguous_assoc_item (
407+ & self ,
408+ bound1 : ty:: PolyTraitRef < ' tcx > ,
409+ bound2 : ty:: PolyTraitRef < ' tcx > ,
410+ matching_candidates : impl Iterator < Item = ty:: PolyTraitRef < ' tcx > > ,
411+ qself : AssocItemQSelf ,
412+ assoc_tag : ty:: AssocTag ,
413+ assoc_ident : Ident ,
414+ span : Span ,
415+ constraint : Option < & hir:: AssocItemConstraint < ' tcx > > ,
416+ ) -> ErrorGuaranteed {
417+ let tcx = self . tcx ( ) ;
418+
419+ let assoc_kind_str = assoc_tag_str ( assoc_tag) ;
420+ let qself_str = qself. to_string ( tcx) ;
421+ let mut err = self . dcx ( ) . create_err ( crate :: errors:: AmbiguousAssocItem {
422+ span,
423+ assoc_kind : assoc_kind_str,
424+ assoc_ident,
425+ qself : & qself_str,
426+ } ) ;
427+ // Provide a more specific error code index entry for equality bindings.
428+ err. code (
429+ if let Some ( constraint) = constraint
430+ && let hir:: AssocItemConstraintKind :: Equality { .. } = constraint. kind
431+ {
432+ E0222
433+ } else {
434+ E0221
435+ } ,
436+ ) ;
437+
438+ // FIXME(#97583): Print associated item bindings properly (i.e., not as equality
439+ // predicates!).
440+ // FIXME: Turn this into a structured, translatable & more actionable suggestion.
441+ let mut where_bounds = vec ! [ ] ;
442+ for bound in [ bound1, bound2] . into_iter ( ) . chain ( matching_candidates) {
443+ let bound_id = bound. def_id ( ) ;
444+ let assoc_item = tcx. associated_items ( bound_id) . find_by_ident_and_kind (
445+ tcx,
446+ assoc_ident,
447+ assoc_tag,
448+ bound_id,
449+ ) ;
450+ let bound_span = assoc_item. and_then ( |item| tcx. hir_span_if_local ( item. def_id ) ) ;
451+
452+ if let Some ( bound_span) = bound_span {
453+ err. span_label (
454+ bound_span,
455+ format ! ( "ambiguous `{assoc_ident}` from `{}`" , bound. print_trait_sugared( ) , ) ,
456+ ) ;
457+ if let Some ( constraint) = constraint {
458+ match constraint. kind {
459+ hir:: AssocItemConstraintKind :: Equality { term } => {
460+ let term: ty:: Term < ' _ > = match term {
461+ hir:: Term :: Ty ( ty) => self . lower_ty ( ty) . into ( ) ,
462+ hir:: Term :: Const ( ct) => {
463+ let assoc_item =
464+ assoc_item. expect ( "assoc_item should be present" ) ;
465+ let projection_term = bound. map_bound ( |trait_ref| {
466+ let item_segment = hir:: PathSegment {
467+ ident : constraint. ident ,
468+ hir_id : constraint. hir_id ,
469+ res : Res :: Err ,
470+ args : Some ( constraint. gen_args ) ,
471+ infer_args : false ,
472+ } ;
473+
474+ let alias_args = self . lower_generic_args_of_assoc_item (
475+ constraint. ident . span ,
476+ assoc_item. def_id ,
477+ & item_segment,
478+ trait_ref. args ,
479+ ) ;
480+ ty:: AliasTerm :: new_from_def_id (
481+ tcx,
482+ assoc_item. def_id ,
483+ alias_args,
484+ )
485+ } ) ;
486+
487+ // FIXME(mgca): code duplication with other places we lower
488+ // the rhs' of associated const bindings
489+ let ty = projection_term. map_bound ( |alias| {
490+ tcx. type_of ( alias. def_id ( ) )
491+ . instantiate ( tcx, alias. args )
492+ . skip_norm_wip ( )
493+ } ) ;
494+ let ty = super :: bounds:: check_assoc_const_binding_type (
495+ self ,
496+ constraint. ident ,
497+ ty,
498+ constraint. hir_id ,
499+ ) ;
500+
501+ self . lower_const_arg ( ct, ty) . into ( )
502+ }
503+ } ;
504+ if term. references_error ( ) {
505+ continue ;
506+ }
507+ // FIXME(#97583): This isn't syntactically well-formed!
508+ where_bounds. push ( format ! (
509+ " T: {trait}::{assoc_ident} = {term}" ,
510+ trait = bound. print_only_trait_path( ) ,
511+ ) ) ;
512+ }
513+ // FIXME: Provide a suggestion.
514+ hir:: AssocItemConstraintKind :: Bound { bounds : _ } => { }
515+ }
516+ } else {
517+ err. span_suggestion_verbose (
518+ span. with_hi ( assoc_ident. span . lo ( ) ) ,
519+ "use fully-qualified syntax to disambiguate" ,
520+ format ! ( "<{qself_str} as {}>::" , bound. print_only_trait_path( ) ) ,
521+ Applicability :: MaybeIncorrect ,
522+ ) ;
523+ }
524+ } else {
525+ let trait_ = tcx. short_string ( bound. print_only_trait_path ( ) , err. long_ty_path ( ) ) ;
526+ err. note ( format ! (
527+ "associated {assoc_kind_str} `{assoc_ident}` could derive from `{trait_}`" ,
528+ ) ) ;
529+ }
530+ }
531+ if !where_bounds. is_empty ( ) {
532+ err. help ( format ! (
533+ "consider introducing a new type parameter `T` and adding `where` constraints:\
534+ \n where\n T: {qself_str},\n {}",
535+ where_bounds. join( ",\n " ) ,
536+ ) ) ;
537+ }
538+ err. emit ( )
539+ }
540+
406541 pub ( crate ) fn report_missing_self_ty_for_resolved_path (
407542 & self ,
408543 trait_def_id : DefId ,
@@ -568,7 +703,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
568703 }
569704 }
570705
571- pub ( super ) fn report_ambiguous_assoc_item_path (
706+ fn report_ambiguous_assoc_item_path (
572707 & self ,
573708 span : Span ,
574709 types : & [ String ] ,
@@ -1847,7 +1982,59 @@ fn generics_args_err_extend<'a>(
18471982 }
18481983}
18491984
1850- pub ( crate ) fn assoc_tag_str ( assoc_tag : ty:: AssocTag ) -> & ' static str {
1985+ pub ( super ) struct AmbiguityBetweenVariantAndAssocItem < ' tcx > {
1986+ pub ( super ) variant_def_id : DefId ,
1987+ pub ( super ) item_def_id : DefId ,
1988+ pub ( super ) span : Span ,
1989+ pub ( super ) segment_ident : Ident ,
1990+ pub ( super ) bound_def_id : DefId ,
1991+ pub ( super ) self_ty : Ty < ' tcx > ,
1992+ pub ( super ) tcx : TyCtxt < ' tcx > ,
1993+ pub ( super ) mode : super :: LowerTypeRelativePathMode ,
1994+ }
1995+
1996+ impl < ' a , ' tcx > rustc_errors:: Diagnostic < ' a , ( ) > for AmbiguityBetweenVariantAndAssocItem < ' tcx > {
1997+ fn into_diag (
1998+ self ,
1999+ dcx : rustc_errors:: DiagCtxtHandle < ' a > ,
2000+ level : rustc_errors:: Level ,
2001+ ) -> Diag < ' a , ( ) > {
2002+ let Self {
2003+ variant_def_id,
2004+ item_def_id,
2005+ span,
2006+ segment_ident,
2007+ bound_def_id,
2008+ self_ty,
2009+ tcx,
2010+ mode,
2011+ } = self ;
2012+ let mut lint = Diag :: new ( dcx, level, "ambiguous associated item" ) ;
2013+
2014+ let mut could_refer_to = |kind : DefKind , def_id, also| {
2015+ let note_msg = format ! (
2016+ "`{}` could{} refer to the {} defined here" ,
2017+ segment_ident,
2018+ also,
2019+ tcx. def_kind_descr( kind, def_id)
2020+ ) ;
2021+ lint. span_note ( tcx. def_span ( def_id) , note_msg) ;
2022+ } ;
2023+
2024+ could_refer_to ( DefKind :: Variant , variant_def_id, "" ) ;
2025+ could_refer_to ( mode. def_kind_for_diagnostics ( ) , item_def_id, " also" ) ;
2026+
2027+ lint. span_suggestion (
2028+ span,
2029+ "use fully-qualified syntax" ,
2030+ format ! ( "<{} as {}>::{}" , self_ty, tcx. item_name( bound_def_id) , segment_ident) ,
2031+ Applicability :: MachineApplicable ,
2032+ ) ;
2033+ lint
2034+ }
2035+ }
2036+
2037+ fn assoc_tag_str ( assoc_tag : ty:: AssocTag ) -> & ' static str {
18512038 match assoc_tag {
18522039 ty:: AssocTag :: Fn => "function" ,
18532040 ty:: AssocTag :: Const => "constant" ,
0 commit comments