diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 2431d2e59cd3..da941cbeb7fe 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -1214,7 +1214,7 @@ object Trees { case TypeTree() => tree case SingletonTypeTree(ref) => - cpy.SingletonTypeTree(tree)(transform(ref)(ctx.fresh.addMode(Mode.InTypeOf))) + cpy.SingletonTypeTree(tree)(transform(ref)(ctx.enterTypeOf())) case AndTypeTree(left, right) => cpy.AndTypeTree(tree)(transform(left), transform(right)) case OrTypeTree(left, right) => diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 2a371661c980..d44479e52f0e 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -116,6 +116,11 @@ object Contexts { protected def owner_=(owner: Symbol) = _owner = owner def owner: Symbol = _owner + /** The owner at the point of entering TypeOf (for SingletonTypeTrees) */ + private[this] var _inTypeOfOwner: Symbol = _ + protected def inTypeOfOwner_=(owner: Symbol) = _inTypeOfOwner = owner + def inTypeOfOwner: Symbol = _inTypeOfOwner + /** The current tree */ private[this] var _tree: Tree[_ >: Untyped]= _ protected def tree_=(tree: Tree[_ >: Untyped]) = _tree = tree @@ -179,12 +184,15 @@ object Contexts { * dependent, we finally also compute `_dependent` based on this context. */ if (!_dependentInit) { - _dependent = this.mode.is(Mode.InTypeOf) || isDepOwner(this.owner) + _dependent = this.isInTypeOf || isDepOwner(this.owner) _dependentInit = true } _dependent } + final def isInTypeOf: Boolean = + this.inTypeOfOwner == this.owner + /** A map in which more contextual properties can be stored * Typically used for attributes that are read and written only in special situations. */ @@ -497,6 +505,7 @@ object Contexts { def setPeriod(period: Period): this.type = { this.period = period; this } def setMode(mode: Mode): this.type = { this.mode = mode; this } def setOwner(owner: Symbol): this.type = { assert(owner != NoSymbol); this.owner = owner; this } + def enterTypeOf(): this.type = { assert(this.owner != NoSymbol); this.inTypeOfOwner = this.owner; this } def setTree(tree: Tree[_ >: Untyped]): this.type = { this.tree = tree; this } def setScope(scope: Scope): this.type = { this.scope = scope; this } def setNewScope: this.type = { this.scope = newScope; this } @@ -561,6 +570,8 @@ object Contexts { final def addMode(mode: Mode): Context = withModeBits(c.mode | mode) final def maskMode(mode: Mode): Context = withModeBits(c.mode & mode) final def retractMode(mode: Mode): Context = withModeBits(c.mode &~ mode) + + final def enterTypeOf(): Context = if (c.isInTypeOf) c else c.fresh.enterTypeOf() } implicit class FreshModeChanges(val c: FreshContext) extends AnyVal { diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 0accceca4e5f..f8ccc67aadcf 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4084,9 +4084,6 @@ object Types { } else tp - private def dependently(implicit ctx: Context): Context = - ctx.addMode(Mode.InTypeOf) - object If { def apply(underlyingTp: Type, condTp: Type, thenTp: Type, elseTp: Type)(implicit ctx: Context): TypeOf = TypeOf(underlyingTp, untpd.If( @@ -4107,7 +4104,7 @@ object Types { treeWithTpe(cond, condTp), treeWithTpe(thenp, thenTp), treeWithTpe(elsep, elseTp) - )(dependently) + )(ctx.enterTypeOf()) }) } @@ -4126,7 +4123,7 @@ object Types { def derived(to: TypeOf)(selectorTp: Type, caseTps: List[Type])(implicit ctx: Context): Type = finalizeDerived(to, to.tree match { case Trees.Match(selector, cases) => - cpy.Match(to.tree)(treeWithTpe(selector, selectorTp), treesWithTpes(cases, caseTps))(dependently) + cpy.Match(to.tree)(treeWithTpe(selector, selectorTp), treesWithTpes(cases, caseTps))(ctx.enterTypeOf()) }) } @@ -4145,7 +4142,7 @@ object Types { def derived(to: TypeOf)(funTp: Type, argTps: List[Type])(implicit ctx: Context): Type = finalizeDerived(to, to.tree match { case Trees.Apply(fun, args) => - cpy.Apply(to.tree)(treeWithTpe(fun, funTp), treesWithTpes(args, argTps))(dependently) + cpy.Apply(to.tree)(treeWithTpe(fun, funTp), treesWithTpes(args, argTps))(ctx.enterTypeOf()) }) } @@ -4164,7 +4161,7 @@ object Types { def derived(to: TypeOf)(funTp: Type, argTps: List[Type])(implicit ctx: Context): Type = finalizeDerived(to, to.tree match { case Trees.TypeApply(fun, args) => - cpy.TypeApply(to.tree)(treeWithTpe(fun, funTp), treesWithTpes(args, argTps))(dependently) + cpy.TypeApply(to.tree)(treeWithTpe(fun, funTp), treesWithTpes(args, argTps))(ctx.enterTypeOf()) }) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 4ca1e8a5a717..7ef19aa38c3c 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -1040,7 +1040,7 @@ class TreeUnpickler(reader: TastyReader, case THROW => Throw(readTerm()) case SINGLETONtpt => - SingletonTypeTree(readTerm()(ctx.fresh.addMode(Mode.InTypeOf))) + SingletonTypeTree(readTerm()(ctx.enterTypeOf())) case BYNAMEtpt => ByNameTypeTree(readTpt()) case NAMEDARG => diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index db394b413fe4..6539ab49e5e2 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1203,7 +1203,7 @@ class Typer extends Namer } def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(implicit ctx: Context): SingletonTypeTree = track("typedSingletonTypeTree") { - val ref1 = typedExpr(tree.ref)(ctx.fresh.addMode(Mode.InTypeOf)) + val ref1 = typedExpr(tree.ref)(ctx.enterTypeOf()) // TODO: Discuss stability requirements of singleton type trees and potentially reenable check // checkStable(ref1.tpe, tree.pos) assignType(cpy.SingletonTypeTree(tree)(ref1), ref1)