Skip to content

Commit 8efbdcd

Browse files
jchybtgodzik
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 b1676da commit 8efbdcd

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
@@ -533,17 +533,42 @@ object Inlines:
533533
val inlined = tpd.Inlined(call, bindings, expansion)
534534

535535
val hasOpaquesInResultFromCallWithTransparentContext =
536+
val owners = call.symbol.ownersIterator.toSet
536537
call.tpe.widenTermRefExpr.existsPart(
537-
part => part.typeSymbol.is(Opaque) && call.symbol.ownersIterator.contains(part.typeSymbol.owner)
538+
part => part.typeSymbol.is(Opaque) && owners.contains(part.typeSymbol.owner)
538539
)
539540

541+
/* Remap ThisType nodes that are incorrect in the inlined context.
542+
* Incorrect ThisType nodes can cause unwanted opaque type dealiasing later
543+
* See test i113461-d
544+
* */
545+
def fixThisTypeModuleClassReferences(tpe: Type): Type =
546+
val owners = ctx.owner.ownersIterator.toSet
547+
TreeTypeMap(
548+
typeMap = new TypeMap:
549+
override def stopAt = StopAt.Package
550+
def apply(t: Type) = mapOver {
551+
t match
552+
case ThisType(tref @ TypeRef(prefix, _)) if tref.symbol.flags.is(Module) && !owners.contains(tref.symbol) =>
553+
TermRef(apply(prefix), tref.symbol.companionModule)
554+
case _ => mapOver(t)
555+
}
556+
).typeMap(tpe)
557+
540558
if !hasOpaqueProxies && !hasOpaquesInResultFromCallWithTransparentContext then inlined
541559
else
542-
val target =
560+
val (target, forceCast) =
543561
if inlinedMethod.is(Transparent) then
544-
call.tpe & unpackProxiesFromResultType(inlined)
545-
else call.tpe
546-
inlined.ensureConforms(target)
562+
val unpacked = unpackProxiesFromResultType(inlined)
563+
val withAdjustedThisTypes = if call.symbol.is(Macro) then fixThisTypeModuleClassReferences(unpacked) else unpacked
564+
(call.tpe & withAdjustedThisTypes, withAdjustedThisTypes != unpacked)
565+
else (call.tpe, false)
566+
if forceCast then
567+
// we need to force the cast for issues with ThisTypes, as ensureConforms will just
568+
// check subtyping and then choose not to cast, leaving the previous, incorrect type
569+
inlined.cast(target)
570+
else
571+
inlined.ensureConforms(target)
547572
// Make sure that the sealing with the declared type
548573
// is type correct. Without it we might get problems since the
549574
// 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)