diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 155d7fe237f1..f69498cc97a4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -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 } diff --git a/tests/pos/i6914.scala b/tests/pos/i6914.scala new file mode 100644 index 000000000000..0278721a1dcf --- /dev/null +++ b/tests/pos/i6914.scala @@ -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" +} \ No newline at end of file