diff --git a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala index 27d95d055f40..4e125f7dd649 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala @@ -399,7 +399,17 @@ class Inliner(val call: tpd.Tree)(using Context): * type aliases, add proxy definitions to `opaqueProxies` that expose these aliases. */ private def addOpaqueProxies(tp: Type, span: Span, forThisProxy: Boolean)(using Context): Unit = - tp.foreachPart { + val foreachTpPart = + (p: Type => Unit) => + if forThisProxy then + // Performs operations on all parts of this type, outside of the applied type arguments + new ForeachAccumulator(p, StopAt.None) { + override def apply(x: Unit, tp: Type) = tp match + case AppliedType(tycon, _) => super.apply(x, tycon) + case other => super.apply(x, other) + }.apply((), tp) + else tp.foreachPart(p) + foreachTpPart { case ref: TermRef => for cls <- ref.widen.baseClasses do if cls.containsOpaques diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index bc4e1a332ff6..3df25e06a3b1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -712,7 +712,13 @@ class Namer { typer: Typer => enterSymbol(classConstructorCompanion(classSym.asClass)) else for moduleSym <- companionVals do - if moduleSym.is(Module) && !moduleSym.isDefinedInCurrentRun then + // by not going through `.lastKnownDenotation` (instead using `.current`), + // we guarantee that the `moduleSym` will be brought forward to the current run, + // rendering `moduleSym.isDefinedInCurrentRun` as always true. + // We want to regenerate the companion instead of bringing it forward, + // as even if we are able to bring forward the object symbol, + // we might not be able to do the same with its stale module class symbol (see `tests/pos/i20449`) + if moduleSym.lastKnownDenotation.is(Module) && !moduleSym.isDefinedInCurrentRun then val companion = if needsConstructorProxies(classSym) then classConstructorCompanion(classSym.asClass) diff --git a/tests/pos-macros/i20449/Macro.scala b/tests/pos-macros/i20449/Macro.scala new file mode 100644 index 000000000000..56c9a625e894 --- /dev/null +++ b/tests/pos-macros/i20449/Macro.scala @@ -0,0 +1,3 @@ +import scala.quoted.* +transparent inline def getTypeInfo[T]() = ${ getTypeInfoImpl[T] } +def getTypeInfoImpl[T: Type](using ctx: Quotes): Expr[Unit] = '{ () } diff --git a/tests/pos-macros/i20449/Main.scala b/tests/pos-macros/i20449/Main.scala new file mode 100644 index 000000000000..c6f5c0b05b69 --- /dev/null +++ b/tests/pos-macros/i20449/Main.scala @@ -0,0 +1,6 @@ + +class Wrapper1[A] +val a = { + getTypeInfo[Any]() + val wrapper2 = Wrapper1[Any]() +} diff --git a/tests/run-macros/i20449.check b/tests/run-macros/i20449.check new file mode 100644 index 000000000000..289b3f95c488 --- /dev/null +++ b/tests/run-macros/i20449.check @@ -0,0 +1,50 @@ +------ UserName.T - Directly ------- +Original: Main_2$package.UserName.T +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ UserName.T - Directly ------- +Original: Main_2$package.UserName +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ ForeignWrapper1[UserName.T] ------- +Original: Main_2$package.UserName.T +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ ForeignWrapper2[UserName.T] ------- +Original: Main_2$package.UserName.T +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ ForeignWrapper1[UserName] ------- +Original: Main_2$package.UserName +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ ForeignWrapper2[UserName] ------- +Original: Main_2$package.UserName +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ Wrapper1[UserName.T] ------- +Original: Main_2$package.UserName.T +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ Wrapper2[UserName.T] ------- +Original: Main_2$package.UserName.T +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ Wrapper1[UserName] ------- +Original: Main_2$package.UserName +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + +------ Wrapper2[UserName] ------- +Original: Main_2$package.UserName +Dealias: Main_2$package.UserName.T +Dealias dealias: Main_2$package.UserName.T + diff --git a/tests/run-macros/i20449/Macro_1.scala b/tests/run-macros/i20449/Macro_1.scala new file mode 100644 index 000000000000..74b1dce3c4d6 --- /dev/null +++ b/tests/run-macros/i20449/Macro_1.scala @@ -0,0 +1,29 @@ +import scala.quoted.* + +class ForeignWrapper1[-A] { + inline def getTypeInfo(inline source: String): String = + ${ getTypeInfoImpl[A]('source) } + def createWrapper2 = ForeignWrapper2(this) +} + +class ForeignWrapper2[-A](val self: ForeignWrapper1[A]) { + inline def getTypeInfo(inline source: String): String = + ${getTypeInfoImpl[A]('source)} +} + +transparent inline def getTypeInfo[T](inline source: String) = + ${ getTypeInfoImpl[T]('source) } + +def getTypeInfoImpl[T: Type](source: Expr[String])(using ctx: Quotes) : Expr[String] = { + import ctx.reflect.* + + val tpe = TypeRepr.of[T] + val str = + s"""|------ ${source.valueOrAbort} ------- + |Original: ${tpe.show} + |Dealias: ${tpe.dealias.show} + |Dealias dealias: ${tpe.dealias.dealias.show} + """.stripMargin + + Expr(str) +} diff --git a/tests/run-macros/i20449/Main_2.scala b/tests/run-macros/i20449/Main_2.scala new file mode 100644 index 000000000000..3d2991489c1b --- /dev/null +++ b/tests/run-macros/i20449/Main_2.scala @@ -0,0 +1,41 @@ +object UserName { + opaque type T = String + + def apply(s: String): T = s +} + +type UserName = UserName.T + +class Wrapper1[-A] { + inline def getTypeInfo(inline source: String): String = + ${ getTypeInfoImpl[A]('source) } + def createWrapper2 = Wrapper2(this) +} + +class Wrapper2[-A](val self: Wrapper1[A]) { + inline def getTypeInfo(inline source: String): String = + ${getTypeInfoImpl[A]('source)} +} + + +@main def Test() = { + println(getTypeInfo[UserName.T]("UserName.T - Directly")) + println(getTypeInfo[UserName]("UserName.T - Directly")) + + val foreignWrapper = ForeignWrapper1[UserName.T]() + println(foreignWrapper.getTypeInfo("ForeignWrapper1[UserName.T]")) + println(foreignWrapper.createWrapper2.getTypeInfo("ForeignWrapper2[UserName.T]")) + + val foreignWrapper2 = ForeignWrapper1[UserName]() + println(foreignWrapper2.getTypeInfo("ForeignWrapper1[UserName]")) + println(foreignWrapper2.createWrapper2.getTypeInfo("ForeignWrapper2[UserName]")) + + val wrapper = Wrapper1[UserName.T]() + println(wrapper.getTypeInfo("Wrapper1[UserName.T]")) + println(wrapper.createWrapper2.getTypeInfo("Wrapper2[UserName.T]")) + + val wrapper2 = Wrapper1[UserName]() + println(wrapper2.getTypeInfo("Wrapper1[UserName]")) + println(wrapper2.createWrapper2.getTypeInfo("Wrapper2[UserName]")) + +}