Skip to content

Commit c8b3504

Browse files
committed
Fix type parameters not getting properly typed
1 parent 5c74900 commit c8b3504

File tree

3 files changed

+107
-18
lines changed

3 files changed

+107
-18
lines changed

dottydoc/test/UsecaseTest.scala

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,95 @@ class UsecaseTest extends DottyTest {
5252
}
5353
}
5454

55+
@Test def simpleUsecaseAddedArg = {
56+
val source = new SourceFile(
57+
"DefWithUseCase.scala",
58+
"""
59+
|package scala
60+
|
61+
|trait Test[A] {
62+
| /** Definition with a "disturbing" signature
63+
| *
64+
| * @usecase def foo(a: A): A
65+
| */
66+
| def foo[B]: A => B
67+
|}
68+
""".stripMargin
69+
)
70+
71+
checkSources(source :: Nil) { packages =>
72+
packages("scala") match {
73+
case PackageImpl(_, _, List(trt: Trait), _, _) =>
74+
val List(foo: Def) = trt.members
75+
76+
val returnValue = foo.returnValue match {
77+
case ref: TypeReference => ref.title
78+
case _ =>
79+
assert(
80+
false,
81+
"Incorrect return value after usecase transformation"
82+
)
83+
""
84+
}
85+
86+
assert(
87+
foo.typeParams.isEmpty,
88+
"Type parameters were not stripped by usecase"
89+
)
90+
assert(returnValue == "A", "Incorrect return type after usecase")
91+
assert(
92+
foo.paramLists.head.list.head.title == "a",
93+
"Incorrect parameter to function after usecase transformation"
94+
)
95+
assert(foo.name == "foo", s"Incorrect name after transform: ${foo.name}")
96+
}
97+
}
98+
}
99+
100+
@Test def simpleTparamUsecase = {
101+
val source = new SourceFile(
102+
"DefWithUseCase.scala",
103+
"""
104+
|package scala
105+
|
106+
|trait Test[A] {
107+
| /** Definition with a "disturbing" signature
108+
| *
109+
| * @usecase def foo[C]: A
110+
| */
111+
| def foo[B]: A => B
112+
|}
113+
""".stripMargin
114+
)
115+
116+
checkSources(source :: Nil) { packages =>
117+
packages("scala") match {
118+
case PackageImpl(_, _, List(trt: Trait), _, _) =>
119+
val List(foo: Def) = trt.members
120+
121+
val returnValue = foo.returnValue match {
122+
case ref: TypeReference => ref.title
123+
case _ =>
124+
assert(
125+
false,
126+
"Incorrect return value after usecase transformation"
127+
)
128+
""
129+
}
130+
131+
assert(
132+
foo.typeParams.nonEmpty,
133+
"Type parameters were incorrectly stripped by usecase"
134+
)
135+
136+
assert(foo.typeParams.head == "C", "Incorrectly switched tparam")
137+
assert(returnValue == "A", "Incorrect return type after usecase")
138+
139+
assert(foo.name == "foo", s"Incorrect name after transform: ${foo.name}")
140+
}
141+
}
142+
}
143+
55144
@Test def checkIterator = {
56145
val sources =
57146
"./scala-scala/src/library/scala/collection/Iterator.scala" :: Nil

src/dotty/tools/dotc/core/Comments.scala

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ object Comments {
6060
/** Entered by Namer */
6161
var symbol: Symbol = _
6262

63+
/** Set by typer */
64+
var tpdCode: tpd.DefDef = _
65+
6366
lazy val untpdCode: untpd.Tree = {
6467
val tree = new Parser(new SourceFile("<usecase>", code)).localDef(codePos.start, EmptyFlags)
6568

@@ -72,19 +75,5 @@ object Comments {
7275
tree
7376
}
7477
}
75-
76-
/** Set by typer calling `typeTree` */
77-
var tpdCode: tpd.DefDef = _
78-
79-
def typeTree()(implicit ctx: Context): Unit = untpdCode match {
80-
case df: untpd.DefDef =>
81-
ctx.typer.typedDefDef(df, symbol) match {
82-
case tree: tpd.DefDef => tpdCode = tree
83-
case _ =>
84-
ctx.error("proper def could not be typed from `@usecase`", codePos)
85-
}
86-
case _ =>
87-
ctx.error("proper def was not found in `@usecase`", codePos)
88-
}
8978
}
9079
}

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,9 +1120,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
11201120
tpt1 = tpt1.withType(avoid(tpt1.tpe, vparamss1.flatMap(_.map(_.symbol))))
11211121
}
11221122

1123-
/** Type usecases */
1124-
ctx.docbase.docstring(sym).map(_.usecases.map(_.typeTree()))
1125-
11261123
assignType(cpy.DefDef(ddef)(name, tparams1, vparamss1, tpt1, rhs1), sym)
11271124
//todo: make sure dependent method types do not depend on implicits or by-name params
11281125
}
@@ -1447,11 +1444,25 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
14471444
buf += typed(stat)(ctx.exprContext(stat, exprOwner))
14481445
traverse(rest)
14491446
case nil =>
1450-
buf.toList
1447+
val tpdStats = buf.toList
1448+
typedUsecases(tpdStats.map(_.symbol), exprOwner)
1449+
tpdStats
14511450
}
14521451
traverse(stats)
14531452
}
14541453

1454+
def typedUsecases(syms: List[Symbol], owner: Symbol)(implicit ctx: Context): Unit =
1455+
for {
1456+
sym <- syms
1457+
usecase <- ctx.docbase.docstring(sym).map(_.usecases).getOrElse(Nil)
1458+
List(tpdTree) = typedStats(usecase.untpdCode :: Nil, owner)
1459+
} yield {
1460+
if (tpdTree.isInstanceOf[tpd.DefDef])
1461+
usecase.tpdCode = tpdTree.asInstanceOf[tpd.DefDef]
1462+
else
1463+
ctx.error("Couldn't compile `@usecase`", usecase.codePos)
1464+
}
1465+
14551466
def typedExpr(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree =
14561467
typed(tree, pt)(ctx retractMode Mode.PatternOrType)
14571468
def typedType(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = // todo: retract mode between Type and Pattern?

0 commit comments

Comments
 (0)