From 44a746c2d5e0eb3ff725e8188aaa2ec8dc28be8c Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 9 Oct 2022 21:25:42 +0200 Subject: [PATCH 1/2] Don't propagate imports into inlined code Imports are supposed to be resolved already, so they need not and should not be copied into inlined code. Fixes #16156, unfortuntely in the sense that it will not work. --- .../dotty/tools/dotc/inlines/Inliner.scala | 3 +++ tests/neg/i16156/Defs_1.scala | 25 +++++++++++++++++++ tests/neg/i16156/Use_2.scala | 4 +++ 3 files changed, 32 insertions(+) create mode 100644 tests/neg/i16156/Defs_1.scala create mode 100644 tests/neg/i16156/Use_2.scala diff --git a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala index bea42e82ce6f..c2a4f1d7aeb4 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala @@ -596,6 +596,9 @@ class Inliner(val call: tpd.Tree)(using Context): // reference to a private method is kept at runtime. cpy.Select(tree)(qual.asInstance(qual.tpe.widen), name) + case tree: ImportOrExport => + EmptyTree + case tree => tree }, oldOwners = inlinedMethod :: Nil, diff --git a/tests/neg/i16156/Defs_1.scala b/tests/neg/i16156/Defs_1.scala new file mode 100644 index 000000000000..81a9d35f6461 --- /dev/null +++ b/tests/neg/i16156/Defs_1.scala @@ -0,0 +1,25 @@ +//import quotes.reflect._ + +trait MyEncoder[T]: + def encode: String +class Context: + inline def summonMyEncoder[T]: String = + ${ SummonEncoder.impl[T] } + implicit val encoderInstance: MyEncoder[String] = + new MyEncoder[String] { def encode = "blah" } +end Context + +import scala.quoted._ + +object SummonEncoder: + def impl[T: Type](using Quotes) = + import quotes.reflect._ + Expr.summon[MyEncoder[T]] match + case Some(enc) => '{ $enc.encode } + case None => report.throwError("can't do it") + +class Repo[T]: + val ctx = new Context + inline def summonEncoder = { import ctx._ // change to: import ctx.{given, _} for the given example + ctx.summonMyEncoder[T] + } diff --git a/tests/neg/i16156/Use_2.scala b/tests/neg/i16156/Use_2.scala new file mode 100644 index 000000000000..fe39d2423aa4 --- /dev/null +++ b/tests/neg/i16156/Use_2.scala @@ -0,0 +1,4 @@ + +object Use: + val repo = new Repo[String] + val v = repo.summonEncoder // error happens here! From 501dfcf04ee8775edb3984b29b0a142884e9cc51 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 10 Oct 2022 20:58:30 +0200 Subject: [PATCH 2/2] Eliminate imports after cross version checks ... except for language imports. It looks this does not change the underlying issue but it's good housekeeping anyway. The problem is that imports would not be transformed in a phase like ExplicitOuter since Import is not by default handled in MegaPhase's transform. As long as no-one checks this might not matter, but it's still weird. So better to get rid of them before. --- .../dotty/tools/dotc/typer/CrossVersionChecks.scala | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala b/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala index 044dd7bb8528..da3608ae1cbc 100644 --- a/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala @@ -8,7 +8,7 @@ import util.SrcPos import config.{ScalaVersion, NoScalaVersion, Feature, ScalaRelease} import MegaPhase.MiniPhase import scala.util.{Failure, Success} -import ast.tpd +import ast.{tpd, untpd} class CrossVersionChecks extends MiniPhase: import tpd.* @@ -21,6 +21,11 @@ class CrossVersionChecks extends MiniPhase: override def runsAfterGroupsOf: Set[String] = Set(FirstTransform.name) // We assume all type trees except TypeTree have been eliminated + override def checkPostCondition(tree: Tree)(using Context): Unit = tree match + case tree: Import => + assert(untpd.languageImport(tree.expr).nonEmpty, i"illegal tree: $tree") + case _ => + // Note: if a symbol has both @deprecated and @migration annotations and both // warnings are enabled, only the first one checked here will be emitted. // I assume that's a consequence of some code trying to avoid noise by suppressing @@ -182,7 +187,8 @@ class CrossVersionChecks extends MiniPhase: case t: RefTree => checkUndesiredProperties(t.symbol, t.srcPos) case _ => } - tree + if untpd.languageImport(tree.expr).isEmpty then EmptyTree + else tree case _ => tree end CrossVersionChecks