Skip to content

Commit af43f16

Browse files
committed
alternative version using implicitNotFound
1 parent 8f2ee3d commit af43f16

File tree

6 files changed

+64
-73
lines changed

6 files changed

+64
-73
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,6 @@ class Definitions {
689689
@tu lazy val Stats_doRecord: Symbol = StatsModule.requiredMethod("doRecord")
690690

691691
@tu lazy val FromDigitsClass: ClassSymbol = ctx.requiredClass("scala.util.FromDigits")
692-
@tu lazy val FromDigits_WithRadixClass: ClassSymbol = ctx.requiredClass("scala.util.FromDigits.WithRadix")
693692
@tu lazy val FromDigitsModule: TermSymbol = ctx.requiredModule("scala.util.FromDigits")
694693
@tu lazy val FromDigits_fromDigits: Symbol = FromDigitsModule.requiredMethod(nme.fromDigits)
695694
@tu lazy val FromDigits_fromRadixDigits: Symbol = FromDigitsModule.requiredMethod(nme.fromRadixDigits)

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

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -534,17 +534,14 @@ class Typer extends Namer
534534
case Decimal => defn.FromDigits_fromDecimalDigits
535535
case Floating => defn.FromDigits_fromFloatingDigits
536536
inferImplicit(defn.FromDigitsClass.typeRef.appliedTo(target), EmptyTree, tree.span) match {
537-
case SearchSuccess(arg, _, _) =>
538-
val summoned = untpd.Apply(untpd.TypedSplice(ref(summoner)), untpd.TypedSplice(arg) :: Nil).setGivenApply()
539-
var fromDigits: untpd.Tree = untpd.Select(summoned, nme.fromDigits).withSpan(tree.span)
537+
case _: SearchSuccess =>
538+
val summoned = untpd.TypedSplice(ref(summoner).appliedToType(target))
539+
val fromDigits = untpd.Select(summoned, nme.fromDigits).withSpan(tree.span)
540540
val firstArg = Literal(Constant(digits))
541-
val otherArgs =
542-
if arg.tpe.widen.classSymbol.isSubClass(defn.FromDigits_WithRadixClass) then
543-
tree.kind match
544-
case Whole(r) if r != 10 => Literal(Constant(r)) :: Nil
545-
case _ => Nil
546-
else
547-
Nil
541+
val otherArgs = tree.kind match {
542+
case Whole(r) if r != 10 => Literal(Constant(r)) :: Nil
543+
case _ => Nil
544+
}
548545
var app: untpd.Tree = untpd.Apply(fromDigits, firstArg :: otherArgs)
549546
if (ctx.mode.is(Mode.Pattern)) app = untpd.Block(Nil, app)
550547
return typed(app, pt)

library/src/scala/util/FromDigits.scala

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import quoted._
44
import quoted.matching._
55
import internal.Chars.digit2int
66
import annotation.internal.sharable
7+
import annotation.implicitNotFound
78

89
/** A typeclass for types that admit numeric literals.
910
*/
@@ -27,6 +28,7 @@ object FromDigits {
2728
/** A subclass of `FromDigits` that also allows to convert whole number literals
2829
* with a radix other than 10
2930
*/
31+
@implicitNotFound("Type ${T} does not have a FromDigits instance for whole numbers with radix other than 10.")
3032
trait WithRadix[T] extends FromDigits[T] {
3133
def fromDigits(digits: String): T = fromDigits(digits, 10)
3234

@@ -39,36 +41,23 @@ object FromDigits {
3941
/** A subclass of `FromDigits` that also allows to convert number
4042
* literals containing a decimal point ".".
4143
*/
44+
@implicitNotFound("Type ${T} does not have a FromDigits instance for numbers with a decimal point.")
4245
trait Decimal[T] extends FromDigits[T]
4346

4447
/** A subclass of `FromDigits`that allows also to convert number
4548
* literals containing a decimal point "." or an
4649
* exponent `('e' | 'E')['+' | '-']digit digit*`.
4750
*/
51+
@implicitNotFound("Type ${T} does not have a FromDigits instance for floating-point numbers.")
4852
trait Floating[T] extends Decimal[T]
4953

5054
inline def fromDigits[T](given x: FromDigits[T]): x.type = x
5155

52-
inline def fromRadixDigits[T](given x: FromDigits[T]): x.type =
53-
${summonDigitsImpl[x.type, FromDigits.WithRadix[T], T]('x, "whole numbers with radix other than 10")}
54-
55-
inline def fromDecimalDigits[T](given x: FromDigits[T]): x.type =
56-
${summonDigitsImpl[x.type, FromDigits.Decimal[T], T]('x, "numbers with a decimal point")}
57-
58-
inline def fromFloatingDigits[T](given x: FromDigits[T]): x.type =
59-
${summonDigitsImpl[x.type, FromDigits.Floating[T], T]('x, "floating-point numbers")}
60-
61-
private def summonDigitsImpl[Inst <: FromDigits[T], Expected <: FromDigits[T], T](x: Expr[Inst], descriptor: String)
62-
(given qctx: QuoteContext, instance: Type[Inst], t: Type[T], expected: Type[Expected]): Expr[Inst] =
63-
import qctx.tasty.{_, given}
64-
if typeOf[Inst] <:< typeOf[Expected] then
65-
x
66-
else
67-
val msg = s"""|Type ${t.show} does not have a FromDigits instance for $descriptor.
68-
| Found: ${instance.show}(${x.show})
69-
| Expected: ${expected.show}""".stripMargin
70-
qctx.error(msg, x)
71-
Expr.nullExpr.cast[Inst]
56+
inline def fromRadixDigits[T](given x: FromDigits.WithRadix[T]): x.type = x
57+
58+
inline def fromDecimalDigits[T](given x: FromDigits.Decimal[T]): x.type = x
59+
60+
inline def fromFloatingDigits[T](given x: FromDigits.Floating[T]): x.type = x
7261

7362
/** The base type for exceptions that can be thrown from
7463
* `fromDigits` conversions

tests/neg-macros/generic-num-lits.check

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

tests/neg/generic-num-lits.check

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
-- Error: tests/neg/generic-num-lits.scala:2:8 -------------------------------------------------------------------------
2+
2 |val b = 0xcafebabe: BigDecimal // error
3+
| ^
4+
| Type BigDecimal does not have a FromDigits instance for whole numbers with radix other than 10.
5+
-- Error: tests/neg/generic-num-lits.scala:3:8 -------------------------------------------------------------------------
6+
3 |val c = 1.3: BigInt // error
7+
| ^
8+
| Type BigInt does not have a FromDigits instance for numbers with a decimal point.
9+
-- Error: tests/neg/generic-num-lits.scala:4:8 -------------------------------------------------------------------------
10+
4 |val d = 2e500: BigInt // error
11+
| ^
12+
| Type BigInt does not have a FromDigits instance for floating-point numbers.
13+
-- Error: tests/neg/generic-num-lits.scala:7:7 -------------------------------------------------------------------------
14+
7 | case 0xcafebabe: BigDecimal => // error
15+
| ^
16+
| Type BigDecimal does not have a FromDigits instance for whole numbers with radix other than 10.
17+
-- Error: tests/neg/generic-num-lits.scala:11:7 ------------------------------------------------------------------------
18+
11 | case 1.3: BigInt => // error
19+
| ^
20+
| Type BigInt does not have a FromDigits instance for numbers with a decimal point.
21+
-- Error: tests/neg/generic-num-lits.scala:15:7 ------------------------------------------------------------------------
22+
15 | case 2e500: BigInt => // error
23+
| ^
24+
| Type BigInt does not have a FromDigits instance for floating-point numbers.
25+
-- Error: tests/neg/generic-num-lits.scala:19:7 ------------------------------------------------------------------------
26+
19 | case 0xa => // error
27+
| ^
28+
| Type BigDecimal does not have a FromDigits instance for whole numbers with radix other than 10.
29+
-- Error: tests/neg/generic-num-lits.scala:23:7 ------------------------------------------------------------------------
30+
23 | case 1.2 => // error
31+
| ^
32+
| Type BigInt does not have a FromDigits instance for numbers with a decimal point.
33+
-- Error: tests/neg/generic-num-lits.scala:27:7 ------------------------------------------------------------------------
34+
27 | case 5e10 => // error
35+
| ^
36+
| Type BigInt does not have a FromDigits instance for floating-point numbers.

tests/neg-macros/generic-num-lits.scala renamed to tests/neg/generic-num-lits.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,15 @@ val f = (??? : Any) match
1414
val g = (??? : Any) match
1515
case 2e500: BigInt => // error
1616
()
17+
18+
val h = (1.3: BigDecimal) match
19+
case 0xa => // error
20+
()
21+
22+
val i = (1: BigInt) match
23+
case 1.2 => // error
24+
()
25+
26+
val j = (1: BigInt) match
27+
case 5e10 => // error
28+
()

0 commit comments

Comments
 (0)