Skip to content

Commit

Permalink
Type ascribe trees that require opaque type usage
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Jun 29, 2023
1 parent 6acaf95 commit e55e139
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 15 deletions.
12 changes: 9 additions & 3 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
state = c.typerState
monitored = false
GADTused = false
opaquesUsed = false
recCount = 0
needsGc = false
if Config.checkTypeComparerReset then checkReset()
Expand All @@ -61,6 +62,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
/** Indicates whether the subtype check used GADT bounds */
private var GADTused: Boolean = false

/** Indicates whether the subtype check used opaque types */
private var opaquesUsed: Boolean = false

private var myInstance: TypeComparer = this
def currentInstance: TypeComparer = myInstance

Expand Down Expand Up @@ -142,8 +146,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling

def testSubType(tp1: Type, tp2: Type): CompareResult =
GADTused = false
opaquesUsed = false
if !topLevelSubType(tp1, tp2) then CompareResult.Fail
else if GADTused then CompareResult.OKwithGADTUsed
else if opaquesUsed then CompareResult.OKwithOpaquesUsed // we cast on GADTused, so handles if both are used
else CompareResult.OK

/** The current approximation state. See `ApproxState`. */
Expand Down Expand Up @@ -1472,12 +1478,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling

def tryLiftedToThis1: Boolean = {
val tp1a = liftToThis(tp1)
(tp1a ne tp1) && recur(tp1a, tp2)
(tp1a ne tp1) && recur(tp1a, tp2) && { opaquesUsed = true; true }
}

def tryLiftedToThis2: Boolean = {
val tp2a = liftToThis(tp2)
(tp2a ne tp2) && recur(tp1, tp2a)
(tp2a ne tp2) && recur(tp1, tp2a) && { opaquesUsed = true; true }
}

// begin recur
Expand Down Expand Up @@ -2924,7 +2930,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
object TypeComparer {

enum CompareResult:
case OK, Fail, OKwithGADTUsed
case OK, Fail, OKwithGADTUsed, OKwithOpaquesUsed

/** Class for unification variables used in `natValue`. */
private class AnyConstantType extends UncachedGroundType with ValueType {
Expand Down
17 changes: 5 additions & 12 deletions compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package dotty.tools.dotc
package dotty.tools
package dotc
package transform

import core.Names.Name
Expand Down Expand Up @@ -744,23 +745,15 @@ object TreeChecker {
override def adapt(tree: Tree, pt: Type, locked: TypeVars)(using Context): Tree = {
def isPrimaryConstructorReturn =
ctx.owner.isPrimaryConstructor && pt.isRef(ctx.owner.owner) && tree.tpe.isRef(defn.UnitClass)
def infoStr(tp: Type) = tp match {
case tp: TypeRef =>
val sym = tp.symbol
i"${sym.showLocated} with ${tp.designator}, flags = ${sym.flagsString}, underlying = ${tp.underlyingIterator.toList}%, %"
case _ =>
"??"
}
if (ctx.mode.isExpr &&
!tree.isEmpty &&
!isPrimaryConstructorReturn &&
!pt.isInstanceOf[FunOrPolyProto])
assert(tree.tpe <:< pt, {
val mismatch = TypeMismatch(tree.tpe, pt, Some(tree))
i"""|${mismatch.msg}
|found: ${infoStr(tree.tpe)}
|expected: ${infoStr(pt)}
|tree = $tree""".stripMargin
i"""Type Mismatch:
|${mismatch.message}
|tree = $tree ${tree.className}""".stripMargin
})
tree
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4062,6 +4062,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
res
} =>
insertGadtCast(tree, wtp, pt)
case CompareResult.OKwithOpaquesUsed if !tree.tpe.frozen_<:<(pt)(using ctx.withOwner(defn.RootClass)) =>
// guard to avoid extra Typed trees, eg. from testSubType(O.T, O.T) which returns OKwithOpaquesUsed
Typed(tree, TypeTree(pt))
case _ =>
//typr.println(i"OK ${tree.tpe}\n${TypeComparer.explained(_.isSubType(tree.tpe, pt))}") // uncomment for unexpected successes
tree
Expand Down
44 changes: 44 additions & 0 deletions tests/pos/i17948.all.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
object O:
opaque type T = Int

inline def get0: Int = Do.get // no proxy needed
inline def get1: Int = Do.get: O.T // no proxy needed
inline def get2: Int = Do.get: T // proxied

inline def set0: Unit = Do.set(0) // was: broken
inline def set1: Unit = Do.set(1: O.T) // no proxy needed
inline def set2: Unit = Do.set(2: T) // proxied

inline def mod0: Int = Do.mod(0) // was: broken
inline def mod1: Int = Do.mod(1): O.T // was: broken
inline def mod2: Int = Do.mod(2): T // was: broken
inline def mod3: Int = Do.mod(3: O.T) // no proxy needed
inline def mod4: Int = Do.mod(4: O.T): O.T // no proxy needed
inline def mod5: Int = Do.mod(5: O.T): T // proxied
inline def mod6: Int = Do.mod(6: T) // proxied
inline def mod7: Int = Do.mod(7: T): O.T // proxied
inline def mod8: Int = Do.mod(8: T): T // proxied

class Test:
def testGet0: Int = O.get0
def testGet1: Int = O.get1
def testGet2: Int = O.get2

def testSet0: Unit = O.set0
def testSet1: Unit = O.set1
def testSet2: Unit = O.set2

def testMod0: Int = O.mod0
def testMod1: Int = O.mod1
def testMod2: Int = O.mod2
def testMod3: Int = O.mod3
def testMod4: Int = O.mod4
def testMod5: Int = O.mod5
def testMod6: Int = O.mod6
def testMod7: Int = O.mod7
def testMod8: Int = O.mod8

object Do:
def get: O.T = ???
def set(x: O.T): Unit = ()
def mod(x: O.T): O.T = x
12 changes: 12 additions & 0 deletions tests/pos/i17948.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
object O:
opaque type T = Int
inline def x: Int = P.id(2)

object P:
def id(x: O.T): O.T = x

object Test {
def main(args: Array[String]): Unit = println(foo())

def foo(): Int = O.x
}

0 comments on commit e55e139

Please sign in to comment.