Skip to content

Commit b13f37a

Browse files
Merge pull request #13576 from dotty-staging/enhance-type-stealer
add type modes to DottyTypeStealer
2 parents ffaedb5 + 7ff93c0 commit b13f37a

File tree

2 files changed

+61
-19
lines changed

2 files changed

+61
-19
lines changed

compiler/test/dotty/tools/DottyTypeStealer.scala

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,58 @@ import dotc.core.Types.Type
1313
* The type signatures will then be printed (singleton types
1414
* are widened.)
1515
*
16+
* @param kind the kind of type we are inspecting [`rhs`, `method`, `class`, `type`]
1617
* @param source top level Scala definitions, e.g. `"class O { type X }"`
1718
* @param typeStrings Scala type signatures, e.g. `"O#X"`
1819
*
1920
* @syntax markdown
2021
*/
21-
@main def printTypes(source: String, typeStrings: String*) = {
22-
val (_, tpes) = DottyTypeStealer.stealType(source, typeStrings*)
23-
tpes.foreach(println)
22+
@main def printTypes(source: String, kind: String, typeStrings: String*) = {
23+
val k = DottyTypeStealer.Kind.lookup(kind)
24+
val (_, tpes) = DottyTypeStealer.stealType(source, k, typeStrings*)
25+
tpes.foreach(t => println(s"$t [${t.getClass}]"))
2426
}
2527

2628
object DottyTypeStealer extends DottyTest {
27-
def stealType(source: String, typeStrings: String*): (Context, List[Type]) = {
29+
30+
enum Kind:
31+
case `rhs`, `method`, `class`, `type`
32+
33+
def format(name: String, arg: String) = this match
34+
case `rhs` => s"val $name: $arg = ???"
35+
case `method` => s"def $name $arg = ???"
36+
case `class` => s"class $name $arg"
37+
case `type` => s"type $name $arg"
38+
39+
object Kind:
40+
41+
def lookup(kind: String): Kind =
42+
values.find(_.productPrefix == kind).getOrElse {
43+
println(s"unknown kind `$kind`, assuming `$rhs`")
44+
rhs
45+
}
46+
47+
end Kind
48+
49+
50+
def stealType(source: String, kind: Kind, typeStrings: String*): (Context, List[Type]) = {
2851
val dummyName = "x_x_x"
29-
val vals = typeStrings.zipWithIndex.map{case (s, x)=> s"val ${dummyName}$x: $s = ???"}.mkString("\n")
52+
val vals = typeStrings.zipWithIndex.map{case (s, x) => kind.format(dummyName + x, s) }.mkString("\n")
3053
val gatheredSource = s" ${source}\n object A$dummyName {$vals}"
3154
var scontext : Context = null
3255
var tp: List[Type] = null
3356
checkCompile("typer", gatheredSource) {
3457
(tree, context) =>
3558
given Context = context
36-
val findValDef: (List[ValDef], tpd.Tree) => List[ValDef] =
59+
val findMemberDef: (List[MemberDef], tpd.Tree) => List[MemberDef] =
3760
(acc , tree) => tree match {
61+
case t: DefDef if t.name.startsWith(dummyName) => t :: acc
3862
case t: ValDef if t.name.startsWith(dummyName) => t :: acc
63+
case t: TypeDef if t.name.startsWith(dummyName) => t :: acc
3964
case _ => acc
4065
}
41-
val d = new DeepFolder[List[ValDef]](findValDef).foldOver(Nil, tree)
42-
tp = d.map(_.tpe.widen).reverse
66+
val d = new DeepFolder[List[MemberDef]](findMemberDef).foldOver(Nil, tree)
67+
tp = d.map(_.symbol.info).reverse
4368
scontext = context
4469
}
4570
(scontext, tp)

docs/docs/contributing/workflow.md

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,35 +40,52 @@ can be enabled through the `dotty.tools.dotc.config.Printers` object. Change any
4040
## Inspecting Types with Type Stealer ##
4141

4242
You can inspect types with the main method `dotty.tools.printTypes` from the sbt shell,
43-
passing at least two arguments. The first argument is a string that introduces some
44-
Scala definitions, the following arguments are type signatures, (i.e. the return type
45-
of a definition) that are allowed to reference definitions from the first argument.
46-
47-
The type signatures will then be printed, displaying their internal structure, using
43+
passing at least three arguments:
44+
- The first argument is a string that introduces some
45+
Scala definitions
46+
- The second argument introduces how the the remaining arguments should be interpreted,
47+
comprising of
48+
- `rhs` - the return type of a definition
49+
- `class` - the signature of a class, after its name
50+
- `method` - the signature of a method, after its name
51+
- `type` - the signature of a type, after its name
52+
- The remaining arguments are type signatures, these may reference definitions introduced by the first argument.
53+
54+
Each type signature is then be printed, displaying their internal structure, alongside their class, using
4855
the same representation that can later be used in pattern matching to decompose the type.
4956

5057
Here, we inspect a refinement of a class `Box`:
5158
```bash
5259
$ sbt
53-
> scala3-compiler-bootstrapped/Test/runMain dotty.tools.printTypes "class Box { def x: Any }" "Box { def x: Int }"
54-
RefinedType(TypeRef(ThisType(TypeRef(NoPrefix,module class <empty>)),class Box),x,ExprType(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),object scala),class Int)))
60+
> scala3-compiler-bootstrapped/Test/runMain dotty.tools.printTypes "class Box { def x: Any }" "rhs" "Box { def x: Int }"
61+
RefinedType(TypeRef(ThisType(TypeRef(NoPrefix, module class <empty>)),class Box), x, ExprType(TypeRef(TermRef(ThisType(TypeRef(NoPrefix, module class <root>)), object scala), class Int))) [class dotty.tools.dotc.core.Types$CachedRefinedType]
5562
```
5663

57-
You can also pass the empty string as the first
64+
You can also pass the empty string as the second
5865
argument, e.g. to inspect a standard library type:
5966
```bash
6067
$ sbt
61-
> scala3-compiler-bootstrapped/Test/runMain dotty.tools.printTypes "" "1 *: EmptyTuple"
62-
AppliedType(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),object scala),class *:),List(ConstantType(Constant(1)), TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class scala)),object Tuple$package),type EmptyTuple)))
68+
> scala3-compiler-bootstrapped/Test/runMain dotty.tools.printTypes "" "rhs" "1 *: EmptyTuple"
69+
AppliedType(TypeRef(TermRef(ThisType(TypeRef(NoPrefix, module class <root>)), object scala), class *:), List(ConstantType(Constant(1)), TypeRef(TermRef(ThisType(TypeRef(NoPrefix, module class scala)), object Tuple$package), type EmptyTuple)))
6370
```
6471

72+
Here are some other examples you can follow:
73+
- `...printTypes "" class "[T] extends Foo[T] {}"`
74+
- `...printTypes "" method "(x: Int): x.type"`
75+
- `...printTypes "" type "<: Int" "= [T] =>> List[T]"`
76+
6577
If you want to further inspect the types, and not just print them, the object `dotty.tools.DottyTypeStealer` has a
6678
method `stealType`. It takes the same arguments as `printTypes`, but returns both a `Context` containing the
6779
definitions passed, along with the list of types:
6880
```scala
6981
// compiler/test/dotty/tools/DottyTypeStealer.scala
7082
object DottyTypeStealer extends DottyTest {
71-
def stealType(source: String, typeStrings: String*): (Context, List[Type]) = {
83+
84+
enum Kind:
85+
case `rhs`, `method`, `class`, `type`
86+
...
87+
88+
def stealType(kind: Kind, source: String, typeStrings: String*): (Context, List[Type]) = {
7289
...
7390
}
7491
}

0 commit comments

Comments
 (0)