diff --git a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala index 3e00907332f2..e7dfc74bd760 100644 --- a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala +++ b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala @@ -1041,18 +1041,28 @@ class CheckCaptures extends Recheck, SymTransformer: checkConformsExpr(argType, paramType, param) .showing(i"compared expected closure formal $argType against $param with ${paramTpt.nuType}", capt) if resType.isValueType && isFullyDefined(resType, ForceDegree.none) then - val localResType = pt match + + def updateTpt(localResType: Type) = + mdef.tpt.updNuType(localResType) + // Make sure we affect the info of the anonfun by the previous updNuType + // unless the info is already defined in a previous phase and does not change. + assert(!anonfun.isCompleted || anonfun.denot.validFor.firstPhaseId != thisPhase.id) + + pt match case RefinedType(_, _, mt: MethodType) => - inContext(ctx.withOwner(anonfun)): - Internalize(mt)(resType) - case _ => resType - mdef.tpt.updNuType(localResType) - // Make sure we affect the info of the anonfun by the previous updNuType - // unless the info is already defined in a previous phase and does not change. - assert(!anonfun.isCompleted || anonfun.denot.validFor.firstPhaseId != thisPhase.id) - //println(i"updating ${mdef.tpt} to $localResType/${mdef.tpt.nuType}") + if !mt.isResultDependent then + // If mt is result dependent we could compensate this by + // internalizing `resType.substParams(mt, params.tpes)`. + // But this tends to give worse error messages, so we refrain + // from doing that and don't update the local result type instead. + val localResType = inContext(ctx.withOwner(anonfun)): + Internalize(mt)(resType) + updateTpt(localResType) + case _ => + updateTpt(resType) case _ => case Nil => + end matchParamsAndResult openClosures = (anonfun, pt) :: openClosures // openClosures is needed for errors but currently makes no difference diff --git a/tests/neg-custom-args/captures/filevar.check b/tests/neg-custom-args/captures/filevar.check index 0bfc7f71cd9d..41d749727a04 100644 --- a/tests/neg-custom-args/captures/filevar.check +++ b/tests/neg-custom-args/captures/filevar.check @@ -1,12 +1,13 @@ -- [E007] Type Mismatch Error: tests/neg-custom-args/captures/filevar.scala:15:12 -------------------------------------- 15 | withFile: f => // error with level checking, was OK under both schemes before | ^ - |Found: (f: File^'s1) ->'s2 Unit - |Required: (f: File^{l}) => Unit + |Found: (l: scala.caps.Capability^) ?->'s1 File^'s2 ->'s3 Unit + |Required: (l: scala.caps.Capability^) ?-> (f: File^{l}) => Unit | - |Note that capability l cannot be included in outer capture set 's1 of parameter f. + |Note that capability l cannot be included in outer capture set 's4 of parameter f. | - |where: => refers to a fresh root capability created in anonymous function of type (using l: scala.caps.Capability): File^{l} -> Unit when instantiating expected result type (f: File^{l}) ->{cap} Unit of function literal + |where: => refers to a root capability associated with the result type of (using l: scala.caps.Capability^): (f: File^{l}) => Unit + | ^ refers to the universal root capability 16 | val o = Service() 17 | o.file = f 18 | o.log diff --git a/tests/neg-custom-args/captures/i15923.check b/tests/neg-custom-args/captures/i15923.check index e018a2ea9f4b..6ae4cb76f4ac 100644 --- a/tests/neg-custom-args/captures/i15923.check +++ b/tests/neg-custom-args/captures/i15923.check @@ -1,22 +1,13 @@ --- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i15923.scala:27:23 --------------------------------------- -27 | val leak = withCap(cap => mkId(cap)) // error (was: no error here since type aliases don't box) - | ^^^^^^^^^^^^^^^^ - |Found: (cap: test2.Cap^'s1) ->'s2 [T] => (op: test2.Cap^'s3 ->'s4 T) ->'s5 T - |Required: test2.Cap^{lcap} => [T] => (op: test2.Cap^'s6 ->'s7 T) ->'s8 T - | - |Note that capability lcap cannot be included in outer capture set 's1 of parameter cap. - | - |where: => refers to a fresh root capability created in anonymous function of type (using lcap: scala.caps.Capability): test2.Cap^{lcap} -> [T] => (op: test2.Cap^{lcap} => T) -> T when instantiating expected result type test2.Cap^{lcap} ->{cap²} [T] => (op: test2.Cap^'s6 ->'s7 T) ->'s8 T of function literal - | - | longer explanation available when compiling with `-explain` -- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i15923.scala:12:21 --------------------------------------- 12 | val leak = withCap(cap => mkId(cap)) // error | ^^^^^^^^^^^^^^^^ - |Found: (cap: Cap^'s9) ->'s10 Id[Cap^'s11]^'s12 - |Required: Cap^{lcap} => Id[Cap^'s13]^'s14 + |Found: (lcap: scala.caps.Capability^) ?->'s1 Cap^'s2 ->'s3 Id[Cap^'s4]^'s5 + |Required: (lcap: scala.caps.Capability^) ?-> Cap^{lcap} => Id[Cap^'s6]^'s7 | - |Note that capability lcap cannot be included in outer capture set 's9 of parameter cap. + |Note that capability cap cannot be included in outer capture set 's6. | - |where: => refers to a fresh root capability created in anonymous function of type (using lcap: scala.caps.Capability): Cap^{lcap} -> Id[Cap] when instantiating expected result type Cap^{lcap} ->{cap²} Id[Cap^'s13]^'s14 of function literal + |where: => refers to a root capability associated with the result type of (using lcap: scala.caps.Capability^): Cap^{lcap} => Id[Cap^'s6]^'s7 + | ^ refers to the universal root capability + | cap is a root capability associated with the result type of (x$0: Cap^'s2): Id[Cap^'s4]^'s5 | | longer explanation available when compiling with `-explain` diff --git a/tests/neg-custom-args/captures/i15923.scala b/tests/neg-custom-args/captures/i15923.scala index 9f7d176c6e14..8287be150761 100644 --- a/tests/neg-custom-args/captures/i15923.scala +++ b/tests/neg-custom-args/captures/i15923.scala @@ -24,6 +24,6 @@ object test2: result } - val leak = withCap(cap => mkId(cap)) // error (was: no error here since type aliases don't box) + val leak = withCap(cap => mkId(cap)) // no error here since type aliases don't box leak { cap => cap.use() } } \ No newline at end of file diff --git a/tests/pos-custom-args/captures/i23727.scala b/tests/pos-custom-args/captures/i23727.scala new file mode 100644 index 000000000000..b4c584c7ec14 --- /dev/null +++ b/tests/pos-custom-args/captures/i23727.scala @@ -0,0 +1,3 @@ +def test1(): Unit = + val t1: (x: () => Unit) -> (y: () ->{x} Unit) -> Unit = + x => y => () // should ok, but error \ No newline at end of file