Skip to content

Commit d97ec4e

Browse files
committed
Implement prototype summonIgnoring
1 parent 4ae5d61 commit d97ec4e

File tree

14 files changed

+100
-22
lines changed

14 files changed

+100
-22
lines changed

compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ class InlineReducer(inliner: Inliner)(using Context):
198198
val evTyper = new Typer(ctx.nestingLevel + 1)
199199
val evCtx = ctx.fresh.setTyper(evTyper)
200200
inContext(evCtx) {
201-
val evidence = evTyper.inferImplicitArg(tpt.tpe, tpt.span)
201+
val evidence = evTyper.inferImplicitArg(tpt.tpe, tpt.span, ignored = Set.empty)
202202
evidence.tpe match {
203203
case fail: Implicits.AmbiguousImplicits =>
204204
report.error(evTyper.missingArgMsg(evidence, tpt.tpe, ""), tpt.srcPos)

compiler/src/dotty/tools/dotc/inlines/Inlines.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ object Inlines:
441441
val evTyper = new Typer(ctx.nestingLevel + 1)
442442
val evCtx = ctx.fresh.setTyper(evTyper)
443443
inContext(evCtx) {
444-
val evidence = evTyper.inferImplicitArg(tpe, callTypeArgs.head.span)
444+
val evidence = evTyper.inferImplicitArg(tpe, callTypeArgs.head.span, ignored = Set.empty)
445445
evidence.tpe match
446446
case fail: Implicits.SearchFailureType =>
447447
errorTree(call, evTyper.missingArgMsg(evidence, tpe, ""))

compiler/src/dotty/tools/dotc/interactive/Completion.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ object Completion:
662662
*/
663663
private def implicitConversionTargets(qual: tpd.Tree)(using Context): Set[SearchSuccess] = {
664664
val typer = ctx.typer
665-
val conversions = new typer.ImplicitSearch(defn.AnyType, qual, pos.span).allImplicits
665+
val conversions = new typer.ImplicitSearch(defn.AnyType, qual, pos.span, Set.empty).allImplicits
666666

667667
interactiv.println(i"implicit conversion targets considered: ${conversions.toList}%, %")
668668
conversions

compiler/src/dotty/tools/dotc/staging/HealType.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class HealType(pos: SrcPos)(using Context) extends TypeMap {
8686
*/
8787
protected def tryHeal(tp: TypeRef): Type = {
8888
val reqType = defn.QuotedTypeClass.typeRef.appliedTo(tp)
89-
val tag = ctx.typer.inferImplicitArg(reqType, pos.span)
89+
val tag = ctx.typer.inferImplicitArg(reqType, pos.span, ignored = Set.empty)
9090
tag.tpe match
9191
case tp: TermRef =>
9292
ctx.typer.checkStable(tp, pos, "type witness")

compiler/src/dotty/tools/dotc/typer/Implicits.scala

+13-11
Original file line numberDiff line numberDiff line change
@@ -901,7 +901,7 @@ trait Implicits:
901901
}
902902

903903
try
904-
val inferred = inferImplicit(adjust(to), from, from.span)
904+
val inferred = inferImplicit(adjust(to), from, from.span, ignored = Set.empty)
905905

906906
inferred match {
907907
case SearchSuccess(_, ref, _, false) if isOldStyleFunctionConversion(ref.underlying) =>
@@ -928,8 +928,8 @@ trait Implicits:
928928
/** Find an implicit argument for parameter `formal`.
929929
* Return a failure as a SearchFailureType in the type of the returned tree.
930930
*/
931-
def inferImplicitArg(formal: Type, span: Span)(using Context): Tree =
932-
inferImplicit(formal, EmptyTree, span) match
931+
def inferImplicitArg(formal: Type, span: Span, ignored: Set[Symbol])(using Context): Tree =
932+
inferImplicit(formal, EmptyTree, span, ignored) match
933933
case SearchSuccess(arg, _, _, _) => arg
934934
case fail @ SearchFailure(failed) =>
935935
if fail.isAmbiguous then failed
@@ -944,7 +944,7 @@ trait Implicits:
944944

945945
/** Search an implicit argument and report error if not found */
946946
def implicitArgTree(formal: Type, span: Span, where: => String = "")(using Context): Tree = {
947-
val arg = inferImplicitArg(formal, span)
947+
val arg = inferImplicitArg(formal, span, ignored = Set.empty)
948948
if (arg.tpe.isInstanceOf[SearchFailureType])
949949
report.error(missingArgMsg(arg, formal, where), ctx.source.atSpan(span))
950950
arg
@@ -968,7 +968,7 @@ trait Implicits:
968968
def ignoredInstanceNormalImport = arg.tpe match
969969
case fail: SearchFailureType =>
970970
if (fail.expectedType eq pt) || isFullyDefined(fail.expectedType, ForceDegree.none) then
971-
inferImplicit(fail.expectedType, fail.argument, arg.span)(
971+
inferImplicit(fail.expectedType, fail.argument, arg.span, Set.empty)(
972972
using findHiddenImplicitsCtx(ctx)) match {
973973
case s: SearchSuccess => Some(s)
974974
case f: SearchFailure =>
@@ -1082,7 +1082,7 @@ trait Implicits:
10821082
* it should be applied, EmptyTree otherwise.
10831083
* @param span The position where errors should be reported.
10841084
*/
1085-
def inferImplicit(pt: Type, argument: Tree, span: Span)(using Context): SearchResult = ctx.profiler.onImplicitSearch(pt):
1085+
def inferImplicit(pt: Type, argument: Tree, span: Span, ignored: Set[Symbol])(using Context): SearchResult = ctx.profiler.onImplicitSearch(pt):
10861086
trace(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", implicits, show = true) {
10871087
record("inferImplicit")
10881088
assert(ctx.phase.allowsImplicitSearch,
@@ -1110,7 +1110,7 @@ trait Implicits:
11101110
else i"conversion from ${argument.tpe} to $pt"
11111111

11121112
CyclicReference.trace(i"searching for an implicit $searchStr"):
1113-
try ImplicitSearch(pt, argument, span)(using searchCtx).bestImplicit
1113+
try ImplicitSearch(pt, argument, span, ignored)(using searchCtx).bestImplicit
11141114
catch case ce: CyclicReference =>
11151115
ce.inImplicitSearch = true
11161116
throw ce
@@ -1130,9 +1130,9 @@ trait Implicits:
11301130
result
11311131
case result: SearchFailure if result.isAmbiguous =>
11321132
val deepPt = pt.deepenProto
1133-
if (deepPt ne pt) inferImplicit(deepPt, argument, span)
1133+
if (deepPt ne pt) inferImplicit(deepPt, argument, span, ignored)
11341134
else if (migrateTo3 && !ctx.mode.is(Mode.OldImplicitResolution))
1135-
withMode(Mode.OldImplicitResolution)(inferImplicit(pt, argument, span)) match {
1135+
withMode(Mode.OldImplicitResolution)(inferImplicit(pt, argument, span, ignored)) match {
11361136
case altResult: SearchSuccess =>
11371137
report.migrationWarning(
11381138
result.reason.msg
@@ -1243,7 +1243,7 @@ trait Implicits:
12431243
}
12441244

12451245
/** An implicit search; parameters as in `inferImplicit` */
1246-
class ImplicitSearch(protected val pt: Type, protected val argument: Tree, span: Span)(using Context):
1246+
class ImplicitSearch(protected val pt: Type, protected val argument: Tree, span: Span, ignored: Set[Symbol])(using Context):
12471247
assert(argument.isEmpty || argument.tpe.isValueType || argument.tpe.isInstanceOf[ExprType],
12481248
em"found: $argument: ${argument.tpe}, expected: $pt")
12491249

@@ -1684,7 +1684,7 @@ trait Implicits:
16841684
SearchFailure(TooUnspecific(pt), span)
16851685
else
16861686
val contextual = ctxImplicits != null
1687-
val preEligible = // the eligible candidates, ignoring positions
1687+
val prePreEligible = // the eligible candidates, ignoring positions
16881688
if ctxImplicits != null then
16891689
if ctx.gadt.isNarrowing then
16901690
withoutMode(Mode.ImplicitsEnabled) {
@@ -1693,6 +1693,8 @@ trait Implicits:
16931693
else ctxImplicits.eligible(wildProto)
16941694
else implicitScope(wildProto).eligible
16951695

1696+
val preEligible =
1697+
prePreEligible.filter(candidate => !ignored.contains(candidate.implicitRef.underlyingRef.symbol))
16961698
/** Does candidate `cand` come too late for it to be considered as an
16971699
* eligible candidate? This is the case if `cand` appears in the same
16981700
* scope as a given definition of the form `given ... = ...` that

compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ trait QuotesAndSplices {
4545
report.warning("Canceled splice directly inside a quote. '{ ${ XYZ } } is equivalent to XYZ.", tree.srcPos)
4646
case _ =>
4747
}
48-
val quotes = inferImplicitArg(defn.QuotesClass.typeRef, tree.span)
48+
val quotes = inferImplicitArg(defn.QuotesClass.typeRef, tree.span, ignored = Set.empty)
4949

5050
if quotes.tpe.isInstanceOf[SearchFailureType] then
5151
report.error(missingArgMsg(quotes, defn.QuotesClass.typeRef, ""), ctx.source.atSpan(tree.span))

compiler/src/dotty/tools/dotc/typer/Synthesizer.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
4545
case arg :: Nil =>
4646
instArg(arg) match
4747
case defn.ArrayOf(elemTp) =>
48-
val etag = typer.inferImplicitArg(defn.ClassTagClass.typeRef.appliedTo(elemTp), span)
48+
val etag = typer.inferImplicitArg(defn.ClassTagClass.typeRef.appliedTo(elemTp), span, Set.empty)
4949
if etag.tpe.isError then EmptyTree else etag.select(nme.wrap)
5050
case tp if hasStableErasure(tp) && !tp.isBottomTypeAfterErasure =>
5151
val sym = tp.typeSymbol
@@ -148,7 +148,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
148148

149149
/** Is there an `CanEqual[T, T]` instance, assuming -strictEquality? */
150150
def hasEq(tp: Type)(using Context): Boolean =
151-
val inst = typer.inferImplicitArg(defn.CanEqualClass.typeRef.appliedTo(tp, tp), span)
151+
val inst = typer.inferImplicitArg(defn.CanEqualClass.typeRef.appliedTo(tp, tp), span, ignored = Set.empty)
152152
!inst.isEmpty && !inst.tpe.isError
153153

154154
/** Can we assume the canEqualAny instance for `tp1`, `tp2`?

compiler/src/dotty/tools/dotc/typer/Typer.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -1098,7 +1098,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
10981098
case Decimal => defn.FromDigits_DecimalClass
10991099
case Floating => defn.FromDigits_FloatingClass
11001100
}
1101-
inferImplicit(fromDigitsCls.typeRef.appliedTo(target), EmptyTree, tree.span) match {
1101+
inferImplicit(fromDigitsCls.typeRef.appliedTo(target), EmptyTree, tree.span, ignored = Set.empty) match {
11021102
case SearchSuccess(arg, _, _, _) =>
11031103
val fromDigits = untpd.Select(untpd.TypedSplice(arg), nme.fromDigits).withSpan(tree.span)
11041104
val firstArg = Literal(Constant(digits))
@@ -1271,7 +1271,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
12711271
def withTag(tpe: Type): Option[Tree] = {
12721272
require(ctx.mode.is(Mode.Pattern))
12731273
withoutMode(Mode.Pattern)(
1274-
inferImplicit(tpe, EmptyTree, tree.tpt.span)
1274+
inferImplicit(tpe, EmptyTree, tree.tpt.span, ignored = Set.empty)
12751275
) match
12761276
case SearchSuccess(clsTag, _, _, _) =>
12771277
withMode(Mode.InTypeTest) {
@@ -4173,7 +4173,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
41734173
else formals1
41744174
implicitArgs(formals2, argIndex + 1, pt)
41754175

4176-
val arg = inferImplicitArg(formal, tree.span.endPos)
4176+
val arg = inferImplicitArg(formal, tree.span.endPos, ignored = Set.empty)
41774177
arg.tpe match
41784178
case failed: AmbiguousImplicits =>
41794179
val pt1 = pt.deepenProtoTrans

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

+9-1
Original file line numberDiff line numberDiff line change
@@ -2527,7 +2527,15 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
25272527
object Implicits extends ImplicitsModule:
25282528
def search(tpe: TypeRepr): ImplicitSearchResult =
25292529
import tpd.TreeOps
2530-
val implicitTree = ctx.typer.inferImplicitArg(tpe, Position.ofMacroExpansion.span)
2530+
val implicitTree = ctx.typer.inferImplicitArg(tpe, Position.ofMacroExpansion.span, ignored = Set.empty)
2531+
// Make sure that we do not have any uninstantiated type variables.
2532+
// See tests/pos-macros/i16636.
2533+
// See tests/pos-macros/exprSummonWithTypeVar with -Xcheck-macros.
2534+
dotc.typer.Inferencing.fullyDefinedType(implicitTree.tpe, "", implicitTree)
2535+
implicitTree
2536+
def searchIgnoring(tpe: TypeRepr)(ignored: Symbol*): ImplicitSearchResult =
2537+
import tpd.TreeOps
2538+
val implicitTree = ctx.typer.inferImplicitArg(tpe, Position.ofMacroExpansion.span, ignored.toSet)
25312539
// Make sure that we do not have any uninstantiated type variables.
25322540
// See tests/pos-macros/i16636.
25332541
// See tests/pos-macros/exprSummonWithTypeVar with -Xcheck-macros.

library/src/scala/quoted/Expr.scala

+8
Original file line numberDiff line numberDiff line change
@@ -280,4 +280,12 @@ object Expr {
280280
}
281281
}
282282

283+
@scala.annotation.experimental def summonIgnoring[T](using Type[T])(using quotes: Quotes)(ignored: quotes.reflect.Symbol*): Option[Expr[T]] = {
284+
import quotes.reflect._
285+
Implicits.searchIgnoring(TypeRepr.of[T])(ignored*) match {
286+
case iss: ImplicitSearchSuccess => Some(iss.tree.asExpr.asInstanceOf[Expr[T]])
287+
case isf: ImplicitSearchFailure => None
288+
}
289+
}
290+
283291
}

library/src/scala/quoted/Quotes.scala

+2
Original file line numberDiff line numberDiff line change
@@ -3705,6 +3705,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
37053705
* @param tpe type of the implicit parameter
37063706
*/
37073707
def search(tpe: TypeRepr): ImplicitSearchResult
3708+
3709+
@experimental def searchIgnoring(tpe: TypeRepr)(ignored: Symbol*): ImplicitSearchResult
37083710
}
37093711

37103712
/** Result of a given instance search */

tests/run-macros/summonIgnoring.check

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
No given in scope:
2+
TC[C2] generated in macro without TC[C1]
3+
Given in scope:
4+
TC[C2] generated in macro using:
5+
TC[C1] defined by a user
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//> using options -experimental
2+
import scala.quoted._
3+
class C1
4+
trait TC[T] {
5+
def print(): Unit
6+
}
7+
object TC {
8+
implicit transparent inline def auto[T]: TC[T] = ${autoImpl[T]}
9+
def autoImpl[T: Type](using Quotes): Expr[TC[T]] =
10+
import quotes.reflect._
11+
if(TypeRepr.of[T].typeSymbol == Symbol.classSymbol("C1")){
12+
'{
13+
new TC[T] {
14+
def print() = {
15+
println("TC[C1] generated in macro")
16+
}
17+
}
18+
}
19+
} else {
20+
Expr.summonIgnoring[TC[C1]](Symbol.classSymbol("TC").companionModule.methodMember("auto")*) match
21+
case Some(a) =>
22+
'{
23+
new TC[T] {
24+
def print(): Unit =
25+
println(s"TC[${${Expr(TypeRepr.of[T].show)}}] generated in macro using:")
26+
$a.print()
27+
}
28+
}
29+
case None =>
30+
'{
31+
new TC[T]{
32+
def print(): Unit =
33+
println(s"TC[${${Expr(TypeRepr.of[T].show)}}] generated in macro without TC[C1]")
34+
}
35+
}
36+
}
37+
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//> using options -experimental
2+
3+
@main def Test(): Unit = {
4+
class C2
5+
println("No given in scope:")
6+
summon[TC[C2]].print()
7+
8+
{
9+
println("Given in scope:")
10+
given TC[C1] = new TC[C1] {
11+
def print() = println("TC[C1] defined by a user")
12+
}
13+
summon[TC[C2]].print()
14+
}
15+
}

0 commit comments

Comments
 (0)