Skip to content

Commit 3630d9d

Browse files
committed
Fix #10359: Add GivenSelector to reflection API
1 parent 2a7f19a commit 3630d9d

File tree

5 files changed

+106
-7
lines changed

5 files changed

+106
-7
lines changed

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1474,7 +1474,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
14741474

14751475
object SimpleSelectorTypeTest extends TypeTest[ImportSelector, SimpleSelector]:
14761476
def unapply(x: ImportSelector): Option[SimpleSelector & x.type] = x match
1477-
case x: (untpd.ImportSelector & x.type) if x.renamed.isEmpty => Some(x)
1477+
case x: (untpd.ImportSelector & x.type) if x.renamed.isEmpty && !x.isGiven => Some(x)
14781478
case _ => None // TODO: handle import bounds
14791479
end SimpleSelectorTypeTest
14801480

@@ -1534,6 +1534,29 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
15341534
end extension
15351535
end OmitSelectorMethodsImpl
15361536

1537+
type GivenSelector = untpd.ImportSelector
1538+
1539+
object GivenSelectorTypeTest extends TypeTest[ImportSelector, GivenSelector]:
1540+
def unapply(x: ImportSelector): Option[GivenSelector & x.type] = x match {
1541+
case self: (untpd.ImportSelector & x.type) if x.isGiven => Some(self)
1542+
case _ => None
1543+
}
1544+
end GivenSelectorTypeTest
1545+
1546+
object GivenSelector extends GivenSelectorModule:
1547+
def unapply(x: GivenSelector): Option[Option[TypeTree]] =
1548+
Some(GivenSelectorMethodsImpl.bound(x))
1549+
end GivenSelector
1550+
1551+
object GivenSelectorMethodsImpl extends GivenSelectorMethods:
1552+
extension (self: GivenSelector):
1553+
def bound: Option[TypeTree] =
1554+
self.bound match
1555+
case untpd.TypedSplice(tpt) => Some(tpt)
1556+
case _ => None
1557+
end extension
1558+
end GivenSelectorMethodsImpl
1559+
15371560
type TypeRepr = dotc.core.Types.Type
15381561

15391562
object TypeRepr extends TypeReprModule:

compiler/src/scala/quoted/runtime/impl/printers/Extractors.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ object Extractors {
237237
case SimpleSelector(id) => this += "SimpleSelector(" += id += ")"
238238
case RenameSelector(id1, id2) => this += "RenameSelector(" += id1 += ", " += id2 += ")"
239239
case OmitSelector(id) => this += "OmitSelector(" += id += ")"
240+
case GivenSelector(bound) => this += "GivenSelector(" += bound += ")"
240241
}
241242

242243
def visitSymbol(x: Symbol): this.type =

compiler/src/scala/quoted/runtime/impl/printers/SourceCode.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,13 @@ object SourceCode {
12261226
case SimpleSelector(name) => this += name
12271227
case OmitSelector(name) => this += name += " => _"
12281228
case RenameSelector(name, newName) => this += name += " => " += newName
1229+
case GivenSelector(bound) =>
1230+
bound match
1231+
case Some(tpt) =>
1232+
this += "given "
1233+
printTree(tpt)
1234+
case _ =>
1235+
this += "given"
12291236
}
12301237

12311238
private def printDefinitionName(tree: Definition): this.type = tree match {

library/src/scala/quoted/Quotes.scala

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
153153
* +- ImportSelector -+- SimpleSelector
154154
* +- RenameSelector
155155
* +- OmitSelector
156+
* +- GivenSelector
156157
*
157158
* +- Signature
158159
*
@@ -1735,13 +1736,17 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
17351736
* * SimpleSelector: `.bar` in `import foo.bar`
17361737
* * RenameSelector: `.{bar => baz}` in `import foo.{bar => baz}`
17371738
* * OmitSelector: `.{bar => _}` in `import foo.{bar => _}`
1739+
* * GivneSelector: `.given`/`.{given T}` in `import foo.given`/`import foo.{given T}`
17381740
*/
17391741
type ImportSelector <: AnyRef
17401742

17411743
val ImportSelector: ImportSelectorModule
17421744

17431745
trait ImportSelectorModule { this: ImportSelector.type => }
17441746

1747+
/** Simple import selector: `.bar` in `import foo.bar` */
1748+
type SimpleSelector <: ImportSelector
1749+
17451750
given TypeTest[ImportSelector, SimpleSelector] = SimpleSelectorTypeTest
17461751
protected val SimpleSelectorTypeTest: TypeTest[ImportSelector, SimpleSelector]
17471752

@@ -1751,9 +1756,6 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
17511756
def unapply(x: SimpleSelector): Option[String]
17521757
}
17531758

1754-
/** Simple import selector: `.bar` in `import foo.bar` */
1755-
type SimpleSelector <: ImportSelector
1756-
17571759
given SimpleSelectorMethods as SimpleSelectorMethods = SimpleSelectorMethodsImpl
17581760
protected val SimpleSelectorMethodsImpl: SimpleSelectorMethods
17591761

@@ -1776,9 +1778,6 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
17761778
def unapply(x: RenameSelector): Option[(String, String)]
17771779
}
17781780

1779-
/** Omit import selector: `.{bar => _}` in `import foo.{bar => _}` */
1780-
type OmitSelector <: ImportSelector
1781-
17821781
given RenameSelectorMethods as RenameSelectorMethods = RenameSelectorMethodsImpl
17831782
protected val RenameSelectorMethodsImpl: RenameSelectorMethods
17841783

@@ -1791,6 +1790,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
17911790
end extension
17921791
end RenameSelectorMethods
17931792

1793+
/** Omit import selector: `.{bar => _}` in `import foo.{bar => _}` */
1794+
type OmitSelector <: ImportSelector
1795+
17941796
given TypeTest[ImportSelector, OmitSelector] = OmitSelectorTypeTest
17951797
protected val OmitSelectorTypeTest: TypeTest[ImportSelector, OmitSelector]
17961798

@@ -1809,6 +1811,26 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
18091811
def namePos: Position
18101812
end OmitSelectorMethods
18111813

1814+
/** Omit import selector: `.given`/`.{given T}` in `import foo.given`/`import foo.{given T}` */
1815+
type GivenSelector <: ImportSelector
1816+
1817+
given TypeTest[ImportSelector, GivenSelector] = GivenSelectorTypeTest
1818+
protected val GivenSelectorTypeTest: TypeTest[ImportSelector, GivenSelector]
1819+
1820+
val GivenSelector: GivenSelectorModule
1821+
1822+
trait GivenSelectorModule { this: GivenSelector.type =>
1823+
def unapply(x: GivenSelector): Option[Option[TypeTree]]
1824+
}
1825+
1826+
given GivenSelectorMethods as GivenSelectorMethods = GivenSelectorMethodsImpl
1827+
protected val GivenSelectorMethodsImpl: GivenSelectorMethods
1828+
1829+
trait GivenSelectorMethods:
1830+
extension (self: GivenSelector):
1831+
def bound: Option[TypeTree]
1832+
end GivenSelectorMethods
1833+
18121834
///////////////
18131835
// TYPES //
18141836
///////////////
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import scala.quoted._
2+
import scala.tasty.inspector._
3+
4+
object Bar {
5+
class Givens {
6+
given Int = 23
7+
given String = "the string"
8+
}
9+
class Foo {
10+
val g: Givens = Givens()
11+
import g.given
12+
import g.{given}
13+
import g.{given Int}
14+
}
15+
}
16+
17+
// Case object implementation
18+
sealed trait Flavor
19+
case object Vanilla extends Flavor
20+
case object Chocolate extends Flavor
21+
case object Bourbon extends Flavor
22+
23+
object Test {
24+
def main(args: Array[String]): Unit = {
25+
// Artefact of the current test infrastructure
26+
// TODO improve infrastructure to avoid needing this code on each test
27+
val classpath = dotty.tools.dotc.util.ClasspathFromClassloader(this.getClass.getClassLoader).split(java.io.File.pathSeparator).find(_.contains("runWithCompiler")).get
28+
val allTastyFiles = dotty.tools.io.Path(classpath).walkFilter(_.extension == "tasty").map(_.toString).toList
29+
val tastyFiles = allTastyFiles.filter(_.contains("TraitParams"))
30+
31+
val inspect = new TestInspector()
32+
inspect.inspectTastyFiles(allTastyFiles.filter(_.contains("Bar")))
33+
}
34+
}
35+
36+
class TestInspector() extends TastyInspector:
37+
38+
protected def processCompilationUnit(using Quotes)(root: qctx.reflect.Tree): Unit =
39+
import qctx.reflect._
40+
41+
val code = root.show
42+
assert(code.contains("import Foo.this.g.{given}"), code)
43+
assert(code.contains("import Foo.this.g.{given scala.Int}"), code)
44+
45+
val extractors = root.showExtractors
46+
assert(extractors.contains("GivenSelector"), extractors)

0 commit comments

Comments
 (0)