From 3419fb73bb88c718b4a55d0b48e537824e8358cb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 22 Jun 2019 12:42:48 +0200 Subject: [PATCH 1/4] Strengthen type of LazyTree --- compiler/src/dotty/tools/dotc/ast/Trees.scala | 42 ++++++++++--------- .../tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 73e9707f230d..61b16d1e0d74 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -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]`. @@ -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. @@ -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` ? */ @@ -727,15 +727,15 @@ 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" @@ -743,12 +743,12 @@ object Trees { /** 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 @@ -756,7 +756,7 @@ object Trees { } 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" @@ -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 @@ -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 @@ -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 } @@ -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] diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 312caff64a5a..8eb233d321d8 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -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) From 8461cf46b733c43355eae1481e8884454fa98fdf Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 22 Jun 2019 12:49:30 +0200 Subject: [PATCH 2/4] Use union type for Name#derivedNames --- compiler/src/dotty/tools/dotc/core/Names.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 8c76620a5ae5..cb987d7ebf16 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -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 => From b2cd7619baba0c937b8bc43a32f76d373576671e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 22 Jun 2019 12:53:19 +0200 Subject: [PATCH 3/4] Use union type for TreeOrProvider --- compiler/src/dotty/tools/dotc/core/Symbols.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 63b024c53eba..0669c4c74cbd 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -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 From 755c242f76bf4d4d5e0d536a2a77eab9015414be Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 22 Jun 2019 12:57:41 +0200 Subject: [PATCH 4/4] Use union type for TypeOrSymbol --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 4 ++-- compiler/src/dotty/tools/dotc/printing/Formatting.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 35f1c7064d01..67ee4bd91d0f 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -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) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 947f4572ac19..36f2d07dbc8c 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -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. @@ -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 } diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index b76c1d966250..8cff705619eb 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -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 => diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index f22bed919c62..a1a117e8559a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -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)