Skip to content

Commit a331da7

Browse files
authored
Merge pull request #8212 from dotty-staging/drop-withbounds
Generalize TypeBoundsTree to bounded opaque aliases
2 parents af9e7f0 + 3e7d5af commit a331da7

File tree

16 files changed

+76
-85
lines changed

16 files changed

+76
-85
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ object desugar {
252252

253253
if (meth1.mods.is(Inline))
254254
meth1.tpt match {
255-
case TypeBoundsTree(_, tpt1) =>
255+
case TypeBoundsTree(_, tpt1, _) =>
256256
meth1 = cpy.DefDef(meth1)(tpt = tpt1)
257257
case tpt if !tpt.isEmpty && !meth1.rhs.isEmpty =>
258258
meth1 = cpy.DefDef(meth1)(rhs = Typed(meth1.rhs, tpt))
@@ -684,7 +684,7 @@ object desugar {
684684
val mods = constr1.mods
685685
mods.is(Private) || (!mods.is(Protected) && mods.hasPrivateWithin)
686686
}
687-
687+
688688
/** Does one of the parameter's types (in the first param clause)
689689
* mention a preceding parameter?
690690
*/
@@ -1156,7 +1156,8 @@ object desugar {
11561156
val legalOpaque: MemberDefTest = {
11571157
case TypeDef(_, rhs) =>
11581158
def rhsOK(tree: Tree): Boolean = tree match {
1159-
case _: TypeBoundsTree | _: Template => false
1159+
case bounds: TypeBoundsTree => !bounds.alias.isEmpty
1160+
case _: Template => false
11601161
case LambdaTypeTree(_, body) => rhsOK(body)
11611162
case _ => true
11621163
}

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

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -690,8 +690,10 @@ object Trees {
690690
type ThisTree[-T >: Untyped] = ByNameTypeTree[T]
691691
}
692692

693-
/** >: lo <: hi */
694-
case class TypeBoundsTree[-T >: Untyped] private[ast] (lo: Tree[T], hi: Tree[T])(implicit @constructorOnly src: SourceFile)
693+
/** >: lo <: hi
694+
* >: lo <: hi = alias for RHS of bounded opaque type
695+
*/
696+
case class TypeBoundsTree[-T >: Untyped] private[ast] (lo: Tree[T], hi: Tree[T], alias: Tree[T])(implicit @constructorOnly src: SourceFile)
695697
extends TypTree[T] {
696698
type ThisTree[-T >: Untyped] = TypeBoundsTree[T]
697699
}
@@ -760,7 +762,8 @@ object Trees {
760762
/** mods class name template or
761763
* mods trait name template or
762764
* mods type name = rhs or
763-
* mods type name >: lo <: hi, if rhs = TypeBoundsTree(lo, hi) & (lo ne hi)
765+
* mods type name >: lo <: hi, if rhs = TypeBoundsTree(lo, hi) or
766+
* mods type name >: lo <: hi = rhs if rhs = TypeBoundsTree(lo, hi, alias) and opaque in mods
764767
*/
765768
case class TypeDef[-T >: Untyped] private[ast] (name: TypeName, rhs: Tree[T])(implicit @constructorOnly src: SourceFile)
766769
extends MemberDef[T] {
@@ -811,8 +814,6 @@ object Trees {
811814
extends ProxyTree[T] {
812815
type ThisTree[-T >: Untyped] = Annotated[T]
813816
def forwardTo: Tree[T] = arg
814-
override def disableOverlapChecks = true
815-
// disable overlaps checks since the WithBounds annotation swaps type and annotation.
816817
}
817818

818819
trait WithoutTypeOrPos[-T >: Untyped] extends Tree[T] {
@@ -1151,9 +1152,9 @@ object Trees {
11511152
case tree: ByNameTypeTree if (result eq tree.result) => tree
11521153
case _ => finalize(tree, untpd.ByNameTypeTree(result)(sourceFile(tree)))
11531154
}
1154-
def TypeBoundsTree(tree: Tree)(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree = tree match {
1155-
case tree: TypeBoundsTree if (lo eq tree.lo) && (hi eq tree.hi) => tree
1156-
case _ => finalize(tree, untpd.TypeBoundsTree(lo, hi)(sourceFile(tree)))
1155+
def TypeBoundsTree(tree: Tree)(lo: Tree, hi: Tree, alias: Tree)(implicit ctx: Context): TypeBoundsTree = tree match {
1156+
case tree: TypeBoundsTree if (lo eq tree.lo) && (hi eq tree.hi) && (alias eq tree.alias) => tree
1157+
case _ => finalize(tree, untpd.TypeBoundsTree(lo, hi, alias)(sourceFile(tree)))
11571158
}
11581159
def Bind(tree: Tree)(name: Name, body: Tree)(implicit ctx: Context): Bind = tree match {
11591160
case tree: Bind if (name eq tree.name) && (body eq tree.body) => tree
@@ -1304,8 +1305,8 @@ object Trees {
13041305
cpy.MatchTypeTree(tree)(transform(bound), transform(selector), transformSub(cases))
13051306
case ByNameTypeTree(result) =>
13061307
cpy.ByNameTypeTree(tree)(transform(result))
1307-
case TypeBoundsTree(lo, hi) =>
1308-
cpy.TypeBoundsTree(tree)(transform(lo), transform(hi))
1308+
case TypeBoundsTree(lo, hi, alias) =>
1309+
cpy.TypeBoundsTree(tree)(transform(lo), transform(hi), transform(alias))
13091310
case Bind(name, body) =>
13101311
cpy.Bind(tree)(name, transform(body))
13111312
case Alternative(trees) =>
@@ -1428,8 +1429,8 @@ object Trees {
14281429
this(this(this(x, bound), selector), cases)
14291430
case ByNameTypeTree(result) =>
14301431
this(x, result)
1431-
case TypeBoundsTree(lo, hi) =>
1432-
this(this(x, lo), hi)
1432+
case TypeBoundsTree(lo, hi, alias) =>
1433+
this(this(this(x, lo), hi), alias)
14331434
case Bind(name, body) =>
14341435
this(x, body)
14351436
case Alternative(trees) =>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
179179
def MatchTypeTree(bound: Tree, selector: Tree, cases: List[CaseDef])(implicit ctx: Context): MatchTypeTree =
180180
ta.assignType(untpd.MatchTypeTree(bound, selector, cases), bound, selector, cases)
181181

182-
def TypeBoundsTree(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree =
183-
ta.assignType(untpd.TypeBoundsTree(lo, hi), lo, hi)
182+
def TypeBoundsTree(lo: Tree, hi: Tree, alias: Tree = EmptyTree)(implicit ctx: Context): TypeBoundsTree =
183+
ta.assignType(untpd.TypeBoundsTree(lo, hi, alias), lo, hi, alias)
184184

185185
def Bind(sym: Symbol, body: Tree)(implicit ctx: Context): Bind =
186186
ta.assignType(untpd.Bind(sym.name, body), sym)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
376376
def LambdaTypeTree(tparams: List[TypeDef], body: Tree)(implicit src: SourceFile): LambdaTypeTree = new LambdaTypeTree(tparams, body)
377377
def MatchTypeTree(bound: Tree, selector: Tree, cases: List[CaseDef])(implicit src: SourceFile): MatchTypeTree = new MatchTypeTree(bound, selector, cases)
378378
def ByNameTypeTree(result: Tree)(implicit src: SourceFile): ByNameTypeTree = new ByNameTypeTree(result)
379-
def TypeBoundsTree(lo: Tree, hi: Tree)(implicit src: SourceFile): TypeBoundsTree = new TypeBoundsTree(lo, hi)
379+
def TypeBoundsTree(lo: Tree, hi: Tree, alias: Tree = EmptyTree)(implicit src: SourceFile): TypeBoundsTree = new TypeBoundsTree(lo, hi, alias)
380380
def Bind(name: Name, body: Tree)(implicit src: SourceFile): Bind = new Bind(name, body)
381381
def Alternative(trees: List[Tree])(implicit src: SourceFile): Alternative = new Alternative(trees)
382382
def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree])(implicit src: SourceFile): UnApply = new UnApply(fun, implicits, patterns)

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

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -173,22 +173,6 @@ object Annotations {
173173
else None
174174
}
175175

176-
/** Extractor for WithBounds[T] annotations */
177-
object WithBounds {
178-
def unapply(ann: Annotation)(implicit ctx: Context): Option[TypeBounds] =
179-
if (ann.symbol == defn.WithBoundsAnnot) {
180-
import ast.Trees._
181-
// We need to extract the type of the type tree in the New itself.
182-
// The annotation's type has been simplified as the type of an expression,
183-
// which means that `&` or `|` might have been lost.
184-
// Test in pos/reference/opaque.scala
185-
val Apply(TypeApply(Select(New(tpt), nme.CONSTRUCTOR), _), Nil) = ann.tree
186-
val AppliedType(_, lo :: hi :: Nil) = tpt.tpe
187-
Some(TypeBounds(lo, hi))
188-
}
189-
else None
190-
}
191-
192176
def makeSourceFile(path: String)(implicit ctx: Context): Annotation =
193177
apply(defn.SourceFileAnnot, Literal(Constant(path)))
194178
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,6 @@ class Definitions {
784784
@tu lazy val AnnotationDefaultAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.AnnotationDefault")
785785
@tu lazy val BodyAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.Body")
786786
@tu lazy val ChildAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.Child")
787-
@tu lazy val WithBoundsAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.WithBounds")
788787
@tu lazy val CovariantBetweenAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.CovariantBetween")
789788
@tu lazy val ContravariantBetweenAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.ContravariantBetween")
790789
@tu lazy val DeprecatedAnnot: ClassSymbol = ctx.requiredClass("scala.deprecated")

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Scopes.Scope
1111
import dotty.tools.io.AbstractFile
1212
import Decorators.SymbolIteratorDecorator
1313
import ast._
14+
import ast.Trees.{LambdaTypeTree, TypeBoundsTree}
1415
import Trees.Literal
1516
import Variances.Variance
1617
import annotation.tailrec
@@ -433,8 +434,9 @@ object SymDenotations {
433434
*
434435
* @param info Is assumed to be a (lambda-abstracted) right hand side TypeAlias
435436
* of the opaque type definition.
437+
* @param rhs The right hand side tree of the type definition
436438
*/
437-
def opaqueToBounds(info: Type)(given Context): Type =
439+
def opaqueToBounds(info: Type, rhs: tpd.Tree)(given Context): Type =
438440

439441
def setAlias(tp: Type) =
440442
def recur(self: Type): Unit = self match
@@ -446,21 +448,19 @@ object SymDenotations {
446448
recur(owner.asClass.givenSelfType)
447449
end setAlias
448450

449-
def split(tp: Type): (Type, TypeBounds) = tp match
450-
case AnnotatedType(alias, Annotation.WithBounds(bounds)) =>
451-
(alias, bounds)
452-
case tp: HKTypeLambda =>
453-
val (alias1, bounds1) = split(tp.resType)
454-
(tp.derivedLambdaType(resType = alias1),
455-
HKTypeLambda.boundsFromParams(tp.typeParams, bounds1))
451+
def bounds(t: tpd.Tree): TypeBounds = t match
452+
case LambdaTypeTree(_, body) =>
453+
bounds(body)
454+
case TypeBoundsTree(lo, hi, alias) =>
455+
assert(!alias.isEmpty)
456+
TypeBounds(lo.tpe, hi.tpe)
456457
case _ =>
457-
(tp, HKTypeLambda.boundsFromParams(tp.typeParams, TypeBounds.empty))
458+
TypeBounds.empty
458459

459460
info match
460-
case TypeAlias(tp) if isOpaqueAlias && owner.isClass =>
461-
val (alias, bounds) = split(tp)
461+
case TypeAlias(alias) if isOpaqueAlias && owner.isClass =>
462462
setAlias(alias)
463-
bounds
463+
HKTypeLambda.boundsFromParams(alias.typeParams, bounds(rhs))
464464
case _ =>
465465
info
466466
end opaqueToBounds

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -588,11 +588,15 @@ class TreePickler(pickler: TastyPickler) {
588588
case LambdaTypeTree(tparams, body) =>
589589
writeByte(LAMBDAtpt)
590590
withLength { pickleParams(tparams); pickleTree(body) }
591-
case TypeBoundsTree(lo, hi) =>
591+
case TypeBoundsTree(lo, hi, alias) =>
592592
writeByte(TYPEBOUNDStpt)
593593
withLength {
594594
pickleTree(lo);
595-
if (hi ne lo) pickleTree(hi)
595+
if alias.isEmpty then
596+
if hi ne lo then pickleTree(hi)
597+
else
598+
pickleTree(hi)
599+
pickleTree(alias)
596600
}
597601
case Hole(_, idx, args) =>
598602
writeByte(HOLE)

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -833,11 +833,12 @@ class TreeUnpickler(reader: TastyReader,
833833
override def completerTypeParams(sym: Symbol)(implicit ctx: Context) =
834834
rhs.tpe.typeParams
835835
}
836-
sym.info = sym.opaqueToBounds {
837-
rhs.tpe match
836+
sym.info = sym.opaqueToBounds(
837+
rhs.tpe match {
838838
case _: TypeBounds | _: ClassInfo => checkNonCyclic(sym, rhs.tpe, reportErrors = false)
839839
case _ => rhs.tpe.toBounds
840-
}
840+
},
841+
rhs)
841842
if sym.isOpaqueAlias then sym.typeRef.recomputeDenot() // make sure we see the new bounds from now on
842843
sym.resetFlag(Provisional)
843844
TypeDef(rhs)
@@ -1209,8 +1210,9 @@ class TreeUnpickler(reader: TastyReader,
12091210
MatchTypeTree(bound, scrut, readCases(end))
12101211
case TYPEBOUNDStpt =>
12111212
val lo = readTpt()
1212-
val hi = if (currentAddr == end) lo else readTpt()
1213-
TypeBoundsTree(lo, hi)
1213+
val hi = if currentAddr == end then lo else readTpt()
1214+
val alias = if currentAddr == end then EmptyTree else readTpt()
1215+
TypeBoundsTree(lo, hi, alias)
12141216
case HOLE =>
12151217
readHole(end, isType = false)
12161218
case _ =>

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3344,20 +3344,16 @@ object Parsers {
33443344
rhs match {
33453345
case mtt: MatchTypeTree =>
33463346
bounds match {
3347-
case TypeBoundsTree(EmptyTree, upper) =>
3347+
case TypeBoundsTree(EmptyTree, upper, _) =>
33483348
rhs = MatchTypeTree(upper, mtt.selector, mtt.cases)
33493349
case _ =>
33503350
syntaxError(i"cannot combine lower bound and match type alias", eqOffset)
33513351
}
33523352
case _ =>
3353-
if (mods.is(Opaque)) {
3354-
val annotType = AppliedTypeTree(
3355-
TypeTree(defn.WithBoundsAnnot.typeRef),
3356-
bounds.lo.orElse(TypeTree(defn.NothingType)) ::
3357-
bounds.hi.orElse(TypeTree(defn.AnyType)) :: Nil)
3358-
rhs = Annotated(rhs, ensureApplied(wrapNew(annotType)))
3359-
}
3360-
else syntaxError(i"cannot combine bound and alias", eqOffset)
3353+
if mods.is(Opaque) then
3354+
rhs = TypeBoundsTree(bounds.lo, bounds.hi, rhs)
3355+
else
3356+
syntaxError(i"cannot combine bound and alias", eqOffset)
33613357
}
33623358
makeTypeDef(rhs)
33633359
}
@@ -3568,7 +3564,7 @@ object Parsers {
35683564
DefDef(name, tparams, vparamss, parents.head, subExpr())
35693565
else
35703566
parents match
3571-
case TypeBoundsTree(_, _) :: _ => syntaxError("`=` expected")
3567+
case (_: TypeBoundsTree) :: _ => syntaxError("`=` expected")
35723568
case _ =>
35733569
possibleTemplateStart()
35743570
val tparams1 = tparams.map(tparam => tparam.withMods(tparam.mods | PrivateLocal))

0 commit comments

Comments
 (0)