@@ -545,29 +545,49 @@ trait Implicits { self: Typer =>
545545 /** If `formal` is of the form ClassTag[T], where `T` is a class type,
546546 * synthesize a class tag for `T`.
547547 */
548- def synthesizedClassTag(formal: Type, pos: Position)(implicit ctx: Context): Tree = {
549- if (formal.isRef(defn.ClassTagClass))
550- formal.argTypes match {
551- case arg :: Nil =>
552- fullyDefinedType(arg, "ClassTag argument", pos) match {
553- case defn.ArrayOf(elemTp) =>
554- val etag = inferImplicitArg(defn.ClassTagType.appliedTo(elemTp), error, pos)
555- if (etag.isEmpty) etag else etag.select(nme.wrap)
556- case tp if hasStableErasure(tp) =>
557- if (defn.isBottomClass(tp.typeSymbol))
558- error(where => i"attempt to take ClassTag of undetermined type for $where")
559- ref(defn.ClassTagModule)
560- .select(nme.apply)
561- .appliedToType(tp)
562- .appliedTo(clsOf(erasure(tp)))
563- .withPos(pos)
564- case tp =>
565- EmptyTree
566- }
567- case _ =>
568- EmptyTree
569- }
570- else EmptyTree
548+ def synthesizedClassTag(formal: Type)(implicit ctx: Context): Tree =
549+ formal.argTypes match {
550+ case arg :: Nil =>
551+ fullyDefinedType(arg, "ClassTag argument", pos) match {
552+ case defn.ArrayOf(elemTp) =>
553+ val etag = inferImplicitArg(defn.ClassTagType.appliedTo(elemTp), error, pos)
554+ if (etag.isEmpty) etag else etag.select(nme.wrap)
555+ case tp if hasStableErasure(tp) =>
556+ if (defn.isBottomClass(tp.typeSymbol))
557+ error(where => i"attempt to take ClassTag of undetermined type for $where")
558+ ref(defn.ClassTagModule)
559+ .select(nme.apply)
560+ .appliedToType(tp)
561+ .appliedTo(clsOf(erasure(tp)))
562+ .withPos(pos)
563+ case tp =>
564+ EmptyTree
565+ }
566+ case _ =>
567+ EmptyTree
568+ }
569+
570+ /** If `formal` is of the form Eq[T, U], where no `Eq` instance exists for
571+ * either `T` or `U`, synthesize `Eq.eqAny[T, U]` as solution.
572+ */
573+ def synthesizedEq(formal: Type)(implicit ctx: Context): Tree = {
574+ //println(i"synth eq $formal / ${formal.argTypes}%, %")
575+ formal.argTypes match {
576+ case args @ (arg1 :: arg2 :: Nil)
577+ if !ctx.featureEnabled(defn.LanguageModuleClass, nme.strictEquality) &&
578+ validEqAnyArgs(arg1, arg2)(ctx.fresh.setExploreTyperState) =>
579+ ref(defn.Eq_eqAny).appliedToTypes(args).withPos(pos)
580+ case _ =>
581+ EmptyTree
582+ }
583+ }
584+
585+ def hasEq(tp: Type): Boolean =
586+ inferImplicit(defn.EqType.appliedTo(tp, tp), EmptyTree, pos).isInstanceOf[SearchSuccess]
587+
588+ def validEqAnyArgs(tp1: Type, tp2: Type)(implicit ctx: Context) = {
589+ List(tp1, tp2).foreach(fullyDefinedType(_, "eqAny argument", pos))
590+ assumedCanEqual(tp1, tp2) || !hasEq(tp1) && !hasEq(tp2)
571591 }
572592
573593 /** The context to be used when resolving a by-name implicit argument.
@@ -606,7 +626,13 @@ trait Implicits { self: Typer =>
606626 error(where => s"ambiguous implicits: ${ambi.explanation} of $where")
607627 EmptyTree
608628 case failure: SearchFailure =>
609- val arg = synthesizedClassTag(formalValue, pos)
629+ val arg =
630+ if (formalValue.isRef(defn.ClassTagClass))
631+ synthesizedClassTag(formalValue)
632+ else if (formalValue.isRef(defn.EqClass))
633+ synthesizedEq(formalValue)
634+ else
635+ EmptyTree
610636 if (!arg.isEmpty) arg
611637 else {
612638 var msgFn = (where: String) =>
@@ -638,10 +664,10 @@ trait Implicits { self: Typer =>
638664 }
639665
640666 val lift = new TypeMap {
641- def apply(t: Type) = t match {
667+ def apply(t: Type): Type = t match {
642668 case t: TypeRef =>
643669 t.info match {
644- case TypeBounds(lo, hi) if lo ne hi => hi
670+ case TypeBounds(lo, hi) if lo ne hi => apply(hi)
645671 case _ => t
646672 }
647673 case _ =>
@@ -714,6 +740,8 @@ trait Implicits { self: Typer =>
714740 if (argument.isEmpty) f(resultType) else ViewProto(f(argument.tpe.widen), f(resultType))
715741 // Not clear whether we need to drop the `.widen` here. All tests pass with it in place, though.
716742
743+ private def isCoherent = pt.isRef(defn.EqClass)
744+
717745 assert(argument.isEmpty || argument.tpe.isValueType || argument.tpe.isInstanceOf[ExprType],
718746 em"found: $argument: ${argument.tpe}, expected: $pt")
719747
@@ -761,40 +789,16 @@ trait Implicits { self: Typer =>
761789 case _ => false
762790 }
763791 }
764- // Does there exist an implicit value of type `Eq[tp, tp]`
765- // which is different from `eqAny`?
766- def hasEq(tp: Type): Boolean = {
767- def search(contextual: Boolean): Boolean =
768- new ImplicitSearch(defn.EqType.appliedTo(tp, tp), EmptyTree, pos)
769- .bestImplicit(contextual) match {
770- case result: SearchSuccess =>
771- result.ref.symbol != defn.Predef_eqAny ||
772- contextual && search(contextual = false)
773- case result: AmbiguousImplicits => true
774- case _ => false
775- }
776- search(contextual = true)
777- }
778792
779- def validEqAnyArgs(tp1: Type, tp2: Type) = {
780- List(tp1, tp2).foreach(fullyDefinedType(_, "eqAny argument", pos))
781- assumedCanEqual(tp1, tp2) || !hasEq(tp1) && !hasEq(tp2) ||
782- { implicits.println(i"invalid eqAny[$tp1, $tp2]"); false }
783- }
784793 if (ctx.reporter.hasErrors)
785794 nonMatchingImplicit(ref, ctx.reporter.removeBufferedMessages)
786795 else if (contextual && !ctx.mode.is(Mode.ImplicitShadowing) &&
787796 !shadowing.tpe.isError && !refSameAs(shadowing)) {
788797 implicits.println(i"SHADOWING $ref in ${ref.termSymbol.owner} is shadowed by $shadowing in ${shadowing.symbol.owner}")
789798 shadowedImplicit(ref, methPart(shadowing).tpe)
790799 }
791- else generated1 match {
792- case TypeApply(fn, targs @ (arg1 :: arg2 :: Nil))
793- if fn.symbol == defn.Predef_eqAny && !validEqAnyArgs(arg1.tpe, arg2.tpe) =>
794- nonMatchingImplicit(ref, Nil)
795- case _ =>
796- SearchSuccess(generated1, ref, cand.level, ctx.typerState)
797- }
800+ else
801+ SearchSuccess(generated1, ref, cand.level, ctx.typerState)
798802 }}
799803
800804 /** Given a list of implicit references, produce a list of all implicit search successes,
@@ -812,7 +816,7 @@ trait Implicits { self: Typer =>
812816 case fail: SearchFailure =>
813817 rankImplicits(pending1, acc)
814818 case best: SearchSuccess =>
815- if (ctx.mode.is(Mode.ImplicitExploration)) best :: Nil
819+ if (ctx.mode.is(Mode.ImplicitExploration) || isCoherent ) best :: Nil
816820 else {
817821 val newPending = pending1.filter(cand1 =>
818822 isAsGood(cand1.ref, best.ref, cand1.level, best.level)(nestedContext.setExploreTyperState))
0 commit comments