Skip to content
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

Failure to unify types in pattern match #22405

Open
nrinaudo opened this issue Jan 18, 2025 · 0 comments
Open

Failure to unify types in pattern match #22405

nrinaudo opened this issue Jan 18, 2025 · 0 comments
Labels
itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label

Comments

@nrinaudo
Copy link

nrinaudo commented Jan 18, 2025

Compiler version

scalac -version
Scala compiler version 3.6.2 -- Copyright 2002-2024, LAMP/EPFL

Minimized code

enum Type:
  case Num
  case Bool

enum TypedExpr[A <: Type]:
  case Num(value: Int) extends TypedExpr[Type.Num.type]
  case Bool(value: Boolean) extends TypedExpr[Type.Bool.type]

case class Typing[A <: Type](expr: TypedExpr[A], tpe: A):
  def cast[B <: Type](to: B): Either[String, TypedExpr[B]] = this match
    case Typing(expr, `to`) => Right(expr)
    case _                  => Left("Failed")

Output

-- [E007] Type Mismatch Error: Test.scala:12:35 --------------------------------
12 |  case Typing(expr, `to`) => Right(expr)
   |                                   ^^^^
   |                Found:    (expr : TypedExpr[A])
   |                Required: TypedExpr[B]
   |
   |                where:    A is a type in method cast with bounds <: Type
   |                          B is a type in method cast with bounds <: Type
   |
   | longer explanation available when compiling with `-explain`

Expectation

I would expect the compiler to understand that:

  • to is equal to repr, so they must be of the same type.
  • this implies that A and B are the same type.
  • which implies that expr is a legal TypedExpr[B].

This might be an unreasonable expectation on my part, but I think it's born out by the fact that the following works flawlessly (keeping the same Type and TypedExpr:

enum TypeRepr[A <: Type]:
  case Num extends TypeRepr[Type.Num.type]
  case Bool extends TypeRepr[Type.Bool.type]

case class Typing[A <: Type](expr: TypedExpr[A], repr: TypeRepr[A]):
  def cast[B <: Type](to: TypeRepr[B]): Either[String, TypedExpr[B]] = this match
    case Typing(expr, `to`) => Right(expr)
    case _                  => Left("Failed")

With that code, the compiler seems perfectly happy to concluse that A and B are the same type and expr is a valid TypedExpr[B].

The only difference, as far as I understand, is that TypeRepr is indexed on Type rather than being a Type directly, but I'm not sure what additional information / confidence this gives the compiler.

@nrinaudo nrinaudo added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Jan 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label
Projects
None yet
Development

No branches or pull requests

1 participant