From 81e2e7f60bd79b9aa77bc59d78439e415ed1e0d1 Mon Sep 17 00:00:00 2001 From: odersky Date: Thu, 9 Nov 2023 19:01:45 +0100 Subject: [PATCH] Address review comments --- .../src/dotty/tools/dotc/core/Types.scala | 24 ++++++++++--------- .../dotty/tools/dotc/typer/Inferencing.scala | 10 +++++++- tests/neg/foldinf-ill-kinded.check | 7 ++++++ tests/neg/foldinf-ill-kinded.scala | 10 ++++++++ 4 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 tests/neg/foldinf-ill-kinded.check create mode 100644 tests/neg/foldinf-ill-kinded.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 0881de48f666..2561d9d3d7d7 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4895,16 +4895,16 @@ object Types { /** Instantiate variable with given type */ def instantiateWith(tp: Type)(using Context): Type = { assert(tp ne this, i"self instantiation of $origin, constraint = ${ctx.typerState.constraint}") - if !myInst.exists then - typr.println(i"instantiating $this with $tp") + assert(!myInst.exists, i"$origin is already instantiated to $myInst but we attempted to instantiate it to $tp") + typr.println(i"instantiating $this with $tp") - if Config.checkConstraintsSatisfiable then - assert(currentEntry.bounds.contains(tp), - i"$origin is constrained to be $currentEntry but attempted to instantiate it to $tp") + if Config.checkConstraintsSatisfiable then + assert(currentEntry.bounds.contains(tp), + i"$origin is constrained to be $currentEntry but attempted to instantiate it to $tp") - if ((ctx.typerState eq owningState.nn.get.uncheckedNN) && !TypeComparer.subtypeCheckInProgress) - setInst(tp) - ctx.typerState.constraint = ctx.typerState.constraint.replace(origin, tp) + if ((ctx.typerState eq owningState.nn.get.uncheckedNN) && !TypeComparer.subtypeCheckInProgress) + setInst(tp) + ctx.typerState.constraint = ctx.typerState.constraint.replace(origin, tp) tp } @@ -5811,11 +5811,13 @@ object Types { protected def derivedLambdaType(tp: LambdaType)(formals: List[tp.PInfo], restpe: Type): Type = tp.derivedLambdaType(tp.paramNames, formals, restpe) + protected def mapArg(arg: Type, tparam: ParamInfo): Type = arg match + case arg: TypeBounds => this(arg) + case arg => atVariance(variance * tparam.paramVarianceSign)(this(arg)) + protected def mapArgs(args: List[Type], tparams: List[ParamInfo]): List[Type] = args match case arg :: otherArgs if tparams.nonEmpty => - val arg1 = arg match - case arg: TypeBounds => this(arg) - case arg => atVariance(variance * tparams.head.paramVarianceSign)(this(arg)) + val arg1 = mapArg(arg, tparams.head) val otherArgs1 = mapArgs(otherArgs, tparams.tail) if ((arg1 eq arg) && (otherArgs1 eq otherArgs)) args else arg1 :: otherArgs1 diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index eb5c58294127..57620b32038b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -165,7 +165,9 @@ object Inferencing { (using Context) extends TypeAccumulator[Boolean] { /** Replace toplevel-covariant occurrences (i.e. covariant without double flips) - * of Nothing by fresh type variables. + * of Nothing by fresh type variables. Double-flips are not covered to be + * conservative and save a bit of time on traversals; we could probably + * generalize that if we see use cases. * For singleton types and references to module classes: try to * improve the widened type. For module classes, the widened type * is the intersection of all its non-transparent parent types. @@ -191,6 +193,12 @@ object Inferencing { mapOver(t) else t + // Don't map Nothing arguments for higher-kinded types; we'd get the wrong kind */ + override def mapArg(arg: Type, tparam: ParamInfo): Type = + if tparam.paramInfo.isLambdaSub then arg + else super.mapArg(arg, tparam) + end improve + /** Instantiate type variable with possibly improved computed instance type. * @return true if variable was instantiated with improved type, which * in this case should not be instantiated further, false otherwise. diff --git a/tests/neg/foldinf-ill-kinded.check b/tests/neg/foldinf-ill-kinded.check new file mode 100644 index 000000000000..c19c70c00a0c --- /dev/null +++ b/tests/neg/foldinf-ill-kinded.check @@ -0,0 +1,7 @@ +-- [E007] Type Mismatch Error: tests/neg/foldinf-ill-kinded.scala:9:16 ------------------------------------------------- +9 | ys.combine(x) // error + | ^^^^^^^^^^^^^ + | Found: Foo[List] + | Required: Foo[Nothing] + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg/foldinf-ill-kinded.scala b/tests/neg/foldinf-ill-kinded.scala new file mode 100644 index 000000000000..d4824561b0fc --- /dev/null +++ b/tests/neg/foldinf-ill-kinded.scala @@ -0,0 +1,10 @@ +class Foo[+T[_]]: + def combine[T1[x] >: T[x]](x: T1[Int]): Foo[T1] = new Foo +object Foo: + def empty: Foo[Nothing] = new Foo + +object X: + def test(xs: List[List[Int]]): Unit = + xs.foldLeft(Foo.empty)((ys, x) => + ys.combine(x) // error + )