Skip to content

Commit 8bb3395

Browse files
authored
Merge pull request #595 from scala/backport-lts-3.3-21527
Backport "Fix pkg obj prefix of opaque tp ext meth" to 3.3 LTS
2 parents 1f1a3d2 + 302f873 commit 8bb3395

File tree

12 files changed

+126
-36
lines changed

12 files changed

+126
-36
lines changed

compiler/src/dotty/tools/dotc/core/TypeErasure.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package core
55
import Symbols.*, Types.*, Contexts.*, Flags.*, Names.*, StdNames.*, Phases.*
66
import Flags.JavaDefined
77
import Uniques.unique
8-
import TypeOps.makePackageObjPrefixExplicit
98
import backend.sjs.JSDefinitions
109
import transform.ExplicitOuter.*
1110
import transform.ValueClasses.*

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -598,36 +598,6 @@ object TypeOps:
598598
widenMap(tp)
599599
}
600600

601-
/** If `tpe` is of the form `p.x` where `p` refers to a package
602-
* but `x` is not owned by a package, expand it to
603-
*
604-
* p.package.x
605-
*/
606-
def makePackageObjPrefixExplicit(tpe: NamedType)(using Context): Type = {
607-
def tryInsert(pkgClass: SymDenotation): Type = pkgClass match {
608-
case pkg: PackageClassDenotation =>
609-
var sym = tpe.symbol
610-
if !sym.exists && tpe.denot.isOverloaded then
611-
// we know that all alternatives must come from the same package object, since
612-
// otherwise we would get "is already defined" errors. So we can take the first
613-
// symbol we see.
614-
sym = tpe.denot.alternatives.head.symbol
615-
val pobj = pkg.packageObjFor(sym)
616-
if (pobj.exists) tpe.derivedSelect(pobj.termRef)
617-
else tpe
618-
case _ =>
619-
tpe
620-
}
621-
if (tpe.symbol.isRoot)
622-
tpe
623-
else
624-
tpe.prefix match {
625-
case pre: ThisType if pre.cls.is(Package) => tryInsert(pre.cls)
626-
case pre: TermRef if pre.symbol.is(Package) => tryInsert(pre.symbol.moduleClass)
627-
case _ => tpe
628-
}
629-
}
630-
631601
/** An argument bounds violation is a triple consisting of
632602
* - the argument tree
633603
* - a string "upper" or "lower" indicating which bound is violated

compiler/src/dotty/tools/dotc/core/TypeUtils.scala

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package dotc
33
package core
44

55
import TypeErasure.ErasedValueType
6-
import Types.*, Contexts.*, Symbols.*, Flags.*, Decorators.*
6+
import Types.*, Contexts.*, Symbols.*, Flags.*, Decorators.*, SymDenotations.*
77
import Names.Name
88
import StdNames.nme
99

@@ -147,6 +147,37 @@ class TypeUtils:
147147
val cls = self.underlyingClassRef(refinementOK = false).typeSymbol
148148
cls.isTransparentClass && (!traitOnly || cls.is(Trait))
149149

150+
151+
/** If `self` is of the form `p.x` where `p` refers to a package
152+
* but `x` is not owned by a package, expand it to
153+
*
154+
* p.package.x
155+
*/
156+
def makePackageObjPrefixExplicit(using Context): Type =
157+
def tryInsert(tpe: NamedType, pkgClass: SymDenotation): Type = pkgClass match
158+
case pkg: PackageClassDenotation =>
159+
var sym = tpe.symbol
160+
if !sym.exists && tpe.denot.isOverloaded then
161+
// we know that all alternatives must come from the same package object, since
162+
// otherwise we would get "is already defined" errors. So we can take the first
163+
// symbol we see.
164+
sym = tpe.denot.alternatives.head.symbol
165+
val pobj = pkg.packageObjFor(sym)
166+
if pobj.exists then tpe.derivedSelect(pobj.termRef)
167+
else tpe
168+
case _ =>
169+
tpe
170+
self match
171+
case tpe: NamedType =>
172+
if tpe.symbol.isRoot then
173+
tpe
174+
else
175+
tpe.prefix match
176+
case pre: ThisType if pre.cls.is(Package) => tryInsert(tpe, pre.cls)
177+
case pre: TermRef if pre.symbol.is(Package) => tryInsert(tpe, pre.symbol.moduleClass)
178+
case _ => tpe
179+
case tpe => tpe
180+
150181
/** The constructors of this type that are applicable to `argTypes`, without needing
151182
* an implicit conversion. Curried constructors are always excluded.
152183
* @param adaptVarargs if true, allow a constructor with just a varargs argument to

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1192,7 +1192,7 @@ class TreeUnpickler(reader: TastyReader,
11921192
val tpe0 = name match
11931193
case name: TypeName => TypeRef(qualType, name, denot)
11941194
case name: TermName => TermRef(qualType, name, denot)
1195-
val tpe = TypeOps.makePackageObjPrefixExplicit(tpe0)
1195+
val tpe = tpe0.makePackageObjPrefixExplicit
11961196
ConstFold.Select(untpd.Select(qual, name).withType(tpe))
11971197

11981198
def completeSelect(name: Name, sig: Signature, target: Name): Select =

compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ trait TypeAssigner {
8181
defn.FromJavaObjectType
8282
else tpe match
8383
case tpe: NamedType =>
84-
val tpe1 = TypeOps.makePackageObjPrefixExplicit(tpe)
84+
val tpe1 = tpe.makePackageObjPrefixExplicit
8585
if tpe1 ne tpe then
8686
accessibleType(tpe1, superAccess)
8787
else

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
319319
// so we ignore that import.
320320
if reallyExists(denot) && !isScalaJsPseudoUnion then
321321
if unimported.isEmpty || !unimported.contains(pre.termSymbol) then
322-
return pre.select(name, denot)
322+
return pre.select(name, denot).makePackageObjPrefixExplicit
323323
case _ =>
324324
if imp.importSym.isCompleting then
325325
report.warning(i"cyclic ${imp.importSym}, ignored", pos)
@@ -479,7 +479,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
479479
defDenot.symbol.owner
480480
else
481481
curOwner
482-
effectiveOwner.thisType.select(name, defDenot)
482+
effectiveOwner.thisType.select(name, defDenot).makePackageObjPrefixExplicit
483483
}
484484
if !curOwner.is(Package) || isDefinedInCurrentUnit(defDenot) then
485485
result = checkNewOrShadowed(found, Definition) // no need to go further out, we found highest prec entry

tests/pos/i18097.1.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
opaque type Pos = Double
2+
3+
object Pos:
4+
extension (x: Pos)
5+
def mult1(y: Pos): Pos = x * y
6+
7+
extension (x: Pos)
8+
def mult2(y: Pos): Pos = x * y
9+
10+
class Test:
11+
def test(key: String, a: Pos, b: Pos): Unit =
12+
val tup1 = new Tuple1(Pos.mult1(a)(b))
13+
val res1: Pos = tup1._1
14+
15+
val tup2 = new Tuple1(a.mult1(b))
16+
val res2: Pos = tup2._1
17+
18+
val tup3 = new Tuple1(mult2(a)(b))
19+
val res3: Pos = tup3._1
20+
21+
val tup4 = new Tuple1(a.mult2(b))
22+
val res4: Pos = tup4._1 // was error: Found: (tup4._4 : Double) Required: Pos

tests/pos/i18097.2.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
opaque type Namespace = List[String]
2+
3+
object Namespace:
4+
def apply(head: String): Namespace = List(head)
5+
6+
extension (ns: Namespace)
7+
def appended(segment: String): Namespace = ns.appended(segment)
8+
9+
object Main:
10+
def main(args: Array[String]): Unit =
11+
val a: Namespace = Namespace("a")
12+
.appended("B")
13+
.appended("c") // was error: Found: List[String] Required: Namespace

tests/pos/i18097.2.works.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
object Main:
2+
opaque type Namespace = List[String]
3+
4+
object Namespace:
5+
def apply(head: String): Namespace = List(head)
6+
7+
extension (ns: Namespace)
8+
def appended(segment: String): Namespace = ns.appended(segment)
9+
10+
def main(args: Array[String]): Unit =
11+
val a: Namespace = Namespace("a")
12+
.appended("B")
13+
.appended("c")

tests/pos/i18097.3/Opaque.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package test
2+
3+
type Foo = Unit
4+
val bar: Foo = ()
5+
6+
opaque type Opaque = Unit
7+
8+
extension (foo: Foo)
9+
def go: Option[Opaque] = ???

0 commit comments

Comments
 (0)