Skip to content

Commit 42c422b

Browse files
authored
Merge pull request #6755 from dotty-staging/drop-backquoted
Use attachment to tag backquoted trees
2 parents 5eb667f + 94a90cd commit 42c422b

File tree

15 files changed

+55
-85
lines changed

15 files changed

+55
-85
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ object desugar {
310310
* ```
311311
*/
312312
def transformQuotedPatternName(tree: ValOrDefDef)(implicit ctx: Context): ValOrDefDef = {
313-
if (ctx.mode.is(Mode.QuotedPattern) && !tree.isBackquoted && tree.name != nme.ANON_FUN && tree.name.startsWith("$")) {
313+
if (ctx.mode.is(Mode.QuotedPattern) && !isBackquoted(tree) && tree.name != nme.ANON_FUN && tree.name.startsWith("$")) {
314314
val mods = tree.mods.withAddedAnnotation(New(ref(defn.InternalQuoted_patternBindHoleAnnot.typeRef)).withSpan(tree.span))
315315
tree.withMods(mods)
316316
} else tree
@@ -1478,7 +1478,7 @@ object desugar {
14781478
// This is a deliberate departure from scalac, where StringContext is not rooted (See #4732)
14791479
Apply(Select(Apply(scalaDot(nme.StringContext), strs), id), elems)
14801480
case PostfixOp(t, op) =>
1481-
if ((ctx.mode is Mode.Type) && !op.isBackquoted && op.name == tpnme.raw.STAR) {
1481+
if ((ctx.mode is Mode.Type) && !isBackquoted(op) && op.name == tpnme.raw.STAR) {
14821482
val seqType = if (ctx.compilationUnit.isJava) defn.ArrayType else defn.SeqType
14831483
Annotated(
14841484
AppliedTypeTree(ref(seqType), t),

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,12 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
140140
case _ => false
141141
}
142142

143+
/** Is tree a backquoted identifier or definition */
144+
def isBackquoted(tree: Tree): Boolean = tree.hasAttachment(Backquoted)
145+
143146
/** Is tree a variable pattern? */
144147
def isVarPattern(pat: Tree): Boolean = unsplice(pat) match {
145-
case x: BackquotedIdent => false
146-
case x: Ident => x.name.isVariableName
148+
case x: Ident => x.name.isVariableName && !isBackquoted(x)
147149
case _ => false
148150
}
149151

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import dotty.tools.dotc.core.TypeError
99
import scala.annotation.tailrec
1010

1111
/** A TreeMap that maintains the necessary infrastructure to support
12-
* contxtual implicit searches (type-scope implicits are supported anyway).
12+
* contextual implicit searches (type-scope implicits are supported anyway).
1313
*
14-
* This incudes impicits defined in scope as well as imported implicits.
14+
* This incudes implicits defined in scope as well as imported implicits.
1515
*/
1616
class TreeMapWithImplicits extends tpd.TreeMap {
1717
import tpd._

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

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ object Trees {
3131
@sharable var ntrees: Int = 0
3232

3333
/** Property key for trees with documentation strings attached */
34-
val DocComment: Property.StickyKey[Comments.Comment] = new Property.StickyKey
34+
val DocComment: Property.StickyKey[Comments.Comment] = Property.StickyKey()
35+
36+
/** Property key for backquoted identifiers and definitions */
37+
val Backquoted: Property.StickyKey[Unit] = Property.StickyKey()
3538

3639
/** Trees take a parameter indicating what the type of their `tpe` field
3740
* is. Two choices: `Type` or `Untyped`.
@@ -363,9 +366,6 @@ object Trees {
363366
def tpt: Tree[T]
364367
def unforcedRhs: LazyTree[T] = unforced
365368
def rhs(implicit ctx: Context): Tree[T] = forceIfLazy
366-
367-
/** Is this a `BackquotedValDef` or `BackquotedDefDef` ? */
368-
def isBackquoted: Boolean = false
369369
}
370370

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

379-
/** Is this a `BackquotedIdent` ? */
380-
def isBackquoted: Boolean = false
381-
}
382-
383-
class BackquotedIdent[-T >: Untyped]private[ast] (name: Name)(implicit @constructorOnly src: SourceFile)
384-
extends Ident[T](name) {
385-
override def isBackquoted: Boolean = true
386-
387-
override def toString: String = s"BackquotedIdent($name)"
379+
def isBackquoted: Boolean = hasAttachment(Backquoted)
388380
}
389381

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

440-
def isGivenApply = getAttachment(untpd.ApplyGiven).nonEmpty
432+
def isGivenApply = hasAttachment(untpd.ApplyGiven)
441433
def setGivenApply() = { pushAttachment(untpd.ApplyGiven, ()); this }
442434
}
443435

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

738-
class BackquotedValDef[-T >: Untyped] private[ast] (name: TermName, tpt: Tree[T], preRhs: LazyTree[T @uncheckedVariance])(implicit @constructorOnly src: SourceFile)
739-
extends ValDef[T](name, tpt, preRhs) {
740-
override def isBackquoted: Boolean = true
741-
override def productPrefix: String = "BackquotedValDef"
742-
}
743-
744730
/** mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs */
745731
case class DefDef[-T >: Untyped] private[ast] (name: TermName, tparams: List[TypeDef[T]],
746732
vparamss: List[List[ValDef[T]]], tpt: Tree[T], private var preRhs: LazyTree[T @uncheckedVariance])(implicit @constructorOnly src: SourceFile)
@@ -755,13 +741,6 @@ object Trees {
755741
// their for clause, but the two appear swapped in the DefDef.
756742
}
757743

758-
class BackquotedDefDef[-T >: Untyped] private[ast] (name: TermName, tparams: List[TypeDef[T]],
759-
vparamss: List[List[ValDef[T]]], tpt: Tree[T], preRhs: LazyTree[T])(implicit @constructorOnly src: SourceFile)
760-
extends DefDef[T](name, tparams, vparamss, tpt, preRhs) {
761-
override def isBackquoted: Boolean = true
762-
override def productPrefix: String = "BackquotedDefDef"
763-
}
764-
765744
/** mods class name template or
766745
* mods trait name template or
767746
* mods type name = rhs or
@@ -947,7 +926,6 @@ object Trees {
947926
type LazyTreeList = Trees.LazyTreeList[T]
948927

949928
type Ident = Trees.Ident[T]
950-
type BackquotedIdent = Trees.BackquotedIdent[T]
951929
type SearchFailureIdent = Trees.SearchFailureIdent[T]
952930
type Select = Trees.Select[T]
953931
type SelectWithSig = Trees.SelectWithSig[T]
@@ -986,9 +964,7 @@ object Trees {
986964
type Alternative = Trees.Alternative[T]
987965
type UnApply = Trees.UnApply[T]
988966
type ValDef = Trees.ValDef[T]
989-
type BackquotedValDef = Trees.BackquotedValDef[T]
990967
type DefDef = Trees.DefDef[T]
991-
type BackquotedDefDef = Trees.BackquotedDefDef[T]
992968
type TypeDef = Trees.TypeDef[T]
993969
type Template = Trees.Template[T]
994970
type Import = Trees.Import[T]
@@ -1036,9 +1012,6 @@ object Trees {
10361012
postProcess(tree, copied.withSpan(tree.span).withAttachmentsFrom(tree))
10371013

10381014
def Ident(tree: Tree)(name: Name)(implicit ctx: Context): Ident = tree match {
1039-
case tree: BackquotedIdent =>
1040-
if (name == tree.name) tree
1041-
else finalize(tree, new BackquotedIdent(name)(sourceFile(tree)))
10421015
case tree: Ident if name == tree.name => tree
10431016
case _ => finalize(tree, untpd.Ident(name)(sourceFile(tree)))
10441017
}
@@ -1181,16 +1154,10 @@ object Trees {
11811154
case _ => finalize(tree, untpd.UnApply(fun, implicits, patterns)(sourceFile(tree)))
11821155
}
11831156
def ValDef(tree: Tree)(name: TermName, tpt: Tree, rhs: LazyTree)(implicit ctx: Context): ValDef = tree match {
1184-
case tree: BackquotedValDef =>
1185-
if ((name == tree.name) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs)) tree
1186-
else finalize(tree, untpd.BackquotedValDef(name, tpt, rhs)(sourceFile(tree)))
11871157
case tree: ValDef if (name == tree.name) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree
11881158
case _ => finalize(tree, untpd.ValDef(name, tpt, rhs)(sourceFile(tree)))
11891159
}
11901160
def DefDef(tree: Tree)(name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: LazyTree)(implicit ctx: Context): DefDef = tree match {
1191-
case tree: BackquotedDefDef =>
1192-
if ((name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs)) tree
1193-
else finalize(tree, untpd.BackquotedDefDef(name, tparams, vparamss, tpt, rhs)(sourceFile(tree)))
11941161
case tree: DefDef if (name == tree.name) && (tparams eq tree.tparams) && (vparamss eq tree.vparamss) && (tpt eq tree.tpt) && (rhs eq tree.unforcedRhs) => tree
11951162
case _ => finalize(tree, untpd.DefDef(name, tparams, vparamss, tpt, rhs)(sourceFile(tree)))
11961163
}

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

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
299299
// ------ Creation methods for untyped only -----------------
300300

301301
def Ident(name: Name)(implicit src: SourceFile): Ident = new Ident(name)
302-
def BackquotedIdent(name: Name)(implicit src: SourceFile): BackquotedIdent = new BackquotedIdent(name)
303302
def SearchFailureIdent(name: Name)(implicit src: SourceFile): SearchFailureIdent = new SearchFailureIdent(name)
304303
def Select(qualifier: Tree, name: Name)(implicit src: SourceFile): Select = new Select(qualifier, name)
305304
def SelectWithSig(qualifier: Tree, name: Name, sig: Signature)(implicit src: SourceFile): Select = new SelectWithSig(qualifier, name, sig)
@@ -338,9 +337,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
338337
def Alternative(trees: List[Tree])(implicit src: SourceFile): Alternative = new Alternative(trees)
339338
def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree])(implicit src: SourceFile): UnApply = new UnApply(fun, implicits, patterns)
340339
def ValDef(name: TermName, tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): ValDef = new ValDef(name, tpt, rhs)
341-
def BackquotedValDef(name: TermName, tpt: Tree, rhs: LazyTree)(implicit src: SourceFile): ValDef = new BackquotedValDef(name, tpt, rhs)
342340
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)
343-
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)
344341
def TypeDef(name: TypeName, rhs: Tree)(implicit src: SourceFile): TypeDef = new TypeDef(name, rhs)
345342
def Template(constr: DefDef, parents: List[Tree], derived: List[Tree], self: ValDef, body: LazyTreeList)(implicit src: SourceFile): Template =
346343
if (derived.isEmpty) new Template(constr, parents, self, body)
@@ -431,9 +428,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
431428
AppliedTypeTree(ref(defn.andType.typeRef), left :: right :: Nil)
432429

433430
def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers = EmptyModifiers, isBackquoted: Boolean = false)(implicit ctx: Context): ValDef = {
434-
val vdef =
435-
if (isBackquoted) BackquotedValDef(pname, tpe, EmptyTree)
436-
else ValDef(pname, tpe, EmptyTree)
431+
val vdef = ValDef(pname, tpe, EmptyTree)
432+
if (isBackquoted) vdef.pushAttachment(Backquoted, ())
437433
vdef.withMods(mods | Param)
438434
}
439435

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -408,9 +408,9 @@ object Parsers {
408408
*/
409409
def convertToParam(tree: Tree, expected: String = "formal parameter"): ValDef = tree match {
410410
case id @ Ident(name) =>
411-
makeParameter(name.asTermName, TypeTree(), isBackquoted = id.isBackquoted).withSpan(tree.span)
411+
makeParameter(name.asTermName, TypeTree(), isBackquoted = isBackquoted(id)).withSpan(tree.span)
412412
case Typed(id @ Ident(name), tpt) =>
413-
makeParameter(name.asTermName, tpt, isBackquoted = id.isBackquoted).withSpan(tree.span)
413+
makeParameter(name.asTermName, tpt, isBackquoted = isBackquoted(id)).withSpan(tree.span)
414414
case Typed(Splice(Ident(name)), tpt) =>
415415
makeParameter(("$" + name).toTermName, tpt).withSpan(tree.span)
416416
case _ =>
@@ -628,9 +628,8 @@ object Parsers {
628628
makeIdent(in.token, in.offset, ident().toTypeName)
629629

630630
private def makeIdent(tok: Token, offset: Offset, name: Name) = {
631-
val tree =
632-
if (tok == BACKQUOTED_IDENT) BackquotedIdent(name)
633-
else Ident(name)
631+
val tree = Ident(name)
632+
if (tok == BACKQUOTED_IDENT) tree.pushAttachment(Backquoted, ())
634633

635634
// Make sure that even trees with parsing errors have a offset that is within the offset
636635
val errorOffset = offset min (in.lastOffset - 1)
@@ -2526,10 +2525,10 @@ object Parsers {
25262525
}
25272526
} else EmptyTree
25282527
lhs match {
2529-
case (id: BackquotedIdent) :: Nil if id.name.isTermName =>
2530-
finalizeDef(BackquotedValDef(id.name.asTermName, tpt, rhs), mods, start)
2531-
case Ident(name: TermName) :: Nil =>
2532-
finalizeDef(ValDef(name, tpt, rhs), mods, start)
2528+
case (id @ Ident(name: TermName)) :: Nil =>
2529+
val vdef = ValDef(name, tpt, rhs)
2530+
if (isBackquoted(id)) vdef.pushAttachment(Backquoted, ())
2531+
finalizeDef(vdef, mods, start)
25332532
case _ =>
25342533
PatDef(mods, lhs, tpt, rhs)
25352534
}
@@ -2606,8 +2605,9 @@ object Parsers {
26062605
expr()
26072606
}
26082607

2609-
if (ident.isBackquoted) finalizeDef(BackquotedDefDef(ident.name.asTermName, tparams, vparamss, tpt, rhs), mods1, start)
2610-
else finalizeDef(DefDef(ident.name.asTermName, tparams, vparamss, tpt, rhs), mods1, start)
2608+
val ddef = DefDef(ident.name.asTermName, tparams, vparamss, tpt, rhs)
2609+
if (isBackquoted(ident)) ddef.pushAttachment(Backquoted, ())
2610+
finalizeDef(ddef, mods1, start)
26112611
}
26122612
}
26132613

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,24 +334,23 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
334334
}
335335

336336
tree match {
337-
case id: Trees.BackquotedIdent[_] if !homogenizedView =>
338-
"`" ~ toText(id.name) ~ "`"
339337
case id: Trees.SearchFailureIdent[_] =>
340338
tree.typeOpt match {
341339
case reason: Implicits.SearchFailureType =>
342340
toText(id.name) ~ "implicitly[" ~ toText(reason.clarify(reason.expectedType)) ~ "]"
343341
case _ =>
344342
toText(id.name)
345343
}
346-
case Ident(name) =>
344+
case id @ Ident(name) =>
347345
val txt = tree.typeOpt match {
348346
case tp: NamedType if name != nme.WILDCARD =>
349347
val pre = if (tp.symbol.is(JavaStatic)) tp.prefix.widen else tp.prefix
350348
toTextPrefix(pre) ~ withPos(selectionString(tp), tree.sourcePos)
351349
case _ =>
352350
toText(name)
353351
}
354-
if (name.isTypeName) typeText(txt)
352+
if (isBackquoted(tree) && !homogenizedView) "`" ~ toText(name) ~ "`"
353+
else if (name.isTypeName) typeText(txt)
355354
else txt
356355
case tree @ Select(qual, name) =>
357356
if (!printDebug && tree.hasType && tree.symbol == defn.QuotedType_splice) typeText("${") ~ toTextLocal(qual) ~ typeText("}")

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,7 @@ object PatternMatcher {
188188
case Typed(_, tpt) if tpt.tpe.isRepeatedParam => true
189189
case Bind(nme.WILDCARD, WildcardPattern()) => true // don't skip when binding an interesting symbol!
190190
case t if isWildcardArg(t) => true
191-
case x: BackquotedIdent => false
192-
case x: Ident => x.name.isVariableName
191+
case x: Ident => x.name.isVariableName && !isBackquoted(x)
193192
case Alternative(ps) => ps.forall(unapply)
194193
case EmptyTree => true
195194
case _ => false

compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ object TypeTestsCasts {
298298

299299
if (sym.isTypeTest) {
300300
val argType = tree.args.head.tpe
301-
val isTrusted = tree.getAttachment(PatternMatcher.TrustedTypeTestKey).nonEmpty
301+
val isTrusted = tree.hasAttachment(PatternMatcher.TrustedTypeTestKey)
302302
if (!isTrusted && !checkable(expr.tpe, argType, tree.span))
303303
ctx.warning(i"the type test for $argType cannot be checked at runtime", tree.sourcePos)
304304
transformTypeTest(expr, tree.args.head.tpe, flagUnrelated = true)

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
330330
Typ(c.value.asInstanceOf[Symbol].termRef, false)
331331
else
332332
Typ(ConstantType(c), false)
333-
case _: BackquotedIdent => Typ(pat.tpe, false)
333+
case pat: Ident if isBackquoted(pat) => Typ(pat.tpe, false)
334334
case Ident(nme.WILDCARD) =>
335335
Or(Typ(pat.tpe.stripAnnots, false) :: nullSpace :: Nil)
336336
case Ident(_) | Select(_, _) =>

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -752,16 +752,15 @@ trait Checking {
752752
isInfix(sym.owner.linkedClass)
753753

754754
tree.op match {
755-
case _: untpd.BackquotedIdent =>
756-
()
757-
case Ident(name: Name) =>
755+
case id @ Ident(name: Name) =>
758756
name.toTermName match {
759757
case name: SimpleName
760-
if !name.exists(isOperatorPart) &&
761-
!isInfix(meth) &&
762-
!meth.maybeOwner.is(Scala2x) &&
763-
!infixOKSinceFollowedBy(tree.right) &&
764-
ctx.settings.strict.value =>
758+
if !untpd.isBackquoted(id) &&
759+
!name.exists(isOperatorPart) &&
760+
!isInfix(meth) &&
761+
!meth.maybeOwner.is(Scala2x) &&
762+
!infixOKSinceFollowedBy(tree.right) &&
763+
ctx.settings.strict.value =>
765764
val (kind, alternative) =
766765
if (ctx.mode.is(Mode.Type))
767766
("type", (n: Name) => s"prefix syntax $n[...]")

compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ trait TypeAssigner {
282282
*/
283283
def accessibleSelectionType(tree: untpd.RefTree, qual1: Tree)(implicit ctx: Context): Type = {
284284
val ownType = selectionType(tree, qual1)
285-
if (tree.getAttachment(desugar.SuppressAccessCheck).isDefined) ownType
285+
if (tree.hasAttachment(desugar.SuppressAccessCheck)) ownType
286286
else ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.sourcePos)
287287
}
288288

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2437,7 +2437,7 @@ class Typer extends Namer
24372437
}
24382438

24392439
def isSyntheticApply(tree: Tree): Boolean = tree match {
2440-
case tree: Select => tree.getAttachment(InsertedApply).isDefined
2440+
case tree: Select => tree.hasAttachment(InsertedApply)
24412441
case _ => false
24422442
}
24432443

@@ -2459,7 +2459,7 @@ class Typer extends Namer
24592459
else pt match {
24602460
case pt @ FunProto(Nil, _)
24612461
if tree.symbol.allOverriddenSymbols.exists(_.info.isNullaryMethod) &&
2462-
tree.getAttachment(DroppedEmptyArgs).isEmpty =>
2462+
!tree.hasAttachment(DroppedEmptyArgs) =>
24632463
tree.putAttachment(DroppedEmptyArgs, ())
24642464
pt.markAsDropped()
24652465
tree

compiler/src/dotty/tools/dotc/util/Attachment.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ object Attachment {
2323
else nx.getAttachment[V](key)
2424
}
2525

26+
/** Does an attachment corresponding to `key` exist? */
27+
final def hasAttachment[V](key: Key[V]): Boolean = {
28+
val nx = next
29+
if (nx == null) false
30+
else if (nx.key eq key) true
31+
else nx.hasAttachment[V](key)
32+
}
33+
2634
/** The attachment corresponding to `key`.
2735
* @throws NoSuchElementException if no attachment with key exists
2836
*/
@@ -107,7 +115,7 @@ object Attachment {
107115
}
108116

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

compiler/test/dotty/tools/dotc/ast/AttachmentsTest.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ class AttachmentsTests extends DottyTest {
5151

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

5858
case _ =>
5959
fail

0 commit comments

Comments
 (0)