From 76802e31a131d2ac5933b8283a292735b6ab8366 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Wed, 3 May 2023 21:09:50 +0000
Subject: [PATCH] Error message for ambiguous RTN from super bounds

---
 compiler/rustc_hir_analysis/messages.ftl      |  4 +++
 .../rustc_hir_analysis/src/astconv/mod.rs     | 12 +++++--
 compiler/rustc_hir_analysis/src/errors.rs     | 14 +++++++-
 compiler/rustc_middle/src/ty/print/pretty.rs  |  6 ++++
 .../super-method-bound-ambig.rs               | 32 +++++++++++++++++++
 .../super-method-bound-ambig.stderr           | 19 +++++++++++
 6 files changed, 84 insertions(+), 3 deletions(-)
 create mode 100644 tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs
 create mode 100644 tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr

diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 703f168b766..2035b256daa 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -194,6 +194,10 @@ hir_analysis_return_type_notation_equality_bound =
 hir_analysis_return_type_notation_missing_method =
     cannot find associated function `{$assoc_name}` for `{$ty_name}`
 
+hir_analysis_return_type_notation_conflicting_bound =
+    ambiguous associated function `{$assoc_name}` for `{$ty_name}`
+    .note = `{$assoc_name}` is declared in two supertraits: `{$first_bound}` and `{$second_bound}`
+
 hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
     .label = not allowed in type signatures
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 7880a248cb0..9abb71d8b1a 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2083,8 +2083,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
         };
 
-        if let Some(_conflicting_candidate) = matching_candidates.next() {
-            todo!()
+        if let Some(conflicting_candidate) = matching_candidates.next() {
+            return Err(self.tcx().sess.emit_err(
+                crate::errors::ReturnTypeNotationConflictingBound {
+                    span,
+                    ty_name: ty_name.to_string(),
+                    assoc_name: assoc_name.name,
+                    first_bound: candidate.print_only_trait_path(),
+                    second_bound: conflicting_candidate.print_only_trait_path(),
+                },
+            ));
         }
 
         Ok(candidate)
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 48330a94255..32c66b16fb9 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_errors::{
     MultiSpan,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{self, print::TraitRefPrintOnlyTraitPath, Ty};
 use rustc_span::{symbol::Ident, Span, Symbol};
 
 #[derive(Diagnostic)]
@@ -516,6 +516,18 @@ pub(crate) struct ReturnTypeNotationMissingMethod {
     pub assoc_name: Symbol,
 }
 
+#[derive(Diagnostic)]
+#[diag(hir_analysis_return_type_notation_conflicting_bound)]
+#[note]
+pub(crate) struct ReturnTypeNotationConflictingBound<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub ty_name: String,
+    pub assoc_name: Symbol,
+    pub first_bound: ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+    pub second_bound: ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = "E0121")]
 pub(crate) struct PlaceholderNotAllowedItemSignatures {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 2aced27f7bb..32403d9a5e6 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2633,6 +2633,12 @@ macro_rules! define_print_and_forward_display {
 #[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
 pub struct TraitRefPrintOnlyTraitPath<'tcx>(ty::TraitRef<'tcx>);
 
+impl<'tcx> rustc_errors::IntoDiagnosticArg for TraitRefPrintOnlyTraitPath<'tcx> {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        self.to_string().into_diagnostic_arg()
+    }
+}
+
 impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Display::fmt(self, f)
diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs
new file mode 100644
index 00000000000..028e526b5f5
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs
@@ -0,0 +1,32 @@
+// edition:2021
+
+#![feature(async_fn_in_trait, return_type_notation)]
+//~^ WARN the feature `return_type_notation` is incomplete
+
+trait Super1<'a> {
+    async fn test();
+}
+impl Super1<'_> for () {
+    async fn test() {}
+}
+
+trait Super2 {
+    async fn test();
+}
+impl Super2 for () {
+    async fn test() {}
+}
+
+trait Foo: for<'a> Super1<'a> + Super2 {}
+impl Foo for () {}
+
+fn test<T>()
+where
+    T: Foo<test(): Send>,
+    //~^ ERROR ambiguous associated function `test` for `Foo`
+{
+}
+
+fn main() {
+    test::<()>();
+}
diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr
new file mode 100644
index 00000000000..5bc8dbde4bc
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr
@@ -0,0 +1,19 @@
+warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/super-method-bound-ambig.rs:3:31
+   |
+LL | #![feature(async_fn_in_trait, return_type_notation)]
+   |                               ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: ambiguous associated function `test` for `Foo`
+  --> $DIR/super-method-bound-ambig.rs:25:12
+   |
+LL |     T: Foo<test(): Send>,
+   |            ^^^^^^^^^^^^
+   |
+   = note: `test` is declared in two supertraits: `Super2` and `Super1<'a>`
+
+error: aborting due to previous error; 1 warning emitted
+