diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 0e577a5ac774..491d71e37dd0 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -10,7 +10,7 @@ import core._ import util.Spans._, Types._, Contexts._, Constants._, Names._, Flags._, NameOps._ import Symbols._, StdNames._, Annotations._, Trees._, Symbols._ import Decorators._, DenotTransformers._ -import collection.mutable +import collection.{immutable, mutable} import util.{Property, SourceFile, NoSource} import NameKinds.{TempResultName, OuterSelectName} import typer.ConstFold @@ -730,6 +730,25 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { if (from == to) tree else loop(from, Nil, to :: Nil) } + /** + * Set the owner of every definition in this tree which is not itself contained in this + * tree to be `newowner` + */ + def changeNonLocalOwners(newOwner: Symbol)(implicit ctx: Context): Tree = { + val ownerAcc = new TreeAccumulator[immutable.Set[Symbol]] { + def apply(ss: immutable.Set[Symbol], tree: Tree)(implicit ctx: Context) = tree match { + case tree: DefTree => + if (tree.symbol.exists) ss + tree.symbol.owner + else ss + case _ => + foldOver(ss, tree) + } + } + val owners = ownerAcc(immutable.Set.empty[Symbol], tree).toList + val newOwners = List.fill(owners.size)(newOwner) + new TreeTypeMap(oldOwners = owners, newOwners = newOwners).apply(tree) + } + /** After phase `trans`, set the owner of every definition in this tree that was formerly * owner by `from` to `to`. */ diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 85430730c76e..6bb41b258f91 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1577,7 +1577,7 @@ final class SearchRoot extends SearchHistory { val nrhss = rhss.map(rhsMap(_)) val vdefs = (nsyms zip nrhss) map { - case (nsym, nrhs) => ValDef(nsym.asTerm, nrhs) + case (nsym, nrhs) => ValDef(nsym.asTerm, nrhs.changeNonLocalOwners(nsym)) } val constr = ctx.newConstructor(classSym, Synthetic, Nil, Nil).entered diff --git a/tests/pos/i5766.scala b/tests/pos/i5766.scala new file mode 100644 index 000000000000..a33468e8a4fe --- /dev/null +++ b/tests/pos/i5766.scala @@ -0,0 +1,32 @@ +object Test1 { + trait Foo { def next: Foo } + + inline implicit def foo(implicit loop: => Foo): Foo = new Foo { def next = loop } + + def summon(implicit f: Foo) = () + summon +} + +object Test2 { + trait Foo { def next: Bar } + trait Bar { def next: Foo } + + implicit def foo(implicit loop: => Bar): Foo = new Foo { def next = loop } + inline implicit def bar(implicit loop: Foo): Bar = new Bar { def next = loop } + + def summon(implicit f: Foo) = () + summon +} + +object Test3 { + trait Foo { def next: Bar } + trait Bar { def next: Baz } + trait Baz { def next: Foo } + + implicit def foo(implicit loop: Bar): Foo = new Foo { def next = loop } + inline implicit def bar(implicit loop: Baz): Bar = new Bar { def next = loop } + inline implicit def baz(implicit loop: => Foo): Baz = new Baz { def next = loop } + + def summon(implicit f: Foo) = () + summon +}