Skip to content

Commit

Permalink
Move logic under feature.experimental.betterMatchTypesExtractors
Browse files Browse the repository at this point in the history
This way we can merge this PR without waiting for the SIP committee to approve
it.
  • Loading branch information
smarter committed May 5, 2024
1 parent 45975e9 commit 9f5fc2e
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 45 deletions.
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/config/Feature.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ object Feature:
val pureFunctions = experimental("pureFunctions")
val captureChecking = experimental("captureChecking")
val into = experimental("into")
val betterMatchTypeExtractors = experimental("betterMatchTypeExtractors")

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

def scala2ExperimentalMacroEnabled(using Context) = enabled(scala2macros)

def betterMatchTypeExtractorsEnabled(using Context) = enabled(betterMatchTypeExtractors)

/** Is pureFunctions enabled for this compilation unit? */
def pureFunsEnabled(using Context) =
enabledBySetting(pureFunctions)
Expand Down
11 changes: 8 additions & 3 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import TypeOps.refineUsingParent
import collection.mutable
import util.{Stats, NoSourcePosition, EqHashMap}
import config.Config
import config.Feature.{migrateTo3, sourceVersion}
import config.Feature.{betterMatchTypeExtractorsEnabled, migrateTo3, sourceVersion}
import config.Printers.{subtyping, gadts, matchTypes, noPrinter}
import config.SourceVersion
import TypeErasure.{erasedLub, erasedGlb}
Expand Down Expand Up @@ -3519,6 +3519,11 @@ class MatchReducer(initctx: Context) extends TypeComparer(initctx) {

case MatchTypeCasePattern.TypeMemberExtractor(typeMemberName, capture) =>
/** Try to remove references to `skolem` from a type in accordance with the spec.
*
* If `betterMatchTypeExtractorsEnabled` is enabled then references
* to `skolem` occuring are avoided by following aliases and
* singletons, otherwise no attempt made to avoid references to
* `skolem`.
*
* If any reference to `skolem` remains in the result type,
* `refersToSkolem` is set to true.
Expand All @@ -3530,7 +3535,7 @@ class MatchReducer(initctx: Context) extends TypeComparer(initctx) {
case `skolem` =>
refersToSkolem = true
tp
case tp: NamedType =>
case tp: NamedType if betterMatchTypeExtractorsEnabled =>
var savedRefersToSkolem = refersToSkolem
refersToSkolem = false
try
Expand All @@ -3553,7 +3558,7 @@ class MatchReducer(initctx: Context) extends TypeComparer(initctx) {
tp.derivedSelect(pre1)
finally
refersToSkolem |= savedRefersToSkolem
case tp: LazyRef =>
case tp: LazyRef if betterMatchTypeExtractorsEnabled =>
// By default, TypeMap maps LazyRefs lazily. We need to
// force it for `refersToSkolem` to be correctly set.
apply(tp.ref)
Expand Down
7 changes: 7 additions & 0 deletions library/src/scala/runtime/stdLibPatches/language.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ object language:
@compileTimeOnly("`relaxedExtensionImports` can only be used at compile time in import statements")
@deprecated("The experimental.relaxedExtensionImports language import is no longer needed since the feature is now standard", since = "3.4")
object relaxedExtensionImports

/** Enhance match type extractors to follow aliases and singletons.
*
* @see [[https://github.com/scala/improvement-proposals/pull/84]]
*/
@compileTimeOnly("`betterMatchTypeExtractors` can only be used at compile time in import statements")
object betterMatchTypeExtractors
end experimental

/** The deprecated object contains features that are no longer officially suypported in Scala.
Expand Down
60 changes: 60 additions & 0 deletions tests/neg/mt-deskolemize-2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//> using options -language:experimental.betterMatchTypeExtractors

trait Expr:
type Value
object Expr:
type Of[V] = Expr { type Value = V }
type ExtractValue[F <: Expr] = F match
case Expr.Of[v] => v
import Expr.ExtractValue

class SimpleLoop1 extends Expr:
type Value = ExtractValue[SimpleLoop2]

class SimpleLoop2 extends Expr:
type Value = ExtractValue[SimpleLoop1]

object Test1:
val x: ExtractValue[SimpleLoop1] = 1 // error

trait Description:
type Elem <: Tuple

class PrimBroken extends Expr:
type Value = Alias
type Alias = Value // error

class Prim extends Expr:
type Value = BigInt

class VecExpr[E <: Expr] extends Expr:
type Value = Vector[ExtractValue[E]]

trait ProdExpr extends Expr:
val description: Description
type Value = Tuple.Map[description.Elem, [X] =>> ExtractValue[X & Expr]]


class MyExpr1 extends ProdExpr:
final val description = new Description:
type Elem = (VecExpr[Prim], MyExpr2)

class MyExpr2 extends ProdExpr:
final val description = new Description:
type Elem = (VecExpr[VecExpr[MyExpr1]], Prim)

trait Constable[E <: Expr]:
def lit(v: ExtractValue[E]): E
object Constable:
given [E <: Expr]: Constable[E] = ???

object Test2:
def fromLiteral[E <: Expr : Constable](v: ExtractValue[E]): E =
summon[Constable[E]].lit(v)
val x0: ExtractValue[Prim] = "" // error
val x1: ExtractValue[PrimBroken] = 1 // error

val foo: MyExpr2 = new MyExpr2
val v: foo.Value = (Vector(Vector()), 1) // error: Recursion limit exceeded
val c: MyExpr2 = fromLiteral:
(Vector(Vector()), 1) // error: Recursion limit exceeded
42 changes: 0 additions & 42 deletions tests/neg/mt-deskolemize.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,45 +14,3 @@ class SimpleLoop2 extends Expr:

object Test1:
val x: ExtractValue[SimpleLoop1] = 1 // error

trait Description:
type Elem <: Tuple

class PrimBroken extends Expr:
type Value = Alias
type Alias = Value // error

class Prim extends Expr:
type Value = BigInt

class VecExpr[E <: Expr] extends Expr:
type Value = Vector[ExtractValue[E]]

trait ProdExpr extends Expr:
val description: Description
type Value = Tuple.Map[description.Elem, [X] =>> ExtractValue[X & Expr]]


class MyExpr1 extends ProdExpr:
final val description = new Description:
type Elem = (VecExpr[Prim], MyExpr2)

class MyExpr2 extends ProdExpr:
final val description = new Description:
type Elem = (VecExpr[VecExpr[MyExpr1]], Prim)

trait Constable[E <: Expr]:
def lit(v: ExtractValue[E]): E
object Constable:
given [E <: Expr]: Constable[E] = ???

object Test2:
def fromLiteral[E <: Expr : Constable](v: ExtractValue[E]): E =
summon[Constable[E]].lit(v)
val x0: ExtractValue[Prim] = "" // error
val x1: ExtractValue[PrimBroken] = 1 // error

val foo: MyExpr2 = new MyExpr2
val v: foo.Value = (Vector(Vector()), 1) // error: Recursion limit exceeded
val c: MyExpr2 = fromLiteral:
(Vector(Vector()), 1) // error: Recursion limit exceeded
2 changes: 2 additions & 0 deletions tests/pos/mt-deskolemize.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//> using options -language:experimental.betterMatchTypeExtractors

trait Expr:
type Value

Expand Down

0 comments on commit 9f5fc2e

Please sign in to comment.