Skip to content

Use union types in compiler #6728

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 22 additions & 20 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ object Trees {
/** Property key for trees with documentation strings attached */
val DocComment: Property.StickyKey[Comments.Comment] = new Property.StickyKey

type LazyTree = AnyRef /* really: Tree | Lazy[Tree] */
type LazyTreeList = AnyRef /* really: List[Tree] | Lazy[List[Tree]] */

/** Trees take a parameter indicating what the type of their `tpe` field
* is. Two choices: `Type` or `Untyped`.
* Untyped trees have type `Tree[Untyped]`.
Expand Down Expand Up @@ -236,6 +233,9 @@ object Trees {
override def getMessage: String = s"type of $tree is not assigned"
}

type LazyTree[-T >: Untyped] = Tree[T] | Lazy[Tree[T]]
type LazyTreeList[-T >: Untyped] = List[Tree[T]] | Lazy[List[Tree[T]]]

// ------ Categories of trees -----------------------------------

/** Instances of this class are trees for which isType is definitely true.
Expand Down Expand Up @@ -361,7 +361,7 @@ object Trees {
type ThisTree[-T >: Untyped] <: ValOrDefDef[T]
def name: TermName
def tpt: Tree[T]
def unforcedRhs: LazyTree = unforced
def unforcedRhs: LazyTree[T] = unforced
def rhs(implicit ctx: Context): Tree[T] = forceIfLazy

/** Is this a `BackquotedValDef` or `BackquotedDefDef` ? */
Expand Down Expand Up @@ -727,36 +727,36 @@ object Trees {
}

/** mods val name: tpt = rhs */
case class ValDef[-T >: Untyped] private[ast] (name: TermName, tpt: Tree[T], private var preRhs: LazyTree)(implicit @constructorOnly src: SourceFile)
case class ValDef[-T >: Untyped] private[ast] (name: TermName, tpt: Tree[T], private var preRhs: LazyTree[T @uncheckedVariance])(implicit @constructorOnly src: SourceFile)
extends ValOrDefDef[T] {
type ThisTree[-T >: Untyped] = ValDef[T]
assert(isEmpty || tpt != genericEmptyTree)
def unforced: LazyTree = preRhs
protected def force(x: AnyRef): Unit = preRhs = x
def unforced: LazyTree[T] = preRhs
protected def force(x: Tree[T @uncheckedVariance]): Unit = preRhs = x
}

class BackquotedValDef[-T >: Untyped] private[ast] (name: TermName, tpt: Tree[T], preRhs: LazyTree)(implicit @constructorOnly src: SourceFile)
class BackquotedValDef[-T >: Untyped] private[ast] (name: TermName, tpt: Tree[T], preRhs: LazyTree[T @uncheckedVariance])(implicit @constructorOnly src: SourceFile)
extends ValDef[T](name, tpt, preRhs) {
override def isBackquoted: Boolean = true
override def productPrefix: String = "BackquotedValDef"
}

/** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs */
case class DefDef[-T >: Untyped] private[ast] (name: TermName, tparams: List[TypeDef[T]],
vparamss: List[List[ValDef[T]]], tpt: Tree[T], private var preRhs: LazyTree)(implicit @constructorOnly src: SourceFile)
vparamss: List[List[ValDef[T]]], tpt: Tree[T], private var preRhs: LazyTree[T @uncheckedVariance])(implicit @constructorOnly src: SourceFile)
extends ValOrDefDef[T] {
type ThisTree[-T >: Untyped] = DefDef[T]
assert(tpt != genericEmptyTree)
def unforced: LazyTree = preRhs
protected def force(x: AnyRef): Unit = preRhs = x
def unforced: LazyTree[T] = preRhs
protected def force(x: Tree[T @uncheckedVariance]): Unit = preRhs = x

override def disableOverlapChecks = rawMods.is(Delegate)
// disable order checks for implicit aliases since their given clause follows
// their for clause, but the two appear swapped in the DefDef.
}

class BackquotedDefDef[-T >: Untyped] private[ast] (name: TermName, tparams: List[TypeDef[T]],
vparamss: List[List[ValDef[T]]], tpt: Tree[T], preRhs: LazyTree)(implicit @constructorOnly src: SourceFile)
vparamss: List[List[ValDef[T]]], tpt: Tree[T], preRhs: LazyTree[T])(implicit @constructorOnly src: SourceFile)
extends DefDef[T](name, tparams, vparamss, tpt, preRhs) {
override def isBackquoted: Boolean = true
override def productPrefix: String = "BackquotedDefDef"
Expand All @@ -780,12 +780,12 @@ object Trees {
* if this is of class untpd.DerivingTemplate.
* Typed templates only have parents.
*/
case class Template[-T >: Untyped] private[ast] (constr: DefDef[T], parentsOrDerived: List[Tree[T]], self: ValDef[T], private var preBody: LazyTreeList)(implicit @constructorOnly src: SourceFile)
case class Template[-T >: Untyped] private[ast] (constr: DefDef[T], parentsOrDerived: List[Tree[T]], self: ValDef[T], private var preBody: LazyTreeList[T @uncheckedVariance])(implicit @constructorOnly src: SourceFile)
extends DefTree[T] with WithLazyField[List[Tree[T]]] {
type ThisTree[-T >: Untyped] = Template[T]
def unforcedBody: LazyTreeList = unforced
def unforced: LazyTreeList = preBody
protected def force(x: AnyRef): Unit = preBody = x
def unforcedBody: LazyTreeList[T] = unforced
def unforced: LazyTreeList[T] = preBody
protected def force(x: List[Tree[T @uncheckedVariance]]): Unit = preBody = x
def body(implicit ctx: Context): List[Tree[T]] = forceIfLazy

def parents: List[Tree[T]] = parentsOrDerived // overridden by DerivingTemplate
Expand Down Expand Up @@ -905,12 +905,12 @@ object Trees {

/** A tree that can have a lazy field
* The field is represented by some private `var` which is
* proxied `unforced` and `force`. Forcing the field will
* accessed by `unforced` and `force`. Forcing the field will
* set the `var` to the underlying value.
*/
trait WithLazyField[+T <: AnyRef] {
def unforced: AnyRef
protected def force(x: AnyRef): Unit
def unforced: T | Lazy[T]
protected def force(x: T @uncheckedVariance): Unit
def forceIfLazy(implicit ctx: Context): T = unforced match {
case lzy: Lazy[T @unchecked] =>
val x = lzy.complete
Expand All @@ -924,7 +924,7 @@ object Trees {
* These can be instantiated with Lazy instances which
* can delay tree construction until the field is first demanded.
*/
trait Lazy[T <: AnyRef] {
trait Lazy[+T <: AnyRef] {
def complete(implicit ctx: Context): T
}

Expand All @@ -943,6 +943,8 @@ object Trees {
type DefTree = Trees.DefTree[T]
type MemberDef = Trees.MemberDef[T]
type ValOrDefDef = Trees.ValOrDefDef[T]
type LazyTree = Trees.LazyTree[T]
type LazyTreeList = Trees.LazyTreeList[T]

type Ident = Trees.Ident[T]
type BackquotedIdent = Trees.BackquotedIdent[T]
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Names.scala
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,10 @@ object Names {
def underlying: TermName = unsupported("underlying")

@sharable // because of synchronized block in `and`
private[this] var derivedNames: AnyRef /* immutable.Map[NameInfo, DerivedName] | j.u.HashMap */ =
private[this] var derivedNames: immutable.Map[NameInfo, DerivedName] | HashMap[NameInfo, DerivedName] =
immutable.Map.empty[NameInfo, DerivedName]

private def getDerived(info: NameInfo): DerivedName /* | Null */ = derivedNames match {
private def getDerived(info: NameInfo): DerivedName /* | Null */ = (derivedNames: @unchecked) match {
case derivedNames: immutable.AbstractMap[NameInfo, DerivedName] @unchecked =>
if (derivedNames.contains(info)) derivedNames(info) else null
case derivedNames: HashMap[NameInfo, DerivedName] @unchecked =>
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,7 @@ object SymDenotations {
if (this.is(ModuleClass))
myInfo match {
case ClassInfo(_, _, _, _, selfType) =>
def sourceOfSelf(tp: TypeOrSymbol): Symbol = tp match {
def sourceOfSelf(tp: TypeOrSymbol): Symbol = (tp: @unchecked) match {
case tp: TermRef => tp.symbol
case tp: Symbol => sourceOfSelf(tp.info)
case tp: RefinedType => sourceOfSelf(tp.parent)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,7 @@ object Symbols {

type ThisName = TypeName

type TreeOrProvider = AnyRef /* tpd.TreeProvider | tpd.PackageDef | tpd.TypeDef | tpd.EmptyTree | Null */
type TreeOrProvider = tpd.TreeProvider | tpd.Tree

private[this] var myTree: TreeOrProvider = tpd.EmptyTree

Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3940,7 +3940,7 @@ object Types {

// ------ ClassInfo, Type Bounds --------------------------------------------------

type TypeOrSymbol = AnyRef /* should be: Type | Symbol */
type TypeOrSymbol = Type | Symbol

/** Roughly: the info of a class during a period.
* @param prefix The prefix on which parents, decls, and selfType need to be rebased.
Expand Down Expand Up @@ -4618,7 +4618,7 @@ object Types {
override def mapClassInfo(tp: ClassInfo): ClassInfo = {
val prefix1 = this(tp.prefix)
val parents1 = tp.parents mapConserve this
val selfInfo1 = tp.selfInfo match {
val selfInfo1: TypeOrSymbol = tp.selfInfo match {
case selfInfo: Type => this(selfInfo)
case selfInfo => selfInfo
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ class TreeUnpickler(reader: TastyReader,

val localCtx = localContext(sym)

def readRhs(implicit ctx: Context) =
def readRhs(implicit ctx: Context): LazyTree =
if (nothingButMods(end))
EmptyTree
else if (sym.isInlineMethod)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/printing/Formatting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ object Formatting {
}
}

private def wrapNonSensical(arg: Any /* Type | Symbol */, str: String)(implicit ctx: Context): String = {
private def wrapNonSensical(arg: Any, str: String)(implicit ctx: Context): String = {
import MessageContainer._
def isSensical(arg: Any): Boolean = arg match {
case tpe: Type =>
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ trait NamerContextOps { this: Context =>
}

/** A new context for the interior of a class */
def inClassContext(selfInfo: AnyRef /* Should be Type | Symbol*/): Context = {
def inClassContext(selfInfo: TypeOrSymbol): Context = {
val localCtx: Context = ctx.fresh.setNewScope
selfInfo match {
case sym: Symbol if sym.exists && sym.name != nme.WILDCARD => localCtx.scope.openForMutations.enter(sym)
Expand Down