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

Regression in match types combined with type lambda #19710

Closed
WojciechMazur opened this issue Feb 16, 2024 · 7 comments · Fixed by #19761
Closed

Regression in match types combined with type lambda #19710

WojciechMazur opened this issue Feb 16, 2024 · 7 comments · Fixed by #19761
Assignees
Labels
area:typer itype:bug regression This worked in a previous version but doesn't anymore
Milestone

Comments

@WojciechMazur
Copy link
Contributor

Based on forum post: https://users.scala-lang.org/t/scala-3-how-do-we-make-a-lambda-type-conform-to-a-subtype/9805

Compiler version

3.3.1
Last good release: 3.3.1-RC1-bin-20230514-b0ccf40-NIGHTLY
First bad release: 3.3.1-RC1-bin-20230515-22b2259-NIGHTLY
Bisect points to d1d6c2e

Minimized code

import scala.util.NotGiven

type HasName1 = [n] =>> [x] =>> x match {
    case n => true
    case _ => false
  }
@main def Test = {
  summon[HasName1["foo"]["foo"] =:= true]
  summon[NotGiven[HasName1["foo"]["bar"] =:= true]]
  summon[Tuple.Filter[(1, "foo", 2, "bar"), HasName1["foo"]] =:= Tuple1["foo"]] // error
}

Output

-- [E057] Type Mismatch Error: /Users/wmazur/projects/dotty/bisect/main.scala:10:44 
10 |  summon[Tuple.Filter[(1, "foo", 2, "bar"), HasName1["foo"]] =:= Tuple1["foo"]]
   |                                            ^
   |Type argument HasName1[("foo" : String)] does not conform to upper bound [_] =>> Boolean
   |
   |Note: a match type could not be fully reduced:
   |
   |  trying to reduce  HasName1[("foo" : String)]
   |
   | longer explanation available when compiling with `-explain`
1 error found

Expectation

Should comile (probably)

@WojciechMazur WojciechMazur added itype:bug area:typer regression This worked in a previous version but doesn't anymore labels Feb 16, 2024
@WojciechMazur
Copy link
Contributor Author

Not sure to whom it should be assigned. Maybe @dwijnand (merged the PR) or @odersky (supervision?)?

@odersky
Copy link
Contributor

odersky commented Feb 16, 2024

Maybe @sjrd could take a look.

@EugeneFlesselle
Copy link
Contributor

I believe this is as expected given the current subtyping rules for match types.
Unless an upper bound is declared, the unreduced match type is not determined to be <: Boolean.

type HasFoo[X] <: Boolean = X match {
  case "foo" => true
  case _ => false
}
type HasBar[X] = X match {
  case "bar" => true
  case _ => false
}

type F1 = Tuple.Filter[(1, "foo", 2, "bar"), HasFoo] // Ok
type F2 = Tuple.Filter[(1, "foo", 2, "bar"), HasBar] // Error

@hmf
Copy link

hmf commented Feb 20, 2024

@EugeneFlesselle I was the one who originally posted the question in scala-users discourse. I am aware that the "standard" match type above works and agree with you. However, I am using a type lambda that takes in a type parameter. So my question is, how do I add the upper bound in this case? I have tried the obvious, but that does not seem to work.

TIA

@EugeneFlesselle
Copy link
Contributor

EugeneFlesselle commented Feb 20, 2024

@hmf Unfortunately, upper bounds are simply not supported for type lambdas. In fact, I think they can only appear in an alias for a match type, as they can be necessary when defining recursive match types.

So in this case you are forced to use type aliases, ending up with something like:

type HasName2[N] = [M] =>> HasName3[N, M]
type HasName3[N, M] <: Boolean = M match
  case N => true
  case M => false

summon[Tuple.Filter[(1, "foo", 2, "bar"), HasName2["foo"]] =:= Tuple1["foo"]] // Ok

@EugeneFlesselle
Copy link
Contributor

EugeneFlesselle commented Feb 20, 2024

It's also debatable whether the parameter P of Tuple.Filter needed such an upper bound to begin with. You could also define:

type Filter1[T <: Tuple, P[_]] = T match
  case EmptyTuple => EmptyTuple
  case h *: t => P[h] match
    case true => h *: Filter1[t, P]
    case false => Filter1[t, P]

summon[Filter1[(1, "foo", 2, "bar"), HasName1["foo"]] =:= Tuple1["foo"]] // Ok

@hmf
Copy link

hmf commented Feb 21, 2024

@EugeneFlesselle Thanks for the information. Your type alias solution is ok for me. As for the Tuple.Filter upper bound, personally I think it is ok too.

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.

7 participants