Skip to content

Commit e9d3f48

Browse files
authored
Merge pull request #2962 from dotty-staging/fix-#2960
Fix #2960: Only allow one inserted apply per tree
2 parents c835586 + 0b0cbb3 commit e9d3f48

File tree

6 files changed

+95
-19
lines changed

6 files changed

+95
-19
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ object Erasure {
635635
super.typedStats(stats1, exprOwner).filter(!_.isEmpty)
636636
}
637637

638-
override def adapt(tree: Tree, pt: Type, original: untpd.Tree)(implicit ctx: Context): Tree =
638+
override def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
639639
ctx.traceIndented(i"adapting ${tree.showSummary}: ${tree.tpe} to $pt", show = true) {
640640
assert(ctx.phase == ctx.erasurePhase.next, ctx.phase)
641641
if (tree.isEmpty) tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ class TreeChecker extends Phase with SymTransformer {
436436
override def ensureNoLocalRefs(tree: Tree, pt: Type, localSyms: => List[Symbol])(implicit ctx: Context): Tree =
437437
tree
438438

439-
override def adapt(tree: Tree, pt: Type, original: untpd.Tree = untpd.EmptyTree)(implicit ctx: Context) = {
439+
override def adapt(tree: Tree, pt: Type)(implicit ctx: Context) = {
440440
def isPrimaryConstructorReturn =
441441
ctx.owner.isPrimaryConstructor && pt.isRef(ctx.owner.owner) && tree.tpe.isRef(defn.UnitClass)
442442
if (ctx.mode.isExpr &&

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
546546
init()
547547

548548
def addArg(arg: Tree, formal: Type): Unit =
549-
typedArgBuf += adaptInterpolated(arg, formal.widenExpr, EmptyTree)
549+
typedArgBuf += adaptInterpolated(arg, formal.widenExpr)
550550

551551
def makeVarArg(n: Int, elemFormal: Type): Unit = {
552552
val args = typedArgBuf.takeRight(n).toList
@@ -1477,7 +1477,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
14771477
def harmonize(trees: List[Tree])(implicit ctx: Context): List[Tree] = {
14781478
def adapt(tree: Tree, pt: Type): Tree = tree match {
14791479
case cdef: CaseDef => tpd.cpy.CaseDef(cdef)(body = adapt(cdef.body, pt))
1480-
case _ => adaptInterpolated(tree, pt, tree)
1480+
case _ => adaptInterpolated(tree, pt)
14811481
}
14821482
if (ctx.isAfterTyper) trees else harmonizeWith(trees)(_.tpe, adapt)
14831483
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ object ProtoTypes {
238238
*/
239239
def typedArg(arg: untpd.Tree, formal: Type)(implicit ctx: Context): Tree = {
240240
val targ = cacheTypedArg(arg, typer.typedUnadapted(_, formal))
241-
typer.adapt(targ, formal, arg)
241+
typer.adapt(targ, formal)
242242
}
243243

244244
/** The type of the argument `arg`.

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

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ object Typer {
6060
assert(tree.pos.exists, s"position not set for $tree # ${tree.uniqueId}")
6161

6262
private val ExprOwner = new Property.Key[Symbol]
63+
private val InsertedApply = new Property.Key[Unit]
6364
}
6465

6566
class Typer extends Namer with TypeAssigner with Applications with Implicits with Dynamic with Checking with Docstrings {
@@ -1706,7 +1707,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
17061707

17071708
def typed(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = /*>|>*/ ctx.traceIndented (i"typing $tree", typr, show = true) /*<|<*/ {
17081709
assertPositioned(tree)
1709-
try adapt(typedUnadapted(tree, pt), pt, tree)
1710+
try adapt(typedUnadapted(tree, pt), pt)
17101711
catch {
17111712
case ex: CyclicReference => errorTree(tree, cyclicErrorMsg(ex))
17121713
case ex: TypeError => errorTree(tree, ex.getMessage)
@@ -1818,9 +1819,17 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
18181819
*/
18191820
def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: => Tree)(implicit ctx: Context): Tree = {
18201821

1822+
def isSyntheticApply(tree: Tree): Boolean = tree match {
1823+
case tree: Select => tree.getAttachment(InsertedApply).isDefined
1824+
case Apply(fn, _) => fn.getAttachment(InsertedApply).isDefined
1825+
case _ => false
1826+
}
1827+
18211828
def tryApply(implicit ctx: Context) = {
18221829
val sel = typedSelect(untpd.Select(untpd.TypedSplice(tree), nme.apply), pt)
1823-
if (sel.tpe.isError) sel else adapt(sel, pt)
1830+
sel.pushAttachment(InsertedApply, ())
1831+
if (sel.tpe.isError) sel
1832+
else try adapt(sel, pt) finally sel.removeAttachment(InsertedApply)
18241833
}
18251834

18261835
def tryImplicit =
@@ -1832,7 +1841,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
18321841
pt.markAsDropped()
18331842
tree
18341843
case _ =>
1835-
if (isApplyProto(pt)) tryImplicit
1844+
if (isApplyProto(pt) || isSyntheticApply(tree)) tryImplicit
18361845
else tryEither(tryApply(_))((_, _) => tryImplicit)
18371846
}
18381847
}
@@ -1845,7 +1854,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
18451854
case Select(qual, name) =>
18461855
val qualProto = SelectionProto(name, pt, NoViewsAllowed, privateOK = false)
18471856
tryEither { implicit ctx =>
1848-
val qual1 = adaptInterpolated(qual, qualProto, EmptyTree)
1857+
val qual1 = adaptInterpolated(qual, qualProto)
18491858
if ((qual eq qual1) || ctx.reporter.hasErrors) None
18501859
else Some(typed(cpy.Select(tree)(untpd.TypedSplice(qual1), name), pt))
18511860
} { (_, _) => None
@@ -1854,12 +1863,12 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
18541863
}
18551864
}
18561865

1857-
def adapt(tree: Tree, pt: Type, original: untpd.Tree = untpd.EmptyTree)(implicit ctx: Context): Tree = /*>|>*/ track("adapt") /*<|<*/ {
1866+
def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree = /*>|>*/ track("adapt") /*<|<*/ {
18581867
/*>|>*/ ctx.traceIndented(i"adapting $tree of type ${tree.tpe} to $pt", typr, show = true) /*<|<*/ {
18591868
if (tree.isDef) interpolateUndetVars(tree, tree.symbol)
18601869
else if (!tree.tpe.widen.isInstanceOf[LambdaType]) interpolateUndetVars(tree, NoSymbol)
18611870
tree.overwriteType(tree.tpe.simplified)
1862-
adaptInterpolated(tree, pt, original)
1871+
adaptInterpolated(tree, pt)
18631872
}
18641873
}
18651874

@@ -1901,7 +1910,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
19011910
* (14) When in mode EXPRmode, apply a view
19021911
* If all this fails, error
19031912
*/
1904-
def adaptInterpolated(tree: Tree, pt: Type, original: untpd.Tree)(implicit ctx: Context): Tree = {
1913+
def adaptInterpolated(tree: Tree, pt: Type)(implicit ctx: Context): Tree = {
19051914

19061915
assert(pt.exists)
19071916

@@ -1919,7 +1928,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
19191928
TermRef.withSigAndDenot(ref.prefix, ref.name, alt.info.signature, alt))
19201929
resolveOverloaded(alts, pt) match {
19211930
case alt :: Nil =>
1922-
adapt(tree.withType(alt), pt, original)
1931+
adapt(tree.withType(alt), pt)
19231932
case Nil =>
19241933
def noMatches =
19251934
errorTree(tree,
@@ -1956,7 +1965,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
19561965
def adaptToArgs(wtp: Type, pt: FunProto): Tree = wtp match {
19571966
case _: MethodOrPoly =>
19581967
if (pt.args.lengthCompare(1) > 0 && isUnary(wtp) && ctx.canAutoTuple)
1959-
adaptInterpolated(tree, pt.tupled, original)
1968+
adaptInterpolated(tree, pt.tupled)
19601969
else
19611970
tree
19621971
case _ => tryInsertApplyOrImplicit(tree, pt) {
@@ -1992,7 +2001,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
19922001

19932002
def adaptNoArgs(wtp: Type): Tree = wtp match {
19942003
case wtp: ExprType =>
1995-
adaptInterpolated(tree.withType(wtp.resultType), pt, original)
2004+
adaptInterpolated(tree.withType(wtp.resultType), pt)
19962005
case wtp: ImplicitMethodType if constrainResult(wtp, followAlias(pt)) =>
19972006
val tvarsToInstantiate = tvarsInParams(tree)
19982007
wtp.paramInfos.foreach(instantiateSelected(_, tvarsToInstantiate))
@@ -2108,7 +2117,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
21082117
!(isSyntheticApply(tree) && !isExpandableApply))
21092118
typed(etaExpand(tree, wtp, arity), pt)
21102119
else if (wtp.paramInfos.isEmpty && isAutoApplied(tree.symbol))
2111-
adaptInterpolated(tpd.Apply(tree, Nil), pt, EmptyTree)
2120+
adaptInterpolated(tpd.Apply(tree, Nil), pt)
21122121
else if (wtp.isImplicit)
21132122
err.typeMismatch(tree, pt)
21142123
else
@@ -2212,7 +2221,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
22122221
val prevConstraint = ctx.typerState.constraint
22132222
if (pt.isInstanceOf[ProtoType] && !failure.isInstanceOf[AmbiguousImplicits]) tree
22142223
else if (isFullyDefined(wtp, force = ForceDegree.all) &&
2215-
ctx.typerState.constraint.ne(prevConstraint)) adapt(tree, pt, original)
2224+
ctx.typerState.constraint.ne(prevConstraint)) adapt(tree, pt)
22162225
else err.typeMismatch(tree, pt, failure)
22172226
}
22182227
}
@@ -2249,7 +2258,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
22492258
pt match {
22502259
case pt: FunProto
22512260
if pt.args.lengthCompare(1) > 0 && isUnary(ref) && ctx.canAutoTuple =>
2252-
adaptInterpolated(tree, pt.tupled, original)
2261+
adaptInterpolated(tree, pt.tupled)
22532262
case _ =>
22542263
adaptOverloaded(ref)
22552264
}
@@ -2262,7 +2271,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
22622271
}
22632272
if (typeArgs.isEmpty) typeArgs = constrained(poly, tree)._2
22642273
convertNewGenericArray(
2265-
adaptInterpolated(tree.appliedToTypeTrees(typeArgs), pt, original))
2274+
adaptInterpolated(tree.appliedToTypeTrees(typeArgs), pt))
22662275
}
22672276
case wtp =>
22682277
if (isStructuralTermSelect(tree)) adapt(handleStructural(tree), pt)

tests/neg/i2960.scala

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package org.glavo.dotty {
2+
3+
import scala.collection.mutable
4+
5+
sealed trait Node {
6+
def mkString(n: Int): String
7+
}
8+
9+
class Tag(val name: String,
10+
val attributes: mutable.LinkedHashMap[Symbol, String] = mutable.LinkedHashMap(),
11+
val children: mutable.Buffer[Node] = mutable.Buffer()) extends Node {
12+
13+
override def mkString(n: Int): String = {
14+
Tag.spaces(n) + s"<$name ${attributes.map(_.name + "=" + Tag.unescape(_)).mkString(" ")}>" +
15+
(if(children.isEmpty) "\n"
16+
else children.map(_.mkString(n + 4)).mkString("\n", "\n", "\n")) +
17+
Tag.spaces(n) + s"</$name>"
18+
}
19+
20+
def apply(attrs: (Symbol, String)*): this.type = {
21+
attributes ++= attrs
22+
this
23+
}
24+
25+
def apply[U](f: implicit Tag => U)(implicit t: Tag = null): this.type = {
26+
if(t != null) t.children += this
27+
f(this)
28+
this
29+
}
30+
}
31+
32+
object Tag {
33+
def spaces(n: Int = 0): String = {
34+
if(n == 0) ""
35+
else {
36+
val cs = new Array[Char](n)
37+
for (i <- 0 until n)
38+
cs(i) = 0
39+
40+
new String(cs)
41+
}
42+
}
43+
44+
def unescape(str: String): String = {
45+
"\"" + str + "\""
46+
}
47+
48+
implicit def symbolToTag(symbol: Symbol): Tag =
49+
new Tag(symbol.name)
50+
51+
implicit class PairMaker(val tag: Symbol) extends AnyVal {
52+
def :=(value: String): (Symbol, String) = (tag, value)
53+
}
54+
}
55+
56+
class Text(val value: String) extends Node {
57+
override def mkString(n: Int): String = {
58+
Tag.spaces(n) + value
59+
}
60+
}
61+
}
62+
63+
object Test {
64+
import org.glavo.dotty._
65+
import org.glavo.dotty.Tag._
66+
'html{} // error
67+
}

0 commit comments

Comments
 (0)