Skip to content

Commit 85793ba

Browse files
authored
Merge pull request #4982 from sjrd/labeled
Introduce Labeled blocks, and use them in PatternMatcher
2 parents 973b675 + 4c53008 commit 85793ba

20 files changed

+756
-411
lines changed

compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
6161
type If = tpd.If
6262
type ValDef = tpd.ValDef
6363
type Throw = tpd.Apply
64+
type Labeled = tpd.Labeled
6465
type Return = tpd.Return
6566
type Block = tpd.Block
6667
type Typed = tpd.Typed
@@ -193,6 +194,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
193194
implicit val LabelDefTag: ClassTag[LabelDef] = ClassTag[LabelDef](classOf[LabelDef])
194195
implicit val ValDefTag: ClassTag[ValDef] = ClassTag[ValDef](classOf[ValDef])
195196
implicit val ThrowTag: ClassTag[Throw] = ClassTag[Throw](classOf[Throw])
197+
implicit val LabeledTag: ClassTag[Labeled] = ClassTag[Labeled](classOf[Labeled])
196198
implicit val ReturnTag: ClassTag[Return] = ClassTag[Return](classOf[Return])
197199
implicit val LiteralTag: ClassTag[Literal] = ClassTag[Literal](classOf[Literal])
198200
implicit val BlockTag: ClassTag[Block] = ClassTag[Block](classOf[Block])
@@ -1076,8 +1078,14 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
10761078
def apply(s: Symbol): This = tpd.This(s.asClass)
10771079
}
10781080

1081+
object Labeled extends LabeledDeconstructor {
1082+
def _1: Bind = field.bind
1083+
def _2: Tree = field.expr
1084+
}
1085+
10791086
object Return extends ReturnDeconstructor {
1080-
def get = field.expr
1087+
def _1: Tree = field.expr
1088+
def _2: Symbol = if (field.from.symbol.isLabel) field.from.symbol else NoSymbol
10811089
}
10821090

10831091
object Ident extends IdentDeconstructor {

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,8 +532,15 @@ object Trees {
532532
type ThisTree[-T >: Untyped] = CaseDef[T]
533533
}
534534

535+
/** label[tpt]: { expr } */
536+
case class Labeled[-T >: Untyped] private[ast] (bind: Bind[T], expr: Tree[T])
537+
extends NameTree[T] {
538+
type ThisTree[-T >: Untyped] = Labeled[T]
539+
def name: Name = bind.name
540+
}
541+
535542
/** return expr
536-
* where `from` refers to the method from which the return takes place
543+
* where `from` refers to the method or label from which the return takes place
537544
* After program transformations this is not necessarily the enclosing method, because
538545
* closures can intervene.
539546
*/
@@ -896,6 +903,7 @@ object Trees {
896903
type Match = Trees.Match[T]
897904
type RewriteMatch = Trees.RewriteMatch[T]
898905
type CaseDef = Trees.CaseDef[T]
906+
type Labeled = Trees.Labeled[T]
899907
type Return = Trees.Return[T]
900908
type Try = Trees.Try[T]
901909
type SeqLiteral = Trees.SeqLiteral[T]
@@ -1044,6 +1052,10 @@ object Trees {
10441052
case tree: CaseDef if (pat eq tree.pat) && (guard eq tree.guard) && (body eq tree.body) => tree
10451053
case _ => finalize(tree, untpd.CaseDef(pat, guard, body))
10461054
}
1055+
def Labeled(tree: Tree)(bind: Bind, expr: Tree)(implicit ctx: Context): Labeled = tree match {
1056+
case tree: Labeled if (bind eq tree.bind) && (expr eq tree.expr) => tree
1057+
case _ => finalize(tree, untpd.Labeled(bind, expr))
1058+
}
10471059
def Return(tree: Tree)(expr: Tree, from: Tree)(implicit ctx: Context): Return = tree match {
10481060
case tree: Return if (expr eq tree.expr) && (from eq tree.from) => tree
10491061
case _ => finalize(tree, untpd.Return(expr, from))
@@ -1218,6 +1230,8 @@ object Trees {
12181230
cpy.Match(tree)(transform(selector), transformSub(cases))
12191231
case CaseDef(pat, guard, body) =>
12201232
cpy.CaseDef(tree)(transform(pat), transform(guard), transform(body))
1233+
case Labeled(bind, expr) =>
1234+
cpy.Labeled(tree)(transformSub(bind), transform(expr))
12211235
case Return(expr, from) =>
12221236
cpy.Return(tree)(transform(expr), transformSub(from))
12231237
case Try(block, cases, finalizer) =>
@@ -1350,6 +1364,8 @@ object Trees {
13501364
this(this(x, selector), cases)
13511365
case CaseDef(pat, guard, body) =>
13521366
this(this(this(x, pat), guard), body)
1367+
case Labeled(bind, expr) =>
1368+
this(this(x, bind), expr)
13531369
case Return(expr, from) =>
13541370
this(this(x, expr), from)
13551371
case Try(block, handler, finalizer) =>

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
120120
def Match(selector: Tree, cases: List[CaseDef])(implicit ctx: Context): Match =
121121
ta.assignType(untpd.Match(selector, cases), cases)
122122

123+
def Labeled(bind: Bind, expr: Tree)(implicit ctx: Context): Labeled =
124+
ta.assignType(untpd.Labeled(bind, expr))
125+
126+
def Labeled(sym: TermSymbol, expr: Tree)(implicit ctx: Context): Labeled =
127+
Labeled(Bind(sym, EmptyTree), expr)
128+
123129
def Return(expr: Tree, from: Tree)(implicit ctx: Context): Return =
124130
ta.assignType(untpd.Return(expr, from))
125131

@@ -594,6 +600,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
594600
}
595601
}
596602

603+
override def Labeled(tree: Tree)(bind: Bind, expr: Tree)(implicit ctx: Context): Labeled =
604+
ta.assignType(untpd.cpy.Labeled(tree)(bind, expr))
605+
597606
override def Return(tree: Tree)(expr: Tree, from: Tree)(implicit ctx: Context): Return =
598607
ta.assignType(untpd.cpy.Return(tree)(expr, from))
599608

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
280280
def Match(selector: Tree, cases: List[CaseDef]): Match = new Match(selector, cases)
281281
def RewriteMatch(selector: Tree, cases: List[CaseDef]): Match = new RewriteMatch(selector, cases)
282282
def CaseDef(pat: Tree, guard: Tree, body: Tree): CaseDef = new CaseDef(pat, guard, body)
283+
def Labeled(bind: Bind, expr: Tree): Labeled = new Labeled(bind, expr)
283284
def Return(expr: Tree, from: Tree): Return = new Return(expr, from)
284285
def Try(expr: Tree, cases: List[CaseDef], finalizer: Tree): Try = new Try(expr, cases, finalizer)
285286
def SeqLiteral(elems: List[Tree], elemtpt: Tree): SeqLiteral = new SeqLiteral(elems, elemtpt)

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

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -314,12 +314,8 @@ object NameKinds {
314314

315315
/** Kinds of unique names generated by the pattern matcher */
316316
val PatMatStdBinderName = new UniqueNameKind("x")
317-
val PatMatPiName = new UniqueNameKind("pi") // FIXME: explain what this is
318-
val PatMatPName = new UniqueNameKind("p") // FIXME: explain what this is
319-
val PatMatOName = new UniqueNameKind("o") // FIXME: explain what this is
320-
val PatMatCaseName = new UniqueNameKind("case")
321-
val PatMatMatchFailName = new UniqueNameKind("matchFail")
322-
val PatMatSelectorName = new UniqueNameKind("selector")
317+
val PatMatAltsName = new UniqueNameKind("matchAlts")
318+
val PatMatResultName = new UniqueNameKind("matchResult")
323319

324320
val LocalOptInlineLocalObj = new UniqueNameKind("ilo")
325321

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ object TypeErasure {
178178
if (defn.isPolymorphicAfterErasure(sym)) eraseParamBounds(sym.info.asInstanceOf[PolyType])
179179
else if (sym.isAbstractType) TypeAlias(WildcardType)
180180
else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(erasureCtx))
181+
else if (sym.is(Label, butNot = Method)) erase.eraseResult(sym.info)(erasureCtx)
181182
else erase.eraseInfo(tp, sym)(erasureCtx) match {
182183
case einfo: MethodType =>
183184
if (sym.isGetter && einfo.resultType.isRef(defn.UnitClass))

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,14 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
372372
else changePrec(GlobalPrec) { toText(sel) ~ keywordStr(" match ") ~ blockText(cases) }
373373
case CaseDef(pat, guard, body) =>
374374
keywordStr("case ") ~ inPattern(toText(pat)) ~ optText(guard)(keywordStr(" if ") ~ _) ~ " => " ~ caseBlockText(body)
375+
case Labeled(bind, expr) =>
376+
changePrec(GlobalPrec) { toText(bind.name) ~ keywordStr("[") ~ toText(bind.symbol.info) ~ keywordStr("]: ") ~ toText(expr) }
375377
case Return(expr, from) =>
376-
changePrec(GlobalPrec) { keywordStr("return") ~ optText(expr)(" " ~ _) }
378+
val sym = from.symbol
379+
if (sym.is(Label))
380+
changePrec(GlobalPrec) { keywordStr("return[") ~ toText(sym.name) ~ keywordStr("]") ~ optText(expr)(" " ~ _) }
381+
else
382+
changePrec(GlobalPrec) { keywordStr("return") ~ optText(expr)(" " ~ _) }
377383
case Try(expr, cases, finalizer) =>
378384
changePrec(GlobalPrec) {
379385
keywordStr("try ") ~ toText(expr) ~ optText(cases)(keywordStr(" catch ") ~ _) ~ optText(finalizer)(keywordStr(" finally ") ~ _)

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ object MegaPhase {
6666
def prepareForClosure(tree: Closure)(implicit ctx: Context) = ctx
6767
def prepareForMatch(tree: Match)(implicit ctx: Context) = ctx
6868
def prepareForCaseDef(tree: CaseDef)(implicit ctx: Context) = ctx
69+
def prepareForLabeled(tree: Labeled)(implicit ctx: Context) = ctx
6970
def prepareForReturn(tree: Return)(implicit ctx: Context) = ctx
7071
def prepareForTry(tree: Try)(implicit ctx: Context) = ctx
7172
def prepareForSeqLiteral(tree: SeqLiteral)(implicit ctx: Context) = ctx
@@ -98,6 +99,7 @@ object MegaPhase {
9899
def transformClosure(tree: Closure)(implicit ctx: Context): Tree = tree
99100
def transformMatch(tree: Match)(implicit ctx: Context): Tree = tree
100101
def transformCaseDef(tree: CaseDef)(implicit ctx: Context): Tree = tree
102+
def transformLabeled(tree: Labeled)(implicit ctx: Context): Tree = tree
101103
def transformReturn(tree: Return)(implicit ctx: Context): Tree = tree
102104
def transformTry(tree: Try)(implicit ctx: Context): Tree = tree
103105
def transformSeqLiteral(tree: SeqLiteral)(implicit ctx: Context): Tree = tree
@@ -165,6 +167,7 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
165167
case tree: ValDef => goValDef(tree, start)
166168
case tree: DefDef => goDefDef(tree, start)
167169
case tree: TypeDef => goTypeDef(tree, start)
170+
case tree: Labeled => goLabeled(tree, start)
168171
case tree: Bind => goBind(tree, start)
169172
case _ => goOther(tree, start)
170173
}
@@ -249,6 +252,11 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
249252
implicit val ctx = prepTypeDef(tree, start)(outerCtx)
250253
val rhs = transformTree(tree.rhs, start)(localContext)
251254
goTypeDef(cpy.TypeDef(tree)(tree.name, rhs), start)
255+
case tree: Labeled =>
256+
implicit val ctx = prepLabeled(tree, start)(outerCtx)
257+
val bind = transformTree(tree.bind, start).asInstanceOf[Bind]
258+
val expr = transformTree(tree.expr, start)
259+
goLabeled(cpy.Labeled(tree)(bind, expr), start)
252260
case tree: Bind =>
253261
implicit val ctx = prepBind(tree, start)(outerCtx)
254262
val body = transformTree(tree.body, start)
@@ -745,6 +753,21 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
745753
}
746754
}
747755

756+
def prepLabeled(tree: Labeled, start: Int)(implicit ctx: Context): Context = {
757+
val phase = nxReturnPrepPhase(start)
758+
if (phase == null) ctx
759+
else prepLabeled(tree, phase.idxInGroup + 1)(phase.prepareForLabeled(tree))
760+
}
761+
762+
def goLabeled(tree: Labeled, start: Int)(implicit ctx: Context): Tree = {
763+
val phase = nxReturnTransPhase(start)
764+
if (phase == null) tree
765+
else phase.transformLabeled(tree)(ctx) match {
766+
case tree1: Labeled => goLabeled(tree1, phase.idxInGroup + 1)
767+
case tree1 => transformNode(tree1, phase.idxInGroup + 1)
768+
}
769+
}
770+
748771
def prepReturn(tree: Return, start: Int)(implicit ctx: Context): Context = {
749772
val phase = nxReturnPrepPhase(start)
750773
if (phase == null) ctx

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import collection.mutable
1111
object NonLocalReturns {
1212
import ast.tpd._
1313
def isNonLocalReturn(ret: Return)(implicit ctx: Context) =
14-
ret.from.symbol != ctx.owner.enclosingMethod || ctx.owner.is(Lazy)
14+
!ret.from.symbol.is(Label) && (ret.from.symbol != ctx.owner.enclosingMethod || ctx.owner.is(Lazy))
1515
}
1616

1717
/** Implement non-local returns using NonLocalReturnControl exceptions.

0 commit comments

Comments
 (0)