From 69e9222a1eed8714b468f4729db95f7728c62b25 Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Thu, 11 Dec 2025 10:18:22 +0100 Subject: [PATCH] Make `->` sugar an inline method Must wait for 3.10.0 currently it is transparent inline, to avoid inline proxy objects appearing in capture sets and breaking type checking. --- library/src/scala/Predef.scala | 7 +++++++ .../pc/tests/completion/CompletionExtensionSuite.scala | 2 +- .../dotty/tools/pc/tests/completion/CompletionSuite.scala | 2 +- tests/run-staging/i5965.check | 2 +- tests/run-staging/i5965b.check | 2 +- tests/semanticdb/expect/Synthetic.expect.scala | 2 +- tests/semanticdb/metac.expect | 7 +++---- 7 files changed, 15 insertions(+), 9 deletions(-) diff --git a/library/src/scala/Predef.scala b/library/src/scala/Predef.scala index 46b000714187..d6d91885c6ff 100644 --- a/library/src/scala/Predef.scala +++ b/library/src/scala/Predef.scala @@ -389,7 +389,9 @@ object Predef extends LowPriorityImplicits { // implicit classes ----------------------------------------------------- /** @group implicit-classes-any */ + @deprecated("Use `->` extension method instead.", since = "3.10.0") implicit final class ArrowAssoc[A](private val self: A) extends AnyVal { + @deprecated("Use `->` extension method instead.", since = "3.10.0") @inline def -> [B](y: B): (A, B) = (self, y) @deprecated("Use `->` instead. If you still wish to display it as one character, consider using a font with programming ligatures such as Fira Code.", "2.13.0") def →[B](y: B): (A, B) = ->(y) @@ -609,6 +611,11 @@ object Predef extends LowPriorityImplicits { */ inline def runtimeChecked: x.type @RuntimeChecked = x: @RuntimeChecked + // extension method sugar --------------------------------------------- + extension[A] (self: A) + transparent inline def -> [B](y: B): (A, B) = (self, y) + + } /** The `LowPriorityImplicits` class provides implicit values that diff --git a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionExtensionSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionExtensionSuite.scala index 16535381165c..5acbad7b6f08 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionExtensionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionExtensionSuite.scala @@ -453,6 +453,7 @@ class CompletionExtensionSuite extends BaseCompletionSuite: """|baz(): Unit |copy(): Bar |qux: Unit + |->[B](y: B): (Bar, B) |asInstanceOf[X0]: X0 |canEqual(that: Any): Boolean |equals(x$0: Any): Boolean @@ -467,7 +468,6 @@ class CompletionExtensionSuite extends BaseCompletionSuite: |productPrefix: String |synchronized[X0](x$0: X0): X0 |toString(): String - |->[B](y: B): (Bar, B) |ensuring(cond: Boolean): Bar |ensuring(cond: Bar => Boolean): Bar |ensuring(cond: Boolean, msg: => Any): Bar diff --git a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala index 103f365f8af6..928ef8fa4b6f 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala @@ -109,6 +109,7 @@ class CompletionSuite extends BaseCompletionSuite: |tabulate[A](n: Int)(f: Int => A): List[A] |unapplySeq[A](x: List[A] @uncheckedVariance): UnapplySeqWrapper[A] |unfold[A, S](init: S)(f: S => Option[(A, S)]): List[A] + |->[B](y: B): (List.type, B) |fromSpecific(from: Any)(it: IterableOnce[Nothing]): List[Nothing] |fromSpecific(it: IterableOnce[Nothing]): List[Nothing] |toFactory(from: Any): Factory[Nothing, List[Nothing]] @@ -120,7 +121,6 @@ class CompletionSuite extends BaseCompletionSuite: |isInstanceOf[X0]: Boolean |synchronized[X0](x$0: X0): X0 |toString(): String - |->[B](y: B): (List.type, B) |ensuring(cond: Boolean): List.type |ensuring(cond: List.type => Boolean): List.type |ensuring(cond: Boolean, msg: => Any): List.type diff --git a/tests/run-staging/i5965.check b/tests/run-staging/i5965.check index 2e991af71892..7711f2db455c 100644 --- a/tests/run-staging/i5965.check +++ b/tests/run-staging/i5965.check @@ -11,7 +11,7 @@ List(1, 2, 3) } Some(4) { - val y: [V >: scala.Nothing <: scala.Any] =>> scala.collection.immutable.Map[scala.Int, V][scala.Int] = scala.Predef.Map.apply[scala.Int, scala.Int](scala.Predef.ArrowAssoc[scala.Int](4).->[scala.Int](1)) + val y: [V >: scala.Nothing <: scala.Any] =>> scala.collection.immutable.Map[scala.Int, V][scala.Int] = scala.Predef.Map.apply[scala.Int, scala.Int](scala.Predef.->[scala.Int](4)[scala.Int](1)) (y: scala.collection.immutable.Map[scala.Int, scala.Int]) } diff --git a/tests/run-staging/i5965b.check b/tests/run-staging/i5965b.check index f88ef8f53869..475a87e5a05f 100644 --- a/tests/run-staging/i5965b.check +++ b/tests/run-staging/i5965b.check @@ -11,7 +11,7 @@ List(1, 2, 3) } Some(4) { - val y: scala.collection.immutable.Map[scala.Int, scala.Int] = scala.Predef.Map.apply[scala.Int, scala.Int](scala.Predef.ArrowAssoc[scala.Int](4).->[scala.Int](1)) + val y: scala.collection.immutable.Map[scala.Int, scala.Int] = scala.Predef.Map.apply[scala.Int, scala.Int](scala.Predef.->[scala.Int](4)[scala.Int](1)) (y: scala.collection.immutable.Map[scala.Int, scala.Int]) } diff --git a/tests/semanticdb/expect/Synthetic.expect.scala b/tests/semanticdb/expect/Synthetic.expect.scala index 5286745100a7..e040733eaffd 100644 --- a/tests/semanticdb/expect/Synthetic.expect.scala +++ b/tests/semanticdb/expect/Synthetic.expect.scala @@ -17,7 +17,7 @@ class Synthetic/*<-example::Synthetic#*/ { val lst/*<-example::Synthetic#lst.*/ = 1 #:: 2 #:: LazyList/*->scala::package.LazyList.*/.empty/*->scala::collection::immutable::LazyList.empty().*/ - for (x/*<-local0*/ <- 1 to/*->scala::runtime::RichInt#to().*/ 10; y/*<-local1*/ <- 0 until/*->scala::runtime::RichInt#until().*/ 10) println/*->scala::Predef.println(+1).*/(x/*->local0*/ ->/*->scala::Predef.ArrowAssoc#`->`().*/ x/*->local0*/) + for (x/*<-local0*/ <- 1 to/*->scala::runtime::RichInt#to().*/ 10; y/*<-local1*/ <- 0 until/*->scala::runtime::RichInt#until().*/ 10) println/*->scala::Predef.println(+1).*/(x/*->local0*/ ->/*->scala::Predef.`->`().*/ x/*->local0*/) for (i/*<-local2*/ <- 1 to/*->scala::runtime::RichInt#to().*/ 10; j/*<-local3*/ <- 0 until/*->scala::runtime::RichInt#until().*/ 10) yield (i/*->local2*/, j/*->local3*/) for (i/*<-local4*/ <- 1 to/*->scala::runtime::RichInt#to().*/ 10; j/*<-local5*/ <- 0 until/*->scala::runtime::RichInt#until().*/ 10 if i/*->local4*/ %/*->scala::Int#`%`(+3).*/ 2 ==/*->scala::Int#`==`(+3).*/ 0) yield (i/*->local4*/, j/*->local5*/) diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index db6d2e640f63..25631287ed12 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -3838,7 +3838,7 @@ Language => Scala Symbols => 62 entries Occurrences => 165 entries Diagnostics => 4 entries -Synthetics => 48 entries +Synthetics => 47 entries Symbols: example/Synthetic# => class Synthetic extends Object { self: Synthetic => +23 decls } @@ -3944,7 +3944,7 @@ Occurrences: [19:28..19:33): until -> scala/runtime/RichInt#until(). [19:38..19:45): println -> scala/Predef.println(+1). [19:46..19:47): x -> local0 -[19:48..19:50): -> -> scala/Predef.ArrowAssoc#`->`(). +[19:48..19:50): -> -> scala/Predef.`->`(). [19:51..19:52): x -> local0 [20:7..20:8): i <- local2 [20:14..20:16): to -> scala/runtime/RichInt#to(). @@ -4104,8 +4104,7 @@ Synthetics: [17:24..17:38):LazyList.empty => *[Nothing] [19:12..19:13):1 => intWrapper(*) [19:26..19:27):0 => intWrapper(*) -[19:46..19:50):x -> => *[Int] -[19:46..19:47):x => ArrowAssoc[Int](*) +[19:48..19:50):-> => *[Int] [20:12..20:13):1 => intWrapper(*) [20:26..20:27):0 => intWrapper(*) [20:44..20:50):(i, j) => Tuple2.apply[Int, Int](*)