Skip to content

Commit

Permalink
Initial split
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Jun 5, 2023
1 parent d0b790e commit b78bdde
Show file tree
Hide file tree
Showing 8 changed files with 1,440 additions and 18 deletions.
1,392 changes: 1,392 additions & 0 deletions compiler/src/dotty/tools/dotc/core/GadtTypeComparer.scala

Large diffs are not rendered by default.

24 changes: 14 additions & 10 deletions compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@ import Decorators._
import Symbols._
import Types._
import Flags._
import Contexts.ctx
import Contexts.*
import dotty.tools.dotc.reporting.trace
import config.Feature.migrateTo3
import config.Printers._

trait PatternTypeConstrainer { self: TypeComparer =>
trait PatternTypeConstrainer {
protected given given_Context[DummySoItsADef]: Context

protected def either(op1: => Boolean, op2: => Boolean): Boolean
protected def isSubType(tp1: Type, tp2: Type): Boolean

protected def rollbackUnless(op: => Boolean): Boolean

/** Derive type and GADT constraints that necessarily follow from a pattern with the given type matching
* a scrutinee of the given type.
Expand Down Expand Up @@ -73,7 +79,7 @@ trait PatternTypeConstrainer { self: TypeComparer =>
* scrutinee and pattern types. This does not apply if the pattern type is only applied to type variables,
* in which case the subtyping relationship "heals" the type.
*/
def constrainPatternType(pat: Type, scrut: Type, forceInvariantRefinement: Boolean = false): Boolean = trace(i"constrainPatternType($scrut, $pat)", gadts) {
def constrainPatternType(pat: Type, scrut: Type, forceInvariantRefinement: Boolean = false): Boolean = trace(i"constrainPatternType($pat, $scrut)", gadts) {

def classesMayBeCompatible: Boolean = {
import Flags._
Expand Down Expand Up @@ -230,7 +236,8 @@ trait PatternTypeConstrainer { self: TypeComparer =>
* case classes without also appropriately extending the relevant case class
* (see `RefChecks#checkCaseClassInheritanceInvariant`).
*/
def constrainSimplePatternType(patternTp: Type, scrutineeTp: Type, forceInvariantRefinement: Boolean): Boolean = {
private def constrainSimplePatternType(patternTp: Type, scrutineeTp: Type, forceInvariantRefinement: Boolean): Boolean =
trace(i"constrainSimplePatternType($patternTp, $scrutineeTp, forceInvariantRefinement=$forceInvariantRefinement)") {
def refinementIsInvariant(tp: Type): Boolean = tp match {
case tp: SingletonType => true
case tp: ClassInfo => tp.cls.is(Final) || tp.cls.is(Case)
Expand Down Expand Up @@ -261,11 +268,10 @@ trait PatternTypeConstrainer { self: TypeComparer =>
val assumeInvariantRefinement =
migrateTo3 || forceInvariantRefinement || refinementIsInvariant(patternTp)

trace(i"constraining simple pattern type $tp >:< $pt", gadts, (res: Boolean) => i"$res gadt = ${ctx.gadt}") {
trace(i"constraining simple pattern type $tp >:< $pt assumeInvariantRefinement=$assumeInvariantRefinement", gadts, (res: Boolean) => i"$res gadt = ${ctx.gadt}") {
(tp, pt) match {
case (AppliedType(tyconS, argsS), AppliedType(tyconP, argsP)) =>
val saved = state.nn.constraint
val result =
rollbackUnless {
ctx.gadtState.rollbackGadtUnless {
tyconS.typeParams.lazyZip(argsS).lazyZip(argsP).forall { (param, argS, argP) =>
val variance = param.paramVarianceSign
Expand All @@ -283,9 +289,7 @@ trait PatternTypeConstrainer { self: TypeComparer =>
else true
}
}
if !result then
constraint = saved
result
}
case _ =>
// Give up if we don't get AppliedType, e.g. if we upcasted to Any.
// Note that this doesn't mean that patternTp, scrutineeTp cannot possibly
Expand Down
13 changes: 10 additions & 3 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import cc.{CapturingType, derivedCapturingType, CaptureSet, stripCapturing, isBo

/** Provides methods to compare types.
*/
class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling, PatternTypeConstrainer {
class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling {
import TypeComparer._
Stats.record("TypeComparer")

Expand All @@ -49,6 +49,13 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
needsGc = false
if Config.checkTypeComparerReset then checkReset()

protected def rollbackUnless(op: => Boolean): Boolean =
val saved = constraint
var success = false
try success = op
finally if !success then constraint = saved
success

private var pendingSubTypes: util.MutableSet[(Type, Type)] | Null = null
private var recCount = 0
private var monitored = false
Expand Down Expand Up @@ -2891,7 +2898,7 @@ object TypeComparer {
case OK, Fail, OKwithGADTUsed

/** Class for unification variables used in `natValue`. */
private class AnyConstantType extends UncachedGroundType with ValueType {
final class AnyConstantType extends UncachedGroundType with ValueType {
var tpe: Type = NoType
}

Expand Down Expand Up @@ -3034,7 +3041,7 @@ object TypeComparer {
comparing(_.dropTransparentTraits(tp, bound))

def constrainPatternType(pat: Type, scrut: Type, forceInvariantRefinement: Boolean = false)(using Context): Boolean =
comparing(_.constrainPatternType(pat, scrut, forceInvariantRefinement))
GadtTypeComparer(ctx).constrainPatternType(pat, scrut, forceInvariantRefinement)

def explained[T](op: ExplainingTypeComparer => T, header: String = "Subtype trace:")(using Context): String =
comparing(_.explained(op, header))
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4797,7 +4797,7 @@ object Types {
def instantiateWith(tp: Type)(using Context): Type = {
assert(tp ne this, i"self instantiation of $origin, constraint = ${ctx.typerState.constraint}")
assert(!myInst.exists, i"$origin is already instantiated to $myInst but we attempted to instantiate it to $tp")
typr.println(i"instantiating $this with $tp")
//println(i"instantiating $this with $tp")

if Config.checkConstraintsSatisfiable then
assert(currentEntry.bounds.contains(tp),
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ object TypeTestsCasts {
// If we perform widening, we will get X = Nothing, and we don't have
// Ident[X] <:< Ident[Int] any more.
TypeComparer.constrainPatternType(P1, X, forceInvariantRefinement = true)
debug.println(
TypeComparer.explained(_.constrainPatternType(P1, X, forceInvariantRefinement = true))
)
//debug.println(
// TypeComparer.explained(_.constrainPatternType(P1, X, forceInvariantRefinement = true))
//)
}

// Maximization of the type means we try to cover all possible values
Expand Down
11 changes: 11 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1417,8 +1417,19 @@ trait Applications extends Compatibility {
// We ignore whether constraining the pattern succeeded.
// Constraining only fails if the pattern cannot possibly match,
// but useless pattern checks detect more such cases, so we simply rely on them instead.
var c, c2 = ctx.typerState.constraint
var g, g2 = ctx.gadt
def pp(s: String) =
//println(s)
c2 = ctx.typerState.constraint
g2 = ctx.gadt
//if c2 != c then { c = c2; println(i"$c") }
//if g2 != g then { g = g2; println(i"$g") }
pp(i"inp: $unapplyArgType vs scrut $selType")
withMode(Mode.GadtConstraintInference)(TypeComparer.constrainPatternType(unapplyArgType, selType))
pp(i"cpt: $unapplyArgType vs scrut $selType")
val patternBound = maximizeType(unapplyArgType, unapplyFn.span.endPos)
pp(i"max: $unapplyArgType vs scrut $selType")
if (patternBound.nonEmpty) unapplyFn = addBinders(unapplyFn, patternBound)
unapp.println(i"case 2 $unapplyArgType ${ctx.typerState.constraint}")
unapplyArgType
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1847,7 +1847,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
else report.error(new DuplicateBind(b, cdef), b.srcPos)
if (!ctx.isAfterTyper) {
val bounds = ctx.gadt.fullBounds(sym)
if (bounds != null) sym.info = bounds
if (bounds != null)
//println(i"changing sym $sym info from ${sym.info} to $bounds ${bounds.className} ${bounds}")
sym.info = bounds
}
b
case t: UnApply if t.symbol.is(Inline) => Inlines.inlinedUnapply(t)
Expand Down
6 changes: 6 additions & 0 deletions tests/pos/basic-unapply-tvar.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
sealed trait Foo[X]
final case class Bar[Y](value: Y) extends Foo[Y]

class Test:
def test[T](foo: Foo[T]): T = foo match
case Bar/*[?Y]*/(value) => value

0 comments on commit b78bdde

Please sign in to comment.