From 64d151a0466522e8b5e0a887938d374dec2882fa Mon Sep 17 00:00:00 2001
From: Dale Wijnand <dale.wijnand@gmail.com>
Date: Wed, 14 Jun 2023 18:20:26 +0100
Subject: [PATCH 1/2] Fix hasMatchingMember handling NoDenotation

---
 compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 2 +-
 tests/neg/i17581.check                                | 7 +++++++
 tests/neg/i17581.scala                                | 9 +++++++++
 tests/neg/i7812.scala                                 | 2 +-
 4 files changed, 18 insertions(+), 2 deletions(-)
 create mode 100644 tests/neg/i17581.check
 create mode 100644 tests/neg/i17581.scala

diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
index a0922c1f0574..264ff52d0af9 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -2021,7 +2021,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
         || (tp1.isStable && isSubType(TermRef(tp1, m.symbol), tp2.refinedInfo))
 
       tp1.member(name) match // inlined hasAltWith for performance
-        case mbr: SingleDenotation => qualifies(mbr)
+        case mbr: SingleDenotation => mbr.exists && qualifies(mbr)
         case mbr => mbr hasAltWith qualifies
     }
 
diff --git a/tests/neg/i17581.check b/tests/neg/i17581.check
new file mode 100644
index 000000000000..e21e9fd32019
--- /dev/null
+++ b/tests/neg/i17581.check
@@ -0,0 +1,7 @@
+-- [E007] Type Mismatch Error: tests/neg/i17581.scala:9:6 --------------------------------------------------------------
+9 |  foo(test) // error // was NoSuchMethodException
+  |      ^^^^
+  |      Found:    (test : Test)
+  |      Required: Object{def bar: Any}
+  |
+  | longer explanation available when compiling with `-explain`
diff --git a/tests/neg/i17581.scala b/tests/neg/i17581.scala
new file mode 100644
index 000000000000..1cd86a9d39cd
--- /dev/null
+++ b/tests/neg/i17581.scala
@@ -0,0 +1,9 @@
+import scala.reflect.Selectable.reflectiveSelectable
+
+class Test
+
+def foo[A <: { def bar: Any }](ob: A) = ob.bar
+
+@main def main =
+  val test = new Test
+  foo(test) // error // was NoSuchMethodException
diff --git a/tests/neg/i7812.scala b/tests/neg/i7812.scala
index 264258fa4db3..9cbd58071bc8 100644
--- a/tests/neg/i7812.scala
+++ b/tests/neg/i7812.scala
@@ -1,3 +1,3 @@
 def f(): Any = ???
 var f: (UndefinedA & UndefinedB) { val x: Int } = ??? // error // error
-val a = f // error
\ No newline at end of file
+val a = f

From 4373d48d20c872a2a45514aa5e6878572fc5e179 Mon Sep 17 00:00:00 2001
From: Dale Wijnand <dale.wijnand@gmail.com>
Date: Sat, 17 Jun 2023 11:36:55 +0100
Subject: [PATCH 2/2] Introduce hasAltWithInline, to fix all usages

---
 compiler/src/dotty/tools/dotc/core/Denotations.scala   | 4 ++++
 compiler/src/dotty/tools/dotc/core/TypeComparer.scala  | 4 +---
 compiler/src/dotty/tools/dotc/typer/Applications.scala | 5 +----
 compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala   | 4 +---
 4 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala
index 82368fd4dbf5..a535048d2e73 100644
--- a/compiler/src/dotty/tools/dotc/core/Denotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala
@@ -261,6 +261,10 @@ object Denotations {
     /** Does this denotation have an alternative that satisfies the predicate `p`? */
     def hasAltWith(p: SingleDenotation => Boolean): Boolean
 
+    inline final def hasAltWithInline(inline p: SingleDenotation => Boolean): Boolean = inline this match
+      case mbr: SingleDenotation => mbr.exists && p(mbr)
+      case mbr => mbr.hasAltWith(p)
+
     /** The denotation made up from the alternatives of this denotation that
      *  are accessible from prefix `pre`, or NoDenotation if no accessible alternative exists.
      */
diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
index 264ff52d0af9..6c7af839f008 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -2020,9 +2020,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
         || matchAbstractTypeMember(m.info)
         || (tp1.isStable && isSubType(TermRef(tp1, m.symbol), tp2.refinedInfo))
 
-      tp1.member(name) match // inlined hasAltWith for performance
-        case mbr: SingleDenotation => mbr.exists && qualifies(mbr)
-        case mbr => mbr hasAltWith qualifies
+      tp1.member(name).hasAltWithInline(qualifies)
     }
 
   final def ensureStableSingleton(tp: Type): SingletonType = tp.stripTypeVar match {
diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala
index 17b79ab0f801..08437a529a88 100644
--- a/compiler/src/dotty/tools/dotc/typer/Applications.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala
@@ -1517,10 +1517,7 @@ trait Applications extends Compatibility {
       && isApplicableType(
             normalize(tp.select(xname, mbr), WildcardType),
             argType :: Nil, resultType)
-    tp.memberBasedOnFlags(xname, required = ExtensionMethod) match {
-      case mbr: SingleDenotation => qualifies(mbr)
-      case mbr => mbr.hasAltWith(qualifies(_))
-    }
+    tp.memberBasedOnFlags(xname, required = ExtensionMethod).hasAltWithInline(qualifies)
   }
 
   /** Drop any leading type or implicit parameter sections */
diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
index 8b04ca8dd75b..ad07b0ebd7a5 100644
--- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -212,9 +212,7 @@ object ProtoTypes {
               || tp1.isValueType && compat.normalizedCompatible(NamedType(tp1, name, m), memberProto, keepConstraint))
                 // Note: can't use `m.info` here because if `m` is a method, `m.info`
                 //       loses knowledge about `m`'s default arguments.
-          mbr match // hasAltWith inlined for performance
-            case mbr: SingleDenotation => mbr.exists && qualifies(mbr)
-            case _ => mbr hasAltWith qualifies
+          mbr.hasAltWithInline(qualifies)
         catch case ex: TypeError =>
           // A scenario where this can happen is in pos/15673.scala:
           // We have a type `CC[A]#C` where `CC`'s upper bound is `[X] => Any`, but