Skip to content

Commit 18c04b9

Browse files
committed
Only include accessible base classes in orDominator
By joining union types we could previously uncover inaccessible base classes that could lead to access errors at runtime. We now filter out such classes when computing the orDominator. Fixes #16474
1 parent 716d93d commit 18c04b9

File tree

9 files changed

+72
-2
lines changed

9 files changed

+72
-2
lines changed

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ object TypeOps:
209209

210210
/** Approximate union type by intersection of its dominators.
211211
* That is, replace a union type Tn | ... | Tn
212-
* by the smallest intersection type of base-class instances of T1,...,Tn.
212+
* by the smallest intersection type of accessible base-class instances of T1,...,Tn.
213213
* Example: Given
214214
*
215215
* trait C[+T]
@@ -370,8 +370,14 @@ object TypeOps:
370370
}
371371
}
372372

373+
def isAccessible(cls: ClassSymbol) =
374+
if cls.isOneOf(AccessFlags) || cls.privateWithin.exists then
375+
cls.isAccessibleFrom(tp.baseType(cls).normalizedPrefix)
376+
else true
377+
373378
// Step 3: Intersect base classes of both sides
374-
val commonBaseClasses = orBaseClasses(tp)
379+
val commonBaseClasses = orBaseClasses(tp).filterConserve(isAccessible)
380+
375381
val doms = dominators(commonBaseClasses, Nil)
376382
def baseTp(cls: ClassSymbol): Type =
377383
tp.baseType(cls).mapReduceOr(identity)(mergeRefinedOrApplied)

tests/pos/i16474.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
object o:
2+
3+
private[o] trait A
4+
trait B
5+
class C extends A, B
6+
class D extends A, B
7+
8+
def test =
9+
def f[T](x: T): T => T = identity
10+
val g = f(if ??? then o.C() else o.D())
11+
g(new o.B{})
12+
13+

tests/run/i16474/BaseProvider.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// BaseProvider.java
2+
package repro.impl;
3+
4+
import repro.*;
5+
abstract class BaseProvider{}
6+

tests/run/i16474/Case1.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Case1.java
2+
package repro;
3+
4+
import repro.impl.*;
5+
6+
public class Case1 extends Case1Provider implements Encrypter {
7+
public Case1(){}
8+
}
9+

tests/run/i16474/Case1Provider.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Case1Provider.java
2+
package repro.impl;
3+
4+
public abstract class Case1Provider extends BaseProvider {}
5+

tests/run/i16474/Case2.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Case2.java
2+
package repro;
3+
4+
import repro.impl.*;
5+
6+
public class Case2 extends Case2Provider implements Encrypter {
7+
public Case2(){}
8+
}

tests/run/i16474/Case2Provider.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Case2Provider.java
2+
package repro.impl;
3+
4+
public abstract class Case2Provider extends BaseProvider {}
5+

tests/run/i16474/Encrypter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Encrypter.java
2+
package repro;
3+
public interface Encrypter{}
4+

tests/run/i16474/test.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// test.scala
2+
import repro.*
3+
import scala.util.Try
4+
5+
def get(arg: Any): Try[Encrypter] = Try {
6+
val x: Any = 1
7+
arg match
8+
case 1 => new Case1()
9+
case 2 => new Case2()
10+
case _ => throw new RuntimeException(s"Unsupported got $arg")
11+
}
12+
13+
@main def Test =
14+
val result = get(null)

0 commit comments

Comments
 (0)