diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 50e01e0f2c68..c67f33a15094 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3930,6 +3930,10 @@ object Types { def hasLowerBound(implicit ctx: Context): Boolean = !ctx.typerState.constraint.entry(origin).loBound.isBottomType + /** For uninstantiated type variables: Is the upper bound different from Any? */ + def hasUpperBound(implicit ctx: Context): Boolean = + !ctx.typerState.constraint.entry(origin).hiBound.isRef(defn.AnyClass) + /** Unwrap to instance (if instantiated) or origin (if not), until result * is no longer a TypeVar */ diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index dc086b630a62..e587eb8e2fff 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -46,7 +46,7 @@ object Inferencing { /** Instantiate selected type variables `tvars` in type `tp` */ def instantiateSelected(tp: Type, tvars: List[Type])(implicit ctx: Context): Unit = if (tvars.nonEmpty) - new IsFullyDefinedAccumulator(new ForceDegree.Value(tvars.contains, minimizeAll = true)).process(tp) + new IsFullyDefinedAccumulator(new ForceDegree.Value(tvars.contains, minimizeAll = true, allowBottom = false)).process(tp) /** Instantiate any type variables in `tp` whose bounds contain a reference to * one of the parameters in `tparams` or `vparamss`. @@ -108,10 +108,9 @@ object Inferencing { && ctx.typerState.constraint.contains(tvar) && { val direction = instDirection(tvar.origin) - def avoidBottom = - !force.allowBottom && - defn.isBottomType(ctx.typeComparer.approximation(tvar.origin, fromBelow = true)) - def preferMin = force.minimizeAll || variance >= 0 && !avoidBottom + def preferMin = + force.minimizeAll && (tvar.hasLowerBound || !tvar.hasUpperBound) + || variance >= 0 && (force.allowBottom || tvar.hasLowerBound) if (direction != 0) instantiate(tvar, direction < 0) else if (preferMin) instantiate(tvar, fromBelow = true) else toMaximize = true diff --git a/tests/neg/i1802.scala b/tests/neg/i1802.scala index c2e65d8dd8d7..d136b448a54a 100644 --- a/tests/neg/i1802.scala +++ b/tests/neg/i1802.scala @@ -14,7 +14,7 @@ object Exception { def apply(x: Throwable): T = f(downcast(x).get) } - def mkThrowableCatcher[T](isDef: Throwable => Boolean, f: Throwable => T) = mkCatcher(isDef, f) // error: undetermined ClassTag + def mkThrowableCatcher[T](isDef: Throwable => Boolean, f: Throwable => T) = mkCatcher(isDef, f) implicit def throwableSubtypeToCatcher[Ex <: Throwable: ClassTag, T](pf: PartialFunction[Ex, T]) = // error: result type needs to be given mkCatcher(pf.isDefinedAt _, pf.apply _) // error: method needs return type diff --git a/tests/pos/i7840.scala b/tests/pos/i7840.scala new file mode 100644 index 000000000000..e3ae73cc7178 --- /dev/null +++ b/tests/pos/i7840.scala @@ -0,0 +1,17 @@ +object Example extends App { + + trait ZSink[-R, +E, +A0, -A, +B] { + def flatMap[R1 <: R, E1 >: E, A00 >: A0, A1 <: A, C]( + f: B => ZSink[R1, E1, A00, A1, C] + )(implicit ev: A00 =:= A1, e2: A1 =:= A00): ZSink[R1, E1, A00, A1, C] = + ??? + } + + object ZSink { + def identity[A]: ZSink[Any, Unit, Nothing, A, A] = ??? + def succeed[A, B](b: B): ZSink[Any, Nothing, A, A, B] = ??? + } + + // cannot prove that Int =:= Nothing + ZSink.identity[Int].flatMap(n => ZSink.succeed[Int, String](n.toString)) +} \ No newline at end of file