Skip to content

Use attachment to tag backquoted trees #6755

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 5 commits into from
Jun 26, 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
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ object desugar {
* ```
*/
def transformQuotedPatternName(tree: ValOrDefDef)(implicit ctx: Context): ValOrDefDef = {
if (ctx.mode.is(Mode.QuotedPattern) && !tree.isBackquoted && tree.name != nme.ANON_FUN && tree.name.startsWith("$")) {
if (ctx.mode.is(Mode.QuotedPattern) && !isBackquoted(tree) && tree.name != nme.ANON_FUN && tree.name.startsWith("$")) {
val mods = tree.mods.withAddedAnnotation(New(ref(defn.InternalQuoted_patternBindHoleAnnot.typeRef)).withSpan(tree.span))
tree.withMods(mods)
} else tree
Expand Down Expand Up @@ -1478,7 +1478,7 @@ object desugar {
// This is a deliberate departure from scalac, where StringContext is not rooted (See #4732)
Apply(Select(Apply(scalaDot(nme.StringContext), strs), id), elems)
case PostfixOp(t, op) =>
if ((ctx.mode is Mode.Type) && !op.isBackquoted && op.name == tpnme.raw.STAR) {
if ((ctx.mode is Mode.Type) && !isBackquoted(op) && op.name == tpnme.raw.STAR) {
val seqType = if (ctx.compilationUnit.isJava) defn.ArrayType else defn.SeqType
Annotated(
AppliedTypeTree(ref(seqType), t),
Expand Down
6 changes: 4 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,12 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
case _ => false
}

/** Is tree a backquoted identifier or definition */
def isBackquoted(tree: Tree): Boolean = tree.hasAttachment(Backquoted)

/** Is tree a variable pattern? */
def isVarPattern(pat: Tree): Boolean = unsplice(pat) match {
case x: BackquotedIdent => false
case x: Ident => x.name.isVariableName
case x: Ident => x.name.isVariableName && !isBackquoted(x)
case _ => false
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/TreeMapWithImplicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import dotty.tools.dotc.core.TypeError
import scala.annotation.tailrec

/** A TreeMap that maintains the necessary infrastructure to support
* contxtual implicit searches (type-scope implicits are supported anyway).
* contextual implicit searches (type-scope implicits are supported anyway).
*
* This incudes impicits defined in scope as well as imported implicits.
* This incudes implicits defined in scope as well as imported implicits.
*/
class TreeMapWithImplicits extends tpd.TreeMap {
import tpd._
Expand Down
45 changes: 6 additions & 39 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ object Trees {
@sharable var ntrees: Int = 0

/** Property key for trees with documentation strings attached */
val DocComment: Property.StickyKey[Comments.Comment] = new Property.StickyKey
val DocComment: Property.StickyKey[Comments.Comment] = Property.StickyKey()

/** Property key for backquoted identifiers and definitions */
val Backquoted: Property.StickyKey[Unit] = Property.StickyKey()

/** Trees take a parameter indicating what the type of their `tpe` field
* is. Two choices: `Type` or `Untyped`.
Expand Down Expand Up @@ -363,9 +366,6 @@ object Trees {
def tpt: Tree[T]
def unforcedRhs: LazyTree[T] = unforced
def rhs(implicit ctx: Context): Tree[T] = forceIfLazy

/** Is this a `BackquotedValDef` or `BackquotedDefDef` ? */
def isBackquoted: Boolean = false
}

// ----------- Tree case classes ------------------------------------
Expand All @@ -376,15 +376,7 @@ object Trees {
type ThisTree[-T >: Untyped] = Ident[T]
def qualifier: Tree[T] = genericEmptyTree

/** Is this a `BackquotedIdent` ? */
def isBackquoted: Boolean = false
}

class BackquotedIdent[-T >: Untyped]private[ast] (name: Name)(implicit @constructorOnly src: SourceFile)
extends Ident[T](name) {
override def isBackquoted: Boolean = true

override def toString: String = s"BackquotedIdent($name)"
def isBackquoted: Boolean = hasAttachment(Backquoted)
}

class SearchFailureIdent[-T >: Untyped] private[ast] (name: Name)(implicit @constructorOnly src: SourceFile)
Expand Down Expand Up @@ -437,7 +429,7 @@ object Trees {
extends GenericApply[T] {
type ThisTree[-T >: Untyped] = Apply[T]

def isGivenApply = getAttachment(untpd.ApplyGiven).nonEmpty
def isGivenApply = hasAttachment(untpd.ApplyGiven)
def setGivenApply() = { pushAttachment(untpd.ApplyGiven, ()); this }
}

Expand Down Expand Up @@ -735,12 +727,6 @@ object Trees {
protected def force(x: Tree[T @uncheckedVariance]): Unit = preRhs = x
}

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[T @uncheckedVariance])(implicit @constructorOnly src: SourceFile)
Expand All @@ -755,13 +741,6 @@ object Trees {
// 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[T])(implicit @constructorOnly src: SourceFile)
extends DefDef[T](name, tparams, vparamss, tpt, preRhs) {
override def isBackquoted: Boolean = true
override def productPrefix: String = "BackquotedDefDef"
}

/** mods class name template or
* mods trait name template or
* mods type name = rhs or
Expand Down Expand Up @@ -947,7 +926,6 @@ object Trees {
type LazyTreeList = Trees.LazyTreeList[T]

type Ident = Trees.Ident[T]
type BackquotedIdent = Trees.BackquotedIdent[T]
type SearchFailureIdent = Trees.SearchFailureIdent[T]
type Select = Trees.Select[T]
type SelectWithSig = Trees.SelectWithSig[T]
Expand Down Expand Up @@ -986,9 +964,7 @@ object Trees {
type Alternative = Trees.Alternative[T]
type UnApply = Trees.UnApply[T]
type ValDef = Trees.ValDef[T]
type BackquotedValDef = Trees.BackquotedValDef[T]
type DefDef = Trees.DefDef[T]
type BackquotedDefDef = Trees.BackquotedDefDef[T]
type TypeDef = Trees.TypeDef[T]
type Template = Trees.Template[T]
type Import = Trees.Import[T]
Expand Down Expand Up @@ -1036,9 +1012,6 @@ object Trees {
postProcess(tree, copied.withSpan(tree.span).withAttachmentsFrom(tree))

def Ident(tree: Tree)(name: Name)(implicit ctx: Context): Ident = tree match {
case tree: BackquotedIdent =>
if (name == tree.name) tree
else finalize(tree, new BackquotedIdent(name)(sourceFile(tree)))
case tree: Ident if name == tree.name => tree
case _ => finalize(tree, untpd.Ident(name)(sourceFile(tree)))
}
Expand Down Expand Up @@ -1181,16 +1154,10 @@ object Trees {
case _ => finalize(tree, untpd.UnApply(fun, implicits, patterns)(sourceFile(tree)))
}
def ValDef(tree: Tree)(name: TermName, tpt: Tree, rhs: LazyTree)(implicit ctx: Context): ValDef = tree match {
case tree: BackquotedValDef =>
if ((name == tree.name) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs)) tree
else finalize(tree, untpd.BackquotedValDef(name, tpt, rhs)(sourceFile(tree)))
case tree: ValDef if (name == tree.name) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree
case _ => finalize(tree, untpd.ValDef(name, tpt, rhs)(sourceFile(tree)))
}
def DefDef(tree: Tree)(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree)(implicit ctx: Context): DefDef = tree match {
case tree: BackquotedDefDef =>
if ((name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs)) tree
else finalize(tree, untpd.BackquotedDefDef(name, tparams, vparamss, tpt, rhs)(sourceFile(tree)))
case tree: DefDef if (name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree
case _ => finalize(tree, untpd.DefDef(name, tparams, vparamss, tpt, rhs)(sourceFile(tree)))
}
Expand Down
8 changes: 2 additions & 6 deletions compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
// ------ Creation methods for untyped only -----------------

def Ident(name: Name)(implicit src: SourceFile): Ident = new Ident(name)
def BackquotedIdent(name: Name)(implicit src: SourceFile): BackquotedIdent = new BackquotedIdent(name)
def SearchFailureIdent(name: Name)(implicit src: SourceFile): SearchFailureIdent = new SearchFailureIdent(name)
def Select(qualifier: Tree, name: Name)(implicit src: SourceFile): Select = new Select(qualifier, name)
def SelectWithSig(qualifier: Tree, name: Name, sig: Signature)(implicit src: SourceFile): Select = new SelectWithSig(qualifier, name, sig)
Expand Down Expand Up @@ -338,9 +337,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def Alternative(trees: List[Tree])(implicit src: SourceFile): Alternative = new Alternative(trees)
def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree])(implicit src: SourceFile): UnApply = new UnApply(fun, implicits, patterns)
def ValDef(name: TermName, tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): ValDef = new ValDef(name, tpt, rhs)
def BackquotedValDef(name: TermName, tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): ValDef = new BackquotedValDef(name, tpt, rhs)
def DefDef(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): DefDef = new DefDef(name, tparams, vparamss, tpt, rhs)
def BackquotedDefDef(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): DefDef = new BackquotedDefDef(name, tparams, vparamss, tpt, rhs)
def TypeDef(name: TypeName, rhs: Tree)(implicit src: SourceFile): TypeDef = new TypeDef(name, rhs)
def Template(constr: DefDef, parents: List[Tree], derived: List[Tree], self: ValDef, body: LazyTreeList)(implicit src: SourceFile): Template =
if (derived.isEmpty) new Template(constr, parents, self, body)
Expand Down Expand Up @@ -431,9 +428,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
AppliedTypeTree(ref(defn.andType.typeRef), left :: right :: Nil)

def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers = EmptyModifiers, isBackquoted: Boolean = false)(implicit ctx: Context): ValDef = {
val vdef =
if (isBackquoted) BackquotedValDef(pname, tpe, EmptyTree)
else ValDef(pname, tpe, EmptyTree)
val vdef = ValDef(pname, tpe, EmptyTree)
if (isBackquoted) vdef.pushAttachment(Backquoted, ())
vdef.withMods(mods | Param)
}

Expand Down
22 changes: 11 additions & 11 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -408,9 +408,9 @@ object Parsers {
*/
def convertToParam(tree: Tree, expected: String = "formal parameter"): ValDef = tree match {
case id @ Ident(name) =>
makeParameter(name.asTermName, TypeTree(), isBackquoted = id.isBackquoted).withSpan(tree.span)
makeParameter(name.asTermName, TypeTree(), isBackquoted = isBackquoted(id)).withSpan(tree.span)
case Typed(id @ Ident(name), tpt) =>
makeParameter(name.asTermName, tpt, isBackquoted = id.isBackquoted).withSpan(tree.span)
makeParameter(name.asTermName, tpt, isBackquoted = isBackquoted(id)).withSpan(tree.span)
case Typed(Splice(Ident(name)), tpt) =>
makeParameter(("$" + name).toTermName, tpt).withSpan(tree.span)
case _ =>
Expand Down Expand Up @@ -628,9 +628,8 @@ object Parsers {
makeIdent(in.token, in.offset, ident().toTypeName)

private def makeIdent(tok: Token, offset: Offset, name: Name) = {
val tree =
if (tok == BACKQUOTED_IDENT) BackquotedIdent(name)
else Ident(name)
val tree = Ident(name)
if (tok == BACKQUOTED_IDENT) tree.pushAttachment(Backquoted, ())

// Make sure that even trees with parsing errors have a offset that is within the offset
val errorOffset = offset min (in.lastOffset - 1)
Expand Down Expand Up @@ -2526,10 +2525,10 @@ object Parsers {
}
} else EmptyTree
lhs match {
case (id: BackquotedIdent) :: Nil if id.name.isTermName =>
finalizeDef(BackquotedValDef(id.name.asTermName, tpt, rhs), mods, start)
case Ident(name: TermName) :: Nil =>
finalizeDef(ValDef(name, tpt, rhs), mods, start)
case (id @ Ident(name: TermName)) :: Nil =>
val vdef = ValDef(name, tpt, rhs)
if (isBackquoted(id)) vdef.pushAttachment(Backquoted, ())
finalizeDef(vdef, mods, start)
case _ =>
PatDef(mods, lhs, tpt, rhs)
}
Expand Down Expand Up @@ -2606,8 +2605,9 @@ object Parsers {
expr()
}

if (ident.isBackquoted) finalizeDef(BackquotedDefDef(ident.name.asTermName, tparams, vparamss, tpt, rhs), mods1, start)
else finalizeDef(DefDef(ident.name.asTermName, tparams, vparamss, tpt, rhs), mods1, start)
val ddef = DefDef(ident.name.asTermName, tparams, vparamss, tpt, rhs)
if (isBackquoted(ident)) ddef.pushAttachment(Backquoted, ())
finalizeDef(ddef, mods1, start)
}
}

Expand Down
7 changes: 3 additions & 4 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -334,24 +334,23 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}

tree match {
case id: Trees.BackquotedIdent[_] if !homogenizedView =>
"`" ~ toText(id.name) ~ "`"
case id: Trees.SearchFailureIdent[_] =>
tree.typeOpt match {
case reason: Implicits.SearchFailureType =>
toText(id.name) ~ "implicitly[" ~ toText(reason.clarify(reason.expectedType)) ~ "]"
case _ =>
toText(id.name)
}
case Ident(name) =>
case id @ Ident(name) =>
val txt = tree.typeOpt match {
case tp: NamedType if name != nme.WILDCARD =>
val pre = if (tp.symbol.is(JavaStatic)) tp.prefix.widen else tp.prefix
toTextPrefix(pre) ~ withPos(selectionString(tp), tree.sourcePos)
case _ =>
toText(name)
}
if (name.isTypeName) typeText(txt)
if (isBackquoted(tree) && !homogenizedView) "`" ~ toText(name) ~ "`"
else if (name.isTypeName) typeText(txt)
else txt
case tree @ Select(qual, name) =>
if (!printDebug && tree.hasType && tree.symbol == defn.QuotedType_splice) typeText("${") ~ toTextLocal(qual) ~ typeText("}")
Expand Down
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,7 @@ object PatternMatcher {
case Typed(_, tpt) if tpt.tpe.isRepeatedParam => true
case Bind(nme.WILDCARD, WildcardPattern()) => true // don't skip when binding an interesting symbol!
case t if isWildcardArg(t) => true
case x: BackquotedIdent => false
case x: Ident => x.name.isVariableName
case x: Ident => x.name.isVariableName && !isBackquoted(x)
case Alternative(ps) => ps.forall(unapply)
case EmptyTree => true
case _ => false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ object TypeTestsCasts {

if (sym.isTypeTest) {
val argType = tree.args.head.tpe
val isTrusted = tree.getAttachment(PatternMatcher.TrustedTypeTestKey).nonEmpty
val isTrusted = tree.hasAttachment(PatternMatcher.TrustedTypeTestKey)
if (!isTrusted && !checkable(expr.tpe, argType, tree.span))
ctx.warning(i"the type test for $argType cannot be checked at runtime", tree.sourcePos)
transformTypeTest(expr, tree.args.head.tpe, flagUnrelated = true)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/patmat/Space.scala
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
Typ(c.value.asInstanceOf[Symbol].termRef, false)
else
Typ(ConstantType(c), false)
case _: BackquotedIdent => Typ(pat.tpe, false)
case pat: Ident if isBackquoted(pat) => Typ(pat.tpe, false)
case Ident(nme.WILDCARD) =>
Or(Typ(pat.tpe.stripAnnots, false) :: nullSpace :: Nil)
case Ident(_) | Select(_, _) =>
Expand Down
15 changes: 7 additions & 8 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -752,16 +752,15 @@ trait Checking {
isInfix(sym.owner.linkedClass)

tree.op match {
case _: untpd.BackquotedIdent =>
()
case Ident(name: Name) =>
case id @ Ident(name: Name) =>
name.toTermName match {
case name: SimpleName
if !name.exists(isOperatorPart) &&
!isInfix(meth) &&
!meth.maybeOwner.is(Scala2x) &&
!infixOKSinceFollowedBy(tree.right) &&
ctx.settings.strict.value =>
if !untpd.isBackquoted(id) &&
!name.exists(isOperatorPart) &&
!isInfix(meth) &&
!meth.maybeOwner.is(Scala2x) &&
!infixOKSinceFollowedBy(tree.right) &&
ctx.settings.strict.value =>
val (kind, alternative) =
if (ctx.mode.is(Mode.Type))
("type", (n: Name) => s"prefix syntax $n[...]")
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ trait TypeAssigner {
*/
def accessibleSelectionType(tree: untpd.RefTree, qual1: Tree)(implicit ctx: Context): Type = {
val ownType = selectionType(tree, qual1)
if (tree.getAttachment(desugar.SuppressAccessCheck).isDefined) ownType
if (tree.hasAttachment(desugar.SuppressAccessCheck)) ownType
else ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.sourcePos)
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2437,7 +2437,7 @@ class Typer extends Namer
}

def isSyntheticApply(tree: Tree): Boolean = tree match {
case tree: Select => tree.getAttachment(InsertedApply).isDefined
case tree: Select => tree.hasAttachment(InsertedApply)
case _ => false
}

Expand All @@ -2459,7 +2459,7 @@ class Typer extends Namer
else pt match {
case pt @ FunProto(Nil, _)
if tree.symbol.allOverriddenSymbols.exists(_.info.isNullaryMethod) &&
tree.getAttachment(DroppedEmptyArgs).isEmpty =>
!tree.hasAttachment(DroppedEmptyArgs) =>
tree.putAttachment(DroppedEmptyArgs, ())
pt.markAsDropped()
tree
Expand Down
10 changes: 9 additions & 1 deletion compiler/src/dotty/tools/dotc/util/Attachment.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ object Attachment {
else nx.getAttachment[V](key)
}

/** Does an attachment corresponding to `key` exist? */
final def hasAttachment[V](key: Key[V]): Boolean = {
val nx = next
if (nx == null) false
else if (nx.key eq key) true
else nx.hasAttachment[V](key)
}

/** The attachment corresponding to `key`.
* @throws NoSuchElementException if no attachment with key exists
*/
Expand Down Expand Up @@ -107,7 +115,7 @@ object Attachment {
}

final def pushAttachment[V](key: Key[V], value: V): Unit = {
assert(!getAttachment(key).isDefined, s"duplicate attachment for key $key")
assert(!hasAttachment(key), s"duplicate attachment for key $key")
next = new Link(key, value, next)
}

Expand Down
6 changes: 3 additions & 3 deletions compiler/test/dotty/tools/dotc/ast/AttachmentsTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ class AttachmentsTests extends DottyTest {

val copy = tpd.cpy.TypeDef(clazz)(rhs = tpd.EmptyTree)
assertTrue("A copy should have been returned", clazz ne copy)
assertTrue("Attachment should be present", copy.getAttachment(StickyTestKey).isDefined)
assertTrue("Attachment shouldn't be present", copy.getAttachment(TestKey).isEmpty)
assertTrue("Attachment should be present", copy.getAttachment(StickyTestKey2).isDefined)
assertTrue("Attachment should be present", copy.hasAttachment(StickyTestKey))
assertTrue("Attachment shouldn't be present", !copy.hasAttachment(TestKey))
assertTrue("Attachment should be present", copy.hasAttachment(StickyTestKey2))

case _ =>
fail
Expand Down