Skip to content

Dependent Typing example no longer works with -source:3.1 and Matchable #10930

Closed
@deanwampler

Description

@deanwampler

Minimized code

The example here, https://dotty.epfl.ch/docs/reference/new-types/match-types.html#dependent-typing fails when 3.1 is enabled. I'm posting this as a bug, because it's not clear to me how to make it work. Reproducing the code here, the match type definition works fine:

type LeafElem[X] = X match
   case String => Char
   case Array[t] => LeafElem[t]
   case Iterable[t] => LeafElem[t]
   case AnyVal => X

But the method doesn't:

def leafElem[X](x: X): LeafElem[X] = x match
   case x: String      => x.charAt(0)
   case x: Array[t]    => leafElem(x(9))
   case x: Iterable[t] => leafElem(x.next())
   case x: AnyVal      => x

The error messages are these:

2 |   case x: String      => x.charAt(0)
  |           ^^^^^^
  |           pattern selector should be an instance of Matchable,
  |           but it has unmatchable type X instead
3 |   case x: Array[t]    => leafElem(x(9))
  |           ^^^^^^^^
  |           pattern selector should be an instance of Matchable,
  |           but it has unmatchable type X instead
4 |   case x: Iterable[t] => leafElem(x.next())
  |           ^^^^^^^^^^^
  |           pattern selector should be an instance of Matchable,
  |           but it has unmatchable type X instead
5 |   case x: AnyVal      => x
  |           ^^^^^^
  |           pattern selector should be an instance of Matchable,
  |           but it has unmatchable type X instead
4 |   case x: Iterable[t] => leafElem(x.next())
  |                                   ^^^^^^
  |value next is not a member of X & Iterable[t] - did you mean x.head?
  |
  |where:    X is a type in method leafElem with bounds >: (?1 : Iterable[t])

(There's also a bug in the Iterable line; it doesn't like x.next(). Using x.head does work...)

Adding a bound to X reduces the problem to the Array and Iterable lines:

scala> def leafElem[X <: Matchable](x: X): LeafElem[X] = x match
     |    case x: String      => x.charAt(0)
     |    case x: Array[t]    => leafElem(x(9))
     |    case x: Iterable[t] => leafElem(x.head)
     |    case x: AnyVal      => x
     |
3 |   case x: Array[t]    => leafElem(x(9))
  |                                   ^^^^
  |                                 value should be an instance of Matchable,
  |                                 but it has unmatchable type t instead
4 |   case x: Iterable[t] => leafElem(x.head)
  |                                   ^^^^^^
  |                                 value should be an instance of Matchable,
  |                                 but it has unmatchable type t instead

I've tried various ways to fix those warnings, like the following, which fail for different reasons:

def leafElem[X <: Matchable, X2 <: Matchable](x: X): LeafElem[X] = x match
   case x: String       => x.charAt(0)
   case x: Array[X2]    => leafElem(x(9))
   case x: Iterable[X2] => leafElem(x.head)
   case x: AnyVal       => x

def leafElem[X <: Matchable](x: X): LeafElem[X] = x match
   case x: String      => x.charAt(0)
   case x: Array[t <: Matchable]    => leafElem(x(9))
   case x: Iterable[t <: Matchable] => leafElem(x.head)
   case x: AnyVal      => x

Output

Inline above.

Expectation

Defining leafElem would be as straightforward as it is with Scala 3.0 flexibility.

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions