Skip to content

Fix #14319: Use correct stat context when transforming Block #14411

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions compiler/src/dotty/tools/dotc/ast/TreeMapWithImplicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,7 @@ class TreeMapWithImplicits extends tpd.TreeMapWithPreciseStatContexts {
override def transform(tree: Tree)(using Context): Tree = {
try tree match {
case Block(stats, expr) =>
inContext(nestedScopeCtx(stats)) {
if stats.exists(_.isInstanceOf[Import]) then
// need to transform stats and expr together to account for import visibility
val stats1 = transformStats(stats :+ expr, ctx.owner)
cpy.Block(tree)(stats1.init, stats1.last)
else super.transform(tree)
}
super.transform(tree)(using nestedScopeCtx(stats))
case tree: DefDef =>
inContext(localCtx(tree)) {
cpy.DefDef(tree)(
Expand Down
7 changes: 7 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,13 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
* - imports are reflected in the contexts of subsequent statements
*/
class TreeMapWithPreciseStatContexts(cpy: TreeCopier = tpd.cpy) extends TreeMap(cpy):
override def transform(tree: Tree)(using Context): Tree = tree match
case Block(stats, expr) =>
val stats1 = transformStats(stats :+ expr, ctx.owner)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will lead to great tree node churn. Every block will get new statements on every transform, so everything containing a block will be copied, which means you get a complete copy of the AST for a macro transform. I don't think this is acceptable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is better to have an optional expr argument in transformStats. It's more convoluted but I don't see an alternative.

cpy.Block(tree)(stats1.init, stats1.last)
case _ =>
super.transform(tree)

override def transformStats(trees: List[Tree], exprOwner: Symbol)(using Context): List[Tree] =
trees.mapStatements(exprOwner, transform(_))

Expand Down
10 changes: 10 additions & 0 deletions tests/explicit-nulls/pos/unsafe-chain.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import java.nio.file.FileSystems
import java.util.ArrayList

def directorySeparator: String =
import scala.language.unsafeNulls
FileSystems.getDefault().getSeparator()

def getFirstOfFirst(xs: ArrayList[ArrayList[ArrayList[String]]]): String =
import scala.language.unsafeNulls
xs.get(0).get(0).get(0)