Skip to content

Commit fe3c152

Browse files
dwijnandWojciechMazur
authored andcommitted
Rework ProtoType's constrained API
Remove the single use overload, replace with a much more used alternative Also return TypeVars instead of TypeTrees, so we don't have to unwrap the useless wrapper a bunch of times, and instead we wrap the few times we really do want to. [Cherry-picked 5b57e09]
1 parent 56ac7fd commit fe3c152

File tree

11 files changed

+37
-43
lines changed

11 files changed

+37
-43
lines changed

compiler/src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,7 @@ object Trees {
759759
/** A type tree that represents an existing or inferred type */
760760
case class TypeTree[+T <: Untyped]()(implicit @constructorOnly src: SourceFile)
761761
extends DenotingTree[T] with TypTree[T] {
762-
type ThisTree[+T <: Untyped] = TypeTree[T]
762+
type ThisTree[+T <: Untyped] <: TypeTree[T]
763763
override def isEmpty: Boolean = !hasType
764764
override def toString: String =
765765
s"TypeTree${if (hasType) s"[$typeOpt]" else ""}"
@@ -783,7 +783,8 @@ object Trees {
783783
* - as a (result-)type of an inferred ValDef or DefDef.
784784
* Every TypeVar is created as the type of one InferredTypeTree.
785785
*/
786-
class InferredTypeTree[+T <: Untyped](implicit @constructorOnly src: SourceFile) extends TypeTree[T]
786+
class InferredTypeTree[+T <: Untyped](implicit @constructorOnly src: SourceFile) extends TypeTree[T]:
787+
type ThisTree[+T <: Untyped] <: InferredTypeTree[T]
787788

788789
/** ref.type */
789790
case class SingletonTypeTree[+T <: Untyped] private[ast] (ref: Tree[T])(implicit @constructorOnly src: SourceFile)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3125,7 +3125,7 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
31253125
def matchCase(cas: Type): MatchResult = trace(i"$scrut match ${MatchTypeTrace.caseText(cas)}", matchTypes, show = true) {
31263126
val cas1 = cas match {
31273127
case cas: HKTypeLambda =>
3128-
caseLambda = constrained(cas)
3128+
caseLambda = constrained(cas, ast.tpd.EmptyTree)._1
31293129
caseLambda.resultType
31303130
case _ =>
31313131
cas

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4885,6 +4885,9 @@ object Types {
48854885
if (inst.exists) inst else origin
48864886
}
48874887

4888+
def wrapInTypeTree(owningTree: Tree)(using Context): InferredTypeTree =
4889+
new InferredTypeTree().withSpan(owningTree.span).withType(this)
4890+
48884891
override def computeHash(bs: Binders): Int = identityHash(bs)
48894892
override def equals(that: Any): Boolean = this.eq(that.asInstanceOf[AnyRef])
48904893

compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -501,12 +501,9 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
501501
(rawRef, rawInfo)
502502
baseInfo match
503503
case tl: PolyType =>
504-
val (tl1, tpts) = constrained(tl, untpd.EmptyTree, alwaysAddTypeVars = true)
505-
val targs =
506-
for (tpt <- tpts) yield
507-
tpt.tpe match {
508-
case tvar: TypeVar => tvar.instantiate(fromBelow = false)
509-
}
504+
val tvars = constrained(tl)
505+
val targs = for tvar <- tvars yield
506+
tvar.instantiate(fromBelow = false)
510507
(baseRef.appliedTo(targs), extractParams(tl.instantiate(targs)))
511508
case methTpe =>
512509
(baseRef, extractParams(methTpe))

compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ object TypeTestsCasts {
8282
case tp: TypeProxy => underlyingLambda(tp.superType)
8383
}
8484
val typeLambda = underlyingLambda(tycon)
85-
val tvars = constrained(typeLambda, untpd.EmptyTree, alwaysAddTypeVars = true)._2.map(_.tpe)
85+
val tvars = constrained(typeLambda)
8686
val P1 = tycon.appliedTo(tvars)
8787

8888
debug.println("before " + ctx.typerState.constraint.show)

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ object SpaceEngine {
540540
val mt: MethodType = unapp.widen match {
541541
case mt: MethodType => mt
542542
case pt: PolyType =>
543-
val tvars = constrained(pt, EmptyTree)._2.tpes
543+
val tvars = constrained(pt)
544544
val mt = pt.instantiate(tvars).asInstanceOf[MethodType]
545545
scrutineeTp <:< mt.paramInfos(0)
546546
// force type inference to infer a narrower type: could be singleton

compiler/src/dotty/tools/dotc/typer/Inferencing.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ object Inferencing {
317317
def inferTypeParams(tree: Tree, pt: Type)(using Context): Tree = tree.tpe match
318318
case tl: TypeLambda =>
319319
val (tl1, tvars) = constrained(tl, tree)
320-
var tree1 = AppliedTypeTree(tree.withType(tl1), tvars)
320+
val tree1 = AppliedTypeTree(tree.withType(tl1), tvars.map(_.wrapInTypeTree(tree)))
321321
tree1.tpe <:< pt
322322
if isFullyDefined(tree1.tpe, force = ForceDegree.failBottom) then
323323
tree1

compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -713,41 +713,39 @@ object ProtoTypes {
713713
tl: TypeLambda, owningTree: untpd.Tree,
714714
alwaysAddTypeVars: Boolean,
715715
nestingLevel: Int = ctx.nestingLevel
716-
): (TypeLambda, List[TypeTree]) = {
716+
): (TypeLambda, List[TypeVar]) = {
717717
val state = ctx.typerState
718718
val addTypeVars = alwaysAddTypeVars || !owningTree.isEmpty
719719
if (tl.isInstanceOf[PolyType])
720720
assert(!ctx.typerState.isCommittable || addTypeVars,
721721
s"inconsistent: no typevars were added to committable constraint ${state.constraint}")
722722
// hk type lambdas can be added to constraints without typevars during match reduction
723723

724-
def newTypeVars(tl: TypeLambda): List[TypeTree] =
725-
for (paramRef <- tl.paramRefs)
726-
yield {
727-
val tt = InferredTypeTree().withSpan(owningTree.span)
724+
def newTypeVars(tl: TypeLambda): List[TypeVar] =
725+
for paramRef <- tl.paramRefs
726+
yield
728727
val tvar = TypeVar(paramRef, state, nestingLevel)
729728
state.ownedVars += tvar
730-
tt.withType(tvar)
731-
}
729+
tvar
732730

733731
val added = state.constraint.ensureFresh(tl)
734-
val tvars = if (addTypeVars) newTypeVars(added) else Nil
735-
TypeComparer.addToConstraint(added, tvars.tpes.asInstanceOf[List[TypeVar]])
732+
val tvars = if addTypeVars then newTypeVars(added) else Nil
733+
TypeComparer.addToConstraint(added, tvars)
736734
(added, tvars)
737735
}
738736

739-
def constrained(tl: TypeLambda, owningTree: untpd.Tree)(using Context): (TypeLambda, List[TypeTree]) =
737+
def constrained(tl: TypeLambda, owningTree: untpd.Tree)(using Context): (TypeLambda, List[TypeVar]) =
740738
constrained(tl, owningTree,
741739
alwaysAddTypeVars = tl.isInstanceOf[PolyType] && ctx.typerState.isCommittable)
742740

743-
/** Same as `constrained(tl, EmptyTree)`, but returns just the created type lambda */
744-
def constrained(tl: TypeLambda)(using Context): TypeLambda =
745-
constrained(tl, EmptyTree)._1
741+
/** Same as `constrained(tl, EmptyTree, alwaysAddTypeVars = true)`, but returns just the created type vars. */
742+
def constrained(tl: TypeLambda)(using Context): List[TypeVar] =
743+
constrained(tl, EmptyTree, alwaysAddTypeVars = true)._2
746744

747745
/** Instantiate `tl` with fresh type variables added to the constraint. */
748746
def instantiateWithTypeVars(tl: TypeLambda)(using Context): Type =
749-
val targs = constrained(tl, ast.tpd.EmptyTree, alwaysAddTypeVars = true)._2
750-
tl.instantiate(targs.tpes)
747+
val tvars = constrained(tl)
748+
tl.instantiate(tvars)
751749

752750
/** A fresh type variable added to the current constraint.
753751
* @param bounds The initial bounds of the variable
@@ -766,7 +764,7 @@ object ProtoTypes {
766764
pt => bounds :: Nil,
767765
pt => represents.orElse(defn.AnyType))
768766
constrained(poly, untpd.EmptyTree, alwaysAddTypeVars = true, nestingLevel)
769-
._2.head.tpe.asInstanceOf[TypeVar]
767+
._2.head
770768

771769
/** If `param` was created using `newTypeVar(..., represents = X)`, returns X.
772770
* This is used in:

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4260,7 +4260,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
42604260
var typeArgs = tree match
42614261
case Select(qual, nme.CONSTRUCTOR) => qual.tpe.widenDealias.argTypesLo.map(TypeTree(_))
42624262
case _ => Nil
4263-
if typeArgs.isEmpty then typeArgs = constrained(poly, tree)._2
4263+
if typeArgs.isEmpty then typeArgs = constrained(poly, tree)._2.map(_.wrapInTypeTree(tree))
42644264
convertNewGenericArray(readapt(tree.appliedToTypeTrees(typeArgs)))
42654265
case wtp =>
42664266
val isStructuralCall = wtp.isValueType && isStructuralTermSelectOrApply(tree)

compiler/test/dotty/tools/SignatureTest.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class SignatureTest:
6363
| def tuple2(x: Foo *: (T | Tuple) & Foo): Unit = {}
6464
|""".stripMargin):
6565
val cls = requiredClass("A")
66-
val tvar = constrained(cls.requiredMethod(nme.CONSTRUCTOR).info.asInstanceOf[TypeLambda], untpd.EmptyTree, alwaysAddTypeVars = true)._2.head.tpe
66+
val tvar = constrained(cls.requiredMethod(nme.CONSTRUCTOR).info.asInstanceOf[TypeLambda]).head
6767
tvar <:< defn.TupleTypeRef
6868
val prefix = cls.typeRef.appliedTo(tvar)
6969

@@ -89,7 +89,7 @@ class SignatureTest:
8989
| def and(x: T & Foo): Unit = {}
9090
|""".stripMargin):
9191
val cls = requiredClass("A")
92-
val tvar = constrained(cls.requiredMethod(nme.CONSTRUCTOR).info.asInstanceOf[TypeLambda], untpd.EmptyTree, alwaysAddTypeVars = true)._2.head.tpe
92+
val tvar = constrained(cls.requiredMethod(nme.CONSTRUCTOR).info.asInstanceOf[TypeLambda]).head
9393
val prefix = cls.typeRef.appliedTo(tvar)
9494
val ref = prefix.select(cls.requiredMethod("and")).asInstanceOf[TermRef]
9595

compiler/test/dotty/tools/dotc/core/ConstraintsTest.scala

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ class ConstraintsTest:
1919
@Test def mergeParamsTransitivity: Unit =
2020
inCompilerContext(TestConfiguration.basicClasspath,
2121
scalaSources = "trait A { def foo[S, T, R]: Any }") {
22-
val tvars = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda], EmptyTree, alwaysAddTypeVars = true)._2
23-
val List(s, t, r) = tvars.tpes
22+
val List(s, t, r) = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda])
2423

2524
val innerCtx = ctx.fresh.setExploreTyperState()
2625
inContext(innerCtx) {
@@ -38,8 +37,7 @@ class ConstraintsTest:
3837
@Test def mergeBoundsTransitivity: Unit =
3938
inCompilerContext(TestConfiguration.basicClasspath,
4039
scalaSources = "trait A { def foo[S, T]: Any }") {
41-
val tvars = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda], EmptyTree, alwaysAddTypeVars = true)._2
42-
val List(s, t) = tvars.tpes
40+
val List(s, t) = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda])
4341

4442
val innerCtx = ctx.fresh.setExploreTyperState()
4543
inContext(innerCtx) {
@@ -57,32 +55,29 @@ class ConstraintsTest:
5755
@Test def validBoundsInit: Unit = inCompilerContext(
5856
TestConfiguration.basicClasspath,
5957
scalaSources = "trait A { def foo[S >: T <: T | Int, T <: String]: Any }") {
60-
val tvars = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda], EmptyTree, alwaysAddTypeVars = true)._2
61-
val List(s, t) = tvars.tpes
58+
val List(s, t) = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda])
6259

63-
val TypeBounds(lo, hi) = ctx.typerState.constraint.entry(t.asInstanceOf[TypeVar].origin): @unchecked
60+
val TypeBounds(lo, hi) = ctx.typerState.constraint.entry(t.origin): @unchecked
6461
assert(lo =:= defn.NothingType, i"Unexpected lower bound $lo for $t: ${ctx.typerState.constraint}")
6562
assert(hi =:= defn.StringType, i"Unexpected upper bound $hi for $t: ${ctx.typerState.constraint}") // used to be Any
6663
}
6764

6865
@Test def validBoundsUnify: Unit = inCompilerContext(
6966
TestConfiguration.basicClasspath,
7067
scalaSources = "trait A { def foo[S >: T <: T | Int, T <: String | Int]: Any }") {
71-
val tvars = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda], EmptyTree, alwaysAddTypeVars = true)._2
72-
val List(s, t) = tvars.tpes
68+
val List(s, t) = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda])
7369

7470
s <:< t
7571

76-
val TypeBounds(lo, hi) = ctx.typerState.constraint.entry(t.asInstanceOf[TypeVar].origin): @unchecked
72+
val TypeBounds(lo, hi) = ctx.typerState.constraint.entry(t.origin): @unchecked
7773
assert(lo =:= defn.NothingType, i"Unexpected lower bound $lo for $t: ${ctx.typerState.constraint}")
7874
assert(hi =:= (defn.StringType | defn.IntType), i"Unexpected upper bound $hi for $t: ${ctx.typerState.constraint}")
7975
}
8076

8177
@Test def validBoundsReplace: Unit = inCompilerContext(
8278
TestConfiguration.basicClasspath,
8379
scalaSources = "trait X; trait A { def foo[S <: U | X, T, U]: Any }") {
84-
val tvarTrees = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda], EmptyTree, alwaysAddTypeVars = true)._2
85-
val tvars @ List(s, t, u) = tvarTrees.tpes.asInstanceOf[List[TypeVar]]
80+
val tvars @ List(s, t, u) = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda])
8681
s =:= t
8782
t =:= u
8883

0 commit comments

Comments
 (0)