Skip to content

Commit cda0a9d

Browse files
Merge pull request #10469 from dotty-staging/fix-#10359
Fix #10359: Add GivenSelector to reflection API
2 parents 8e991cc + dc35ca5 commit cda0a9d

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
@@ -156,6 +156,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
156156
* +- ImportSelector -+- SimpleSelector
157157
* +- RenameSelector
158158
* +- OmitSelector
159+
* +- GivenSelector
159160
*
160161
* +- Signature
161162
*
@@ -1738,13 +1739,17 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
17381739
* * SimpleSelector: `.bar` in `import foo.bar`
17391740
* * RenameSelector: `.{bar => baz}` in `import foo.{bar => baz}`
17401741
* * OmitSelector: `.{bar => _}` in `import foo.{bar => _}`
1742+
* * GivneSelector: `.given`/`.{given T}` in `import foo.given`/`import foo.{given T}`
17411743
*/
17421744
type ImportSelector <: AnyRef
17431745

17441746
val ImportSelector: ImportSelectorModule
17451747

17461748
trait ImportSelectorModule { this: ImportSelector.type => }
17471749

1750+
/** Simple import selector: `.bar` in `import foo.bar` */
1751+
type SimpleSelector <: ImportSelector
1752+
17481753
given TypeTest[ImportSelector, SimpleSelector] = SimpleSelectorTypeTest
17491754
protected val SimpleSelectorTypeTest: TypeTest[ImportSelector, SimpleSelector]
17501755

@@ -1754,9 +1759,6 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
17541759
def unapply(x: SimpleSelector): Option[String]
17551760
}
17561761

1757-
/** Simple import selector: `.bar` in `import foo.bar` */
1758-
type SimpleSelector <: ImportSelector
1759-
17601762
given SimpleSelectorMethods as SimpleSelectorMethods = SimpleSelectorMethodsImpl
17611763
protected val SimpleSelectorMethodsImpl: SimpleSelectorMethods
17621764

@@ -1779,9 +1781,6 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
17791781
def unapply(x: RenameSelector): Option[(String, String)]
17801782
}
17811783

1782-
/** Omit import selector: `.{bar => _}` in `import foo.{bar => _}` */
1783-
type OmitSelector <: ImportSelector
1784-
17851784
given RenameSelectorMethods as RenameSelectorMethods = RenameSelectorMethodsImpl
17861785
protected val RenameSelectorMethodsImpl: RenameSelectorMethods
17871786

@@ -1794,6 +1793,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
17941793
end extension
17951794
end RenameSelectorMethods
17961795

1796+
/** Omit import selector: `.{bar => _}` in `import foo.{bar => _}` */
1797+
type OmitSelector <: ImportSelector
1798+
17971799
given TypeTest[ImportSelector, OmitSelector] = OmitSelectorTypeTest
17981800
protected val OmitSelectorTypeTest: TypeTest[ImportSelector, OmitSelector]
17991801

@@ -1812,6 +1814,26 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
18121814
def namePos: Position
18131815
end OmitSelectorMethods
18141816

1817+
/** Omit import selector: `.given`/`.{given T}` in `import foo.given`/`import foo.{given T}` */
1818+
type GivenSelector <: ImportSelector
1819+
1820+
given TypeTest[ImportSelector, GivenSelector] = GivenSelectorTypeTest
1821+
protected val GivenSelectorTypeTest: TypeTest[ImportSelector, GivenSelector]
1822+
1823+
val GivenSelector: GivenSelectorModule
1824+
1825+
trait GivenSelectorModule { this: GivenSelector.type =>
1826+
def unapply(x: GivenSelector): Option[Option[TypeTree]]
1827+
}
1828+
1829+
given GivenSelectorMethods as GivenSelectorMethods = GivenSelectorMethodsImpl
1830+
protected val GivenSelectorMethodsImpl: GivenSelectorMethods
1831+
1832+
trait GivenSelectorMethods:
1833+
extension (self: GivenSelector):
1834+
def bound: Option[TypeTree]
1835+
end GivenSelectorMethods
1836+
18151837
///////////////
18161838
// TYPES //
18171839
///////////////
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: quotes.reflect.Tree): Unit =
39+
import quotes.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)