Skip to content

Commit 58a36f2

Browse files
Merge pull request #6404 from milessabin/topic/inline-separate
Fix interaction between by-name implicits and inlining
2 parents 72c84f7 + def5246 commit 58a36f2

File tree

4 files changed

+62
-50
lines changed

4 files changed

+62
-50
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,7 +1620,7 @@ final class SearchRoot extends SearchHistory {
16201620
// Substitute dictionary references into dictionary entry RHSs
16211621
val rhsMap = new TreeTypeMap(treeMap = {
16221622
case id: Ident if vsymMap.contains(id.symbol) =>
1623-
tpd.ref(vsymMap(id.symbol)).withSpan(id.span)
1623+
tpd.ref(vsymMap(id.symbol))
16241624
case tree => tree
16251625
})
16261626
val nrhss = rhss.map(rhsMap(_))
@@ -1644,7 +1644,7 @@ final class SearchRoot extends SearchHistory {
16441644

16451645
val res = resMap(tree)
16461646

1647-
val blk = Block(classDef :: inst :: Nil, res)
1647+
val blk = Inliner.reposition(Block(classDef :: inst :: Nil, res), span)
16481648

16491649
success.copy(tree = blk)(success.tstate, success.gstate)
16501650
}

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

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -119,60 +119,60 @@ object Inliner {
119119
}
120120

121121
/** Replace `Inlined` node by a block that contains its bindings and expansion */
122-
def dropInlined(inlined: Inlined)(implicit ctx: Context): Tree = {
122+
def dropInlined(inlined: Inlined)(implicit ctx: Context): Tree =
123123
if (enclosingInlineds.nonEmpty) inlined // Remove in the outer most inlined call
124-
else {
125-
val inlinedAtSpan = inlined.call.span
126-
val curSource = ctx.compilationUnit.source
127-
128-
// Tree copier that changes the source of all trees to `curSource`
129-
val cpyWithNewSource = new TypedTreeCopier {
130-
override protected def sourceFile(tree: tpd.Tree): SourceFile = curSource
131-
override protected val untpdCpy: untpd.UntypedTreeCopier = new untpd.UntypedTreeCopier {
132-
override protected def sourceFile(tree: untpd.Tree): SourceFile = curSource
133-
}
134-
}
124+
else reposition(inlined, inlined.call.span)
135125

136-
/** Removes all Inlined trees, replacing them with blocks.
137-
* Repositions all trees directly inside an inlined expansion of a non empty call to the position of the call.
138-
* Any tree directly inside an empty call (inlined in the inlined code) retains their position.
139-
*/
140-
class Reposition extends TreeMap(cpyWithNewSource) {
141-
def finalize(tree: Tree, copied: untpd.Tree) =
142-
copied.withSpan(tree.span).withAttachmentsFrom(tree).withTypeUnchecked(tree.tpe)
143-
144-
def reposition(tree: Tree)(implicit ctx: Context): Tree = enclosingInlineds match {
145-
case call :: _ if call.symbol.source != curSource =>
146-
tree match {
147-
case _: EmptyTree[_] | _: EmptyValDef[_] => tree
148-
case _ =>
149-
// Until we implement JSR-45, we cannot represent in output positions in other source files.
150-
// So, reposition inlined code from other files with the call position:
151-
tree.withSpan(inlinedAtSpan)
152-
}
153-
case _ => tree
154-
}
126+
def reposition(tree: Tree, span: Span)(implicit ctx: Context): Tree = {
127+
val curSource = ctx.compilationUnit.source
155128

156-
override def transform(tree: Tree)(implicit ctx: Context): Tree = {
157-
val transformed = reposition(tree match {
158-
case tree: Inlined =>
159-
tpd.seq(transformSub(tree.bindings), transform(tree.expansion)(inlineContext(tree.call)))(ctx.withSource(curSource)) : Tree
160-
case tree: Ident => finalize(tree, untpd.Ident(tree.name)(curSource))
161-
case tree: Literal => finalize(tree, untpd.Literal(tree.const)(curSource))
162-
case tree: This => finalize(tree, untpd.This(tree.qual)(curSource))
163-
case tree: JavaSeqLiteral => finalize(tree, untpd.JavaSeqLiteral(transform(tree.elems), transform(tree.elemtpt))(curSource))
164-
case tree: SeqLiteral => finalize(tree, untpd.SeqLiteral(transform(tree.elems), transform(tree.elemtpt))(curSource))
165-
case tree: TypeTree => tpd.TypeTree(tree.tpe)(ctx.withSource(curSource)).withSpan(tree.span)
166-
case tree: Bind => finalize(tree, untpd.Bind(tree.name, transform(tree.body))(curSource))
167-
case _ => super.transform(tree)
168-
})
169-
assert(transformed.isInstanceOf[EmptyTree[_]] || transformed.isInstanceOf[EmptyValDef[_]] || transformed.source == curSource)
170-
transformed
171-
}
129+
// Tree copier that changes the source of all trees to `curSource`
130+
val cpyWithNewSource = new TypedTreeCopier {
131+
override protected def sourceFile(tree: tpd.Tree): SourceFile = curSource
132+
override protected val untpdCpy: untpd.UntypedTreeCopier = new untpd.UntypedTreeCopier {
133+
override protected def sourceFile(tree: untpd.Tree): SourceFile = curSource
172134
}
135+
}
173136

174-
(new Reposition).transform(inlined)
137+
/** Removes all Inlined trees, replacing them with blocks.
138+
* Repositions all trees directly inside an inlined expansion of a non empty call to the position of the call.
139+
* Any tree directly inside an empty call (inlined in the inlined code) retains their position.
140+
*/
141+
class Reposition extends TreeMap(cpyWithNewSource) {
142+
def finalize(tree: Tree, copied: untpd.Tree) =
143+
copied.withSpan(tree.span).withAttachmentsFrom(tree).withTypeUnchecked(tree.tpe)
144+
145+
def reposition(tree: Tree)(implicit ctx: Context): Tree = enclosingInlineds match {
146+
case call :: _ if call.symbol.source != curSource =>
147+
tree match {
148+
case _: EmptyTree[_] | _: EmptyValDef[_] => tree
149+
case _ =>
150+
// Until we implement JSR-45, we cannot represent in output positions in other source files.
151+
// So, reposition inlined code from other files with the call position:
152+
tree.withSpan(span)
153+
}
154+
case _ => tree
155+
}
156+
157+
override def transform(tree: Tree)(implicit ctx: Context): Tree = {
158+
val transformed = reposition(tree match {
159+
case tree: Inlined =>
160+
tpd.seq(transformSub(tree.bindings), transform(tree.expansion)(inlineContext(tree.call)))(ctx.withSource(curSource)) : Tree
161+
case tree: Ident => finalize(tree, untpd.Ident(tree.name)(curSource))
162+
case tree: Literal => finalize(tree, untpd.Literal(tree.const)(curSource))
163+
case tree: This => finalize(tree, untpd.This(tree.qual)(curSource))
164+
case tree: JavaSeqLiteral => finalize(tree, untpd.JavaSeqLiteral(transform(tree.elems), transform(tree.elemtpt))(curSource))
165+
case tree: SeqLiteral => finalize(tree, untpd.SeqLiteral(transform(tree.elems), transform(tree.elemtpt))(curSource))
166+
case tree: TypeTree => tpd.TypeTree(tree.tpe)(ctx.withSource(curSource)).withSpan(tree.span)
167+
case tree: Bind => finalize(tree, untpd.Bind(tree.name, transform(tree.body))(curSource))
168+
case _ => super.transform(tree)
169+
})
170+
assert(transformed.isInstanceOf[EmptyTree[_]] || transformed.isInstanceOf[EmptyValDef[_]] || transformed.source == curSource)
171+
transformed
172+
}
175173
}
174+
175+
(new Reposition).transform(tree)
176176
}
177177

178178
/** Leave only a call trace consisting of

tests/pos/inline-separate/A_1.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object A {
2+
inline def summon[T] = implicit match {
3+
case t: T => t
4+
}
5+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import A._
2+
object Test extends App {
3+
class Foo(f: => Foo)
4+
inline implicit def foo(implicit f: => Foo): Foo = new Foo(summon[Foo])
5+
def summonFoo(implicit ev: Foo): Foo = ev
6+
summonFoo
7+
}

0 commit comments

Comments
 (0)