Skip to content

Dependent function types do not act contravariantly in their parameter types #6357

Closed
@smarter

Description

@smarter

For example:

class A
class B extends A
object Test {
  val f1: A => Any = a => a
  // This compiles
  val f2: B => Any = f1

  val f3: (a: A) => Any = a => a

  // But this doesn't
  val f4: (a: B) => Any = f3
}

Running with -explain-types we get:

-- [E007] Type Mismatch Error: try/df.scala:11:26 ------------------------------
11 |  val f4: (a: B) => Any = f3
   |                          ^^
   |Found:    (a: A) => Any(Test.f3)
   |Required: (a: B) => Any
   |Constraint(
   | uninstVars = ;
   | constrained types =
   | bounds =
   | ordering =
   |)
   |Subtype trace:
   |  ==> (a: A) => Any(Test.f3) <:< (a: B) => Any
   |    ==> A => Any <:< B => Any LoApprox
   |      ==> scala.type(scala) <:< scala.type(scala)
   |      <== scala.type(scala) <:< scala.type(scala)   = true
   |      ==> B <:< A
   |        ==> A <:< A LoApprox
   |        <== A <:< A LoApprox  = true
   |      <== B <:< A   = true
   |      ==> Any <:< Any
   |      <== Any <:< Any   = true
   |    <== A => Any <:< B => Any LoApprox  = true
   |    ==> (v1: A): Any <:< (a: A): Any   frozen
   |      ==> Any <:< Any   frozen
   |      <== Any <:< Any   frozen = true
   |    <== (v1: A): Any <:< (a: A): Any   frozen = true
   |    ==> hasMatchingMember((a: A) => Any(Test.f3) . apply, (a: B): Any), member = (v1: A): Any
   |      ==> (v1: A): Any <:< (a: A): Any   frozen
   |        ==> Any <:< Any   frozen
   |        <== Any <:< Any   frozen = true
   |      <== (v1: A): Any <:< (a: A): Any   frozen = true
   |      ==> (v1: A): Any <:< (a: B): Any
   |      <== (v1: A): Any <:< (a: B): Any   = false
   |    <== hasMatchingMember((a: A) => Any(Test.f3) . apply, (a: B): Any), member = (v1: A): Any = false
   |  <== (a: A) => Any(Test.f3) <:< (a: B) => Any   = false

In particular note (v1: A): Any <:< (a: B): Any = false, this makes sense because when overriding a method in Scala, refining its term parameters contravariantly is not allowed, but dependent function types are encoded with a refined apply method and this is not the behavior we want for them. It seems like we need some special-casing of dependent methods here. @odersky WDYT ?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions