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

No longer able to extract a type from an intersection #19999

Closed
johnhungerford opened this issue Mar 21, 2024 · 5 comments · Fixed by #20007
Closed

No longer able to extract a type from an intersection #19999

johnhungerford opened this issue Mar 21, 2024 · 5 comments · Fixed by #20007
Assignees
Milestone

Comments

@johnhungerford
Copy link

Compiler version

Does not compile on 3.4.0 (or 3.0.0, 3.1.0, 3.2.0, 3.3.0)

Does compile in 2.13.12

Minimized code

sealed trait InIntersection[I, A] {
    type R // Remaining types in the intersection Int
}

object InIntersection {
    implicit def derived[A, R0]: InIntersection[A & R0, A] = new InIntersection[A & R0, A] {
        type R = R0
    }
}

implicitly[InIntersection[Int & String, Int]]

Output

[error] No given instance of type IntersectionBug$_.this.InIntersection[Int & String, Int] was found for parameter e of method implicitly in object Predef.
[error] I found:
[error] 
[error]     this.InIntersection.derived[A, R0]
[error] 
[error] But method derived in object InIntersection does not match type IntersectionBug$_.this.InIntersection[Int & String, Int].
[error] implicitly[InIntersection[Int & String, Int]]
[error]                                              ^
Error compiling project (Scala 3.4.0, JVM (17))
Compilation failed

Expectation

I would expect it to compile. It does compile with scala 2.13.12 (if I change the & to with).

@johnhungerford johnhungerford added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Mar 21, 2024
@som-snytt
Copy link
Contributor

It does compile with scala 2.13.12 (if I change the & to with).

You want -Xsource:3.

@odersky odersky removed the stat:needs triage Every issue needs to have an "area" and "itype" label label Mar 23, 2024
@odersky odersky self-assigned this Mar 23, 2024
@odersky
Copy link
Contributor

odersky commented Mar 23, 2024

Minimization:

class InIntersection[I, A]

def derived[A, R0]: InIntersection[A & R0, A] = new InIntersection[A & R0, A]

val x: InIntersection[Int & String, Int] = derived // error

Here is the error with -explain

-- [E007] Type Mismatch Error: ../new/test.scala:5:43 --------------------------
5 |val x: InIntersection[Int & String, Int] = derived
  |                                           ^^^^^^^
  |                               Found:    InIntersection[A & R0, A]
  |                               Required: InIntersection[Int & String, Int]
  |
  |                               where:    A  is a type variable
  |                                         R0 is a type variable
  |-----------------------------------------------------------------------------
  | Explanation (enabled by `-explain`)
  |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  |
  | Tree: derived[A, R0]
  | I tried to show that
  |   InIntersection[A & R0, A]
  | conforms to
  |   InIntersection[Int & String, Int]
  | but none of the attempts shown below succeeded:
  |
  |   ==> InIntersection[A & R0, A]  <:  InIntersection[Int & String, Int]
  |     ==> Int  <:  A
  |       ==> Int  <:  A in frozen constraint
  |         ==> Int  <:  Int & String in frozen constraint
  |           ==> Int  <:  String in frozen constraint  = false
  |       ==> add constraint A >: Int , constraint =  uninstantiated variables: A, R0  constrained types: [A, R0]: InIntersection[A & R0, A]  bounds:      A >: Int & String <: Int & String      R0 >: Int & String  ordering:  co-deps:  contra-deps: 
  |         ==> Int  <:  Int & String in frozen constraint
  |           ==> Int  <:  String in frozen constraint  = false
  |         ==> Int  <:  Int & String
  |           ==> Int  <:  String  = false
  |
  | The tests were made under a constraint with:
  |  uninstantiated variables: A, R0
  |  constrained types: [A, R0]: InIntersection[A & R0, A]
  |  bounds:
  |      A
  |      R0
  |  ordering:
  |  co-deps:
  |  contra-deps:
   -----------------------------------------------------------------------------

Interestingly it compiles OK if the second type parameter is dropped:

class InIntersection[I]

def derived[A, R0]: InIntersection[A & R0] = new InIntersection[A & R0]

var x: InIntersection[Int & String] = derived // OK

@odersky
Copy link
Contributor

odersky commented Mar 23, 2024

Hint to issue reporters: If possible avoid reference to summon, implicitly, =:=, or <:<, or other implicit mechanisms. It just increases the footprint where the error could be. Of course, if the error is linked to implicits and cannot be reproduced without them, do report it like that.

@odersky
Copy link
Contributor

odersky commented Mar 23, 2024

The example also compiles if the order of parameters is reversed:

class InIntersection[A, I]

def derived[A, R0]: InIntersection[A, A & R0] = new InIntersection[A, A & R0]

var x: InIntersection[Int, Int & String] = derived

What happens in the failing example is that the first constraint A & R0 =:= Int & String is handled first. It results in both A and R0 being instantiated to Int & String. Then the second constraint A =::= Int fails.

@odersky
Copy link
Contributor

odersky commented Mar 23, 2024

We could maybe try to re-order the comparison of type arguments, delaying constraints that look hard. A hard constraint would be one that has a & on the LHS or an | on the RHS, since both of these need a fork via either.

odersky added a commit to dotty-staging/dotty that referenced this issue Mar 23, 2024
When comparing arguments of two applied types, perform hard comparisons
after easy ones. A comparison if hard if it entails a subtype test A <: B
where A is an AndType or B is an OrType. Such comparisons need to perform an either,
which might lose solutions.

Fixes scala#19999
smarter added a commit that referenced this issue Mar 26, 2024
When comparing arguments of two applied types, perform hard comparisons
after easy ones. A comparison is hard if it entails a subtype test A <:
B where A is an AndType or B is an OrType. Such comparisons need to
perform an either, which might lose solutions.

Fixes #19999
@Kordyjan Kordyjan added this to the 3.4.2 milestone Mar 28, 2024
@Kordyjan Kordyjan modified the milestones: 3.4.2, 3.5.0 May 10, 2024
WojciechMazur added a commit that referenced this issue Jul 4, 2024
When comparing arguments of two applied types, perform hard comparisons
after easy ones. A comparison if hard if it entails a subtype test A <: B
where A is an AndType or B is an OrType. Such comparisons need to perform an either,
which might lose solutions.

Fixes #19999

[Cherry-picked bda6763][modified]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants