Skip to content

Commit 24463aa

Browse files
committed
less eager dealiasing of type aliases
1 parent 732ad27 commit 24463aa

32 files changed

+212
-62
lines changed

compiler/src/dotty/tools/dotc/config/Config.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,10 @@ object Config {
174174

175175
/** If this flag is on, always rewrite an application `S[Ts]` where `S` is an alias for
176176
* `[Xs] -> U` to `[Xs := Ts]U`.
177-
* Turning this flag on was observed to give a ~6% speedup on the JUnit test suite.
177+
* Turning this flag on was observed to give a ~6% speedup on the JUnit test suite
178+
* but over-eagerly dealiases type aliases.
178179
*/
179-
inline val simplifyApplications = true
180+
inline val simplifyApplications = false
180181

181182
/** Assume -indent by default */
182183
inline val defaultIndent = true

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
443443
* of the parameter elsewhere in the constraint by type `tp`.
444444
*/
445445
def replace(param: TypeParamRef, tp: Type)(using Context): OrderingConstraint =
446-
val replacement = tp.dealiasKeepAnnots.stripTypeVar
446+
val replacement = tp.stripTypeVar
447447
if param == replacement then this.checkNonCyclic()
448448
else
449449
assert(replacement.isValueTypeOrLambda)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ class TypeApplications(val self: Type) extends AnyVal {
329329
case dealiased: HKTypeLambda =>
330330
def tryReduce =
331331
if (!args.exists(isBounds)) {
332-
val followAlias = Config.simplifyApplications && {
332+
val followAlias = (Config.simplifyApplications || self.typeSymbol.isPrivate) && {
333333
dealiased.resType match {
334334
case AppliedType(tyconBody, dealiasedArgs) =>
335335
// Reduction should not affect type inference when it's

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,25 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
407407
case tp1: NamedType =>
408408
tp1.info match {
409409
case info1: TypeAlias =>
410-
if (recur(info1.alias, tp2)) return true
410+
def realiasConstraint() = tp2 match {
411+
case tp2: TypeParamRef =>
412+
constraint.entry(tp2) match {
413+
case TypeBounds(lo, hi) =>
414+
val aliasLo = tp1 != lo && info1.alias == lo
415+
val aliasHi = tp1 != hi && info1.alias == hi
416+
if aliasLo || aliasHi then
417+
constraint = constraint.updateEntry(tp2, TypeBounds(
418+
if aliasLo then tp1 else lo,
419+
if aliasHi then tp1 else hi))
420+
case tp =>
421+
if tp1 != tp && info1.alias == tp then
422+
constraint = constraint.updateEntry(tp2, tp1)
423+
}
424+
case _ =>
425+
}
426+
val res = recur(info1.alias, tp2)
427+
if (tp1.symbol.isStatic) realiasConstraint()
428+
if (res) return true
411429
if (tp1.prefix.isStable) return tryLiftedToThis1
412430
case _ =>
413431
if (tp1 eq NothingType) || isBottom(tp1) then return true

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ object TypeOps:
423423
override def apply(tp: Type): Type = tp match
424424
case tp: TermRef
425425
if toAvoid(tp) =>
426-
tp.info.widenExpr.dealias match {
426+
tp.info.widenExpr match {
427427
case info: SingletonType => apply(info)
428428
case info => range(defn.NothingType, apply(info))
429429
}

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

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,11 +1304,11 @@ object Types {
13041304
case tp =>
13051305
tp
13061306

1307-
/** Widen all top-level singletons reachable by dealiasing
1308-
* and going to the operands of & and |.
1307+
/** Widen all top-level singletons reachable
1308+
* by going to the operands of & and |.
13091309
* Overridden and cached in OrType.
13101310
*/
1311-
def widenSingletons(using Context): Type = dealias match {
1311+
def widenSingletons(using Context): Type = this match {
13121312
case tp: SingletonType =>
13131313
tp.widen
13141314
case tp: OrType =>
@@ -1856,11 +1856,11 @@ object Types {
18561856
case _ => this
18571857
}
18581858

1859-
/** The set of distinct symbols referred to by this type, after all aliases are expanded */
1859+
/** The set of distinct symbols referred to by this type */
18601860
def coveringSet(using Context): Set[Symbol] =
18611861
(new CoveringSetAccumulator).apply(Set.empty[Symbol], this)
18621862

1863-
/** The number of applications and refinements in this type, after all aliases are expanded */
1863+
/** The number of applications and refinements in this type */
18641864
def typeSize(using Context): Int =
18651865
(new TypeSizeAccumulator).apply(0, this)
18661866

@@ -6178,11 +6178,12 @@ object Types {
61786178

61796179
class TypeSizeAccumulator(using Context) extends TypeAccumulator[Int] {
61806180
var seen = util.HashSet[Type](initialCapacity = 8)
6181-
def apply(n: Int, tp: Type): Int =
6182-
if seen.contains(tp) then n
6181+
def apply(n: Int, tp1: Type): Int =
6182+
val tp0 = tp1.dealias
6183+
if seen.contains(tp0) then n
61836184
else {
6184-
seen += tp
6185-
tp match {
6185+
seen += tp0
6186+
tp0 match {
61866187
case tp: AppliedType =>
61876188
foldOver(n + 1, tp)
61886189
case tp: RefinedType =>
@@ -6192,23 +6193,24 @@ object Types {
61926193
case tp: TypeParamRef =>
61936194
apply(n, TypeComparer.bounds(tp))
61946195
case _ =>
6195-
foldOver(n, tp)
6196+
foldOver(n, tp0)
61966197
}
61976198
}
61986199
}
61996200

62006201
class CoveringSetAccumulator(using Context) extends TypeAccumulator[Set[Symbol]] {
62016202
var seen = util.HashSet[Type](initialCapacity = 8)
6202-
def apply(cs: Set[Symbol], tp: Type): Set[Symbol] =
6203-
if seen.contains(tp) then cs
6203+
def apply(cs: Set[Symbol], tp1: Type): Set[Symbol] =
6204+
val tp0 = tp1.dealias
6205+
if seen.contains(tp0) then cs
62046206
else {
6205-
seen += tp
6206-
tp match {
6207+
seen += tp0
6208+
tp0 match {
62076209
case tp if tp.isExactlyAny || tp.isExactlyNothing =>
62086210
cs
6209-
case tp: AppliedType =>
6211+
case tp: AppliedType if !tp.typeSymbol.isAliasType =>
62106212
foldOver(cs + tp.typeSymbol, tp)
6211-
case tp: RefinedType =>
6213+
case tp: RefinedType if !tp.typeSymbol.isAliasType =>
62126214
foldOver(cs + tp.typeSymbol, tp)
62136215
case tp: TypeRef if tp.info.isTypeAlias =>
62146216
apply(cs, tp.superType)
@@ -6220,7 +6222,7 @@ object Types {
62206222
case tp: TypeParamRef =>
62216223
apply(cs, TypeComparer.bounds(tp))
62226224
case other =>
6223-
foldOver(cs, tp)
6225+
foldOver(cs, tp0)
62246226
}
62256227
}
62266228
}

compiler/src/dotty/tools/dotc/util/Signatures.scala

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,18 +105,20 @@ object Signatures {
105105
ctx.definitions.isTupleClass(tree.symbol.owner.companionClass)
106106

107107
private def extractParamTypess(resultType: Type)(using Context): List[List[Type]] =
108-
resultType match {
108+
resultType.dealias match {
109109
// Reference to a type which is not a type class
110110
case ref: TypeRef if !ref.symbol.isPrimitiveValueClass =>
111111
getExtractorMembers(ref)
112112
// Option or Some applied type. There is special syntax for multiple returned arguments:
113113
// Option[TupleN] and Option[Seq],
114-
// We are not intrested in them, instead we extract proper type parameters from the Option type parameter.
115-
case AppliedType(TypeRef(_, cls), (appliedType @ AppliedType(tycon, args)) :: Nil)
116-
if (cls == ctx.definitions.OptionClass || cls == ctx.definitions.SomeClass) =>
117-
tycon match
118-
case TypeRef(_, cls) if cls == ctx.definitions.SeqClass => List(List(appliedType))
119-
case _ => List(args)
114+
// We are not interested in them, instead we extract proper type parameters from the Option type parameter.
115+
case AppliedType(TypeRef(_, cls), (appliedType @ AppliedType(_, args)) :: Nil)
116+
if cls == ctx.definitions.OptionClass || cls == ctx.definitions.SomeClass =>
117+
appliedType.dealias match
118+
case appliedType @ AppliedType(TypeRef(_, cls), args) =>
119+
if cls == ctx.definitions.SeqClass then List(List(appliedType)) else List(args)
120+
case _ =>
121+
List(args)
120122
// Applied type extractor. We must extract from applied type to retain type parameters
121123
case appliedType: AppliedType => getExtractorMembers(appliedType)
122124
// This is necessary to extract proper result type as unapply can return other methods eg. apply

compiler/test-resources/repl/i5177

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
scala> class A[T]
2+
// defined class A
3+
scala> type B[T] = A[T]
4+
// defined alias type B[T] = A[T]
5+
scala> def b: B[String] = ???
6+
def b: B[String]
7+
scala> class C
8+
// defined class C
9+
scala> type D = C
10+
// defined alias type D = C
11+
scala> def d: D = ???
12+
def d: D

scaladoc/test/dotty/tools/scaladoc/ExternalLocationProviderIntegrationTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class Scaladoc3ExternalLocationProviderIntegrationTest extends ExternalLocationP
4747
".*externalStubs.*::scaladoc3::https://external.stubs/api/"
4848
),
4949
List(
50-
"https://dotty.epfl.ch/api/scala/collection/immutable/Map.html",
50+
"https://dotty.epfl.ch/api/scala/Predef$.html#Map-0",
5151
"https://dotty.epfl.ch/api/scala/Predef$.html#String-0",
5252
"https://dotty.epfl.ch/api/scala/util/matching/Regex$$Match.html",
5353
"https://external.stubs/api/tests/externalStubs/$div$bslash$.html",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
trait Iterable[T]
2+
3+
@deprecated type Traversable[T] = Iterable[T]
4+
5+
def test: Traversable[Int] = ??? // error

tests/neg-macros/i6997.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ import scala.quoted.*
33
class Foo {
44
def mcrImpl(body: Expr[Any])(using t: Type[_ <: Any])(using ctx: Quotes): Expr[Any] = '{
55
val tmp = ???.asInstanceOf[t.Underlying] // error // error
6-
tmp
6+
tmp // error
77
}
88
}

tests/neg/12974.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ object RecMap {
2525

2626
val foo: Any = Rec.empty.fetch("foo") // error
2727
// ^
28-
// Match type reduction failed since selector EmptyTuple.type
28+
// Match type reduction failed since selector EmptyTuple
2929
// matches none of the cases
3030
//
3131
// case (("foo" : String), t) *: _ => t

tests/neg/i12049.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
-- Error: tests/neg/i12049.scala:14:23 ---------------------------------------------------------------------------------
1919
14 |val y3: String = ??? : Last[Int *: Int *: Boolean *: String *: EmptyTuple] // error
2020
| ^
21-
| Match type reduction failed since selector EmptyTuple.type
21+
| Match type reduction failed since selector EmptyTuple
2222
| matches none of the cases
2323
|
2424
| case _ *: _ *: t => Last[t]
@@ -48,7 +48,7 @@
4848
-- Error: tests/neg/i12049.scala:25:26 ---------------------------------------------------------------------------------
4949
25 |val _ = summon[String =:= Last[Int *: Int *: Boolean *: String *: EmptyTuple]] // error
5050
| ^
51-
| Match type reduction failed since selector EmptyTuple.type
51+
| Match type reduction failed since selector EmptyTuple
5252
| matches none of the cases
5353
|
5454
| case _ *: _ *: t => Last[t]

tests/neg/i4565.check

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
-- [E007] Type Mismatch Error: tests/neg/i4565.scala:17:13 -------------------------------------------------------------
2+
17 |def b: Int = a // error
3+
| ^
4+
| Found: Test1[F[Int, String]]
5+
| Required: Int
6+
|
7+
| longer explanation available when compiling with `-explain`
8+
-- [E007] Type Mismatch Error: tests/neg/i4565.scala:20:13 -------------------------------------------------------------
9+
20 |def d: Int = c // error
10+
| ^
11+
| Found: F[Int, String]
12+
| Required: Int
13+
|
14+
| longer explanation available when compiling with `-explain`
15+
-- [E007] Type Mismatch Error: tests/neg/i4565.scala:23:13 -------------------------------------------------------------
16+
23 |def f: Int = e // error
17+
| ^
18+
| Found: F[Int, String]
19+
| Required: Int
20+
|
21+
| longer explanation available when compiling with `-explain`
22+
-- [E007] Type Mismatch Error: tests/neg/i4565.scala:26:13 -------------------------------------------------------------
23+
26 |def h: Int = g // error
24+
| ^
25+
| Found: Test1[B]
26+
| Required: Int
27+
|
28+
| longer explanation available when compiling with `-explain`
29+
-- [E007] Type Mismatch Error: tests/neg/i4565.scala:29:13 -------------------------------------------------------------
30+
29 |def j: Int = i // error
31+
| ^
32+
| Found: Test2[B]
33+
| Required: Int
34+
|
35+
| longer explanation available when compiling with `-explain`
36+
-- [E007] Type Mismatch Error: tests/neg/i4565.scala:32:13 -------------------------------------------------------------
37+
32 |def l: Int = k // error
38+
| ^
39+
| Found: Test3[B]
40+
| Required: Int
41+
|
42+
| longer explanation available when compiling with `-explain`
43+
-- [E007] Type Mismatch Error: tests/neg/i4565.scala:35:13 -------------------------------------------------------------
44+
35 |def n: Int = m // error
45+
| ^
46+
| Found: MyAlias
47+
| Required: Int
48+
|
49+
| longer explanation available when compiling with `-explain`

tests/neg/i4565.scala

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
type F[A, B] = A => B
2+
3+
type LongComplictedType
4+
type B = LongComplictedType
5+
6+
case class Test1[T](v: T)
7+
case class Test2[T <: B](v: T)
8+
case class Test3[T <: LongComplictedType](v: T)
9+
10+
class MyClass
11+
type MyAlias = MyClass
12+
13+
14+
// these tests check that the inferred types are not dealiased
15+
16+
def a = Test1(??? : F[Int, String])
17+
def b: Int = a // error
18+
19+
def c: F[Int, String] = ???
20+
def d: Int = c // error
21+
22+
def e = { val v = ??? : F[Int, String]; v }
23+
def f: Int = e // error
24+
25+
def g = Test1(??? : B)
26+
def h: Int = g // error
27+
28+
def i = Test2(??? : B)
29+
def j: Int = i // error
30+
31+
def k = Test3(??? : B)
32+
def l: Int = k // error
33+
34+
def m: MyAlias = new MyClass
35+
def n: Int = m // error

tests/pos/i14171.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
object Test1:
2+
trait MyTypeclass[F[_]]
3+
def f[F[_]: MyTypeclass, U](t: F[U]) = ???
4+
5+
type MyType[T] = String
6+
given MyTypeclass[MyType] = ???
7+
8+
val stream: Option[MyType[Int]] = ???
9+
for
10+
keyStream <- stream
11+
x = 17
12+
yield f(keyStream)
13+
14+
15+
object Test2:
16+
trait MyTypeclass[F[_]]
17+
def f[F[_]: MyTypeclass, U](t: F[U]) = ???
18+
19+
type MyType[T] = Nil.type
20+
given MyTypeclass[MyType] = ???
21+
22+
val stream: Option[MyType[Int]] = ???
23+
for
24+
keyStream <- stream
25+
x = 17
26+
yield f(keyStream)

tests/printing/i13306.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ package example {
88
final module class Exports() extends Object() { this: example.Exports.type =>
99
val instance: example.MembersContainer = new example.MembersContainer()
1010
export example.Exports.instance.*
11-
final type MyType[T <: example.MyClass] = Comparable[T]
11+
final type MyType[T <: example.MyClass] = example.Exports.instance.MyType[T]
1212
}
1313
}
1414

tests/run-macros/i10863.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
[A >: scala.Nothing <: scala.Any] => scala.collection.immutable.List[A]
1+
scala.List

tests/run-macros/quote-matching-optimize-3.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ Optimized: ls.foreach[scala.Any](((x: scala.Int) => if (((`x₂`: scala.Int) =>
1717
Result: ()
1818

1919
Original: ls.map[scala.Long](((a: scala.Int) => a.toLong)).map[java.lang.String](((b: scala.Long) => b.toString()))
20-
Optimized: ls.map[java.lang.String](((x: scala.Int) => ((b: scala.Long) => b.toString()).apply(((a: scala.Int) => a.toLong).apply(x))))
20+
Optimized: ls.map[scala.Predef.String](((x: scala.Int) => ((b: scala.Long) => b.toString()).apply(((a: scala.Int) => a.toLong).apply(x))))
2121
Result: List(1, 2, 3)
2222

2323
Original: ls.map[scala.Char](((a: scala.Int) => a.toChar)).map[java.lang.String](((b: scala.Char) => b.toString()))
24-
Optimized: ls.map[java.lang.String](((x: scala.Int) => ((b: scala.Char) => b.toString()).apply(((a: scala.Int) => a.toChar).apply(x))))
24+
Optimized: ls.map[scala.Predef.String](((x: scala.Int) => ((b: scala.Char) => b.toString()).apply(((a: scala.Int) => a.toChar).apply(x))))
2525
Result: List(, , )
2626

tests/run-macros/quote-type-matcher.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ Scrutinee: scala.Int
1010
Pattern: 2
1111
Result: None
1212

13-
Scrutinee: scala.collection.immutable.List[scala.Int]
14-
Pattern: scala.collection.immutable.List[scala.Int]
13+
Scrutinee: scala.List[scala.Int]
14+
Pattern: scala.List[scala.Int]
1515
Result: Some(List())
1616

17-
Scrutinee: scala.collection.immutable.List[scala.Int]
18-
Pattern: scala.collection.immutable.List[scala.Double]
17+
Scrutinee: scala.List[scala.Int]
18+
Pattern: scala.List[scala.Double]
1919
Result: None
2020

0 commit comments

Comments
 (0)