Skip to content

Commit 7baac02

Browse files
Merge pull request #12428 from soronpo/summonInline
Special-case summonInline to yield implicitNotFound errors
2 parents 4410752 + dc78b1a commit 7baac02

File tree

6 files changed

+71
-8
lines changed

6 files changed

+71
-8
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ class Definitions {
233233
@tu lazy val Compiletime_constValue : Symbol = CompiletimePackageClass.requiredMethod("constValue")
234234
@tu lazy val Compiletime_constValueOpt: Symbol = CompiletimePackageClass.requiredMethod("constValueOpt")
235235
@tu lazy val Compiletime_summonFrom : Symbol = CompiletimePackageClass.requiredMethod("summonFrom")
236+
@tu lazy val Compiletime_summonInline : Symbol = CompiletimePackageClass.requiredMethod("summonInline")
236237
@tu lazy val CompiletimeTestingPackage: Symbol = requiredPackage("scala.compiletime.testing")
237238
@tu lazy val CompiletimeTesting_typeChecks: Symbol = CompiletimeTestingPackage.requiredMethod("typeChecks")
238239
@tu lazy val CompiletimeTesting_typeCheckErrors: Symbol = CompiletimeTestingPackage.requiredMethod("typeCheckErrors")

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
701701
return Intrinsics.codeOf(arg, call.srcPos)
702702
case _ =>
703703

704-
// Special handling of `constValue[T]` and `constValueOpt[T]`
704+
// Special handling of `constValue[T]`, `constValueOpt[T], and summonInline[T]`
705705
if (callTypeArgs.length == 1)
706706
if (inlinedMethod == defn.Compiletime_constValue) {
707707
val constVal = tryConstValue
@@ -718,6 +718,19 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
718718
else New(defn.SomeClass.typeRef.appliedTo(constVal.tpe), constVal :: Nil)
719719
)
720720
}
721+
else if (inlinedMethod == defn.Compiletime_summonInline) {
722+
def searchImplicit(tpt: Tree) =
723+
val evTyper = new Typer
724+
val evCtx = ctx.fresh.setTyper(evTyper)
725+
val evidence = evTyper.inferImplicitArg(tpt.tpe, tpt.span)(using evCtx)
726+
evidence.tpe match
727+
case fail: Implicits.SearchFailureType =>
728+
val msg = evTyper.missingArgMsg(evidence, tpt.tpe, "")
729+
errorTree(tpt, em"$msg")
730+
case _ =>
731+
evidence
732+
return searchImplicit(callTypeArgs.head)
733+
}
721734

722735
def paramTypess(call: Tree, acc: List[List[Type]]): List[List[Type]] = call match
723736
case Apply(fn, args) =>

docs/docs/reference/metaprogramming/compiletime-ops.md

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,11 +261,30 @@ inline def f: Any = summonFrom {
261261
## `summonInline`
262262

263263
The shorthand `summonInline` provides a simple way to write a `summon` that is delayed until the call is inlined.
264-
264+
Unlike `summonFrom`, `summonInline` also yields the implicit-not-found error, if a given instance of the summoned
265+
type is not found.
265266
```scala
266-
transparent inline def summonInline[T]: T = summonFrom {
267-
case t: T => t
268-
}
267+
import scala.compiletime.summonInline
268+
import scala.annotation.implicitNotFound
269+
270+
@implicitNotFound("Missing One")
271+
trait Missing1
272+
273+
@implicitNotFound("Missing Two")
274+
trait Missing2
275+
276+
trait NotMissing
277+
given NotMissing = ???
278+
279+
transparent inline def summonInlineCheck[T <: Int](inline t : T) : Any =
280+
inline t match
281+
case 1 => summonInline[Missing1]
282+
case 2 => summonInline[Missing2]
283+
case _ => summonInline[NotMissing]
284+
285+
val missing1 = summonInlineCheck(1) // error: Missing One
286+
val missing2 = summonInlineCheck(2) // error: Missing Two
287+
val notMissing : NotMissing = summonInlineCheck(3)
269288
```
270289

271290
## Reference

library/src/scala/compiletime/package.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,8 @@ transparent inline def summonFrom[T](f: Nothing => T): T =
137137
* @tparam T the type of the value to be summoned
138138
* @return the given value typed as the provided type parameter
139139
*/
140-
transparent inline def summonInline[T]: T = summonFrom {
141-
case t: T => t
142-
}
140+
transparent inline def summonInline[T]: T =
141+
error("Compiler bug: `summonInline` was not evaluated by the compiler")
143142

144143
/** Given a tuple T, summons each of its member types and returns them in
145144
* a Tuple.

tests/neg/summonInline.check

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
-- Error: tests/neg/summonInline.scala:19:32 ---------------------------------------------------------------------------
2+
19 |val missing1 = summonInlineCheck(1) // error
3+
| ^^^^^^^^^^^^^^^^^^^^
4+
| Missing One
5+
| This location contains code that was inlined from summonInline.scala:15
6+
-- Error: tests/neg/summonInline.scala:20:32 ---------------------------------------------------------------------------
7+
20 |val missing2 = summonInlineCheck(2) // error
8+
| ^^^^^^^^^^^^^^^^^^^^
9+
| Missing Two
10+
| This location contains code that was inlined from summonInline.scala:16

tests/neg/summonInline.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import scala.compiletime.summonInline
2+
import scala.annotation.implicitNotFound
3+
4+
@implicitNotFound("Missing One")
5+
trait Missing1
6+
7+
@implicitNotFound("Missing Two")
8+
trait Missing2
9+
10+
trait NotMissing
11+
given NotMissing = ???
12+
13+
transparent inline def summonInlineCheck[T <: Int](inline t : T) : Any =
14+
inline t match
15+
case 1 => summonInline[Missing1]
16+
case 2 => summonInline[Missing2]
17+
case _ => summonInline[NotMissing]
18+
19+
val missing1 = summonInlineCheck(1) // error
20+
val missing2 = summonInlineCheck(2) // error
21+
val notMissing : NotMissing = summonInlineCheck(3)

0 commit comments

Comments
 (0)