diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index e09b7ca98955..a66c24df6c09 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1168,7 +1168,7 @@ class Definitions { ) private val compiletimePackageBooleanTypes: Set[Name] = Set(tpnme.Not, tpnme.Xor, tpnme.And, tpnme.Or) private val compiletimePackageStringTypes: Set[Name] = Set( - tpnme.Plus, tpnme.Length, tpnme.Substring, tpnme.Matches + tpnme.Plus, tpnme.Length, tpnme.Substring, tpnme.Matches, tpnme.CharAt ) private val compiletimePackageOpTypes: Set[Name] = Set(tpnme.S) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 949a99c1e016..9f128a71be7b 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -234,6 +234,7 @@ object StdNames { final val Plus: N = "+" final val S: N = "S" final val Substring: N = "Substring" + final val CharAt: N = "CharAt" final val Times: N = "*" final val ToInt: N = "ToInt" final val ToLong: N = "ToLong" diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 7d57b4eb2740..855865b7cc87 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4439,6 +4439,8 @@ object Types { case tpnme.Matches => constantFold2(stringValue, _ matches _) case tpnme.Substring => constantFold3(stringValue, intValue, intValue, (s, b, e) => s.substring(b, e)) + case tpnme.CharAt => + constantFold2AB(stringValue, intValue, _ charAt _) case _ => None } else if (owner == defn.CompiletimeOpsBooleanModuleClass) name match { case tpnme.Not => constantFold1(boolValue, x => !x) diff --git a/library/src/scala/compiletime/ops/any.scala b/library/src/scala/compiletime/ops/any.scala index b3898f7896bb..ba3b6809fb49 100644 --- a/library/src/scala/compiletime/ops/any.scala +++ b/library/src/scala/compiletime/ops/any.scala @@ -1,8 +1,6 @@ package scala.compiletime package ops -import annotation.experimental - object any: /** Equality comparison of two singleton types. * ```scala @@ -41,7 +39,6 @@ object any: * ``` * @syntax markdown */ - @experimental type IsConst[X] <: Boolean /** String conversion of a constant singleton type. @@ -51,5 +48,4 @@ object any: * ``` * @syntax markdown */ - @experimental type ToString[+X] <: String diff --git a/library/src/scala/compiletime/ops/double.scala b/library/src/scala/compiletime/ops/double.scala index e8eb85291a65..91f65f644e4b 100644 --- a/library/src/scala/compiletime/ops/double.scala +++ b/library/src/scala/compiletime/ops/double.scala @@ -1,9 +1,6 @@ package scala.compiletime package ops -import scala.annotation.experimental - -@experimental object double: /** Addition of two `Double` singleton types. * ```scala diff --git a/library/src/scala/compiletime/ops/float.scala b/library/src/scala/compiletime/ops/float.scala index 3b9a3452929f..c42aa4aec70f 100644 --- a/library/src/scala/compiletime/ops/float.scala +++ b/library/src/scala/compiletime/ops/float.scala @@ -1,9 +1,6 @@ package scala.compiletime package ops -import scala.annotation.experimental - -@experimental object float: /** Addition of two `Float` singleton types. * ```scala diff --git a/library/src/scala/compiletime/ops/int.scala b/library/src/scala/compiletime/ops/int.scala index 935d0dd2a45c..ef7707173a00 100644 --- a/library/src/scala/compiletime/ops/int.scala +++ b/library/src/scala/compiletime/ops/int.scala @@ -1,8 +1,6 @@ package scala.compiletime package ops -import annotation.experimental - object int: /** Successor of a natural number where zero is the type 0 and successors are reduced as if the definition was: * @@ -192,7 +190,6 @@ object int: * ``` * @syntax markdown */ - @experimental type ToLong[+X <: Int] <: Long /** Float conversion of an `Int` singleton type. @@ -201,7 +198,6 @@ object int: * ``` * @syntax markdown */ - @experimental type ToFloat[+X <: Int] <: Float /** Double conversion of an `Int` singleton type. @@ -210,7 +206,6 @@ object int: * ``` * @syntax markdown */ - @experimental type ToDouble[+X <: Int] <: Double /** Number of zero bits preceding the highest-order ("leftmost") @@ -225,5 +220,4 @@ object int: * ``` * @syntax markdown */ - @experimental type NumberOfLeadingZeros[+X <: Int] <: Int diff --git a/library/src/scala/compiletime/ops/long.scala b/library/src/scala/compiletime/ops/long.scala index 87c0c90631c9..1d10e3bf3213 100644 --- a/library/src/scala/compiletime/ops/long.scala +++ b/library/src/scala/compiletime/ops/long.scala @@ -1,9 +1,6 @@ package scala.compiletime package ops -import scala.annotation.experimental - -@experimental object long: /** Successor of a natural number where zero is the type 0 and successors are reduced as if the definition was: * diff --git a/library/src/scala/compiletime/ops/string.scala b/library/src/scala/compiletime/ops/string.scala index 472895dca46f..18c5b13871b1 100644 --- a/library/src/scala/compiletime/ops/string.scala +++ b/library/src/scala/compiletime/ops/string.scala @@ -1,8 +1,6 @@ package scala.compiletime package ops -import scala.annotation.experimental - object string: /** Concatenation of two `String` singleton types. * ```scala @@ -18,7 +16,6 @@ object string: * ``` * @syntax markdown */ - @experimental type Length[+X <: String] <: Int /** Substring of a `String` singleton type, with a singleton type @@ -31,7 +28,6 @@ object string: * ``` * @syntax markdown */ - @experimental type Substring[+S <: String, +IBeg <: Int, +IEnd <: Int] <: String /** Tests if this `String` singleton type matches the given @@ -41,5 +37,14 @@ object string: * ``` * @syntax markdown */ - @experimental type Matches[+S <: String, +Regex <: String] <: Boolean + + /** Returns the Char type at the specified index. + * An index ranges from 0 to Length[S] - 1. The first Char of + * the sequence is at index 0, the next at index 1, and so on. + * ```scala + * val c: CharAt["hello", 0] = 'h' + * ``` + * @syntax markdown + */ + type CharAt[+S <: String, +Idx <: Int] <: Char diff --git a/tests/neg/singleton-ops-string.scala b/tests/neg/singleton-ops-string.scala index d9cf2377564b..c24a9c0e64d1 100644 --- a/tests/neg/singleton-ops-string.scala +++ b/tests/neg/singleton-ops-string.scala @@ -15,4 +15,23 @@ object Test { val t9: Matches["hamburger", "ham.*"] = true val t10: Matches["hamburger", "ham.*"] = false // error + + val t11: CharAt["String", 0] = 'S' + val t12: CharAt["String", 1] = 't' + val t13: CharAt["String", 2] = '!' // error + // ^^^ + // Found: ('!' : Char) + // Required: ('r' : Char) + val t14: CharAt["String", 3] = '!' // error + // ^^^ + // Found: ('!' : Char) + // Required: ('i' : Char) + val t15: CharAt["String", 4] = 'n' + val t16: CharAt["String", 5] = 'g' + val t17: CharAt["String", 6] = '!' // error + // ^ + // String index out of range: 6 + val t18: CharAt["String", -1] = '?' // error + // ^ + // String index out of range: -1 } diff --git a/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala b/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala index 0d86b5c05caa..d3797d2d8ac3 100644 --- a/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala +++ b/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala @@ -32,23 +32,6 @@ val experimentalDefinitionInLibrary = Set( "scala.annotation.MainAnnotation", "scala.annotation.MainAnnotation$", - //// New APIs: compiletime.ops - // Can be stabilized in 3.3.0 or later. - // Needs user feedback - "scala.compiletime.ops.any$.IsConst", - "scala.compiletime.ops.any$.ToString", - "scala.compiletime.ops.double", "scala.compiletime.ops.double$", - "scala.compiletime.ops.float", - "scala.compiletime.ops.float$", - "scala.compiletime.ops.int$.NumberOfLeadingZeros", - "scala.compiletime.ops.int$.ToDouble", - "scala.compiletime.ops.int$.ToFloat", - "scala.compiletime.ops.int$.ToLong", - "scala.compiletime.ops.long", "scala.compiletime.ops.long$", - "scala.compiletime.ops.string$.Length", - "scala.compiletime.ops.string$.Matches", - "scala.compiletime.ops.string$.Substring", - //// New APIs: Mirror // Can be stabilized in 3.2.0 or later. "scala.deriving.Mirror$.fromTuple", // Probably for 3.2.0