Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Compensate loss of transitivity" #21356

Merged
merged 2 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 3 additions & 15 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1385,6 +1385,8 @@ trait Implicits:
def disambiguate(alt1: SearchResult, alt2: SearchSuccess) = alt1 match
case alt1: SearchSuccess =>
var diff = compareAlternatives(alt1, alt2, disambiguate = true)
assert(diff <= 0 || isWarnPriorityChangeVersion)
// diff > 0 candidates should already have been eliminated in `rank`
if diff == 0 && alt1.ref =:= alt2.ref then
diff = 1 // See i12951 for a test where this happens
else if diff == 0 && alt2.isExtension then
Expand Down Expand Up @@ -1636,21 +1638,7 @@ trait Implicits:
validateOrdering(ord)
throw ex

val sorted = sort(eligible)
val res = sorted match
case first :: rest =>
val firstIsImplicit = first.ref.symbol.is(Implicit)
if rest.exists(_.ref.symbol.is(Implicit) != firstIsImplicit) then
// Mixture of implicits and givens
// Rank implicits first, then, if there is a given that it better than the best implicit(s)
// switch over to givens.
val (sortedImplicits, sortedGivens) = sorted.partition(_.ref.symbol.is(Implicit))
val implicitResult = rank(sortedImplicits, NoMatchingImplicitsFailure, Nil)
rank(sortedGivens, implicitResult, Nil)
else
rank(sorted, NoMatchingImplicitsFailure, Nil)
case _ =>
NoMatchingImplicitsFailure
val res = rank(sort(eligible), NoMatchingImplicitsFailure, Nil)

// Issue all priority change warnings that can affect the result
val shownWarnings = priorityChangeWarnings.toList.collect:
Expand Down
File renamed without changes.
73 changes: 73 additions & 0 deletions tests/pos/i21320b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import scala.deriving.*
import scala.compiletime.*

trait ConfigMonoid[T]:
def zero: T
def orElse(main: T, defaults: T): T

object ConfigMonoid:
given option[T]: ConfigMonoid[Option[T]] = ???

inline def zeroTuple[C <: Tuple]: Tuple =
inline erasedValue[C] match
case _: EmptyTuple => EmptyTuple
case _: (t *: ts) =>
summonInline[ConfigMonoid[t]].zero *: zeroTuple[ts]

inline def valueTuple[C <: Tuple, T](index: Int, main: T, defaults: T): Tuple =
inline erasedValue[C] match
case _: EmptyTuple => EmptyTuple
case _: (t *: ts) =>
def get(v: T) = v.asInstanceOf[Product].productElement(index).asInstanceOf[t]
summonInline[ConfigMonoid[t]].orElse(get(main), get(defaults)) *: valueTuple[ts, T](
index + 1,
main,
defaults
)

inline given derive[T](using m: Mirror.ProductOf[T]): ConfigMonoid[T] =
new ConfigMonoid[T]:
def zero: T = m.fromProduct(zeroTuple[m.MirroredElemTypes])
def orElse(main: T, defaults: T): T = m.fromProduct(valueTuple[m.MirroredElemTypes, T](0, main, defaults))



final case class PublishOptions(
v1: Option[String] = None,
v2: Option[String] = None,
v3: Option[String] = None,
v4: Option[String] = None,
v5: Option[String] = None,
v6: Option[String] = None,
v7: Option[String] = None,
v8: Option[String] = None,
v9: Option[String] = None,
ci: PublishContextualOptions = PublishContextualOptions(),
)
object PublishOptions:
implicit val monoid: ConfigMonoid[PublishOptions] = ConfigMonoid.derive

final case class PublishContextualOptions(
v1: Option[String] = None,
v2: Option[String] = None,
v3: Option[String] = None,
v4: Option[String] = None,
v5: Option[String] = None,
v6: Option[String] = None,
v7: Option[String] = None,
v8: Option[String] = None,
v9: Option[String] = None,
v10: Option[String] = None,
v11: Option[String] = None,
v12: Option[String] = None,
v13: Option[String] = None,
v14: Option[String] = None,
v15: Option[String] = None,
v16: Option[String] = None,
v17: Option[String] = None,
v18: Option[String] = None,
v19: Option[String] = None,
v20: Option[String] = None
)
object PublishContextualOptions:
implicit val monoid: ConfigMonoid[PublishContextualOptions] = ConfigMonoid.derive // was crash
19 changes: 19 additions & 0 deletions tests/pos/i21352a/schema.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//> using options -source:3.5

case class Schema[T](format: String):
def asOption: Schema[Option[T]] = ???
def name(name: Option[SName]): Schema[T] = ???
def format(f: String): Schema[T] = ???

object Schema extends SchemaCompanionMacros:
implicit def schemaForOption[T: Schema]: Schema[Option[T]] =
implicitly[Schema[T]]
???

trait SchemaCompanionMacros extends SchemaDerivation:
given derivedStringBasedUnionEnumeration[S](using IsUnionOf[String, S]): Schema[S] =
val x: Schema[S] = ???
x.name(None)

@main def Test =
case class Foo(x: Int) derives Schema
26 changes: 26 additions & 0 deletions tests/pos/i21352a/schemaDerivation.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//> using options -source:3.5

import scala.deriving.*
import scala.quoted.*

trait SName
abstract class CaseClass[Typeclass[_], Type]:
def param: CaseClass.Param[Typeclass, Type]

object CaseClass:
trait Param[Typeclass[_], Type]:
type PType
def typeclass: Typeclass[PType]


sealed trait IsUnionOf[T, A]
object IsUnionOf:
transparent inline given derived[T, A]: IsUnionOf[T, A] = ${ deriveImpl[T, A] }
private def deriveImpl[T, A](using quotes: Quotes): Expr[IsUnionOf[T, A]] = ???

trait SchemaDerivation:
inline implicit def derived[T](implicit m: Mirror.Of[T]): Schema[T] =
val ctx: CaseClass[Schema, T] = ???
val valueSchema = ctx.param.typeclass
val format = valueSchema.format
???
33 changes: 33 additions & 0 deletions tests/pos/i21352b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

object serializer:
trait Reader[T]
trait Writer[T]
// Needs to be implicit val
implicit val UnitReader: Reader[Unit] = ???
implicit val StringReader: Reader[String] = ???
// A way to derive instances needs to be available
inline given superTypeReader[T: scala.reflect.ClassTag]: Reader[T] = ???
import serializer.Reader

trait Codec[T]
trait Channel[F[_]]:
def notificationStub[In: Codec](): In => F[Unit]
trait Monadic[F[_]]

sealed abstract class LSPNotification():
type In
given inputReader: Reader[In]

class PreparedNotification[X <: LSPNotification](val x: X, val in: x.In):
type In = x.In

trait Communicate[F[_]]:
def notification[X <: LSPNotification](notif: X, in: notif.In): F[Unit]

object Communicate:
given codec[T: Reader]: Codec[T] = ???

def channel[F[_]: Monadic](channel: Channel[F]) =
new Communicate[F]:
override def notification[X <: LSPNotification](notif: X, in: notif.In): F[Unit] =
channel.notificationStub().apply(in) // was error
17 changes: 17 additions & 0 deletions tests/pos/i21352c.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

trait Text[T]
trait Read[A]
object Read extends ReadImplicits:
implicit val unit: Read[Unit] = ???
trait ReadImplicits:
import scala.deriving.*
given roe: Read[Option[EmptyTuple]] = ???
given rou: Read[Option[Unit]] = ???
given cons1[H, T <: Tuple](using Read[Option[H]], Read[Option[T]]): Read[Option[H *: T]] = ???

trait Fragment:
def query[B: Read]: String = ???

@main def Test =
val f: Fragment = ???
f.query // was error
Loading