From dfc885887fd0e61211956f421af60bad1c26243b Mon Sep 17 00:00:00 2001 From: soronpo Date: Tue, 11 May 2021 23:14:20 +0300 Subject: [PATCH 1/3] Special-case summonInline to yield implicitNotFound errors --- .../dotty/tools/dotc/core/Definitions.scala | 1 + .../src/dotty/tools/dotc/typer/Inliner.scala | 15 ++++++++++- .../metaprogramming/compiletime-ops.md | 27 ++++++++++++++++--- library/src/scala/compiletime/package.scala | 5 ++-- tests/neg/summonInline.check | 12 +++++++++ tests/neg/summonInline.scala | 21 +++++++++++++++ 6 files changed, 73 insertions(+), 8 deletions(-) create mode 100755 tests/neg/summonInline.check create mode 100755 tests/neg/summonInline.scala diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index ea6652705e60..0034e8b2d9ac 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -233,6 +233,7 @@ class Definitions { @tu lazy val Compiletime_constValue : Symbol = CompiletimePackageClass.requiredMethod("constValue") @tu lazy val Compiletime_constValueOpt: Symbol = CompiletimePackageClass.requiredMethod("constValueOpt") @tu lazy val Compiletime_summonFrom : Symbol = CompiletimePackageClass.requiredMethod("summonFrom") + @tu lazy val Compiletime_summonInline : Symbol = CompiletimePackageClass.requiredMethod("summonInline") @tu lazy val CompiletimeTestingPackage: Symbol = requiredPackage("scala.compiletime.testing") @tu lazy val CompiletimeTesting_typeChecks: Symbol = CompiletimeTestingPackage.requiredMethod("typeChecks") @tu lazy val CompiletimeTesting_typeCheckErrors: Symbol = CompiletimeTestingPackage.requiredMethod("typeCheckErrors") diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 4a8f92f30407..b611c25ca40e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -701,7 +701,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { return Intrinsics.codeOf(arg, call.srcPos) case _ => - // Special handling of `constValue[T]` and `constValueOpt[T]` + // Special handling of `constValue[T]`, `constValueOpt[T], and summonInline[T]` if (callTypeArgs.length == 1) if (inlinedMethod == defn.Compiletime_constValue) { val constVal = tryConstValue @@ -718,6 +718,19 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) { else New(defn.SomeClass.typeRef.appliedTo(constVal.tpe), constVal :: Nil) ) } + else if (inlinedMethod == defn.Compiletime_summonInline) { + def searchImplicit(tpt: Tree) = + val evTyper = new Typer + val evCtx = ctx.fresh.setTyper(evTyper) + val evidence = evTyper.inferImplicitArg(tpt.tpe, tpt.span)(using evCtx) + evidence.tpe match + case fail: Implicits.SearchFailureType => + val msg = evTyper.missingArgMsg(evidence, tpt.tpe, "") + errorTree(tpt, em"$msg") + case _ => + evidence + return searchImplicit(callTypeArgs.head) + } def paramTypess(call: Tree, acc: List[List[Type]]): List[List[Type]] = call match case Apply(fn, args) => diff --git a/docs/docs/reference/metaprogramming/compiletime-ops.md b/docs/docs/reference/metaprogramming/compiletime-ops.md index 86d146818dd2..67e38a3ae019 100644 --- a/docs/docs/reference/metaprogramming/compiletime-ops.md +++ b/docs/docs/reference/metaprogramming/compiletime-ops.md @@ -261,11 +261,30 @@ inline def f: Any = summonFrom { ## `summonInline` The shorthand `summonInline` provides a simple way to write a `summon` that is delayed until the call is inlined. - +Unlike `summonFrom`, `summonInline` also yields the implicit-not-found error, if a given instance of the summoned +type is not found. ```scala -transparent inline def summonInline[T]: T = summonFrom { - case t: T => t -} +import scala.compiletime.summonInline +import scala.annotation.implicitNotFound + +@implicitNotFound("Missing One") +trait Missing1 + +@implicitNotFound("Missing Two") +trait Missing2 + +trait NotMissing +given NotMissing = ??? + +transparent inline def summonInlineCheck[T <: Int](inline t : T) : Any = + inline t match + case 1 => summonInline[Missing1] + case 2 => summonInline[Missing2] + case _ => summonInline[NotMissing] + +val missing1 = summonInlineCheck(1) // error: Missing One +val missing2 = summonInlineCheck(2) // error: Missing Two +val notMissing : NotMissing = summonInlineCheck(3) ``` ## Reference diff --git a/library/src/scala/compiletime/package.scala b/library/src/scala/compiletime/package.scala index 84ac4fde4e29..b465a8b5e01e 100644 --- a/library/src/scala/compiletime/package.scala +++ b/library/src/scala/compiletime/package.scala @@ -137,9 +137,8 @@ transparent inline def summonFrom[T](f: Nothing => T): T = * @tparam T the type of the value to be summoned * @return the given value typed as the provided type parameter */ -transparent inline def summonInline[T]: T = summonFrom { - case t: T => t -} +transparent inline def summonInline[T]: T = + error("Compiler bug: `summonInline` was not evaluated by the compiler") /** Given a tuple T, summons each of its member types and returns them in * a Tuple. diff --git a/tests/neg/summonInline.check b/tests/neg/summonInline.check new file mode 100755 index 000000000000..9d88938d3aa4 --- /dev/null +++ b/tests/neg/summonInline.check @@ -0,0 +1,12 @@ +-- Error: tests\neg\summonInline.scala:19:32 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +19 |val missing1 = summonInlineCheck(1) // error + | ^^^^^^^^^^^^^^^^^^^^ + | Missing One + | This location contains code that was inlined from summonInline.scala:15 +-- Error: tests\neg\summonInline.scala:20:32 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +20 |val missing2 = summonInlineCheck(2) // error + | ^^^^^^^^^^^^^^^^^^^^ + | Missing Two + | This location contains code that was inlined from summonInline.scala:16 diff --git a/tests/neg/summonInline.scala b/tests/neg/summonInline.scala new file mode 100755 index 000000000000..463e506bdbdc --- /dev/null +++ b/tests/neg/summonInline.scala @@ -0,0 +1,21 @@ +import scala.compiletime.summonInline +import scala.annotation.implicitNotFound + +@implicitNotFound("Missing One") +trait Missing1 + +@implicitNotFound("Missing Two") +trait Missing2 + +trait NotMissing +given NotMissing = ??? + +transparent inline def summonInlineCheck[T <: Int](inline t : T) : Any = + inline t match + case 1 => summonInline[Missing1] + case 2 => summonInline[Missing2] + case _ => summonInline[NotMissing] + +val missing1 = summonInlineCheck(1) // error +val missing2 = summonInlineCheck(2) // error +val notMissing : NotMissing = summonInlineCheck(3) \ No newline at end of file From c363c58842489190c2fcfcb10135f8d7a8802bb7 Mon Sep 17 00:00:00 2001 From: soronpo Date: Wed, 12 May 2021 02:02:38 +0300 Subject: [PATCH 2/3] fix neg check file --- tests/neg/summonInline.check | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/neg/summonInline.check b/tests/neg/summonInline.check index 9d88938d3aa4..32028f600003 100755 --- a/tests/neg/summonInline.check +++ b/tests/neg/summonInline.check @@ -1,12 +1,10 @@ --- Error: tests\neg\summonInline.scala:19:32 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -19 |val missing1 = summonInlineCheck(1) // error - | ^^^^^^^^^^^^^^^^^^^^ - | Missing One +-- Error: tests\neg\summonInline.scala:19:32 --------------------------------------------------------------------------- +19 |val missing1 = summonInlineCheck(1) // error + | ^^^^^^^^^^^^^^^^^^^^ + | Missing One | This location contains code that was inlined from summonInline.scala:15 --- Error: tests\neg\summonInline.scala:20:32 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -20 |val missing2 = summonInlineCheck(2) // error - | ^^^^^^^^^^^^^^^^^^^^ - | Missing Two +-- Error: tests\neg\summonInline.scala:20:32 --------------------------------------------------------------------------- +20 |val missing2 = summonInlineCheck(2) // error + | ^^^^^^^^^^^^^^^^^^^^ + | Missing Two | This location contains code that was inlined from summonInline.scala:16 From dc78b1a2a027a69f3311af183ae5c822e8222a32 Mon Sep 17 00:00:00 2001 From: Tom Grigg Date: Tue, 11 May 2021 20:06:49 -0700 Subject: [PATCH 3/3] fix check file --- tests/neg/summonInline.check | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/neg/summonInline.check b/tests/neg/summonInline.check index 32028f600003..d118299d6dc5 100755 --- a/tests/neg/summonInline.check +++ b/tests/neg/summonInline.check @@ -1,10 +1,10 @@ --- Error: tests\neg\summonInline.scala:19:32 --------------------------------------------------------------------------- -19 |val missing1 = summonInlineCheck(1) // error - | ^^^^^^^^^^^^^^^^^^^^ - | Missing One +-- Error: tests/neg/summonInline.scala:19:32 --------------------------------------------------------------------------- +19 |val missing1 = summonInlineCheck(1) // error + | ^^^^^^^^^^^^^^^^^^^^ + | Missing One | This location contains code that was inlined from summonInline.scala:15 --- Error: tests\neg\summonInline.scala:20:32 --------------------------------------------------------------------------- -20 |val missing2 = summonInlineCheck(2) // error - | ^^^^^^^^^^^^^^^^^^^^ - | Missing Two +-- Error: tests/neg/summonInline.scala:20:32 --------------------------------------------------------------------------- +20 |val missing2 = summonInlineCheck(2) // error + | ^^^^^^^^^^^^^^^^^^^^ + | Missing Two | This location contains code that was inlined from summonInline.scala:16