Skip to content

Commit

Permalink
Mark import used after implicit ranking chooses it
Browse files Browse the repository at this point in the history
  • Loading branch information
som-snytt committed Nov 10, 2022
1 parent f8e155b commit 5d2ed53
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 6 deletions.
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2736,8 +2736,8 @@ object Types {
override def eql(that: Type): Boolean = this eq that // safe because named types are hash-consed separately
}

/** A reference to an implicit definition. This can be either a TermRef or a
* Implicits.RenamedImplicitRef.
/** A reference to an implicit definition. This can be either a TermRef or
* an Implicits.{ImportedImplicitRef, RenamedImplicitRef}.
*/
trait ImplicitRef {
def implicitName(using Context): TermName
Expand Down
20 changes: 16 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,15 @@ object Implicits:
*/
class ImportedImplicitRef(val underlyingRef: TermRef, val importInfo: ImportInfo, val selector: Int) extends ImplicitRef:
def implicitName(using Context): TermName = underlyingRef.implicitName
override def toString = s"ImportedImplicitRef($underlyingRef, $importInfo, selector=$selector)"

/** An implicit definition `ImplicitRef` that is visible under a different name, `alias`.
* Gets generated if an implicit ref is imported via a renaming import.
*/
class RenamedImplicitRef(underlyingRef: TermRef, importInfo: ImportInfo, selector: Int, val alias: TermName)
extends ImportedImplicitRef(underlyingRef, importInfo, selector):
override def implicitName(using Context): TermName = alias
override def toString = s"ImportedImplicitRef($underlyingRef, $importInfo, selector=$selector, alias=$alias)"

/** Both search candidates and successes are references with a specific nesting level. */
sealed trait RefAndLevel {
Expand Down Expand Up @@ -1157,9 +1159,6 @@ trait Implicits:
SearchFailure(adapted.withType(new MismatchedImplicit(ref, pt, argument)))
}
else
cand match
case Candidate(k: ImportedImplicitRef, _, _) => ctx.usages.use(k.importInfo, k.importInfo.selectors(k.selector))
case _ =>
SearchSuccess(adapted, ref, cand.level, cand.isExtension)(ctx.typerState, ctx.gadt)
}
end typedImplicit
Expand Down Expand Up @@ -1485,7 +1484,20 @@ trait Implicits:
validateOrdering(ord)
throw ex

rank(sort(eligible), NoMatchingImplicitsFailure, Nil)
@tailrec
def markSelector(allEligible: List[Candidate], foundRef: ImplicitRef): Unit =
allEligible match
case Candidate(k: ImportedImplicitRef, _, _) :: _ if k.underlyingRef == foundRef =>
ctx.usages.use(k.importInfo, k.importInfo.selectors(k.selector))
case _ :: rest => markSelector(rest, foundRef)
case nil => ()

rank(sort(eligible), NoMatchingImplicitsFailure, Nil) match {
case res: SearchSuccess if !ctx.mode.is(Mode.ImplicitExploration) =>
markSelector(eligible, res.ref)
res
case res => res
}
end searchImplicit

def isUnderSpecifiedArgument(tp: Type): Boolean =
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/ImportInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class ImportInfo(symf: Context ?=> Symbol,
val enclosingSpan: Span,
val isRootImport: Boolean = false) extends Showable {

override def toString = selectors.mkString(s"ImportInfo#$hashCode(", ",", s") at $enclosingSpan")

private def symNameOpt = qualifier match {
case ref: untpd.RefTree => Some(ref.name.asTermName)
case _ => None
Expand Down
16 changes: 16 additions & 0 deletions tests/neg/t12690a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

// scalac: -Werror -Wunused:imports

class X
class Y extends X
object A { implicit val x: X = new X }
object B { implicit val y: Y = new Y }
class C {
import B._
import A._ // error: unused
def t = implicitly[X]
}

object Test extends App {
println(new C().t)
}
16 changes: 16 additions & 0 deletions tests/neg/t12690b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

// scalac: -Werror -Wunused:imports

class X
class Y extends X
object A { implicit val x: X = new X }
object B { implicit val y: Y = new Y }
class C {
import A._ // error: unused
import B._
def t = implicitly[X]
}

object Test extends App {
println(new C().t)
}

0 comments on commit 5d2ed53

Please sign in to comment.