dotty icon indicating copy to clipboard operation
dotty copied to clipboard

JavaNull not propagated by type inference as anonymous function argument

Open abeln opened this issue 7 years ago • 1 comments

This doesn't typecheck

object Test {

  def main(args: Array[String]): Unit = { 
    val f = new Foo 
    println(1)
    println(f.foo)
    println(2)
    println(f.foo)

    // TODO: Erase
    // Currently not erasing fields for lazy vals
    assert(f.getClass.getDeclaredFields.exists(_.getName.startsWith("foo")), "Field foo erased. Optimized accidentally?")
  }


}

class Foo {
  lazy val foo: Null = { 
    println("foo")
    null
  }
}

because

-- [E008] Member Not Found Error: tests/run/null-lazy-val.scala:13:49 ----------
13 |    assert(f.getClass.getDeclaredFields.exists(_.getName.startsWith("foo")), "Field foo erased. Optimized accidentally?")
   |                                               ^^^^^^^^^
   |       value `getName` is not a member of java.lang.reflect.Field | Null

The argument type for the lambda is inferred to be Field|Null, when it should be Field|JavaNull.

After frontend

        assert(
          refArrayOps[(java.lang.reflect.Field | Null)](
            f.getClass().getDeclaredFields().asInstanceOf[
              Array[java.lang.reflect.Field | JavaNull]
            ]
          ).exists(
            {
              def $anonfun(_$1: java.lang.reflect.Field | Null): Boolean = 
                _$1.getName.startsWith()
              closure($anonfun)
            }
          )

So the implicit conversion is applied, but the argument type is incorrectly inferred. This is because annotations are dropped when subtyping constraints are added to the set of current constraints.

The current workaround is to say .nn.getName.startsWith. I discussed this with Ondrej and we're gonna let it be for now.

Opening this to track the status.

abeln avatar Nov 29 '18 16:11 abeln

In particular, lots of tests need this to do e.g. getClass.getMethods.find. So this could be alleviated by having more precise Java null conversion for methods in the Class class.

abeln avatar Nov 29 '18 17:11 abeln