bug icon indicating copy to clipboard operation
bug copied to clipboard

The expected way to deprecate an implicit class doesn't work

Open scabug opened this issue 8 years ago • 8 comments

Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102).
Type in expressions for evaluation. Or try :help.

scala> @deprecated("Foo is deprecated", "1.0.0")
     | implicit class Foo(i: Int) { def bar = i }
defined class Foo

scala> 1.bar // Expect a warning. Actually no warning
res0: Int = 1

scabug avatar Jan 17 '17 00:01 scabug

Imported From: https://issues.scala-lang.org/browse/SI-10152?orig=1 Reporter: @Atry Affected Versions: 2.12.1 See #8685

scabug avatar Jan 17 '17 00:01 scabug

@som-snytt said: The linked issue is also about synthetics getting the annotation.

Explicit def is not allowed:

scala> @deprecated("nope","forever") def C(i: Int) = new C(i) ; implicit class C(i: Int) { def doubled = i * 2 }
<console>:12: error: method C is defined twice;
  the conflicting method C was defined at line 12:42
       @deprecated("nope","forever") def C(i: Int) = new C(i) ; implicit class C(i: Int) { def doubled = i * 2 }
                                                                               ^

scabug avatar Jan 17 '17 06:01 scabug

@(deprecated @companionMethod) works.

Welcome to Scala 2.12.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_131).
Type in expressions for evaluation. Or try :help.

scala> import scala.annotation.meta._
import scala.annotation.meta._

scala> @(deprecated @companionMethod)("Foo is deprecated", "1.0.0")implicit class Foo(i: Int) { def bar = i }
defined class Foo

scala> 1.bar
<console>:16: warning: method Foo is deprecated (since 1.0.0): Foo is deprecated
       1.bar
       ^
res0: Int = 1

Not sure if it is the expected usage

Atry avatar Jun 15 '17 07:06 Atry

The workaround does not cover "don't warn if enclosing element is deprecated"; we need the annotation on the class:

scala> @(deprecated @companionMethod)("Nope","") implicit class C(@deprecated("Ugh","") val c: Int) extends AnyVal { def bumped = c + 1 }
                                                                                                                                  ^
       warning: value c in class C is deprecated: Ugh
                                                                ^
       warning: value c in class C is deprecated: Ugh
defined class C

scala> @(deprecated @companionMethod)("Nope","") class C(@deprecated("Ugh","") val c: Int) extends AnyVal { def bumped = c + 1 }
defined class C

som-snytt avatar Jan 14 '20 03:01 som-snytt

volunteer to fix this? this is a pretty darn bad bug, IMO

note that you don't even have to invoke the implicit conversion, there is no deprecation warning regardless:

scala 2.13.4> @deprecated("","") class C(x: AnyRef) { def foo = 3 }
class C

scala 2.13.4> (new C(new AnyRef)).foo
                   ^
              warning: class C is deprecated:
val res16: Int = 3

scala 2.13.4> @deprecated("","") implicit class C(x: AnyRef) { def foo = 3 }
class C

scala 2.13.4> new C(new AnyRef)
val res18: C = C@36358417

SethTisue avatar Dec 09 '20 04:12 SethTisue

I'm going to look into this.

SethTisue avatar Feb 01 '21 17:02 SethTisue

scala> @(deprecated @companionMethod)("bye", "forever") @(deprecated @companionClass)("dead", "now") implicit class Foo(i: Int) { def bar = i }
class Foo

scala> 1.bar
       ^
       warning: method Foo is deprecated (since forever): bye
val res0: Int = 1

scala> new Foo(1).bar
           ^
       warning: class Foo is deprecated (since now): dead
val res1: Int = 1

Personally I think @deprecated should emit both, but as per the docs, the fix is making it work like @companionClass.

dwijnand avatar Feb 01 '21 17:02 dwijnand

It changed from "no way to deprecate an implicit class" to "many unexpected ways" to do it.

som-snytt avatar Feb 01 '21 19:02 som-snytt