Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Context-bound on unnamed type parameter becomes Any #11425

Open
dwijnand opened this Issue Mar 8, 2019 · 12 comments

Comments

Projects
None yet
5 participants
@dwijnand
Copy link
Member

dwijnand commented Mar 8, 2019

Welcome to Scala 2.12.8 (OpenJDK 64-Bit Server VM, Java 11.0.2).
Type in expressions for evaluation. Or try :help.

scala> class F[_]
defined class F

scala> class A[_: F]
defined class A

scala> implicit val x: F[Int] = new F[Int]
x: F[Int] = F@217235f5

scala> new A[Int]
<console>:14: error: could not find implicit value for evidence parameter of type F[Any]
       new A[Int]
       ^

@dwijnand dwijnand added the typer label Mar 8, 2019

@szeiger

This comment has been minimized.

Copy link

szeiger commented Mar 8, 2019

Not limited to classes:

scala> def f[_ : F] = ()
[[syntax trees at end of                     typer]] // <console>
...
        def f[_](implicit evidence$1: F[Any]): Unit = ()

The relevant section of the spec is https://www.scala-lang.org/files/archive/spec/2.11/07-implicits.html#context-bounds-and-view-bounds. It does not mention wildcards explicitly but the current behavior violates this part:

A type parameter A of a method or non-trait class may also have one or more context bounds A : T. In this case the type parameter may be instantiated to any type S for which evidence exists at the instantiation point that S satisfies the bound T. Such evidence consists of an implicit value with type T[S].

@szeiger

This comment has been minimized.

Copy link

szeiger commented Mar 8, 2019

Let met try my best @smarter impersonation: "Works in Dotty"

Well, sort of. Dotty doesn't allow wildcard type parameters anymore so the problem doesn't come up in the first place. If that's the way forward then we should do the same in 2.14.

@smarter

This comment has been minimized.

Copy link

smarter commented Mar 8, 2019

If that's the way forward then we should do the same in 2.14.

I believe so, I'd say the fact that wildcards can be used in type parameter position is just an accident of the parser implementation and not a real feature.

@dwijnand

This comment has been minimized.

Copy link
Member Author

dwijnand commented Mar 8, 2019

Is there a problem is supporting this pattern?

On the other side of the equation: can we find a good reason why to support this? Maybe we should run the community build against the removal to see how/why it's used.

@adriaanm

This comment has been minimized.

Copy link
Member

adriaanm commented Mar 8, 2019

It's not intended to be a wildcard, but an unnamed type parameter. I think that's that the bug is.

@adriaanm

This comment has been minimized.

Copy link
Member

adriaanm commented Mar 8, 2019

Just another use of _ 🤷‍♂️

@dwijnand dwijnand changed the title Context-bound on wildcard widens to Any Context-bound on unnamed type parameter becomes Any Mar 8, 2019

@szeiger

This comment has been minimized.

Copy link

szeiger commented Mar 8, 2019

I'd say the fact that wildcards can be used in type parameter position is just an accident of the parser implementation

The syntax is officially documented in the spec though. Just not the semantics, which shouldn't be a problem if they are simply unnamed type parameters. I also assumed that's what they are. In this case it should be easy to fix by synthesizing a name very early (parsers or namers) before the context bound desugaring happens.

Good reasons for disallowing this syntax:

  • It's inconsistent with value parameters:
    scala> def f(_: Int) = ()
    <console>:1: error: identifier expected but '_' found.
    def f(_: Int) = ()
          ^
    
    scala> def f[_] = ()
    f: [_]=> Unit
    
  • It's yet another use for _ in types that can be confused with type constructors and existentials.
@szeiger

This comment has been minimized.

Copy link

szeiger commented Mar 8, 2019

OTOH it is very similar to the use of _ in type members where it also stands for an unnamed type parameter:

scala> type F[_] = Int
// defined alias type F = [_$11] => Int
@dwijnand

This comment has been minimized.

Copy link
Member Author

dwijnand commented Mar 8, 2019

If we don't drop unnamed type parameters, we might want to lift the restriction on naming multiple proper type parameters _:

scala> class G[_]
defined class G

scala> class H[_]
defined class H

scala> class A[_: G, _: H]
<console>:13: error: _ is already defined as type _
       class A[_: G, _: H]
                     ^

like you can for the parameters of a type constructor:

scala> class F[_[_, _]]
defined class F
  • It's inconsistent with value parameters:
    scala> def f(_: Int) = ()
    <console>:1: error: identifier expected but '_' found.
    def f(_: Int) = ()
          ^
    
    scala> def f[_] = ()
    f: [_]=> Unit
    

It would be nice to be able to name a parameter _, so to avoid triggering the unused lint:

15:20:13 $ sc -Ywarn-unused
Welcome to Scala 2.12.8 (OpenJDK 64-Bit Server VM, Java 11.0.2).
Type in expressions for evaluation. Or try :help.

scala> class A { def foo(x: Int) = () }; final class B extends A { override def foo(x: Int) = println(x) }
<console>:11: warning: parameter value x in method foo is never used
       class A { def foo(x: Int) = () }; final class B extends A { override def foo(x: Int) = println(x) }
                         ^
defined class A
defined class B
@smarter

This comment has been minimized.

Copy link

smarter commented Mar 8, 2019

Please no, no extra meaning for _.

@dwijnand

This comment has been minimized.

Copy link
Member Author

dwijnand commented Mar 8, 2019

I wouldn't classify it as extra. It's the same meaning that already exists: the parameter is being (un)named _. It would be removing an inconsistency (which, I thought generally was well appreciated.)

@som-snytt

This comment has been minimized.

Copy link

som-snytt commented Mar 8, 2019

You can already name one parameter _ and get a reprieve from the unused warning:

def f(`_`: Int) = 42

but it may not be a great idea.

The better escape hatch is:

def f(@ annotation.unused x: Int) = 42

There is already a ticket for multiple type params named _.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.