Skip to content

Commit d30a8aa

Browse files
committed
Add untyped types to Tasty
Allow UNTYPEDSPLICE roots with TYPEDSPLICE subtrees. Trees between them are untyped.
1 parent e0f56b7 commit d30a8aa

File tree

4 files changed

+506
-74
lines changed

4 files changed

+506
-74
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
642642

643643
override def skipTransform(tree: Tree)(implicit ctx: Context) = tree.tpe.isError
644644

645-
implicit class TreeOps[ThisTree <: tpd.Tree](val tree: ThisTree) extends AnyVal {
645+
implicit class TreeOps[ThisTree <: tpd.Tree](private val tree: ThisTree) extends AnyVal {
646646

647647
def isValue(implicit ctx: Context): Boolean =
648648
tree.isTerm && tree.tpe.widen.isValueType

compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,21 +55,22 @@ Standard-Section: "ASTs" TopLevelStat*
5555
Stat
5656
5757
Stat = Term
58-
VALDEF Length NameRef type_Term rhs_Term? Modifier*
58+
VALDEF Length NameRef type_Term rhs_Term? Mods
5959
DEFDEF Length NameRef TypeParam* Params* returnType_Term rhs_Term?
60-
Modifier*
61-
TYPEDEF Length NameRef (type_Term | Template) Modifier*
60+
Mods
61+
TYPEDEF Length NameRef (type_Term | Template) Mods
62+
OBJECTDEF Length NameRef Template Mods
6263
IMPORT Length qual_Term Selector*
6364
Selector = IMPORTED name_NameRef
6465
RENAMED to_NameRef
6566
6667
// Imports are for scala.meta, they are not used in the backend
6768
68-
TypeParam = TYPEPARAM Length NameRef Type Modifier*
69+
TypeParam = TYPEPARAM Length NameRef type_Term Mods
6970
Params = PARAMS Length Param*
70-
Param = PARAM Length NameRef Type rhs_Term? Modifier* // rhs_Term is present in the case of an aliased class parameter
71+
Param = PARAM Length NameRef type_Term rhs_Term? Mods // rhs_Term is present in the case of an aliased class parameter
7172
Template = TEMPLATE Length TypeParam* Param* parent_Term* Self? Stat* // Stat* always starts with the primary constructor.
72-
Self = SELFDEF selfName_NameRef selfType_Type
73+
Self = SELFDEF selfName_NameRef selfType_Term
7374
7475
Term = Path
7576
IDENT NameRef Type // used when term ident’s type is not a TermRef
@@ -109,6 +110,7 @@ Standard-Section: "ASTs" TopLevelStat*
109110
EMPTYTREE
110111
SHAREDterm term_ASTRef
111112
HOLE Length idx_Nat arg_Tree*
113+
UNTYPEDSPLICE Length splice_TermUntyped splice_Type
112114
113115
CaseDef = CASEDEF Length pat_Term rhs_Tree guard_Tree?
114116
ImplicitArg = IMPLICITARG arg_Term
@@ -166,6 +168,8 @@ Standard-Section: "ASTs" TopLevelStat*
166168
NamesTypes = NameType*
167169
NameType = paramName_NameRef typeOrBounds_ASTRef
168170
171+
Mods = Modifier* Annotation*
172+
169173
Modifier = PRIVATE
170174
INTERNAL // package private
171175
PROTECTED
@@ -202,6 +206,13 @@ Standard-Section: "ASTs" TopLevelStat*
202206
203207
Annotation = ANNOTATION Length tycon_Type fullAnnotation_Term
204208
209+
// --------------- untyped additions ------------------------------------------
210+
211+
TermUntyped = Term
212+
FUNCTION Length body_Term arg_Term*
213+
INFIXOP Length op_NameRef left_Term right_Term
214+
TYPEDSPLICE Length splice_Term
215+
205216
Note: Tree tags are grouped into 5 categories that determine what follows, and thus allow to compute the size of the tagged tree in a generic way.
206217
207218
Category 1 (tags 1-49) : tag
@@ -320,6 +331,7 @@ object TastyFormat {
320331
final val IMPORTED = 65
321332
final val RENAMED = 66
322333
final val SYMBOLconst = 67
334+
final val UIDENT = 68
323335

324336
// Cat. 3: tag AST
325337

@@ -400,6 +412,7 @@ object TastyFormat {
400412
final val ANNOTATION = 172
401413
final val TERMREFin = 173
402414
final val TYPEREFin = 174
415+
final val OBJECTDEF = 175
403416

404417
// In binary: 101100EI
405418
// I = implicit method type
@@ -409,6 +422,13 @@ object TastyFormat {
409422
final val ERASEDMETHODtype = 178
410423
final val ERASEDIMPLICITMETHODtype = 179
411424

425+
final val UNTYPEDSPLICE = 199
426+
427+
// Tags for untyped trees only:
428+
final val TYPEDSPLICE = 200
429+
final val FUNCTION = 201
430+
final val INFIXOP = 202
431+
412432
def methodType(isImplicit: Boolean = false, isErased: Boolean = false) = {
413433
val implicitOffset = if (isImplicit) 1 else 0
414434
val erasedOffset = if (isErased) 2 else 0
@@ -550,6 +570,7 @@ object TastyFormat {
550570
case VALDEF => "VALDEF"
551571
case DEFDEF => "DEFDEF"
552572
case TYPEDEF => "TYPEDEF"
573+
case OBJECTDEF => "OBJECTDEF"
553574
case IMPORT => "IMPORT"
554575
case TYPEPARAM => "TYPEPARAM"
555576
case PARAMS => "PARAMS"
@@ -617,13 +638,18 @@ object TastyFormat {
617638
case PRIVATEqualified => "PRIVATEqualified"
618639
case PROTECTEDqualified => "PROTECTEDqualified"
619640
case HOLE => "HOLE"
641+
642+
case UNTYPEDSPLICE => "UNTYPEDSPLICE"
643+
case TYPEDSPLICE => "TYPEDSPLICE"
644+
case FUNCTION => "FUNCTION"
645+
case INFIXOP => "INFIXOP"
620646
}
621647

622648
/** @return If non-negative, the number of leading references (represented as nats) of a length/trees entry.
623649
* If negative, minus the number of leading non-reference trees.
624650
*/
625651
def numRefs(tag: Int) = tag match {
626-
case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM | NAMEDARG | RETURN | BIND |
652+
case VALDEF | DEFDEF | TYPEDEF | OBJECTDEF | TYPEPARAM | PARAM | NAMEDARG | RETURN | BIND |
627653
SELFDEF | REFINEDtype | TERMREFin | TYPEREFin | HOLE => 1
628654
case RENAMED | PARAMtype => 2
629655
case POLYtype | METHODtype | TYPELAMBDAtype => -1

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 210 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package core
44
package tasty
55

66
import ast.Trees._
7-
import ast.{untpd, tpd}
7+
import ast.{untpd, tpd, desugar}
88
import TastyFormat._
99
import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annotations._, StdNames.tpnme, NameOps._
1010
import collection.mutable
@@ -546,6 +546,10 @@ class TreePickler(pickler: TastyPickler) {
546546
pickleTree(lo);
547547
if (hi ne lo) pickleTree(hi)
548548
}
549+
case tpd.UntypedSplice(splice) =>
550+
//println(i"UNTYPED: $splice")
551+
writeByte(UNTYPEDSPLICE)
552+
withLength { pickleUntyped(splice); pickleType(tree.tpe) }
549553
case Hole(idx, args) =>
550554
writeByte(HOLE)
551555
withLength {
@@ -643,6 +647,211 @@ class TreePickler(pickler: TastyPickler) {
643647
withLength { pickleType(ann.symbol.typeRef); pickleTree(ann.tree) }
644648
}
645649

650+
// ---- pickling untyped trees ----------------------------------
651+
652+
def pickleUntyped(tree: untpd.Tree)(implicit ctx: Context): Unit = {
653+
try desugar(tree) match {
654+
case Ident(name) =>
655+
writeByte(if (name.isTypeName) TYPEREF else TERMREF)
656+
pickleName(name)
657+
pickleDummyType()
658+
case This(qual) =>
659+
writeByte(QUALTHIS)
660+
pickleUntyped(qual)
661+
case Select(qual, name) =>
662+
writeByte(if (name.isTypeName) SELECTtpt else SELECT)
663+
pickleName(name)
664+
pickleUntyped(qual)
665+
case Apply(fun, args) =>
666+
writeByte(APPLY)
667+
withLength {
668+
pickleUntyped(fun)
669+
args.foreach(pickleUntyped)
670+
}
671+
case untpd.Throw(exc) =>
672+
writeByte(THROW)
673+
pickleUntyped(exc)
674+
case TypeApply(fun, args) =>
675+
writeByte(TYPEAPPLY)
676+
withLength {
677+
pickleUntyped(fun)
678+
args.foreach(pickleUntyped)
679+
}
680+
case Literal(const) =>
681+
pickleConstant(const)
682+
case Super(qual, mix) =>
683+
writeByte(SUPER)
684+
withLength {
685+
pickleUntyped(qual);
686+
if (!mix.isEmpty) pickleUntyped(mix)
687+
}
688+
case New(tpt) =>
689+
writeByte(NEW)
690+
pickleUntyped(tpt)
691+
case Typed(expr, tpt) =>
692+
writeByte(TYPED)
693+
withLength { pickleUntyped(expr); pickleUntyped(tpt) }
694+
case NamedArg(name, arg) =>
695+
writeByte(NAMEDARG)
696+
pickleName(name)
697+
pickleUntyped(arg)
698+
case Assign(lhs, rhs) =>
699+
writeByte(ASSIGN)
700+
withLength { pickleUntyped(lhs); pickleUntyped(rhs) }
701+
case Block(stats, expr) =>
702+
writeByte(BLOCK)
703+
withLength { pickleUntyped(expr); stats.foreach(pickleUntyped) }
704+
case If(cond, thenp, elsep) =>
705+
writeByte(IF)
706+
withLength { pickleUntyped(cond); pickleUntyped(thenp); pickleUntyped(elsep) }
707+
case Match(selector, cases) =>
708+
writeByte(MATCH)
709+
withLength { pickleUntyped(selector); cases.foreach(pickleUntyped) }
710+
case CaseDef(pat, guard, rhs) =>
711+
writeByte(CASEDEF)
712+
withLength { pickleUntyped(pat); pickleUntyped(rhs); pickleUntypedUnlessEmpty(guard) }
713+
case Return(expr, from) =>
714+
writeByte(RETURN)
715+
withLength { pickleDummyRef(); pickleUntypedUnlessEmpty(expr) }
716+
case Try(block, cases, finalizer) =>
717+
writeByte(TRY)
718+
withLength { pickleUntyped(block); cases.foreach(pickleUntyped); pickleUntypedUnlessEmpty(finalizer) }
719+
case Bind(name, body) =>
720+
writeByte(BIND)
721+
withLength {
722+
pickleName(name); pickleDummyType(); pickleUntyped(body)
723+
}
724+
case Alternative(alts) =>
725+
writeByte(ALTERNATIVE)
726+
withLength { alts.foreach(pickleUntyped) }
727+
case tree: untpd.ValDef =>
728+
pickleUntypedDef(VALDEF, tree, tree.tpt, tree.rhs)
729+
case tree: untpd.DefDef =>
730+
pickleUntypedDef(DEFDEF, tree, tree.tpt, tree.rhs, pickleAllUntypedParams(tree))
731+
case tree: untpd.TypeDef =>
732+
pickleUntypedDef(TYPEDEF, tree, tree.rhs)
733+
case tree: untpd.ModuleDef =>
734+
pickleUntypedDef(OBJECTDEF, tree, tree.impl)
735+
case tree: untpd.Template =>
736+
writeByte(TEMPLATE)
737+
tree.parents.foreach(pickleUntyped)
738+
if (!tree.self.isEmpty) {
739+
writeByte(SELFDEF); pickleName(tree.self.name); pickleUntyped(tree.self.tpt)
740+
}
741+
pickleUntyped(tree.constr)
742+
tree.body.foreach(pickleUntyped)
743+
case Import(expr, selectors) =>
744+
writeByte(IMPORT)
745+
withLength { pickleUntyped(expr); pickleSelectors(selectors) }
746+
case tree: untpd.TypeTree =>
747+
pickleDummyType()
748+
case SingletonTypeTree(ref) =>
749+
writeByte(SINGLETONtpt)
750+
pickleUntyped(ref)
751+
case RefinedTypeTree(parent, refinements) =>
752+
writeByte(REFINEDtpt)
753+
withLength { pickleUntyped(parent); refinements.foreach(pickleUntyped) }
754+
case AppliedTypeTree(tycon, args) =>
755+
writeByte(APPLIEDtpt)
756+
withLength { pickleUntyped(tycon); args.foreach(pickleUntyped) }
757+
case AndTypeTree(tp1, tp2) =>
758+
writeByte(ANDtpt)
759+
withLength { pickleUntyped(tp1); pickleUntyped(tp2) }
760+
case OrTypeTree(tp1, tp2) =>
761+
writeByte(ORtpt)
762+
withLength { pickleUntyped(tp1); pickleUntyped(tp2) }
763+
case ByNameTypeTree(tp) =>
764+
writeByte(BYNAMEtpt)
765+
pickleUntyped(tp)
766+
case Annotated(tree, annot) =>
767+
writeByte(ANNOTATEDtpt)
768+
withLength { pickleUntyped(tree); pickleUntyped(annot) }
769+
case LambdaTypeTree(tparams, body) =>
770+
writeByte(LAMBDAtpt)
771+
withLength { pickleUntypedParams(tparams); pickleUntyped(body) }
772+
case TypeBoundsTree(lo, hi) =>
773+
writeByte(TYPEBOUNDStpt)
774+
withLength {
775+
pickleUntyped(lo);
776+
if (hi ne lo) pickleUntyped(hi)
777+
}
778+
case untpd.Function(args, body) =>
779+
writeByte(FUNCTION)
780+
withLength { pickleUntyped(body); args.foreach(pickleUntyped) }
781+
case untpd.InfixOp(l, op, r) =>
782+
writeByte(INFIXOP)
783+
withLength { pickleUntyped(l); pickleUntyped(op); pickleUntyped(r) }
784+
case Thicket(trees) =>
785+
trees.foreach(pickleUntyped)
786+
case untpd.TypedSplice(splice) =>
787+
writeByte(TYPEDSPLICE)
788+
withLength { pickleTree(splice) }
789+
}
790+
catch {
791+
case ex: AssertionError =>
792+
println(i"error when pickling tree $tree")
793+
throw ex
794+
}
795+
}
796+
797+
def pickleUntypedUnlessEmpty(tree: untpd.Tree)(implicit ctx: Context): Unit =
798+
if (!tree.isEmpty) pickleUntyped(tree)
799+
800+
def pickleAllUntypedParams(tree: untpd.DefDef)(implicit ctx: Context): Unit = {
801+
pickleUntypedParams(tree.tparams)
802+
for (vparams <- tree.vparamss) {
803+
writeByte(PARAMS)
804+
withLength { pickleUntypedParams(vparams) }
805+
}
806+
}
807+
808+
def pickleUntypedParams(trees: List[untpd.Tree])(implicit ctx: Context): Unit =
809+
trees.foreach(pickleUntypedParam)
810+
811+
def pickleUntypedDef(tag: Int, tree: untpd.MemberDef, tpt: untpd.Tree, rhs: untpd.Tree = untpd.EmptyTree, pickleParams: => Unit = ())(implicit ctx: Context) = {
812+
import untpd.modsDeco
813+
writeByte(tag)
814+
withLength {
815+
pickleName(tree.name)
816+
pickleParams
817+
pickleUntyped(tpt)
818+
pickleUntypedUnlessEmpty(rhs)
819+
pickleUntypedModifiers(tree.mods)
820+
}
821+
}
822+
823+
def pickleUntypedParam(tree: untpd.Tree)(implicit ctx: Context): Unit = tree match {
824+
case tree: untpd.ValDef => pickleUntypedDef(PARAM, tree, tree.tpt)
825+
case tree: untpd.DefDef => pickleUntypedDef(PARAM, tree, tree.tpt, tree.rhs)
826+
case tree: untpd.TypeDef => pickleUntypedDef(TYPEPARAM, tree, tree.rhs)
827+
}
828+
829+
def pickleUntypedModifiers(mods: untpd.Modifiers)(implicit ctx: Context): Unit = {
830+
import Flags._
831+
var flags = mods.flags
832+
val privateWithin = mods.privateWithin
833+
if (!privateWithin.isEmpty) {
834+
writeByte(if (flags is Protected) PROTECTEDqualified else PRIVATEqualified)
835+
pickleUntyped(untpd.Ident(privateWithin))
836+
flags = flags &~ Protected
837+
}
838+
mods.annotations.foreach(pickleUntypedAnnotation)
839+
}
840+
841+
def pickleUntypedAnnotation(annotTree: untpd.Tree)(implicit ctx: Context) = {
842+
writeByte(ANNOTATION)
843+
withLength { pickleDummyType(); pickleUntyped(annotTree) }
844+
}
845+
846+
def pickleDummyRef(): Unit = writeNat(0)
847+
848+
def pickleDummyType(): Unit = {
849+
writeByte(SHAREDtype)
850+
pickleDummyRef()
851+
}
852+
853+
// ---- main entry points ---------------------------------------
854+
646855
def pickle(trees: List[Tree])(implicit ctx: Context) = {
647856
trees.foreach(tree => if (!tree.isEmpty) pickleTree(tree))
648857
def missing = forwardSymRefs.keysIterator.map(_.showLocated).toList

0 commit comments

Comments
 (0)