Skip to content

Nothing inferred for path dependent type parameter #8991

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

Open
bishabosha opened this issue May 17, 2020 · 4 comments
Open

Nothing inferred for path dependent type parameter #8991

bishabosha opened this issue May 17, 2020 · 4 comments

Comments

@bishabosha
Copy link
Member

bishabosha commented May 17, 2020

Minimized code

object Macros {

  abstract class Universe {
    trait WeakTypeTag[T]
    object WeakTypeTag {
      implicit val IntTag: WeakTypeTag[Int] = ???
    }
  }

  trait Context {
    val universe: Universe
  }

  class MacroImpl(val c: Context) {
    import c.universe._
    def poly[T: WeakTypeTag]: Any = ???
  }

  def test1 = new MacroImpl(???).poly[Int]

}

Output

-- Error: MacroBundleTasty.scala:19:42 
19 |  def test1 = new MacroImpl(???).poly[Int]
   |                                          ^
   |no implicit argument of type Nothing was found for an implicit parameter of method poly in class MacroImpl
1 error found

Expectation

This should compile as it does with Scala 2.13.2
This is also critical to support macro compatibility with macro bundles

The alternative below compiles, but the signature in TASTy for MacroImpl.poly is poly[Signed Signature(List(1, scala.Nothing),Macros$.Universe.Tree)], which is incorrect

object Macros {

  abstract class Universe {
    trait WeakTypeTag[T]
  }

  trait Context {
    val universe: Universe
  }

  class MacroImpl(val c: Context) {
    import c.universe._
    def poly[T: WeakTypeTag]: Any = ???
  }

  def test1 = new MacroImpl(???).poly[Int](???)

}
@bishabosha bishabosha changed the title Wrong signature inferred for path dependent type parameter Nothing inferred for path dependent type parameter May 17, 2020
@smarter
Copy link
Member

smarter commented May 17, 2020

It looks like we don't handle unstable prefixes like in Scala 2:

class Foo {
  class A
  object A {
    implicit val implicitA: A = new A
  }
  def get(implicit a: A): A = a
}

object Test {
  (new Foo).get
}

Dotty fails to find the implicit for (new Foo).get, but scalac figures it out by adding a synthetic definition for the prefix to get a stable path:

  <synthetic> <stable> <artifact> val stabilizer$1: Foo = new Foo();
  stabilizer$1.get(stabilizer$1.A.implicitA)

The alternative below compiles, but the signature in TASTy for MacroImpl.poly is poly[Signed Signature(List(1, scala.Nothing),Macros$.Universe.Tree)], which is incorrect

This sort of makes sense: the type of the parameter is c.universe.WeakTypeTag[T] with c replaced by a stable prefix, but in the expression new MacroImpl(???).poly[Int](???) we don't have a stable prefix, so there's no way to represent this type (and no value we could possibly pass to this type), so we might as well represent it as Nothing. A synthetic stable prefix would also fix this.

In Dotty, synthetic definitions like this are normally created using a "lifter", see https://github.com/lampepfl/dotty/blob/master/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala, perhaps we should add some logic to lift the prefix of an implicit method call when needed (which seems to be at a minimum when the prefix is unstable and the type is a class type).

Note that this can be worked around by manually using a stable prefix:

  def test1 = {
    val m = new MacroImpl(???)
    m.poly[Int]
  }

@smarter
Copy link
Member

smarter commented May 17, 2020

We should check in which situations exactly scalac introduces these stabilizer definitions. Note that some of these situations are already handle by skolemization which is much cheaper: 502c7c9

@bishabosha
Copy link
Member Author

bishabosha commented May 18, 2020

The alternative below compiles, but the signature in TASTy for MacroImpl.poly is poly[Signed Signature(List(1, scala.Nothing),Macros$.Universe.Tree)], which is incorrect

This sort of makes sense:

My intuition was that signatures always mapped to the JVM signature of a matching overload, but this appears to not be the case, a callsites' arguments should not affect it surely? or if an overload was not found then should this not compile

@smarter
Copy link
Member

smarter commented May 18, 2020

My intuition was that signatures always mapped to the JVM signature of a matching overload, but this appears to not be the case

Yeah it's a bt confusing: Dotty uses signatures to distinguish between overloads and overrides, so signatures are always computed as seen from some prefix, e.g. in:

class Foo[A] {
  def foo(x: A): String = "foo"
}
class Bar extends Foo[Int] {
  override def foo(x: A): String = "bar"
}

There's two definitions for foo in Bar, so we find two different denotations, but their signatures as seen from an instance of Bar is the same: Signature(List(scala.Int), java.lang.String, so their denotations get merged together (the signatures don't have to exactly match, the result type may be different).

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

2 participants