Skip to content

Commit 9f5fc2e

Browse files
committed
Move logic under feature.experimental.betterMatchTypesExtractors
This way we can merge this PR without waiting for the SIP committee to approve it.
1 parent 45975e9 commit 9f5fc2e

File tree

6 files changed

+80
-45
lines changed

6 files changed

+80
-45
lines changed

Diff for: compiler/src/dotty/tools/dotc/config/Feature.scala

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ object Feature:
3333
val pureFunctions = experimental("pureFunctions")
3434
val captureChecking = experimental("captureChecking")
3535
val into = experimental("into")
36+
val betterMatchTypeExtractors = experimental("betterMatchTypeExtractors")
3637

3738
def experimentalAutoEnableFeatures(using Context): List[TermName] =
3839
defn.languageExperimentalFeatures
@@ -87,6 +88,8 @@ object Feature:
8788

8889
def scala2ExperimentalMacroEnabled(using Context) = enabled(scala2macros)
8990

91+
def betterMatchTypeExtractorsEnabled(using Context) = enabled(betterMatchTypeExtractors)
92+
9093
/** Is pureFunctions enabled for this compilation unit? */
9194
def pureFunsEnabled(using Context) =
9295
enabledBySetting(pureFunctions)

Diff for: compiler/src/dotty/tools/dotc/core/TypeComparer.scala

+8-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import TypeOps.refineUsingParent
1010
import collection.mutable
1111
import util.{Stats, NoSourcePosition, EqHashMap}
1212
import config.Config
13-
import config.Feature.{migrateTo3, sourceVersion}
13+
import config.Feature.{betterMatchTypeExtractorsEnabled, migrateTo3, sourceVersion}
1414
import config.Printers.{subtyping, gadts, matchTypes, noPrinter}
1515
import config.SourceVersion
1616
import TypeErasure.{erasedLub, erasedGlb}
@@ -3519,6 +3519,11 @@ class MatchReducer(initctx: Context) extends TypeComparer(initctx) {
35193519

35203520
case MatchTypeCasePattern.TypeMemberExtractor(typeMemberName, capture) =>
35213521
/** Try to remove references to `skolem` from a type in accordance with the spec.
3522+
*
3523+
* If `betterMatchTypeExtractorsEnabled` is enabled then references
3524+
* to `skolem` occuring are avoided by following aliases and
3525+
* singletons, otherwise no attempt made to avoid references to
3526+
* `skolem`.
35223527
*
35233528
* If any reference to `skolem` remains in the result type,
35243529
* `refersToSkolem` is set to true.
@@ -3530,7 +3535,7 @@ class MatchReducer(initctx: Context) extends TypeComparer(initctx) {
35303535
case `skolem` =>
35313536
refersToSkolem = true
35323537
tp
3533-
case tp: NamedType =>
3538+
case tp: NamedType if betterMatchTypeExtractorsEnabled =>
35343539
var savedRefersToSkolem = refersToSkolem
35353540
refersToSkolem = false
35363541
try
@@ -3553,7 +3558,7 @@ class MatchReducer(initctx: Context) extends TypeComparer(initctx) {
35533558
tp.derivedSelect(pre1)
35543559
finally
35553560
refersToSkolem |= savedRefersToSkolem
3556-
case tp: LazyRef =>
3561+
case tp: LazyRef if betterMatchTypeExtractorsEnabled =>
35573562
// By default, TypeMap maps LazyRefs lazily. We need to
35583563
// force it for `refersToSkolem` to be correctly set.
35593564
apply(tp.ref)

Diff for: library/src/scala/runtime/stdLibPatches/language.scala

+7
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ object language:
9898
@compileTimeOnly("`relaxedExtensionImports` can only be used at compile time in import statements")
9999
@deprecated("The experimental.relaxedExtensionImports language import is no longer needed since the feature is now standard", since = "3.4")
100100
object relaxedExtensionImports
101+
102+
/** Enhance match type extractors to follow aliases and singletons.
103+
*
104+
* @see [[https://github.com/scala/improvement-proposals/pull/84]]
105+
*/
106+
@compileTimeOnly("`betterMatchTypeExtractors` can only be used at compile time in import statements")
107+
object betterMatchTypeExtractors
101108
end experimental
102109

103110
/** The deprecated object contains features that are no longer officially suypported in Scala.

Diff for: tests/neg/mt-deskolemize-2.scala

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//> using options -language:experimental.betterMatchTypeExtractors
2+
3+
trait Expr:
4+
type Value
5+
object Expr:
6+
type Of[V] = Expr { type Value = V }
7+
type ExtractValue[F <: Expr] = F match
8+
case Expr.Of[v] => v
9+
import Expr.ExtractValue
10+
11+
class SimpleLoop1 extends Expr:
12+
type Value = ExtractValue[SimpleLoop2]
13+
14+
class SimpleLoop2 extends Expr:
15+
type Value = ExtractValue[SimpleLoop1]
16+
17+
object Test1:
18+
val x: ExtractValue[SimpleLoop1] = 1 // error
19+
20+
trait Description:
21+
type Elem <: Tuple
22+
23+
class PrimBroken extends Expr:
24+
type Value = Alias
25+
type Alias = Value // error
26+
27+
class Prim extends Expr:
28+
type Value = BigInt
29+
30+
class VecExpr[E <: Expr] extends Expr:
31+
type Value = Vector[ExtractValue[E]]
32+
33+
trait ProdExpr extends Expr:
34+
val description: Description
35+
type Value = Tuple.Map[description.Elem, [X] =>> ExtractValue[X & Expr]]
36+
37+
38+
class MyExpr1 extends ProdExpr:
39+
final val description = new Description:
40+
type Elem = (VecExpr[Prim], MyExpr2)
41+
42+
class MyExpr2 extends ProdExpr:
43+
final val description = new Description:
44+
type Elem = (VecExpr[VecExpr[MyExpr1]], Prim)
45+
46+
trait Constable[E <: Expr]:
47+
def lit(v: ExtractValue[E]): E
48+
object Constable:
49+
given [E <: Expr]: Constable[E] = ???
50+
51+
object Test2:
52+
def fromLiteral[E <: Expr : Constable](v: ExtractValue[E]): E =
53+
summon[Constable[E]].lit(v)
54+
val x0: ExtractValue[Prim] = "" // error
55+
val x1: ExtractValue[PrimBroken] = 1 // error
56+
57+
val foo: MyExpr2 = new MyExpr2
58+
val v: foo.Value = (Vector(Vector()), 1) // error: Recursion limit exceeded
59+
val c: MyExpr2 = fromLiteral:
60+
(Vector(Vector()), 1) // error: Recursion limit exceeded

Diff for: tests/neg/mt-deskolemize.scala

-42
Original file line numberDiff line numberDiff line change
@@ -14,45 +14,3 @@ class SimpleLoop2 extends Expr:
1414

1515
object Test1:
1616
val x: ExtractValue[SimpleLoop1] = 1 // error
17-
18-
trait Description:
19-
type Elem <: Tuple
20-
21-
class PrimBroken extends Expr:
22-
type Value = Alias
23-
type Alias = Value // error
24-
25-
class Prim extends Expr:
26-
type Value = BigInt
27-
28-
class VecExpr[E <: Expr] extends Expr:
29-
type Value = Vector[ExtractValue[E]]
30-
31-
trait ProdExpr extends Expr:
32-
val description: Description
33-
type Value = Tuple.Map[description.Elem, [X] =>> ExtractValue[X & Expr]]
34-
35-
36-
class MyExpr1 extends ProdExpr:
37-
final val description = new Description:
38-
type Elem = (VecExpr[Prim], MyExpr2)
39-
40-
class MyExpr2 extends ProdExpr:
41-
final val description = new Description:
42-
type Elem = (VecExpr[VecExpr[MyExpr1]], Prim)
43-
44-
trait Constable[E <: Expr]:
45-
def lit(v: ExtractValue[E]): E
46-
object Constable:
47-
given [E <: Expr]: Constable[E] = ???
48-
49-
object Test2:
50-
def fromLiteral[E <: Expr : Constable](v: ExtractValue[E]): E =
51-
summon[Constable[E]].lit(v)
52-
val x0: ExtractValue[Prim] = "" // error
53-
val x1: ExtractValue[PrimBroken] = 1 // error
54-
55-
val foo: MyExpr2 = new MyExpr2
56-
val v: foo.Value = (Vector(Vector()), 1) // error: Recursion limit exceeded
57-
val c: MyExpr2 = fromLiteral:
58-
(Vector(Vector()), 1) // error: Recursion limit exceeded

Diff for: tests/pos/mt-deskolemize.scala

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//> using options -language:experimental.betterMatchTypeExtractors
2+
13
trait Expr:
24
type Value
35

0 commit comments

Comments
 (0)