diff --git a/compiler/src/dotty/tools/dotc/ast/Positioned.scala b/compiler/src/dotty/tools/dotc/ast/Positioned.scala index 1b9da30745e7..bb4721cfd065 100644 --- a/compiler/src/dotty/tools/dotc/ast/Positioned.scala +++ b/compiler/src/dotty/tools/dotc/ast/Positioned.scala @@ -34,7 +34,7 @@ abstract class Positioned extends DotClass with Product { * destructively and the item itself is returned. */ def withPos(pos: Position): this.type = { - val newpd = (if (pos == curPos || curPos.isSynthetic) this else clone).asInstanceOf[Positioned] + val newpd = (if (pos == curPos || curPos.isSynthetic) this else clone.asInstanceOf[Positioned]) newpd.setPos(pos) newpd.asInstanceOf[this.type] } diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index 3d867ee7e722..a8d09ba7b6d8 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -58,7 +58,7 @@ object Config { /** Type comparer will fail with an assert if the upper bound * of a constrained parameter becomes Nothing. This should be turned * on only for specific debugging as normally instantiation to Nothing - * is not an error consdition. + * is not an error condition. */ final val failOnInstantiationToNothing = false diff --git a/compiler/src/dotty/tools/dotc/core/Constraint.scala b/compiler/src/dotty/tools/dotc/core/Constraint.scala index 7431a5e48d28..02d4fc1dd5b9 100644 --- a/compiler/src/dotty/tools/dotc/core/Constraint.scala +++ b/compiler/src/dotty/tools/dotc/core/Constraint.scala @@ -60,7 +60,7 @@ abstract class Constraint extends Showable { * are not contained in the return bounds. * @pre `param` is not part of the constraint domain. */ - def nonParamBounds(param: TypeParamRef): TypeBounds + def nonParamBounds(param: TypeParamRef)(implicit ctx: Context): TypeBounds /** The lower bound of `param` including all known-to-be-smaller parameters */ def fullLowerBound(param: TypeParamRef)(implicit ctx: Context): Type diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index 0dccb26fa617..16c9d4056138 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -341,19 +341,22 @@ trait ConstraintHandling { * and propagate all bounds. * @param tvars See Constraint#add */ - def addToConstraint(tl: TypeLambda, tvars: List[TypeVar]): Unit = - assert { - checkPropagated(i"initialized $tl") { - constraint = constraint.add(tl, tvars) - tl.paramNames.indices.forall { i => - val param = tl.paramRefs(i) - val bounds = constraint.nonParamBounds(param) - val lower = constraint.lower(param) - val upper = constraint.upper(param) - if (lower.nonEmpty && !bounds.lo.isRef(defn.NothingClass) || - upper.nonEmpty && !bounds.hi.isRef(defn.AnyClass)) constr.println(i"INIT*** $tl") - lower.forall(addOneBound(_, bounds.hi, isUpper = true)) && - upper.forall(addOneBound(_, bounds.lo, isUpper = false)) + def addToConstraint(tl: TypeLambda, tvars: List[TypeVar]): Boolean = + checkPropagated(i"initialized $tl") { + constraint = constraint.add(tl, tvars) + tl.paramRefs.forall { param => + constraint.entry(param) match { + case bounds: TypeBounds => + val lower = constraint.lower(param) + val upper = constraint.upper(param) + if (lower.nonEmpty && !bounds.lo.isRef(defn.NothingClass) || + upper.nonEmpty && !bounds.hi.isRef(defn.AnyClass)) constr.println(i"INIT*** $tl") + lower.forall(addOneBound(_, bounds.hi, isUpper = true)) && + upper.forall(addOneBound(_, bounds.lo, isUpper = false)) + case _ => + // Happens if param was already solved while processing earlier params of the same TypeLambda. + // See #4720. + true } } } diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala index 086bb68064fd..6d834b864131 100644 --- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -191,8 +191,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds, def isLess(param1: TypeParamRef, param2: TypeParamRef): Boolean = upper(param1).contains(param2) - def nonParamBounds(param: TypeParamRef): TypeBounds = - entry(param).asInstanceOf[TypeBounds] + def nonParamBounds(param: TypeParamRef)(implicit ctx: Context): TypeBounds = + entry(param).bounds def fullLowerBound(param: TypeParamRef)(implicit ctx: Context): Type = (nonParamBounds(param).lo /: minLower(param))(_ | _) diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 199da3747b7c..020d3a8dcfd8 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -457,10 +457,10 @@ object ProtoTypes { s"inconsistent: no typevars were added to committable constraint ${state.constraint}") def newTypeVars(tl: TypeLambda): List[TypeTree] = - for (n <- (0 until tl.paramNames.length).toList) + for (paramRef <- tl.paramRefs) yield { val tt = new TypeVarBinder().withPos(owningTree.pos) - val tvar = new TypeVar(tl.paramRefs(n), state) + val tvar = new TypeVar(paramRef, state) state.ownedVars += tvar tt.withType(tvar) } diff --git a/tests/neg/i4721.scala b/tests/neg/i4721.scala new file mode 100644 index 000000000000..7e532056a9bd --- /dev/null +++ b/tests/neg/i4721.scala @@ -0,0 +1,4 @@ +object Test { + def main(args: Array[String]):Unit = m(1) // error + def m[Y<:String, Z>:Int, W>:Z<:Y](d:Y):Unit={} +} diff --git a/tests/neg/i4721a.scala b/tests/neg/i4721a.scala new file mode 100644 index 000000000000..7dc4baec2970 --- /dev/null +++ b/tests/neg/i4721a.scala @@ -0,0 +1,4 @@ +object Test { + def main(args: Array[String]):Unit = m("1") // error + def m[Y<:String, Z>:Int, W>:Z<:Y](d:Y):Unit={} +} diff --git a/tests/pos/i4720.scala b/tests/pos/i4720.scala new file mode 100644 index 000000000000..f4df12c42edd --- /dev/null +++ b/tests/pos/i4720.scala @@ -0,0 +1,4 @@ +object Test { + def main(args: Array[String]):Unit = m(1) + def m[Y<:Int, Z>:Int, W>:Z<:Y](d:Y):Unit={} +}