Skip to content

Backport "Fixes for isLegalPrefix change" to 3.3 LTS #181

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

Merged
merged 5 commits into from
Mar 18, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Teach AvoidMap to strip opaque alias refinements
[Cherry-picked 3ac5f2d]
  • Loading branch information
dwijnand authored and tgodzik committed Mar 14, 2025
commit 91e8c44094bb793e6e3d89ba1816a0945cd34341
21 changes: 20 additions & 1 deletion compiler/src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,26 @@ object TypeOps:
tp
else (if pre.isSingleton then NoType else tryWiden(tp, tp.prefix)).orElse {
if (tp.isTerm && variance > 0 && !pre.isSingleton)
apply(tp.info.widenExpr)
tp.prefix match
case prefix: TermRef if prefix.name.is(InlineBinderName) && prefix.symbol.denot.is(Synthetic, butNot=InlineProxy) =>
prefix.info.widenExpr.dealias match
case info: RefinedType =>
// Strip refinements on an opaque alias proxy
// Using pos/i22068 as an example,
// Inliner#addOpaqueProxies add the following opaque alias proxy:
// val $proxy1: foos.type { type Foo[T] = String } =
// foos.$asInstanceOf[foos.type { type Foo[T] = String }]
// Then when InlineCall#expand creates a typed Inlined,
// we type avoid any local bindings, which includes that opaque alias proxy.
// To avoid that the replacement is a non-singleton RefinedType,
// we drop the refinements too and return foos.type.
// That way, when we inline `def m1` and we calculate the asSeenFrom
// of `b1.and(..)` b1 doesn't have an unstable prefix.
derivedSelect(tp, info.stripRefinement)
case _ =>
apply(tp.info.widenExpr)
case _ =>
apply(tp.info.widenExpr)
else if (upper(pre).member(tp.name).exists)
super.derivedSelect(tp, pre)
else
Expand Down
21 changes: 21 additions & 0 deletions tests/pos/i22068.less-min.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class A
class B extends A
class C extends A

object foos:
opaque type Tag[A] = String
object Tag:
inline given mkTag[A]: Tag[A] = ???
type Full[A] = Tag[A] | Set[A]
sealed trait Set[A] extends Any
case class Union[A](tags: Seq[Tag[Any]]) extends AnyVal with Set[A]:
infix def and[B](t2: Full[B]): Unit = ???
object Union:
inline given mkUnion[A]: Union[A] = ???
import foos.Tag.*

class Test:
inline def m1[K1, K2](using b1: Union[K1], b2: Union[K2]): Unit =
b1.and(b2)

def t1(): Unit = m1[B | C, A]
29 changes: 29 additions & 0 deletions tests/pos/i22068.orig.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
trait AnyFreeSpecLike:
inline implicit def convertToFreeSpecStringWrapper(s: String): FreeSpecStringWrapper = ???
protected final class FreeSpecStringWrapper(string: String):
infix def in(testFun: => Any): Unit = ???


import types.Tag.*
class TagTest extends AnyFreeSpecLike{
inline def test[T1, T2](using k1: Union[T1], k2: Union[T2]): Unit =
"T1 <:< T2" in {
val kresult = k1 <:< k2
???
}
class A
class B extends A
class C extends A
test[B | C, A]
}

object types:
opaque type Tag[A] = String
object Tag:
inline given apply[A]: Tag[A] = ???
type Full[A] = Tag[A] | Set[A]
sealed trait Set[A] extends Any
case class Union[A](tags: Seq[Tag[Any]]) extends AnyVal with Set[A]:
infix def <:<[B](t2: Full[B]): Boolean = ???
object Union:
inline given apply[A]: Union[A] = ???
14 changes: 14 additions & 0 deletions tests/pos/i22068.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
object foos:
opaque type Foo[T] = String
object bars:
class Bar1[A] { def and(b: Bar2): Unit = () }
class Bar2
inline def mkBar1[A]: Bar1[A] = new Bar1[A]
def mkBar2 : Bar2 = new Bar2
import foos.*, bars.*

class Test:
inline def m1[X](b1: Bar1[X], b2: Bar2): Unit =
b1.and(b2)

def t1(): Unit = m1(mkBar1[Int], mkBar2)