From 8ab5f002cc4bf1059f8f4241350ae7206d65f221 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Fri, 26 Feb 2021 23:11:41 +0100 Subject: [PATCH] Handle symbol.defTree properly for nested definitions in bindings Nested definitions in inlining bindings will get new symbols in `changeOwner`. The field `Symbol.defTree` is never set for those symbols. The problem is exhibited in the following test tests/pos/i10542.scala The fix in 0f034aa0b51ca7df6cdff54b5a3066b0df6465b8 works by accident: ``` @@ -115,7 +115,9 @@ class ReTyper extends Typer with ReChecking { } override def typedUnadapted(tree: untpd.Tree, pt: Type, locked: TypeVars)(using Context): Tree = try super.typedUnadapted(tree, pt, locked) try super.typedUnadapted(tree, pt, locked) match case member: MemberDef => member.setDefTree case tree => tree ``` The reason is the following: - If we enable `-Ycheck:all`, it will sync the tree definition for all symbols during TreeChecker, thus no crash in initialization checker. - if we disable `-Ycheck:all`, the `defTree` for `` is not set, initialization checker ignores the method, thus no crash. However, if we change `InlineTyper` instead of `Retyper`: ``` + override def typedUnadapted(tree: untpd.Tree, pt: Type, locked: TypeVars)(using Context): Tree = + super.typedUnadapted(tree, pt, locked) match + case member: MemberDef => member.setDefTree + case tree => tree ``` There will be some mysterious behavior in compiling `tests/pos/i10542.scala`: - Without `-Ycheck:all`, it succeeds. - With `-Ycheck:all`, the initialization check crashes due to missing `defTree` for the class `$anon`. The reason for the mysterious behavior is the following: - Without `-Ycheck:all`, there is no defTree for ``, initialization check is skipped, thus no crash. - With `-Ycheck:all`, the method `Typer.typedDefDef` will set `Symbol.defTree` for ``, called from the TreeChecker, which extends `Typer` indirectly via `ReTyper`. However, in `Typer.typedClassDef`, we never set `defTree` for class symbols, thus the `defTree` for the class symbol `$anon` is empty, causing an exception in initialization check. Co-authored-by: Nicolas Stucki --- compiler/src/dotty/tools/dotc/typer/Inliner.scala | 15 ++++++++++++--- compiler/src/dotty/tools/dotc/typer/ReTyper.scala | 4 +--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index d89ba6128274..1f89c8e7337a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -464,7 +464,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { if (isByName) DefDef(boundSym, arg.changeOwner(ctx.owner, boundSym)) else ValDef(boundSym, arg) }.withSpan(boundSym.span) - bindingsBuf += binding.setDefTree + bindingsBuf += binding binding } @@ -521,7 +521,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { ref(rhsClsSym.sourceModule) else inlineCallPrefix - val binding = ValDef(selfSym.asTerm, QuoteUtils.changeOwnerOfTree(rhs, selfSym)).withSpan(selfSym.span).setDefTree + val binding = ValDef(selfSym.asTerm, QuoteUtils.changeOwnerOfTree(rhs, selfSym)).withSpan(selfSym.span) bindingsBuf += binding inlining.println(i"proxy at $level: $selfSym = ${bindingsBuf.last}") lastSelf = selfSym @@ -797,7 +797,12 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { bindingsBuf.mapInPlace { binding => // Set trees to symbols allow macros to see the definition tree. // This is used by `underlyingArgument`. - reducer.normalizeBinding(binding)(using inlineCtx).setDefTree + val binding1 = reducer.normalizeBinding(binding)(using inlineCtx).setDefTree + binding1.foreachSubTree { + case tree: MemberDef => tree.setDefTree + case _ => + } + binding1 } // Run a typing pass over the inlined tree. See InlineTyper for details. @@ -1382,6 +1387,10 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { if Inliner.needsInlining(tree) then Inliner.inlineCall(tree) else tree + override def typedUnadapted(tree: untpd.Tree, pt: Type, locked: TypeVars)(using Context): Tree = + super.typedUnadapted(tree, pt, locked) match + case member: MemberDef => member.setDefTree + case tree => tree } /** Drop any side-effect-free bindings that are unused in expansion or other reachable bindings. diff --git a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala index 42c71c1a7b72..8ff0dfc8c61b 100644 --- a/compiler/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/compiler/src/dotty/tools/dotc/typer/ReTyper.scala @@ -115,9 +115,7 @@ class ReTyper extends Typer with ReChecking { } override def typedUnadapted(tree: untpd.Tree, pt: Type, locked: TypeVars)(using Context): Tree = - try super.typedUnadapted(tree, pt, locked) match - case member: MemberDef => member.setDefTree - case tree => tree + try super.typedUnadapted(tree, pt, locked) catch { case NonFatal(ex) => if ctx.phase != Phases.typerPhase && ctx.phase != Phases.inliningPhase then