Skip to content

Wildcard types are not properly inferred in pattern matching #13998

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

Closed
Atry opened this issue Nov 24, 2021 · 3 comments · Fixed by #14132
Closed

Wildcard types are not properly inferred in pattern matching #13998

Atry opened this issue Nov 24, 2021 · 3 comments · Fixed by #14132
Assignees
Labels
area:typer itype:bug regression This worked in a previous version but doesn't anymore
Milestone

Comments

@Atry
Copy link
Contributor

Atry commented Nov 24, 2021

Compiler version

3.1.0

Minimized code

val as: Array[_ <: Seq[String]] = Array(Seq("text"))

as match {
  case Array(Seq(text)) =>
    text.length
  case _ =>
}

Output

It does not compile

value length is not a member of Any

Expectation

It should compile

@dwijnand
Copy link
Member

dwijnand commented Dec 12, 2021

Got a little worried, perhaps just paranoid, of the use of Array, so I defined my mini array type, and dropped the second pattern to minimise it a little more, and got it to yield (under -explain) some subtyping info:

scala> case class Arr[A](head: A)
// defined case class Arr

scala> val at: Arr[_ <: String] = Arr("text")
val at: Arr[? <: String] = Arr(text)

scala> at match { case Arr(text) => text: String }
-- [E007] Type Mismatch Error: -------------------------------------------------
1 |at match { case Arr(text) => text: String }
  |                             ^^^^
  |                             Found:    (text : A$1)
  |                             Required: String

Explanation
===========

Tree: text

I tried to show that
  (text : A$1)
conforms to
  String
but the comparison trace ended with `false`:

  ==> (text : A$1)  <:  String
    ==> (text : A$1)  <:  String (recurring)
      ==> (text : A$1)  <:  String (recurring)
        ==> A$1  <:  String (left is approximated)
          ==> A$1  <:  String (recurring)
            ==> Any  <:  String (left is approximated)
              ==> Any  <:  String (recurring)
              <== Any  <:  String (recurring) = false
            <== Any  <:  String (left is approximated) = false
            ==> Any  <:  String in frozen constraint
              ==> Any  <:  String (recurring) in frozen constraint
              <== Any  <:  String (recurring) in frozen constraint = false
            <== Any  <:  String in frozen constraint = false
          <== A$1  <:  String (recurring) = false
        <== A$1  <:  String (left is approximated) = false
      <== (text : A$1)  <:  String (recurring) = false
    <== (text : A$1)  <:  String (recurring) = false
  <== (text : A$1)  <:  String = false

The tests were made under the empty constraint

1 error found

Looks to me like the type variable A$1 doesn't properly have a String upper bound? It doesn't explain what kind of approximating it's doing when it goes from A$1 to Any, but that's my first guess.

@dwijnand
Copy link
Member

Looks even worst with a covariant type, as the binding is already typed as Any:

scala> case class Arr2[+A](head: A)
// defined case class Arr2

scala> val at2: Arr2[_ <: String] = Arr2("text")
val at2: Arr2[? <: String] = Arr2(text)

scala> at2 match { case Arr2(text) => text: String }
-- [E007] Type Mismatch Error: -------------------------------------------------
1 |at2 match { case Arr2(text) => text: String }
  |                               ^^^^
  |                               Found:    (text : Any)
  |                               Required: String

Explanation
===========

Tree: text

I tried to show that
  (text : Any)
conforms to
  String
but the comparison trace ended with `false`:

  ==> (text : Any)  <:  String
    ==> (text : Any)  <:  String (recurring)
      ==> (text : Any)  <:  String (recurring)
        ==> Any  <:  String (left is approximated)
          ==> Any  <:  String (recurring)
          <== Any  <:  String (recurring) = false
        <== Any  <:  String (left is approximated) = false
      <== (text : Any)  <:  String (recurring) = false
    <== (text : Any)  <:  String (recurring) = false
  <== (text : Any)  <:  String = false

The tests were made under the empty constraint

1 error found

@dwijnand dwijnand changed the title The element type of a wildcard type in an invariant type is not properly inferred Pattern matching with a wildcard type doesn't properly infer Dec 12, 2021
@Atry Atry changed the title Pattern matching with a wildcard type doesn't properly infer Wildcard type is not properly inferred in pattern matching Dec 13, 2021
@Atry Atry changed the title Wildcard type is not properly inferred in pattern matching Wildcard types are not properly inferred in pattern matching Dec 13, 2021
@SethTisue
Copy link
Member

SethTisue commented Dec 16, 2021

Dang. This is a pretty fundamental bug.

(And, it works in Scala 2.)

@dwijnand dwijnand linked a pull request Dec 18, 2021 that will close this issue
@dwijnand dwijnand added the regression This worked in a previous version but doesn't anymore label Dec 21, 2021
@Kordyjan Kordyjan added this to the 3.1.2 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:typer itype:bug regression This worked in a previous version but doesn't anymore
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants