Skip to content

Commit 60c3a12

Browse files
authored
Merge pull request #7201 from dotty-staging/add-summonFrom
Replace `delegate match` with `summonFrom`.
2 parents b9775e3 + b049b77 commit 60c3a12

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+513
-405
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -930,14 +930,18 @@ object desugar {
930930
else tree
931931
}
932932

933+
/** Invent a name for an anonympus given of type or template `impl`. */
934+
def inventGivenName(impl: Tree)(implicit ctx: Context): SimpleName =
935+
avoidIllegalChars(s"${inventName(impl)}_given".toTermName.asSimpleName)
936+
933937
/** The normalized name of `mdef`. This means
934938
* 1. Check that the name does not redefine a Scala core class.
935939
* If it does redefine, issue an error and return a mangled name instead of the original one.
936940
* 2. If the name is missing (this can be the case for instance definitions), invent one instead.
937941
*/
938942
def normalizeName(mdef: MemberDef, impl: Tree)(implicit ctx: Context): Name = {
939943
var name = mdef.name
940-
if (name.isEmpty) name = name.likeSpaced(avoidIllegalChars(s"${inventName(impl)}_given".toTermName.asSimpleName))
944+
if (name.isEmpty) name = name.likeSpaced(inventGivenName(impl))
941945
if (ctx.owner == defn.ScalaPackageClass && defn.reservedScalaClassNames.contains(name.toTypeName)) {
942946
def kind = if (name.isTypeName) "class" else "object"
943947
ctx.error(em"illegal redefinition of standard $kind $name", mdef.sourcePos)

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

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -308,25 +308,12 @@ object Trees {
308308
/** Tree defines a new symbol */
309309
trait DefTree[-T >: Untyped] extends DenotingTree[T] {
310310
type ThisTree[-T >: Untyped] <: DefTree[T]
311-
override def isDef: Boolean = true
312-
def namedType: NamedType = tpe.asInstanceOf[NamedType]
313-
}
314-
315-
/** Tree defines a new symbol and carries modifiers.
316-
* The position of a MemberDef contains only the defined identifier or pattern.
317-
* The envelope of a MemberDef contains the whole definition and has its point
318-
* on the opening keyword (or the next token after that if keyword is missing).
319-
*/
320-
abstract class MemberDef[-T >: Untyped](implicit @constructorOnly src: SourceFile) extends NameTree[T] with DefTree[T] {
321-
type ThisTree[-T >: Untyped] <: MemberDef[T]
322311

323312
private[this] var myMods: untpd.Modifiers = null
324313

325314
private[dotc] def rawMods: untpd.Modifiers =
326315
if (myMods == null) untpd.EmptyModifiers else myMods
327316

328-
def rawComment: Option[Comment] = getAttachment(DocComment)
329-
330317
def withAnnotations(annots: List[untpd.Tree]): ThisTree[Untyped] = withMods(rawMods.withAnnotations(annots))
331318

332319
def withMods(mods: untpd.Modifiers): ThisTree[Untyped] = {
@@ -338,14 +325,28 @@ object Trees {
338325
def withFlags(flags: FlagSet): ThisTree[Untyped] = withMods(untpd.Modifiers(flags))
339326
def withAddedFlags(flags: FlagSet): ThisTree[Untyped] = withMods(rawMods | flags)
340327

328+
/** Destructively update modifiers. To be used with care. */
329+
def setMods(mods: untpd.Modifiers): Unit = myMods = mods
330+
331+
override def isDef: Boolean = true
332+
def namedType: NamedType = tpe.asInstanceOf[NamedType]
333+
}
334+
335+
/** Tree defines a new symbol and carries modifiers.
336+
* The position of a MemberDef contains only the defined identifier or pattern.
337+
* The envelope of a MemberDef contains the whole definition and has its point
338+
* on the opening keyword (or the next token after that if keyword is missing).
339+
*/
340+
abstract class MemberDef[-T >: Untyped](implicit @constructorOnly src: SourceFile) extends NameTree[T] with DefTree[T] {
341+
type ThisTree[-T >: Untyped] <: MemberDef[T]
342+
343+
def rawComment: Option[Comment] = getAttachment(DocComment)
344+
341345
def setComment(comment: Option[Comment]): this.type = {
342346
comment.map(putAttachment(DocComment, _))
343347
this
344348
}
345349

346-
/** Destructively update modifiers. To be used with care. */
347-
def setMods(mods: untpd.Modifiers): Unit = myMods = mods
348-
349350
/** The position of the name defined by this definition.
350351
* This is a point position if the definition is synthetic, or a range position
351352
* if the definition comes from source.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
457457

458458
abstract class ModsDecorator { def mods: Modifiers }
459459

460-
implicit class modsDeco(val mdef: MemberDef)(implicit ctx: Context) {
460+
implicit class modsDeco(val mdef: DefTree)(implicit ctx: Context) {
461461
def mods: Modifiers = mdef.rawMods
462462
}
463463

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ class Definitions {
220220
@tu lazy val Compiletime_constValue : Symbol = CompiletimePackageObject.requiredMethod("constValue")
221221
@tu lazy val Compiletime_constValueOpt: Symbol = CompiletimePackageObject.requiredMethod("constValueOpt")
222222
@tu lazy val Compiletime_code : Symbol = CompiletimePackageObject.requiredMethod("code")
223+
@tu lazy val Compiletime_summonFrom : Symbol = CompiletimePackageObject.requiredMethod("summonFrom")
223224
@tu lazy val CompiletimeTestingPackageObject: Symbol = ctx.requiredModule("scala.compiletime.testing.package")
224225
@tu lazy val CompiletimeTesting_typeChecks : Symbol = CompiletimeTestingPackageObject.requiredMethod("typeChecks")
225226

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

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import Flags._
1414
import Contexts._
1515
import Names._
1616
import NameKinds.WildcardParamName
17+
import NameOps._
1718
import ast.{Positioned, Trees}
1819
import ast.Trees._
1920
import StdNames._
@@ -202,8 +203,8 @@ object Parsers {
202203
} && !in.isSoftModifierInModifierPosition
203204

204205
def isExprIntro: Boolean =
205-
if (in.token == IMPLIED || in.token == GIVEN) in.lookaheadIn(BitSet(MATCH))
206-
else (canStartExpressionTokens.contains(in.token) && !in.isSoftModifierInModifierPosition)
206+
if (in.token == GIVEN) false
207+
else canStartExpressionTokens.contains(in.token) && !in.isSoftModifierInModifierPosition
207208

208209
def isDefIntro(allowedMods: BitSet, excludedSoftModifiers: Set[TermName] = Set.empty): Boolean =
209210
in.token == AT ||
@@ -1645,15 +1646,6 @@ object Parsers {
16451646
if (in.token == MATCH) impliedMatch(start, imods)
16461647
else implicitClosure(start, location, imods)
16471648
}
1648-
else if (in.token == IMPLIED || in.token == GIVEN) {
1649-
in.nextToken()
1650-
if (in.token == MATCH)
1651-
impliedMatch(start, EmptyModifiers)
1652-
else {
1653-
syntaxError("`match` expected")
1654-
EmptyTree
1655-
}
1656-
}
16571649
else {
16581650
val saved = placeholderParams
16591651
placeholderParams = Nil
@@ -2350,16 +2342,34 @@ object Parsers {
23502342
if (isIdent(nme.raw.BAR)) { in.nextToken(); pattern1() :: patternAlts() }
23512343
else Nil
23522344

2353-
/** Pattern1 ::= Pattern2 [Ascription]
2345+
/** Pattern1 ::= Pattern2 [Ascription]
2346+
* | ‘given’ PatVar ‘:’ RefinedType
23542347
*/
2355-
def pattern1(): Tree = {
2356-
val p = pattern2()
2357-
if (in.token == COLON) {
2358-
in.nextToken()
2359-
ascription(p, Location.InPattern)
2348+
def pattern1(): Tree =
2349+
if (in.token == GIVEN) {
2350+
val givenMod = atSpan(in.skipToken())(Mod.Given())
2351+
atSpan(in.offset) {
2352+
in.token match {
2353+
case IDENTIFIER | USCORE if in.name.isVariableName =>
2354+
val name = in.name
2355+
in.nextToken()
2356+
accept(COLON)
2357+
val typed = ascription(Ident(nme.WILDCARD), Location.InPattern)
2358+
Bind(name, typed).withMods(addMod(Modifiers(), givenMod))
2359+
case _ =>
2360+
syntaxErrorOrIncomplete("pattern variable expected")
2361+
errorTermTree
2362+
}
2363+
}
2364+
}
2365+
else {
2366+
val p = pattern2()
2367+
if (in.token == COLON) {
2368+
in.nextToken()
2369+
ascription(p, Location.InPattern)
2370+
}
2371+
else p
23602372
}
2361-
else p
2362-
}
23632373

23642374
/** Pattern2 ::= [id `@'] InfixPattern
23652375
*/
@@ -3297,10 +3307,17 @@ object Parsers {
32973307
Template(constr, parents, Nil, EmptyValDef, Nil)
32983308
}
32993309

3300-
/** GivenDef ::= [id] [DefTypeParamClause] GivenBody
3301-
* GivenBody ::= [‘as ConstrApp {‘,’ ConstrApp }] {GivenParamClause} [TemplateBody]
3302-
* | ‘as’ Type {GivenParamClause} ‘=’ Expr
3303-
* | ‘(’ DefParam ‘)’ TemplateBody
3310+
/** OLD:
3311+
* GivenDef ::= [id] [DefTypeParamClause] GivenBody
3312+
* GivenBody ::= [‘as ConstrApp {‘,’ ConstrApp }] {GivenParamClause} [TemplateBody]
3313+
* | ‘as’ Type {GivenParamClause} ‘=’ Expr
3314+
* | ‘(’ DefParam ‘)’ TemplateBody
3315+
* NEW:
3316+
* GivenDef ::= [GivenSig (‘:’ | <:)] Type ‘=’ Expr
3317+
* | [GivenSig ‘:’] [ConstrApp {‘,’ ConstrApp }] [TemplateBody]
3318+
* // | [id ‘:’] [ExtParamClause] TemplateBody (not yet implemented)
3319+
* ExtParamClause ::= [DefTypeParamClause] DefParamClause {GivenParamClause}
3320+
* GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause}
33043321
*/
33053322
def instanceDef(newStyle: Boolean, start: Offset, mods: Modifiers, instanceMod: Mod) = atSpan(start, nameStart) {
33063323
var mods1 = addMod(mods, instanceMod)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ object Tokens extends TokensCommon {
221221
USCORE, NULL, THIS, SUPER, TRUE, FALSE, RETURN, QUOTEID, XMLSTART)
222222

223223
final val canStartExpressionTokens: TokenSet = atomicExprTokens | BitSet(
224-
LBRACE, LPAREN, INDENT, QUOTE, IF, DO, WHILE, FOR, NEW, TRY, THROW, IMPLIED, GIVEN)
224+
LBRACE, LPAREN, INDENT, QUOTE, IF, DO, WHILE, FOR, NEW, TRY, THROW, GIVEN)
225225

226226
final val canStartTypeTokens: TokenSet = literalTokens | identifierTokens | BitSet(
227227
THIS, SUPER, USCORE, LPAREN, AT)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
479479
if (lo eq hi) optText(lo)(" = " ~ _)
480480
else optText(lo)(" >: " ~ _) ~ optText(hi)(" <: " ~ _)
481481
case Bind(name, body) =>
482-
("given ": Text).provided(tree.symbol.is(Implicit) && !homogenizedView) ~ // Used for scala.quoted.Type in quote patterns (not pickled)
482+
("given ": Text).provided(tree.symbol.isOneOf(GivenOrImplicit) && !homogenizedView) ~ // Used for scala.quoted.Type in quote patterns (not pickled)
483483
changePrec(InfixPrec) { toText(name) ~ " @ " ~ toText(body) }
484484
case Alternative(trees) =>
485485
changePrec(OrPrec) { toText(trees, " | ") }
@@ -699,7 +699,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
699699
}
700700

701701
/** Print modifiers from symbols if tree has type, overriding the untpd behavior. */
702-
implicit def modsDeco(mdef: untpd.MemberDef)(implicit ctx: Context): untpd.ModsDecorator =
702+
implicit def modsDeco(mdef: untpd.DefTree)(implicit ctx: Context): untpd.ModsDecorator =
703703
new untpd.ModsDecorator {
704704
def mods = if (mdef.hasType) Modifiers(mdef.symbol) else mdef.rawMods
705705
}

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,31 @@ trait Applications extends Compatibility {
890890
case err: ErrorType => cpy.Apply(tree)(fun1, proto.unforcedTypedArgs).withType(err)
891891
case TryDynamicCallType => typedDynamicApply(tree, pt)
892892
case _ =>
893-
if (originalProto.isDropped) fun1
893+
if originalProto.isDropped then fun1
894+
else if fun1.symbol == defn.Compiletime_summonFrom then
895+
// Special handling of `summonFrom { ... }`.
896+
// We currently cannot use a macro for that since unlike other inline methods
897+
// summonFrom needs to expand lazily. For instance, in
898+
//
899+
// summonFrom {
900+
// case given A[t] =>
901+
// summonFrom
902+
// case given `t` => ...
903+
// }
904+
// }
905+
//
906+
// the second `summonFrom` should expand only once the first `summonFrom` is
907+
// evaluated and `t` is bound. But normal inline expansion does not behave that
908+
// way: arguments to inline function are expanded before the function call.
909+
// To make this work using regular inlining, we'd need a way to annotate
910+
// an inline function that it should expand only if there are no enclosing
911+
// applications of inline functions.
912+
tree.args match {
913+
case (arg @ Match(EmptyTree, cases)) :: Nil =>
914+
typed(untpd.InlineMatch(EmptyTree, cases).withSpan(arg.span), pt)
915+
case _ =>
916+
errorTree(tree, em"argument to summonFrom must be a pattern matching closure")
917+
}
894918
else
895919
tryEither {
896920
simpleApply(fun1, proto)

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
413413
/** Register type of leaf node */
414414
private def registerLeaf(tree: Tree): Unit = tree match {
415415
case _: This | _: Ident | _: TypeTree =>
416-
tree.tpe.foreachPart(registerType, stopAtStatic = true)
416+
tree.typeOpt.foreachPart(registerType, stopAtStatic = true)
417417
case _ =>
418418
}
419419

@@ -433,11 +433,12 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
433433
/** The Inlined node representing the inlined call */
434434
def inlined(sourcePos: SourcePosition): Tree = {
435435

436+
// Special handling of `constValue[T]` and `constValueOpt[T]`
436437
if (callTypeArgs.length == 1)
437438
if (inlinedMethod == defn.Compiletime_constValue) {
438439
val constVal = tryConstValue
439440
if (!constVal.isEmpty) return constVal
440-
ctx.error(i"not a constant type: ${callTypeArgs.head}; cannot take constValue", call.sourcePos)
441+
ctx.error(em"not a constant type: ${callTypeArgs.head}; cannot take constValue", call.sourcePos)
441442
}
442443
else if (inlinedMethod == defn.Compiletime_constValueOpt) {
443444
val constVal = tryConstValue
@@ -795,9 +796,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
795796
/** Reduce an inline match
796797
* @param mtch the match tree
797798
* @param scrutinee the scrutinee expression, assumed to be pure, or
798-
* EmptyTree for a delegate match
799+
* EmptyTree for a summonFrom
799800
* @param scrutType its fully defined type, or
800-
* ImplicitScrutineeTypeRef for a delegate match
801+
* ImplicitScrutineeTypeRef for a summonFrom
801802
* @param typer The current inline typer
802803
* @return optionally, if match can be reduced to a matching case: A pair of
803804
* bindings for all pattern-bound variables and the RHS of the case.
@@ -1071,11 +1072,10 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
10711072

10721073
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree =
10731074
constToLiteral(betaReduce(super.typedApply(tree, pt))) match {
1074-
case res: Apply
1075-
if res.symbol == defn.InternalQuoted_exprSplice &&
1076-
level == 0 &&
1077-
call.symbol.is(Macro) &&
1078-
!suppressInline =>
1075+
case res: Apply if res.symbol == defn.InternalQuoted_exprSplice
1076+
&& level == 0
1077+
&& call.symbol.is(Macro)
1078+
&& !suppressInline =>
10791079
expandMacro(res.args.head, tree.span)
10801080
case res => res
10811081
}
@@ -1114,7 +1114,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
11141114
def patStr(cdef: untpd.CaseDef) = i"case ${cdef.pat}${guardStr(cdef.guard)}"
11151115
val msg =
11161116
if (tree.selector.isEmpty)
1117-
em"""cannot reduce delegate match with
1117+
em"""cannot reduce summonFrom with
11181118
| patterns : ${tree.cases.map(patStr).mkString("\n ")}"""
11191119
else
11201120
em"""cannot reduce inline match with

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,7 @@ class Typer extends Namer
10901090
tree.selector match {
10911091
case EmptyTree =>
10921092
if (tree.isInline) {
1093-
checkInInlineContext("delegate match", tree.posd)
1093+
checkInInlineContext("summonFrom", tree.posd)
10941094
val cases1 = tree.cases.mapconserve {
10951095
case cdef @ CaseDef(pat @ Typed(Ident(nme.WILDCARD), _), _, _) =>
10961096
// case _ : T --> case evidence$n : T
@@ -1478,18 +1478,23 @@ class Typer extends Namer
14781478
tpd.cpy.UnApply(body1)(fn, Nil,
14791479
typed(untpd.Bind(tree.name, untpd.TypedSplice(arg)).withSpan(tree.span), arg.tpe) :: Nil)
14801480
case _ =>
1481-
if (tree.name == nme.WILDCARD) body1
1481+
var name = tree.name
1482+
if (name == nme.WILDCARD && tree.mods.is(Given)) {
1483+
val Typed(_, tpt): @unchecked = tree.body
1484+
name = desugar.inventGivenName(tpt)
1485+
}
1486+
if (name == nme.WILDCARD) body1
14821487
else {
14831488
// for a singleton pattern like `x @ Nil`, `x` should get the type from the scrutinee
14841489
// see tests/neg/i3200b.scala and SI-1503
14851490
val symTp =
14861491
if (body1.tpe.isInstanceOf[TermRef]) pt1
14871492
else body1.tpe.underlyingIfRepeated(isJava = false)
1488-
val sym = ctx.newPatternBoundSymbol(tree.name, symTp, tree.span)
1489-
if (pt == defn.ImplicitScrutineeTypeRef) sym.setFlag(Given)
1493+
val sym = ctx.newPatternBoundSymbol(name, symTp, tree.span)
1494+
if (pt == defn.ImplicitScrutineeTypeRef || tree.mods.is(Given)) sym.setFlag(Given)
14901495
if (ctx.mode.is(Mode.InPatternAlternative))
14911496
ctx.error(i"Illegal variable ${sym.name} in pattern alternative", tree.sourcePos)
1492-
assignType(cpy.Bind(tree)(tree.name, body1), sym)
1497+
assignType(cpy.Bind(tree)(name, body1), sym)
14931498
}
14941499
}
14951500
}

0 commit comments

Comments
 (0)