Skip to content

Commit 6929067

Browse files
authored
Merge pull request scala#40 from scalacenter/tasty-hknest
Support classes with nested HK type parameters
2 parents fee6a9e + 8cf7ae5 commit 6929067

25 files changed

+634
-297
lines changed

src/compiler/scala/tools/nsc/tasty/Names.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package scala.tools.nsc.tasty
22

33
import scala.annotation.tailrec
44
import scala.reflect.NameTransformer
5+
import scala.reflect.internal.Variance
56

67
object Names {
78

@@ -22,12 +23,20 @@ object Names {
2223
final val PathSep: SimpleName = SimpleName(".")
2324
final val ExpandedSep: SimpleName = SimpleName("$$")
2425
final val ExpandPrefixSep: SimpleName = SimpleName("$")
26+
final val WildcardSep: SimpleName = SimpleName("_$")
2527
final val InlinePrefix: SimpleName = SimpleName("inline$")
2628
final val SuperPrefix: SimpleName = SimpleName("super$")
2729
final val Constructor: SimpleName = SimpleName("<init>")
2830
final val EmptyPkg: SimpleName = SimpleName("<empty>")
2931
final val RootClass: SimpleName = SimpleName("<root>")
3032

33+
object WildcardName {
34+
def unapply(name: TastyName): Boolean = name match {
35+
case UniqueName(Empty, WildcardSep, _) => true
36+
case _ => false
37+
}
38+
}
39+
3140
final val DefaultGetterStr = "$default$"
3241
final val DefaultGetterInitStr = NameTransformer.encode("<init>") + DefaultGetterStr
3342

@@ -151,5 +160,10 @@ object Names {
151160
case SignedName(_, signature) => signature
152161
case _ => Signature.NotAMethod
153162
}
163+
164+
final def variance: Variance = self match {
165+
case VariantName(_, contravariant) => if (contravariant) Variance.Contravariant else Variance.Covariant
166+
case _ => Variance.Invariant
167+
}
154168
}
155169
}

src/compiler/scala/tools/nsc/tasty/TreeUnpickler.scala

Lines changed: 50 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import scala.annotation.{switch, tailrec}
55
import scala.collection.mutable
66
import scala.reflect.io.AbstractFile
77
import Names.TastyName
8+
import scala.reflect.internal.Variance
9+
import scala.util.chaining._
810

911
/** Unpickler for typed trees
1012
* @param reader the reader from which to unpickle
@@ -29,18 +31,13 @@ class TreeUnpickler[Tasty <: TastyUniverse](
2931
import TastyFlags._
3032
import Signature._
3133
import Contexts._
32-
import TypeOps._
3334

3435
@inline
3536
final protected def assertTasty(cond: Boolean, msg: => String)(implicit ctx: Context): Unit =
3637
if (!cond) {
3738
errorTasty(msg)
3839
}
3940

40-
@inline
41-
final protected def errorTasty(msg: String)(implicit ctx: Context): Unit =
42-
reporter.error(noPosition, s"Scala 2 incompatible TASTy signature of ${ctx.source.name} in ${ctx.owner}: $msg")
43-
4441
/** A map from addresses of definition entries to the symbols they define */
4542
private val symAtAddr = new mutable.HashMap[Addr, Symbol]
4643

@@ -127,6 +124,12 @@ class TreeUnpickler[Tasty <: TastyUniverse](
127124
override def complete(sym: Symbol): Unit = throw new UnsupportedOperationException("complete")
128125
}
129126

127+
final class ErrorCompleter(msg: Symbol => String) extends TastyLazyType {
128+
override def complete(sym: Symbol): Unit = {
129+
throw new symbolTable.TypeError(msg(sym))
130+
}
131+
}
132+
130133
class TreeReader(val reader: TastyReader) {
131134
import reader._
132135

@@ -294,38 +297,27 @@ class TreeUnpickler[Tasty <: TastyUniverse](
294297
val tag = readByte()
295298
ctx.log(s"reading type ${astTagToString(tag)} at $start")
296299

297-
def registeringType[T](tp: Type, op: => T): T = {
300+
def registeringTypeWith[T](tp: Type, op: => T): T = {
298301
typeAtAddr(start) = tp
299302
op
300303
}
301304

302305
def readLengthType(): Type = {
303306
val end = readEnd()
304307

305-
def readMethodic[N <: Name, PInfo <: Type, LT <: LambdaType]
306-
(companion: LambdaTypeCompanion[N, PInfo, LT], nameMap: TastyName => N)(implicit ctx: Context): Type = {
307-
val complete = typeAtAddr.contains(start)
308-
val stored = typeAtAddr.getOrElse(start, {
308+
def readMethodic[N <: Name, PInfo <: Type, LT <: LambdaType, Res <: Type]
309+
(companion: LambdaTypeCompanion[N, PInfo, LT, Res], nameMap: TastyName => N)(implicit ctx: Context): Res = {
310+
val result = typeAtAddr.getOrElse(start, {
309311
val nameReader = fork
310312
nameReader.skipTree() // skip result
311313
val paramReader = nameReader.fork
312-
val paramNames = nameReader.readParamNames(end).map(nameMap)
313-
companion(paramNames)(
314-
pt => registeringType(pt, paramReader.readParamTypes[PInfo](end)),
315-
pt => readType())
314+
val paramNames = nameReader.readParamNames(end)
315+
companion(paramNames)(nameMap,
316+
pt => registeringTypeWith(pt, paramReader.readParamTypes[PInfo](end)),
317+
pt => readType()).tap(typeAtAddr(start) = _)
316318
})
317319
goto(end)
318-
val canonical = {
319-
if (complete) {
320-
stored
321-
}
322-
else {
323-
val canonical = stored.asInstanceOf[LT].canonicalForm
324-
typeAtAddr.update(start, canonical)
325-
canonical
326-
}
327-
}
328-
canonical
320+
result.asInstanceOf[Res]
329321
}
330322

331323
val result =
@@ -357,12 +349,11 @@ class TreeUnpickler[Tasty <: TastyUniverse](
357349
// // Note that the lambda "rt => ..." is not equivalent to a wildcard closure!
358350
// // Eta expansion of the latter puts readType() out of the expression.
359351
case APPLIEDtype =>
360-
val tpe = readType()
361-
mkTypeRef(tpe.typeSymbolDirect.owner.tpe, tpe.typeSymbolDirect, until(end)(readType()))
352+
boundedAppliedType(readType(), until(end)(readType()))
362353
case TYPEBOUNDS =>
363354
val lo = readType()
364355
val hi = readType()
365-
mkTypeBounds(lo, hi) // if (lo.isMatch && (lo `eq` hi)) MatchAlias(lo) else TypeBounds(lo, hi)
356+
TypeBounds.bounded(lo, hi) // if (lo.isMatch && (lo `eq` hi)) MatchAlias(lo) else TypeBounds(lo, hi)
366357
case ANNOTATEDtype =>
367358
mkAnnotatedType(readType(), mkAnnotation(readTerm()))
368359
case ANDtype =>
@@ -388,9 +379,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
388379
case TYPELAMBDAtype =>
389380
readMethodic(HKTypeLambda, _.toEncodedTermName.toTypeName)
390381
case PARAMtype =>
391-
readTypeRef() match {
392-
case binder: LambdaType => binder.paramRefs(readNat())
393-
}
382+
readTypeRef().typeParams(readNat()).ref
394383
}
395384
assert(currentAddr === end, s"$start $currentAddr $end ${astTagToString(tag)}")
396385
result
@@ -399,32 +388,21 @@ class TreeUnpickler[Tasty <: TastyUniverse](
399388
def readSimpleType(): Type = {
400389
(tag: @switch) match {
401390
case TYPEREFdirect | TERMREFdirect =>
402-
mkTypeRef(noPrefix, readSymRef(), Nil)
391+
readSymRef().termRef
403392
case TYPEREFsymbol | TERMREFsymbol =>
404393
readSymNameRef()
405394
case TYPEREFpkg =>
406-
readPackageRef().moduleClass.typeRef
395+
readPackageRef().moduleClass.ref
407396
case TERMREFpkg =>
408397
readPackageRef().termRef
409398
case TYPEREF =>
410399
val name = readTastyName()
411400
val pre = readType()
412-
if (pre.typeSymbol === defn.ScalaPackage && ( name === nme.And || name === nme.Or) ) {
413-
if (name === nme.And) {
414-
AndType
415-
}
416-
else {
417-
errorTasty(s"Union types are not currently supported, [found reference to scala.$name at Addr($start) in ${ctx.classRoot}]")
418-
errorType
419-
}
420-
}
421-
else {
422-
mkTypeRef(pre, name, selectingTerm = false)
423-
}
401+
selectType(pre, name)
424402
case TERMREF =>
425-
val sname = readTastyName()
403+
val name = readTastyName()
426404
val prefix = readType()
427-
mkTypeRef(prefix, sname, selectingTerm = true)
405+
selectTerm(prefix, name)
428406
case THIS =>
429407
val sym = readType() match {
430408
case tpe: TypeRef => tpe.sym
@@ -447,7 +425,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
447425
val ref = readAddr()
448426
typeAtAddr.getOrElseUpdate(ref, forkAt(ref).readType())
449427
case BYNAMEtype =>
450-
mkAppliedType(defn.ByNameParamClass, readType()) // ExprType(readType())
428+
defn.ByNameParamClass.ref(readType() :: Nil) // ExprType(readType())
451429
case ENUMconst =>
452430
errorTasty("Enum Constant") //Constant(readTypeRef().termSymbol)
453431
errorType
@@ -462,14 +440,14 @@ class TreeUnpickler[Tasty <: TastyUniverse](
462440
private def readSymNameRef()(implicit ctx: Context): Type = {
463441
val sym = readSymRef()
464442
val prefix = readType()
465-
val res = NamedType(prefix, sym)
466-
prefix match {
467-
case prefix: ThisType if (prefix.sym `eq` sym.owner) && sym.isTypeParameter /*&& !sym.is(Opaque)*/ =>
468-
mkTypeRef(noPrefix, sym, Nil)
469-
// without this precaution we get an infinite cycle when unpickling pos/extmethods.scala
470-
// the problem arises when a self type of a trait is a type parameter of the same trait.
471-
case _ => res
472-
}
443+
// TODO tasty: restore this if github:lampepfl/dotty/tests/pos/extmethods.scala causes infinite loop
444+
// prefix match {
445+
// case prefix: ThisType if (prefix.sym `eq` sym.owner) && sym.isTypeParameter /*&& !sym.is(Opaque)*/ =>
446+
// mkAppliedType(sym, Nil)
447+
// // without this precaution we get an infinite cycle when unpickling pos/extmethods.scala
448+
// // the problem arises when a self type of a trait is a type parameter of the same trait.
449+
// }
450+
NamedType(prefix, sym)
473451
}
474452

475453
private def readPackageRef()(implicit ctx: Context): TermSymbol = {
@@ -869,10 +847,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
869847
val unsupported = completer.tastyFlagSet &~ supported
870848
assertTasty(!unsupported, s"unsupported Scala 3 flags on $sym: ${show(unsupported)}")
871849
if (completer.tastyFlagSet.is(Inline)) {
872-
sym.addAnnotation(
873-
symbolTable.symbolOf[annotation.compileTimeOnly],
874-
Literal(Constant(s"Unsupported Scala 3 inline $sym"))
875-
)
850+
attachCompiletimeOnly(sym, s"Unsupported Scala 3 inline $sym")
876851
}
877852
if (completer.tastyFlagSet.is(Extension)) ctx.log(s"$name is a Scala 3 extension method.")
878853
val typeParams = {
@@ -886,24 +861,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
886861
}
887862
val vparamss = readParamss(localCtx)
888863
val tpt = readTpt()(localCtx)
889-
val valueParamss = ctx.normalizeIfConstructor(
890-
vparamss.map(_.map(symFromNoCycle)), name === nme.CONSTRUCTOR)
891-
// if (tname === TastyName.SimpleName("apply")
892-
// && sym.is(Synthetic)) {
893-
// sym.flags = sym.flags | Case
894-
// }
895-
// val retType =
896-
// if (tname === TastyName.SimpleName("unapply")
897-
// && sym.is(Synthetic)) {
898-
// sym.flags = sym.flags | Case
899-
// sym.owner.companion.caseFieldAccessors.map(_.tpe) match {
900-
// case Nil => defn.BooleanTpe
901-
// case value :: Nil => defn.optionType(dropNullaryMethod(value))
902-
// case values => defn.optionType(defn.tupleType(values.map(dropNullaryMethod)))
903-
// }
904-
// } else {
905-
// tpt.tpe
906-
// }
864+
val valueParamss = ctx.normalizeIfConstructor(vparamss.map(_.map(symFromNoCycle)), name === nme.CONSTRUCTOR)
907865
val resType = ctx.effectiveResultType(sym, typeParams, tpt.tpe)
908866
sym.info = ctx.methodType(if (name === nme.CONSTRUCTOR) Nil else typeParams, valueParamss, resType)
909867
NoCycle(at = symAddr)
@@ -923,15 +881,22 @@ class TreeUnpickler[Tasty <: TastyUniverse](
923881
readTemplate(symAddr)(localCtx)
924882
}
925883
else {
926-
sym.info = emptyTypeBounds // needed to avoid cyclic references when unpickling rhs, see i3816.scala
884+
sym.info = TypeBounds.empty // needed to avoid cyclic references when unpickling rhs, see i3816.scala
927885
// sym.setFlag(Provisional)
928886
val rhs = readTpt()(localCtx)
929887
sym.info = new NoCompleter {
930888
override def completerTypeParams(sym: Symbol)(implicit ctx: Context) =
931889
rhs.tpe.typeParams
932890
}
933891
// TODO check for cycles
934-
sym.info = rhs.tpe.stripLowerBoundsIfPoly
892+
sym.info = rhs.tpe match {
893+
case bounds @ TypeBounds(lo: PolyType, hi: PolyType) if !(mergeableParams(lo,hi)) =>
894+
new ErrorCompleter(owner =>
895+
s"$owner has diverging type lambdas as bounds:$bounds")
896+
case tpe: TypeBounds => normaliseBounds(tpe)
897+
case tpe => tpe
898+
}
899+
if (sym.is(Param)) sym.flags &= ~(Private | Protected)
935900
// sym.normalizeOpaque()
936901
// sym.resetFlag(Provisional)
937902
NoCycle(at = symAddr)
@@ -949,7 +914,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
949914
}
950915
case _ => sys.error(s"Reading new member with tag ${astTagToString(tag)}")
951916
}
952-
ctx.log(s"typed ${showSym(sym)} : ${sym.tpe} in owner ${showSym(sym.owner)}")
917+
ctx.log(s"typed ${showSym(sym)} : ${if (sym.isClass) sym.tpe else sym.info} in owner ${showSym(sym.owner)}")
953918
goto(end)
954919
noCycle
955920
}
@@ -1277,7 +1242,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
12771242
val selector = if (isTerm) encoded else encoded.toTypeName
12781243
val localCtx = ctx // if (name === nme.CONSTRUCTOR) ctx.addMode(Mode.) else ctx
12791244
def tpeFun(localCtx: Context, selector: Name, qualType: Type): Type =
1280-
if (sig `eq` NotAMethod) mkTypeRef(qualType, name, isTerm)
1245+
if (sig `eq` NotAMethod) selectFromPrefix(qualType, name, isTerm)
12811246
else selectFromSig(qualType, selector, sig)(localCtx)
12821247
f(localCtx, selector, tpeFun)
12831248
}
@@ -1480,8 +1445,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
14801445
val tpe = mkIntersectionType(args.map(_.tpe))
14811446
CompoundTypeTree(args).setType(tpe)
14821447
} else {
1483-
val ownType = mkTypeRef(tycon.tpe.prefix, tycon.tpe.typeSymbolDirect, args.map(_.tpe))
1484-
AppliedTypeTree(tycon, args).setType(ownType)
1448+
AppliedTypeTree(tycon, args).setType(boundedAppliedType(tycon.tpe, args.map(_.tpe)))
14851449
}
14861450
case ANNOTATEDtpt =>
14871451
val tpt = readTpt()
@@ -1490,7 +1454,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
14901454
case LAMBDAtpt =>
14911455
val tparams = readParams[NoCycle](TYPEPARAM)
14921456
val body = readTpt()
1493-
TypeTree(TypeParamLambda(tparams.map(symFromNoCycle), body.tpe).canonicalForm) //LambdaTypeTree(tparams, body)
1457+
TypeTree(mkLambdaFromParams(tparams.map(symFromNoCycle), body.tpe)) //LambdaTypeTree(tparams, body)
14941458
// case MATCHtpt =>
14951459
// val fst = readTpt()
14961460
// val (bound, scrut) =
@@ -1499,7 +1463,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
14991463
case TYPEBOUNDStpt =>
15001464
val lo = readTpt()
15011465
val hi = if (currentAddr === end) lo else readTpt()
1502-
TypeBoundsTree(lo, hi).setType(mkTypeBounds(lo.tpe, hi.tpe))
1466+
TypeBoundsTree(lo, hi).setType(TypeBounds.bounded(lo.tpe, hi.tpe))
15031467
// case HOLE =>
15041468
// readHole(end, isType = false)
15051469
// case _ =>

src/compiler/scala/tools/nsc/tasty/bridge/ContextOps.scala

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ import scala.tools.nsc.tasty.TastyUniverse
88

99
trait ContextOps extends TastyKernel { self: TastyUniverse =>
1010
import FlagSets._
11+
import Contexts._
12+
13+
@inline
14+
final def errorTasty(msg: String)(implicit ctx: Context): Unit =
15+
reporter.error(noPosition, s"Scala 2 incompatible TASTy signature of ${ctx.source.name} in ${ctx.owner}: $msg")
1116

1217
object Contexts {
1318

@@ -39,7 +44,8 @@ trait ContextOps extends TastyKernel { self: TastyUniverse =>
3944

4045
def requiredPackage(name: TermName): TermSymbol = loadingMirror.getPackage(name.toString)
4146

42-
final def log(str: => String): Unit = logTasty(s"#[${classRoot}]: $str")
47+
final def log(str: => String): Unit =
48+
logTasty(str.linesIterator.map(line => s"#[${classRoot}]: $line").mkString(System.lineSeparator))
4349

4450
final def picklerPhase: Phase = symbolTable.picklerPhase
4551
final def extmethodsPhase: Phase = symbolTable.findPhaseWithName("extmethods")
@@ -62,6 +68,9 @@ trait ContextOps extends TastyKernel { self: TastyUniverse =>
6268

6369
def newLocalDummy(owner: Symbol): TermSymbol = owner.newLocalDummy(noPosition)
6470

71+
def newWildcardSym(info: TypeBounds): Symbol =
72+
owner.newTypeParameter(nme.WILDCARD.toTypeName, noPosition, emptyFlags).setInfo(info)
73+
6574
def newSymbol(owner: Symbol, name: Name, flags: FlagSet, completer: TastyLazyType, privateWithin: Symbol = noSymbol): Symbol = {
6675
val sym = {
6776
if (flags.is(Param)) {
@@ -111,7 +120,7 @@ trait ContextOps extends TastyKernel { self: TastyUniverse =>
111120
* type of the constructed instance is returned
112121
*/
113122
def effectiveResultType(sym: Symbol, typeParams: List[Symbol], givenTp: Type): Type =
114-
if (sym.name == nme.CONSTRUCTOR) mkTypeRef(sym.owner.toType.prefix, sym.owner, typeParams.map(_.tpe))
123+
if (sym.name == nme.CONSTRUCTOR) sym.owner.tpe
115124
else givenTp
116125

117126
/** The method type corresponding to given parameters and result type */

src/compiler/scala/tools/nsc/tasty/bridge/FlagOps.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ trait FlagOps extends TastyKernel { self: TastyUniverse =>
1010
import symbolTable.Flag
1111
import scala.reflect.internal.{Flags, ModifierFlags}
1212

13+
val Package: FlagSet = Flags.PACKAGE
14+
1315
val Private: FlagSet = Flag.PRIVATE
1416
val Protected: FlagSet = Flag.PROTECTED
1517
val AbsOverride: FlagSet = Flag.ABSOVERRIDE

0 commit comments

Comments
 (0)