@@ -84,6 +84,9 @@ object Implicits:
8484 def strictEquality(using Context): Boolean =
8585 ctx.mode.is(Mode.StrictEquality) || Feature.enabled(nme.strictEquality)
8686
87+ def strictEqualityPatternMatching(using Context): Boolean =
88+ Feature.enabled(Feature.strictEqualityPatternMatching)
89+
8790
8891 /** A common base class of contextual implicits and of-type implicits which
8992 * represents a set of references to implicit definitions.
@@ -1038,8 +1041,9 @@ trait Implicits:
10381041 * - if one of T, U is an error type, or
10391042 * - if one of T, U is a subtype of the lifted version of the other,
10401043 * unless strict equality is set.
1044+ * - if strictEqualityPatternMatching is set and the necessary conditions are met
10411045 */
1042- def assumedCanEqual(ltp: Type, rtp: Type)(using Context) = {
1046+ def assumedCanEqual(ltp: Type, rtp: Type, leftTree: Tree = EmptyTree )(using Context): Boolean = {
10431047 // Map all non-opaque abstract types to their upper bound.
10441048 // This is done to check whether such types might plausibly be comparable to each other.
10451049 val lift = new TypeMap {
@@ -1062,15 +1066,23 @@ trait Implicits:
10621066
10631067 ltp.isError
10641068 || rtp.isError
1065- || !strictEquality && (ltp <:< lift(rtp) || rtp <:< lift(ltp))
1069+ || locally:
1070+ if strictEquality then
1071+ strictEqualityPatternMatching &&
1072+ (leftTree.symbol.isAllOf(Flags.EnumValue) || leftTree.symbol.isAllOf(Flags.Module | Flags.Case)) &&
1073+ ltp <:< lift(rtp)
1074+ else
1075+ ltp <:< lift(rtp) || rtp <:< lift(ltp)
10661076 }
10671077
1068- /** Check that equality tests between types `ltp` and `rtp` make sense */
1069- def checkCanEqual(ltp: Type, rtp: Type, span: Span)(using Context): Unit =
1070- if (!ctx.isAfterTyper && !assumedCanEqual(ltp, rtp)) {
1078+ /** Check that equality tests between types `ltp` and `left.tpe` make sense.
1079+ * `left` is required to check for the condition for language.strictEqualityPatternMatching.
1080+ */
1081+ def checkCanEqual(left: Tree, rtp: Type, span: Span)(using Context): Unit =
1082+ val ltp = left.tpe.widen
1083+ if !ctx.isAfterTyper && !assumedCanEqual(ltp, rtp, left) then
10711084 val res = implicitArgTree(defn.CanEqualClass.typeRef.appliedTo(ltp, rtp), span)
10721085 implicits.println(i"CanEqual witness found for $ltp / $rtp: $res: ${res.tpe}")
1073- }
10741086
10751087 object hasSkolem extends TreeAccumulator[Boolean]:
10761088 def apply(x: Boolean, tree: Tree)(using Context): Boolean =
0 commit comments