bug icon indicating copy to clipboard operation
bug copied to clipboard

Type inference does not work on methods using dependent types and parameters with default value

Open scabug opened this issue 12 years ago • 10 comments

Here is a minimal test case that shows the problem:

trait Main {

  trait A {
    type B
  }

  trait C {
    def c(a: A, x: Int = 0)(b: a.B)
  }

  def c: C

  def ok(a: A)(b: a.B) = c.c(a, 42)(b)

  def fail(a: A)(b: a.B) = c.c(a)(b)

}

If I remove the x parameter default value, or explicitly fill its value, it works fine. But compiling the above code produces the following error:

[error] /Volumes/Home/workspace/scala-dependent-types/src/main/scala/Main.scala:15: type mismatch;
[error]  found   : b.type (with underlying type a.B)
[error]  required: x$1.B
[error]   def fail(a: A)(b: a.B) = c.c(a)(b)

scabug avatar Mar 08 '13 21:03 scabug

Imported From: https://issues.scala-lang.org/browse/SI-7234?orig=1 Reporter: Julien Richard-Foy (julienrf) Affected Versions: 2.10.1-RC3, 2.11.0-M1 See #7238

scabug avatar Mar 08 '13 21:03 scabug

Julien Richard-Foy (julienrf) said (edited on Mar 8, 2013 10:15:46 PM UTC): Note that if the c method is a top-level method rather than a method of the trait C, it compiles fine:

trait Main {

  trait A {
    type B
  }

  def c(a: A, x: Int = 0)(b: a.B)

  def ok(a: A)(b: a.B) = c(a, 42)(b)

  def ok2(a: A)(b: a.B) = c(a)(b)

}

scabug avatar Mar 08 '13 22:03 scabug

@retronym said: Thanks for the clear bug report.

Working on a fix: https://github.com/retronym/scala/compare/ticket/7234

Still a few subtle interactions to deal with.

Here's a related crasher:

trait Main {
  trait A {
    type B
  }
  trait C {
    def c(a: A, x: Int = 0)(bs: a.B*)
    def d(a: A, x: Int = 0)(b: a.B)
  }
  def c: C
  def fail3(a: A)(b: a.B) = c.c(a)(Seq[A#B](b): _*) // should fail, crashes with .setInfo(null)
}

scabug avatar Mar 09 '13 15:03 scabug

@retronym said (edited on Mar 9, 2013 4:08:04 PM UTC): I've opened another ticket for that crasher, #7238.

scabug avatar Mar 09 '13 16:03 scabug

@retronym said: https://github.com/scala/scala/pull/2225/files

scabug avatar Mar 09 '13 17:03 scabug

Julien Richard-Foy (julienrf) said: Great, thanks for your reactivity.

scabug avatar Mar 11 '13 09:03 scabug

@retronym said: Unfortunately we had to revert this due to #7516.

Right now, I don't see a straight forward way to deliver this fix without breaking that again.

scabug avatar May 27 '13 11:05 scabug

this appears to be another manifestation of the same problem:

scala> trait T; class C[T2 <: T](val t: T2, b: Boolean = true, n: Int = 0)
defined trait T
defined class C

scala> val t = new T { }
t: T = $anon$1@f2a1813

scala> new C[t.type](t)
res0: C[<refinement>.type] = C@7645f03e

scala> new C[t.type](t, n = 1)
<console>:15: error: type mismatch;
 found   : T
 required: <refinement>.type
Error occurred in an application involving default arguments.
       new C[t.type](t, n = 1)
                     ^

@retronym remarks:

We don't have a transform: foo(bar, baz) to val x$1 = bar; val x$2 = baz; foo(x$1, x$2) without messing up the types in some circumstances. If we let the types of the synthetics be inferred (by typechecking the ValDef with an empty tpt), we get unwanted widening. If we manually assign the return type to be the same as type of the expression on the LHS, we ran into some bad interaction in macro land.

SethTisue avatar Jun 27 '17 04:06 SethTisue

is any of this fixed in Scala 3?

SethTisue avatar Sep 12 '24 14:09 SethTisue

I found another manifestation of this bug. When your path-dependent type is "complex" (ie a case class, not a simple alias for string) your arguments must be specified in order of definition, even if you name them.

case class Test(i: Int) {
  case class Complex(foo: String)
  type Simple = String
  val complex: Complex = Complex("hello")
  val simple: Simple = ""
}

def complexTest(f: Test)(x: f.Complex, param1: Int): Boolean = true
def simpleTest(f: Test)(x: f.Simple, param1: Int): Boolean = true

val f = Test(5)
complexTest(f)(f.complex, 6)  // Compiles
complexTest(f)(x = f.complex, param1 = 6)  // Compiles
complexTest(f)(x = f.Complex(""), param1 = 6)  // Compiles
complexTest(f)(param1 = 6, x = f.complex)  // <------- Does not compile, params in wrong order

simpleTest(f)(f.simple, 6)  // Compiles
simpleTest(f)(x = f.simple, param1 = 6)  // Compiles
simpleTest(f)(x = "", param1 = 6)  // Compiles
simpleTest(f)(param1 = 6, x = f.simple)  // Compiles, even though params in wrong order

Weird!

jdrphillips avatar Oct 16 '24 13:10 jdrphillips