Skip to content

Commit ee2bfdb

Browse files
Fix type aliases in beta-reduction of polyfunctions (#17054)
Fixes #17052
2 parents 42fb202 + 1c2ceae commit ee2bfdb

File tree

6 files changed

+88
-21
lines changed

6 files changed

+88
-21
lines changed

compiler/src/dotty/tools/dotc/transform/BetaReduce.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ object BetaReduce:
117117
case ref @ TypeRef(NoPrefix, _) =>
118118
ref.symbol
119119
case _ =>
120-
val binding = TypeDef(newSymbol(ctx.owner, tparam.name, EmptyFlags, targ.tpe, coord = targ.span)).withSpan(targ.span)
120+
val binding = TypeDef(newSymbol(ctx.owner, tparam.name, EmptyFlags, TypeAlias(targ.tpe), coord = targ.span)).withSpan(targ.span)
121121
bindings += binding
122122
binding.symbol
123123

compiler/src/dotty/tools/dotc/transform/TreeChecker.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,11 @@ object TreeChecker {
533533
i"owner chain = ${tree.symbol.ownersIterator.toList}%, %, ctxOwners = ${ctx.outersIterator.map(_.owner).toList}%, %")
534534
}
535535

536+
override def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(using Context): Tree = {
537+
assert(sym.info.isInstanceOf[ClassInfo | TypeBounds], i"wrong type, expect a template or type bounds for ${sym.fullName}, but found: ${sym.info}")
538+
super.typedTypeDef(tdef, sym)
539+
}
540+
536541
override def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(using Context): Tree = {
537542
val TypeDef(_, impl @ Template(constr, _, _, _)) = cdef: @unchecked
538543
assert(cdef.symbol == cls)

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

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,18 +1345,22 @@ object SourceCode {
13451345
}
13461346

13471347
private def printBoundsTree(bounds: TypeBoundsTree)(using elideThis: Option[Symbol]): this.type = {
1348-
bounds.low match {
1349-
case Inferred() =>
1350-
case low =>
1351-
this += " >: "
1352-
printTypeTree(low)
1353-
}
1354-
bounds.hi match {
1355-
case Inferred() => this
1356-
case hi =>
1357-
this += " <: "
1358-
printTypeTree(hi)
1359-
}
1348+
if bounds.low.tpe == bounds.hi.tpe then
1349+
this += " = "
1350+
printTypeTree(bounds.low)
1351+
else
1352+
bounds.low match {
1353+
case Inferred() =>
1354+
case low =>
1355+
this += " >: "
1356+
printTypeTree(low)
1357+
}
1358+
bounds.hi match {
1359+
case Inferred() => this
1360+
case hi =>
1361+
this += " <: "
1362+
printTypeTree(hi)
1363+
}
13601364
}
13611365

13621366
private def printBounds(bounds: TypeBounds)(using elideThis: Option[Symbol]): this.type = {

scaladoc/src/dotty/tools/scaladoc/tasty/Scaladoc2AnchorCreator.scala

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,66 @@ import scala.util.matching.Regex
77

88
object Scaladoc2AnchorCreator:
99

10-
def getScaladoc2Type(using Quotes)(t: reflect.Tree) =
11-
import reflect.*
12-
val regex = t match
13-
case d: DefDef => "def"
14-
case t: TypeDef => "type"
15-
case v: ValDef => "val|var"
16-
t.show(using Printer.TreeShortCode).split(regex, 2)(1).replace(" ","")
10+
def getScaladoc2Type(using Quotes)(sym: quotes.reflect.Symbol) = signatureAnchor(sym)
11+
12+
/** Creates the signature anchor
13+
*
14+
* - `X` for a `type X ...`
15+
* - `x:X` for a `val x: X`
16+
* - `f[U1,...](x1:T1,...)(impliciti1:U1,impliciti2:U2,...)...:R` for a `def f[U1, ...](x1: T1, ...)(implicit i1: U1, i2: U2...)...: R`
17+
*
18+
* Types are printed without their paths. No spaces are printed in the output.
19+
*/
20+
private def signatureAnchor(using Quotes)(sym: quotes.reflect.Symbol): String =
21+
import quotes.reflect.*
22+
def signatureType(tp: quotes.reflect.TypeRepr): String =
23+
tp match
24+
case mt @ MethodType(paramNames, paramTypes, res) =>
25+
val implicitPrefix = if mt.isImplicit then "implicit" else ""
26+
val closeClause = res match
27+
case _: MethodOrPoly => ")"
28+
case _ => "):"
29+
paramNames.zip(paramTypes.map(signatureType))
30+
.map((name, tpe) => s"$implicitPrefix$name:$tpe")
31+
.mkString("(", ",", closeClause) + signatureType(res)
32+
case PolyType(paramNames, paramBounds, res) =>
33+
val closeClause = res match
34+
case _: MethodOrPoly => "]"
35+
case _ => "]:"
36+
paramNames.zip(paramBounds.map(signatureType))
37+
.map((name, tpe) => s"$name$tpe")
38+
.mkString("[", ",", closeClause) + signatureType(res)
39+
case TypeLambda(paramNames, paramBounds, res) =>
40+
paramNames.zip(paramBounds.map(signatureType))
41+
.map((name, tpe) => s"$name$tpe")
42+
.mkString("[", ",", "]") + "=>" + signatureType(res)
43+
case ByNameType(tp) =>
44+
":" + signatureType(tp)
45+
case TypeBounds(low, hi) =>
46+
val lowBound = if low =:= defn.NothingClass.typeRef then "" else ">:" + signatureType(low)
47+
val hiBound = if low =:= defn.AnyClass.typeRef then "" else "<:" + signatureType(hi)
48+
lowBound + hiBound
49+
case tp: ParamRef =>
50+
tp.binder match
51+
case binder: MethodType => binder.paramNames(tp.paramNum) + ".type"
52+
case binder: PolyType => binder.paramNames(tp.paramNum)
53+
case binder: LambdaType => binder.paramNames(tp.paramNum)
54+
case AppliedType(tycon, args) =>
55+
args.map {
56+
case tp: TypeBounds => "_" + signatureType(tp)
57+
case tp => signatureType(tp)
58+
}.mkString(signatureType(tycon) + "[", ",", "]")
59+
case tp: AnnotatedType =>
60+
signatureType(tp.underlying) + "@" + tp.annotation.symbol.owner.name
61+
case tp: ThisType =>
62+
signatureType(tp.tref) + ".this"
63+
case tp: TypeRef =>
64+
tp.name
65+
case tp =>
66+
// TODO handle other cases without using show (show does not have a stable representation)
67+
tp.show(using Printer.TypeReprShortCode).replace(" ","")
68+
69+
sym match
70+
case sym if sym.isType => sym.name
71+
case sym if sym.flags.is(Flags.Method) => sym.name + signatureType(sym.info)
72+
case sym => sym.name + ":" + signatureType(sym.info)

scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ class SymOpsWithLinkCache:
235235
def constructPathForScaladoc2: String =
236236
val l = escapeUrl(location.mkString("/"))
237237
val scaladoc2Anchor = if anchor.isDefined then {
238-
"#" + getScaladoc2Type(sym.tree)
238+
"#" + getScaladoc2Type(sym)
239239
} else ""
240240
docURL + l + extension + scaladoc2Anchor
241241

tests/pos/i17052.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def test[F[_]](fAny: F[Any]) =
2+
{ [X] => (fx: F[X]) => { val fx2: F[X] = fx; () } }.apply[Any](fAny)

0 commit comments

Comments
 (0)