Skip to content

Commit 33a8fbf

Browse files
committed
Thread the needle on "hasUpperBound" instantiating tvars
1 parent dde69ce commit 33a8fbf

File tree

3 files changed

+44
-2
lines changed

3 files changed

+44
-2
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4895,9 +4895,12 @@ object Types {
48954895
/** For uninstantiated type variables: Is the lower bound different from Nothing? */
48964896
def hasLowerBound(using Context): Boolean = !currentEntry.loBound.isExactlyNothing
48974897

4898-
/** For uninstantiated type variables: Is the upper bound different from Any? */
4898+
/** For uninstantiated type variables: Is the upper bound different from Any or any type constructor? */
48994899
def hasUpperBound(using Context): Boolean = !currentEntry.hiBound.finalResultType.isExactlyAny
49004900

4901+
/** For uninstantiated type variables: Is the upper bound different from Any? */
4902+
def hasUpperBoundSimpleKind(using Context): Boolean = !currentEntry.hiBound.isExactlyAny
4903+
49014904
/** Unwrap to instance (if instantiated) or origin (if not), until result
49024905
* is no longer a TypeVar
49034906
*/

compiler/src/dotty/tools/dotc/typer/Inferencing.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ object Inferencing {
182182
if minimizeSelected then
183183
if direction <= 0 && tvar.hasLowerBound then
184184
instantiate(tvar, fromBelow = true)
185-
else if direction >= 0 && tvar.hasUpperBound then
185+
else if direction >= 0 && tvar.hasUpperBoundSimpleKind then
186186
instantiate(tvar, fromBelow = false)
187187
// else hold off instantiating unbounded unconstrained variable
188188
else if direction != 0 then

tests/pos/i18163.scala

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import scala.language.implicitConversions
2+
3+
// We do have 2 `contramap` functions, one provided via `LoggerSyntax` other via `Contravariant.Ops`
4+
// `ContravariantMonoidal` given instances are not used, and they do not match our type. Code fails when we have at least 2 instances of them
5+
// Removal of `import catsSyntax._` allow to compile code
6+
// Removal of `import odinSyntax.LoggerSyntax` and remaining `catsSyntax` would fail to compile the `def fails`
7+
8+
trait Foo[A]
9+
trait Bar[A]
10+
11+
trait WriterT[F[_]: Contravariant, L, V]:
12+
def contramap[Z](fn: Z => V): WriterT[F, L, Z] = ???
13+
trait Logger[F[_]]
14+
class WriterTLogger[F[_]] extends Logger[[G] =>> WriterT[F, List[String], G]]
15+
16+
trait ContravariantMonoidal[F[_]] extends Invariant[F] with Contravariant[F]
17+
trait Invariant[F[_]]
18+
object Invariant:
19+
given ContravariantMonoidal[Foo] = ???
20+
given ContravariantMonoidal[Bar] = ???
21+
22+
trait Contravariant[F[_]] extends Invariant[F]
23+
object Contravariant:
24+
trait Ops[F[_], A]:
25+
def contramap[B](f: B => A): F[B] = ???
26+
27+
object catsSyntax:
28+
implicit def toContravariantOps[F[_]: Contravariant, A](target: F[A]): Contravariant.Ops[F, A] = ???
29+
30+
object odinSyntax:
31+
implicit class LoggerSyntax[F[_]](logger: Logger[F]):
32+
def contramap(f: String => String): Logger[F] = ???
33+
34+
import catsSyntax._
35+
import odinSyntax.LoggerSyntax
36+
37+
class Test:
38+
def fails = new WriterTLogger[Option].contramap(identity)
39+
def works = LoggerSyntax(new WriterTLogger[Option]).contramap(identity)

0 commit comments

Comments
 (0)