scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

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

Open scabug opened 11 years ago

scabug commented 11 years ago

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 commented 11 years ago

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 commented 11 years ago

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 commented 11 years ago

@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 commented 11 years ago

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

scabug commented 11 years ago

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

scabug commented 11 years ago

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

scabug commented 11 years ago

@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.

SethTisue commented 7 years ago

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 commented 1 month ago

is any of this fixed in Scala 3?

jdrphillips commented 1 day ago

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!