question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Matching on Option[Option[T]] where T is abstract and obtained from inline def in super trait emits exhaustivity warning

See original GitHub issue

Compiler version

Scala 3.2.1

Minimized code

trait Base:
    type Value
    inline def oov: Option[Option[Value]] = None
    def get: Option[Value]

trait X extends Base:
    override def get: Option[Value] =
        oov match
            case Some(ov) => ov
            case None => None

Output

The compiler emits the following warning:

[warn] -- [E029] Pattern Match Exhaustivity Warning: /path/to/Test.scala:8:8 
[warn] 8 |        oov match
[warn]   |        ^^^
[warn]   |        match may not be exhaustive.
[warn]   |
[warn]   |        It would fail on pattern case: Some(_)
[warn]   |
[warn]   | longer explanation available when compiling with `-explain`
[warn] one warning found

Expectation

The code should compile.

Workarounds

We have found three ways to make the code compile without this warning and one that gives a new unexpected error:

Extract oov to local value

trait Base:
    type Value
    inline def oov: Option[Option[Value]] = None
    def get: Option[Value]

trait X extends Base:
    override def get: Option[Value] =
        val local_oov = oov
        local_oov match
            case Some(ov) => ov
            case None => None

Remove inline

Without the inline modifier, the code compiles:

trait Base:
    type Value
    def oov: Option[Option[Value]] = None
    def get: Option[Value]

trait X extends Base:
    override def get: Option[Value] =
        oov match
            case Some(ov) => ov
            case None => None

Make type Value concrete

trait Base:
    type Value
    inline def oov: Option[Option[Value]] = None
    def get: Option[Value]

trait X extends Base:
    override type Value = Int
    override def get: Option[Value] =
        oov match
            case Some(ov) => ov
            case None => None

Adding transparent to inline results in new error

This code

trait Base:
    type Value
    transparent inline def oov: Option[Option[Value]] = None
    def get: Option[Value]

trait X extends Base:
    override def get: Option[Value] =
        oov match
            case Some(ov) => ov
            case None => None

causes the compiler to emit this error:

[error] -- [E007] Type Mismatch Error: /path/to/Test.scala:9:29 
[error] 9 |            case Some(ov) => ov
[error]   |                             ^^
[error]   |                             Found:    (ov : Any)
[error]   |                             Required: Option[X.this.Value]

Issue Analytics

  • State:open
  • Created 10 months ago
  • Comments:8 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
dwijnandcommented, Nov 29, 2022

That transparent inline one is also wrong: the type variable ?A in Some.unapply should infer to be upper-bounded by Nothing, and then instantiate to Nothing, not to Any.

0reactions
smartercommented, Dec 15, 2022

Looks like this is caused by the use of tryWiden in https://github.com/lampepfl/dotty/blob/ef653b6a31180416ff6b7fdc432e9ef0343b7075/compiler/src/dotty/tools/dotc/core/TypeOps.scala#L495-L507 In our situation, tp is local.X and pre is this.type. Since the new prefix is a singleton it makes sense to go with that instead of the current logic which ends up widening local.X to Nothing .. Any (and then Any because we’re in a covariant position)

Read more comments on GitHub >

github_iconTop Results From Across the Web

scala - Type parameter circumvents match exhaustivity warning
If the selector of a pattern match is an instance of a sealed class, the compilation of pattern matching can emit warnings which...
Read more >
Match may not be exhaustive warning, is this a big deal?
I have a function like so def foo(bar: Bar): Future[Unit] = { (bar.food, bar.isEnabled) match { case (Food.bread, true) => bazz() case ...
Read more >
The Rust Programming Language
Documentation for how to use and how to build the platform is available. Target, std, rustc, cargo, notes. i686-apple-darwin, ✓ ...
Read more >
The Practical Difference Between Abstract Classes and Traits ...
This short article will compare abstract classes and traits as means of inheritance.
Read more >
Exam 2 Flashcards - Quizlet
A. If a class is declared to be abstract then every method in the class is abstract ... when a concrete class is...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found