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

Incorrect inferred type in contravariant position #4881

Open
scabug opened this issue Aug 6, 2011 · 9 comments
Open

Incorrect inferred type in contravariant position #4881

scabug opened this issue Aug 6, 2011 · 9 comments
Labels
fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) infer
Milestone

Comments

@scabug
Copy link

scabug commented Aug 6, 2011

class Contra[-T]
trait A
trait B extends A
trait C extends B
def contraLBUB[a >: C <: A](): Contra[a] = null
def contraLB[a >: C](): Contra[a] = null
contraLBUB() //inferred Contra[C] instead of Contra[A]
contraLB() //inferred Contra[C] instead of Contra[Any]

According to Language specification (6.26.4 Case 2):
If several substitutions exist,
local-type inference will choose for each type variable ai a minimal or maximal type
Ti of the solution space. A maximal type Ti will be chosen if the type parameter ai
appears contravariantly (§4.5) in the type T of the expression. A minimal type Ti
will be chosen in all other situations, i.e. if the variable appears covariantly, nonvariantly
or not at all in the type T.

What we can see here. Value has Type Contra[a]. So position of a is contravariant. There is no covariant or invariant positions of a => maximal solution should be chosen.

@scabug
Copy link
Author

scabug commented Aug 6, 2011

Imported From: https://issues.scala-lang.org/browse/SI-4881?orig=1
Reporter: @Alefas
Affected Versions: 2.9.0-1

@scabug
Copy link
Author

scabug commented Aug 6, 2011

@retronym said:
Actually, it works as expected as a Value (Case 2)

scala> contraLBUB
res9: Contra[A] = null

scala> contraLB
res10: Contra[Any] = null

So the question is, does "Case 3: Methods" explain these?

scala> contraLBUB()
res11: Contra[C] = null

scala> contraLB()
res12: Contra[C] = null

@scabug
Copy link
Author

scabug commented Aug 7, 2011

@Alefas said:
I'm sure this is wrong if it's different:

foo
foo()

@scabug
Copy link
Author

scabug commented Aug 7, 2011

@paulp said:
Yeah, that's a bit hard to defend:


scala> contraLBUB
res1: Contra[A] = null

scala> contraLBUB()
res2: Contra[C] = null

scala> (contraLBUB _)()
res3: Contra[A] = null

@scabug
Copy link
Author

scabug commented Jun 21, 2012

@retronym said:
Without having checked the consequences (sky falling, etc), but this is enough to restore consistency between inference for the value and method application:

diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.s
index 688dcd9..a34b93d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -575,8 +575,9 @@ trait Infer {
             "argument expression's type is not compatible with formal parameter type" + foundReqMsg(tp1, pt1))
         }
       }
       val targs = solvedTypes(
-        tvars, tparams, tparams map varianceInTypes(formals),
+        tvars, tparams, tparams map varianceInTypes(restpe +: formals),
         false, lubDepth(formals) max lubDepth(argtpes)
       )
       adjustTypeArgs(tparams, tvars, targs, restpe)

Compare with:

https://github.com/scala/scala/blob/039d826e/src/compiler/scala/tools/nsc/typechecker/Infer.scala#L384

@scabug
Copy link
Author

scabug commented Jun 21, 2012

@adriaanm said (edited on Jun 21, 2012 8:09:59 AM UTC):
I think that needs to be adjusted slightly since the variance in formals should be flipped (arguments = contravariant), whereas restpe is in covariant position (the flipping is achieved by the up=false argument to solvedTypes, off the top of my head)

@scabug
Copy link
Author

scabug commented Jul 23, 2012

@adriaanm said:
scala/scala#975

@scabug
Copy link
Author

scabug commented Sep 29, 2012

@paulp said:
This is being reverted for causing #6311.

@scabug
Copy link
Author

scabug commented Sep 30, 2012

@Blaisorblade said:
Fixing this means that Coll would be inferred differently for these two signatures, which look instead equivalent:

def f[T, Coll <: Traversable[T]](p0: String)(p1: Traversable[T]): (Coll => Traversable[T]) = ??? //Here Coll would be maximized.
def f[T, Coll <: Traversable[T]](p0: String)(p1: Traversable[T])(p2: Coll): Traversable[T] = ??? //Here Coll would be minimized.

This is if I get the new expected behavior right, which says that (ignoring mixed variance) a type argument must be minimized (made most specific) if it appears either:
(a) covariantly in the result type (per 4881), hence covariantly in the method type or
(b) covariantly in argument types, hence contravariantly in the method type.

@scabug scabug added this to the Backlog milestone Apr 7, 2017
@scala scala deleted a comment from scabug Jul 24, 2023
@SethTisue SethTisue added the fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) label Jul 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) infer
Projects
None yet
Development

No branches or pull requests

2 participants