Skip to content

Commit 20dabed

Browse files
committed
Implement summonFrom as a replacement for implicit match
1 parent 3403879 commit 20dabed

29 files changed

+149
-139
lines changed

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/typer/Applications.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,14 @@ 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+
tree.args match {
896+
case (arg @ Match(EmptyTree, cases)) :: Nil =>
897+
typed(untpd.InlineMatch(EmptyTree, cases).withSpan(arg.span), pt)
898+
case _ =>
899+
errorTree(tree, em"argument to summonFrom must be a pattern matching closure")
900+
}
894901
else
895902
tryEither {
896903
simpleApply(fun1, proto)

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

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -796,9 +796,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
796796
/** Reduce an inline match
797797
* @param mtch the match tree
798798
* @param scrutinee the scrutinee expression, assumed to be pure, or
799-
* EmptyTree for a delegate match
799+
* EmptyTree for a summonFrom
800800
* @param scrutType its fully defined type, or
801-
* ImplicitScrutineeTypeRef for a delegate match
801+
* ImplicitScrutineeTypeRef for a summonFrom
802802
* @param typer The current inline typer
803803
* @return optionally, if match can be reduced to a matching case: A pair of
804804
* bindings for all pattern-bound variables and the RHS of the case.
@@ -1072,11 +1072,10 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
10721072

10731073
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree =
10741074
constToLiteral(betaReduce(super.typedApply(tree, pt))) match {
1075-
case res: Apply
1076-
if res.symbol == defn.InternalQuoted_exprSplice &&
1077-
level == 0 &&
1078-
call.symbol.is(Macro) &&
1079-
!suppressInline =>
1075+
case res: Apply if res.symbol == defn.InternalQuoted_exprSplice
1076+
&& level == 0
1077+
&& call.symbol.is(Macro)
1078+
&& !suppressInline =>
10801079
expandMacro(res.args.head, tree.span)
10811080
case res => res
10821081
}
@@ -1115,7 +1114,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
11151114
def patStr(cdef: untpd.CaseDef) = i"case ${cdef.pat}${guardStr(cdef.guard)}"
11161115
val msg =
11171116
if (tree.selector.isEmpty)
1118-
em"""cannot reduce delegate match with
1117+
em"""cannot reduce summonFrom with
11191118
| patterns : ${tree.cases.map(patStr).mkString("\n ")}"""
11201119
else
11211120
em"""cannot reduce inline match with

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

Lines changed: 1 addition & 1 deletion
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

library/src/scala/compiletime/package.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,20 @@ package object compiletime {
3737

3838
inline def constValue[T]: T = ???
3939

40+
/** Summons first given matching one of the listed cases. E.g. in
41+
*
42+
* given B { ... }
43+
*
44+
* summonFrom {
45+
* case given A => 1
46+
* case given B => 2
47+
* case given C => 3
48+
* case _ => 4
49+
* }
50+
*
51+
* the returned value would be `2`.
52+
*/
53+
inline def summonFrom(f: Nothing => Any) <: Any = ???
54+
4055
type S[X <: Int] <: Int
4156
}

library/src/scala/tasty/reflect/Core.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ trait Core {
216216
/** Tree representing a pattern match `x match { ... }` in the source code */
217217
type Match = internal.Match
218218

219-
/** Tree representing a pattern match `delegate match { ... }` in the source code */
219+
/** Tree representing a pattern match `delegate match { ... }` in the source code */ // TODO: drop
220220
type ImpliedMatch = internal.ImpliedMatch
221221

222222
/** Tree representing a try catch `try x catch { ... } finally { ... }` in the source code */

tests/neg/cannot-reduce-delegate-match.scala renamed to tests/neg/cannot-reduce-summonFrom.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
object Test {
22

33
inline def bar() =
4-
delegate match { // error
4+
compiletime.summonFrom { // error
55
case _: Int =>
66
}
77

tests/neg/implicitMatch-syntax.scala

Lines changed: 0 additions & 33 deletions
This file was deleted.

tests/neg/implicit-match-ambiguous-bind.scala renamed to tests/neg/summonFrom-ambiguous-bind.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ object `implicit-match-ambiguous-bind` {
22
case class Box[T](value: T)
33
implicit val ibox: Box[Int] = Box(0)
44
implicit val sbox: Box[String] = Box("")
5-
inline def unbox = delegate match {
5+
inline def unbox = compiletime.summonFrom {
66
case b: Box[t] => b.value // error
77
}
88
val unboxed = unbox

tests/invalid/neg/implicitMatch-ambiguous.scala renamed to tests/neg/summonFrom-ambiguous.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ object Test {
44
implicit val a1: A = new A
55
implicit val a2: A = new A
66

7-
inline def f: Any = delegate match {
7+
inline def f: Any = compiletime.summonFrom {
88
case _: A => ??? // error: ambiguous implicits
99
}
1010

0 commit comments

Comments
 (0)