Skip to content

Commit a04b69d

Browse files
jchybWojciechMazur
authored andcommitted
Fix additional test case
Certain macros could return nodes typed with incorrect ThisTypes, which would reference module types outside of their scope. We remap those problematic nodes to TermRefs pointing to objects, and then possibly manually cast the returned node to the remapped type, as the ensureConforms method would just leave the previous incorrect type after confirming that the remapped type is a subtype of the previous incorrect one. [Cherry-picked 6771a79]
1 parent 9e991f7 commit a04b69d

File tree

6 files changed

+46
-6
lines changed

6 files changed

+46
-6
lines changed

compiler/src/dotty/tools/dotc/inlines/Inlines.scala

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -574,17 +574,42 @@ object Inlines:
574574
val inlined = tpd.Inlined(call, bindings, expansion)
575575

576576
val hasOpaquesInResultFromCallWithTransparentContext =
577+
val owners = call.symbol.ownersIterator.toSet
577578
call.tpe.widenTermRefExpr.existsPart(
578-
part => part.typeSymbol.is(Opaque) && call.symbol.ownersIterator.contains(part.typeSymbol.owner)
579+
part => part.typeSymbol.is(Opaque) && owners.contains(part.typeSymbol.owner)
579580
)
580581

582+
/* Remap ThisType nodes that are incorrect in the inlined context.
583+
* Incorrect ThisType nodes can cause unwanted opaque type dealiasing later
584+
* See test i113461-d
585+
* */
586+
def fixThisTypeModuleClassReferences(tpe: Type): Type =
587+
val owners = ctx.owner.ownersIterator.toSet
588+
TreeTypeMap(
589+
typeMap = new TypeMap:
590+
override def stopAt = StopAt.Package
591+
def apply(t: Type) = mapOver {
592+
t match
593+
case ThisType(tref @ TypeRef(prefix, _)) if tref.symbol.flags.is(Module) && !owners.contains(tref.symbol) =>
594+
TermRef(apply(prefix), tref.symbol.companionModule)
595+
case _ => mapOver(t)
596+
}
597+
).typeMap(tpe)
598+
581599
if !hasOpaqueProxies && !hasOpaquesInResultFromCallWithTransparentContext then inlined
582600
else
583-
val target =
601+
val (target, forceCast) =
584602
if inlinedMethod.is(Transparent) then
585-
call.tpe & unpackProxiesFromResultType(inlined)
586-
else call.tpe
587-
inlined.ensureConforms(target)
603+
val unpacked = unpackProxiesFromResultType(inlined)
604+
val withAdjustedThisTypes = if call.symbol.is(Macro) then fixThisTypeModuleClassReferences(unpacked) else unpacked
605+
(call.tpe & withAdjustedThisTypes, withAdjustedThisTypes != unpacked)
606+
else (call.tpe, false)
607+
if forceCast then
608+
// we need to force the cast for issues with ThisTypes, as ensureConforms will just
609+
// check subtyping and then choose not to cast, leaving the previous, incorrect type
610+
inlined.cast(target)
611+
else
612+
inlined.ensureConforms(target)
588613
// Make sure that the sealing with the declared type
589614
// is type correct. Without it we might get problems since the
590615
// expression's type is the opaque alias but the call's type is
File renamed without changes.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import scala.quoted.*
2+
opaque type MyOpaque = Int
3+
object MyOpaque:
4+
val one: MyOpaque = 1
5+
transparent inline def apply(): MyOpaque = ${ applyMacro }
6+
private def applyMacro(using Quotes): Expr[MyOpaque] =
7+
import quotes.reflect.*
8+
'{ one }
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
trait Leak[T]:
2+
type Out
3+
given [T]: Leak[T] with
4+
type Out = T
5+
extension [T](t: T)(using l: Leak[T]) def leak: l.Out = ???
6+
7+
val x = MyOpaque().leak
8+
val shouldWork = summon[x.type <:< MyOpaque]
File renamed without changes.

tests/run/i13461-b.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// TODO taken from issue
21
object Time:
32
opaque type Time = String
43
opaque type Seconds <: Time = String

0 commit comments

Comments
 (0)