Skip to content

Strange type checking error for extractors #2378

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

Closed
liufengyun opened this issue May 5, 2017 · 6 comments
Closed

Strange type checking error for extractors #2378

liufengyun opened this issue May 5, 2017 · 6 comments

Comments

@liufengyun
Copy link
Contributor

The following code type checks fine in Scalac, but failed in Dotty.

trait Cap

trait Toolbox {
  type Tree

  val tpd: TypedTrees
  trait TypedTrees {
    type Tree
  }

  val Apply: ApplyImpl
  trait ApplyImpl {
    def unapply(tree: Tree): Option[(Tree, Seq[Tree])]
    def unapply(tree: tpd.Tree)(implicit c: Cap): Option[(tpd.Tree, Seq[tpd.Tree])]
  }
}

class Test(tb: Toolbox) {
  import tb._
  implicit val cap: Cap = null

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

  def bar(tree: tpd.Tree): Int = tree match {
    case Apply(fun, args) => 3
  }
}

Error message:

-- Error: examples/abstract.scala:22:6 -----------------------------------------
22 |  def foo(tree: Tree): Int = tree match {
   |      ^
   |      non-private method foo refers to private value tb
   |       in its type signature (tree: Test.this.tb.Tree)Int
-- [E006] Unbound Identifier Error: examples/abstract.scala:23:9 ---------------
23 |    case Apply(fun, args) => 3
   |         ^^^^^
   |         not found: type Apply

longer explanation available when compiling with `-explain`
-- Error: examples/abstract.scala:26:6 -----------------------------------------
26 |  def bar(tree: tpd.Tree): Int = tree match {
   |      ^
   |      non-private method bar refers to private value tb
   |       in its type signature (tree: Test.this.tb.tpd.Tree)Int
-- [E006] Unbound Identifier Error: examples/abstract.scala:27:9 ---------------
27 |    case Apply(fun, args) => 3
   |         ^^^^^
   |         not found: type Apply

longer explanation available when compiling with `-explain`

@odersky
Copy link
Contributor

odersky commented May 5, 2017

Yes, that's what dotty requires. The error message is pretty specific: You can't mention a private member in a public type.

@smarter
Copy link
Member

smarter commented May 5, 2017

You need to replace class Test(tb: Toolbox) by class Test(val tb: Toolbox) if you want tb to be part of your method signatures (foo takes a tb.Tree).

@liufengyun
Copy link
Contributor Author

liufengyun commented May 5, 2017

Adding val tb: Toolbox reduces two errors, but why it thinks the extractor is a type?

23 |    case Apply(fun, args) => 3
   |         ^^^^^
   |         not found: type Apply

longer explanation available when compiling with `-explain`
-- [E006] Unbound Identifier Error: examples/abstract.scala:27:9 ---------------
27 |    case Apply(fun, args) => 3
   |         ^^^^^
   |         not found: type Apply

@liufengyun
Copy link
Contributor Author

liufengyun commented May 5, 2017

It seems to do with the overloaded extractor, if I remove the overloaded extractor, everything works fine:

trait Cap

trait Toolbox {
  type Tree

  val tpd: TypedTrees
  trait TypedTrees {
    type Tree
  }

  val Apply: ApplyImpl
  trait ApplyImpl {
    def unapply(tree: Tree): Option[(Tree, Seq[Tree])]
    // def unapply(tree: tpd.Tree)(implicit c: Cap): Option[(tpd.Tree, Seq[tpd.Tree])]
  }
}

class Test(val tb: Toolbox) {
  import tb._
  implicit val cap: Cap = null

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

  // def bar(tree: tpd.Tree): Int = tree match {
  //  case Apply(fun, args) => 3
  // }
}

@liufengyun
Copy link
Contributor Author

Just checked, #2358 also fixes this bug, it's due to incorrect widening of the selector.

liufengyun added a commit to dotty-staging/dotty that referenced this issue May 6, 2017
@odersky odersky closed this as completed in c6d8310 May 6, 2017
@liufengyun
Copy link
Contributor Author

liufengyun commented May 6, 2017

While the PR #2358 fixed this specific problem by avoiding incorrect widening. There's a deeper bug in the compiler about error reporting for ambiguous overloaded extractors:

trait Cap
trait Tree

object Apply {
  def unapply(tree: Tree): Option[(Tree, Seq[Tree])] = ???
  def unapply(tree: Tree)(implicit c: Cap): Option[(Tree, Seq[Tree])] = ???
}

class Test {
  def foo(tree: Tree): Int = tree match {
    case Apply(fun, args) => 3
  }
}

An ambiguous reference to overloaded unapply is expected, but Dotty reports the following:

11 |    case Apply(fun, args) => 3
   |         ^^^^^
   |         not found: type Apply

The root cause is that in Applications.typedUnApply, it tries the following sequence:

  1. Apply.unapply
    • pt = Tree => _: failed due to ambiguous overloading
    • pt = _: failed due to ambiguous overloading
  2. Apply.unapplySeq
    • pt = Tree => _: failed not found
    • pt = _: failed not found
  3. if Apply is a type alias, try apply and unapply on the alias' companion object

The problem is that in the case above, we expect the typer to report the error message from the first step, instead it reports error message from the last try while typing Apply as a type.

@liufengyun liufengyun reopened this May 6, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants