Skip to content

Fix #8188: For the purposes of overloading, contextual methods aren't methodic #8245

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

Merged
merged 1 commit into from
Mar 4, 2020

Conversation

anatoliykmetyuk
Copy link
Contributor

No description provided.

@anatoliykmetyuk anatoliykmetyuk self-assigned this Feb 7, 2020
@anatoliykmetyuk
Copy link
Contributor Author

In the issue, there are two methods for the overloading resolution to try:

    def show(str: String)(given DummyImplicit): String = ???
    def show(str: String)(color: Boolean)(given DummyImplicit): String = ???

After application to str, the result types are:

(given DummyImplicit): String
(color: Boolean)(given DummyImplicit): String 

The overloading mechanism prefers non-methodic result types. One can argue that contextual functions are non-methodic because they are not meant to be used as methods.

@anatoliykmetyuk
Copy link
Contributor Author

Incidentally, also, on master:

scala> class Foo {
     |   def f(x: String)(given DummyImplicit): String = x * 2
     |   def f(x: String)(color: Boolean)(given DummyImplicit): String = x * 3
     | }
// defined class Foo

scala> new Foo().f("foo")
1 |new Foo().f("foo")
  |^^^^^^^^^^^
  |Ambiguous overload. The overloaded alternatives of method f in class Foo with types
  | (x: String)(color: Boolean)(given x$3: DummyImplicit): String
  | (x: String)(given x$2: DummyImplicit): String
  |both match arguments (("foo" : String))

On this PR:

scala> class Foo {
     |   def f(x: String)(given DummyImplicit): String = x * 2
     |   def f(x: String)(color: Boolean)(given DummyImplicit): String = x * 3
     | }
// defined class Foo

scala> new Foo().f("foo")
val res0: String = foofoo

@anatoliykmetyuk
Copy link
Contributor Author

The following test fails to compile: https://github.com/lampepfl/dotty/blob/228b61ea174e1768089d957538cbeb91e35dd76a/tests/pos/i2378.scala

The error message says:

-- [E127] Syntax Error: /Users/kmetiuk/Projects/scala3/pg/i8188/iss_f4.scala:7:7
7 |  case Apply(fun) => 3
  |       ^^^^^
  |Apply cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method

longer explanation available when compiling with `-explain`
1 error found

Also, currently, on master, the following compiles:

object Apply {
  def unapply(tree: String): Option[String] = { println(s"No implicit"); Some(tree) }
  def unapply(tree: Int)(implicit c: DummyImplicit): Option[String] = { println("Implicit"); Some(tree.toString) }
}

def foo(tree: Any): Int = tree match {
  case Apply(fun) => 3
}

@main def Test = foo(2)

On runtime it fails with:

Exception in thread "main" scala.MatchError: 2 (of class java.lang.Integer)
	at iss_f4$package$.foo(iss_f4.scala:7)
	at iss_f4$package$.Test(iss_f4.scala:10)
	at Test.main(iss_f4.scala:10)

Because the first unapply is always preferred. Scala 2 rejects the code above with the following message:

scala> def foo(tree: Any): Int = tree match {
     |   case Apply(fun) => 3
     | }
         case Apply(fun) => 3
              ^
On line 2: error: cannot resolve overloaded unapply

The failing test in question was previously also failing on Dotty, up until d8bcc16 when it was moved from neg to pos.

I think the failing behavior for the test is correct – the pattern match in question is:

  def foo(tree: Tree): Int = (tree: Any) match {
    case tb.Apply(fun, args) => 3
  }

The scrutinee is of type Any, hence both of the unapply methods can be used as extractor on it. However, due to the rule introduced by the above commit, we now prefer methods that are not curried during overload resoltion. This rule gives priority to the methods without implicit parameters. It leads to runtime crashes as in case of @main def Test = foo(2) in the minimized example above.

I think the behavior here should be as in Scala 2: report an overload resolution error if there are two unapplys that can be used, even if one of them accepts implicit parameters. This PR achieves this error report by treating contextual methods as non-methodic. However, the error message needs work, maybe in this PR or maybe in another: it shouldn't say that there are no unapply methods defined in the object but it should instead report an overload resolution error.

WDYT @odersky?

@odersky
Copy link
Contributor

odersky commented Mar 2, 2020

Is this still an issue when #8406 is in?

@odersky odersky assigned anatoliykmetyuk and unassigned odersky Mar 2, 2020
@anatoliykmetyuk
Copy link
Contributor Author

Yes, this seems to be a different issue.

@odersky odersky merged commit 0404238 into scala:master Mar 4, 2020
@odersky odersky deleted the i8188 branch March 4, 2020 10:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Overloaded extension methods with context parameters cannot be fully constructed
2 participants