Skip to content

Fix #6914: Improve type inference for implicit Conversions #6953

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

Merged
merged 2 commits into from
Jul 31, 2019
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
59 changes: 34 additions & 25 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1359,31 +1359,40 @@ trait Implicits { self: Typer =>
//println(i"search implicits $pt / ${eligible.map(_.ref)}")

/** Try to typecheck an implicit reference */
def typedImplicit(cand: Candidate, contextual: Boolean)(implicit ctx: Context): SearchResult =
trace(i"typed implicit ${cand.ref}, pt = $pt, implicitsEnabled == ${ctx.mode is ImplicitsEnabled}", implicits, show = true) {
record("typedImplicit")
val ref = cand.ref
val generated: Tree = tpd.ref(ref).withSpan(span.startPos)
val locked = ctx.typerState.ownedVars
val adapted =
if (argument.isEmpty)
adapt(generated, pt.widenExpr, locked)
else {
val untpdGenerated = untpd.TypedSplice(generated)
def tryConversion(implicit ctx: Context) =
typed(
untpd.Apply(untpdGenerated, untpd.TypedSplice(argument) :: Nil),
pt, locked)
if (cand.isExtension) {
val SelectionProto(name: TermName, mbrType, _, _) = pt
val result = extMethodApply(untpd.Select(untpdGenerated, name), argument, mbrType)
if (!ctx.reporter.hasErrors && cand.isConversion) {
val testCtx = ctx.fresh.setExploreTyperState()
tryConversion(testCtx)
if (testCtx.reporter.hasErrors)
ctx.error(em"ambiguous implicit: $generated is eligible both as an implicit conversion and as an extension method container")
}
result
def typedImplicit(cand: Candidate, contextual: Boolean)(implicit ctx: Context): SearchResult = trace(i"typed implicit ${cand.ref}, pt = $pt, implicitsEnabled == ${ctx.mode is ImplicitsEnabled}", implicits, show = true) {
record("typedImplicit")
val ref = cand.ref
val generated: Tree = tpd.ref(ref).withSpan(span.startPos)
val locked = ctx.typerState.ownedVars
val adapted =
if (argument.isEmpty)
adapt(generated, pt.widenExpr, locked)
else {
def untpdGenerated = untpd.TypedSplice(generated)
def tryConversion(implicit ctx: Context) = {
val untpdConv =
if (ref.symbol.is(Given))
untpd.Select(
untpd.TypedSplice(
adapt(generated,
defn.ConversionClass.typeRef.appliedTo(argument.tpe.widen, pt),
locked)),
nme.apply)
else untpdGenerated
typed(
untpd.Apply(untpdConv, untpd.TypedSplice(argument) :: Nil),
pt, locked)
}
if (cand.isExtension) {
val SelectionProto(name: TermName, mbrType, _, _) = pt
val result = extMethodApply(untpd.Select(untpdGenerated, name), argument, mbrType)
if (!ctx.reporter.hasErrors && cand.isConversion) {
val testCtx = ctx.fresh.setExploreTyperState()
tryConversion(testCtx)
if (testCtx.reporter.hasErrors)
ctx.error(em"ambiguous implicit: $generated is eligible both as an implicit conversion and as an extension method container")
}
result
}
else tryConversion
}
Expand Down
29 changes: 29 additions & 0 deletions tests/pos/i6914.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
trait Expr[T]
trait Liftable[T]

object test1 {
class ToExpr[T] given Liftable[T] extends Conversion[T, Expr[T]] {
def apply(x: T): Expr[T] = ???
}
given toExpr[T] as ToExpr[T] given Liftable[T]

given as Liftable[Int] = ???
given as Liftable[String] = ???

def x = the[ToExpr[String]]
def y = the[Conversion[String, Expr[String]]]

def a: Expr[String] = "abc"
}

object test2 {

given autoToExpr[T] as Conversion[T, Expr[T]] given Liftable[T] {
def apply(x: T): Expr[T] = ???
}

given as Liftable[Int] = ???
given as Liftable[String] = ???

def a: Expr[String] = "abc"
}