diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 0109780c6bc6..20e092679237 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2618,12 +2618,11 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling case tp1: TypeVar if tp1.isInstantiated => tp1.underlying & tp2 case CapturingType(parent1, refs1) => - if subCaptures(tp2.captureSet, refs1, frozen = true).isOK + val refs2 = tp2.captureSet + if subCaptures(refs2, refs1, frozen = true).isOK && tp1.isBoxedCapturing == tp2.isBoxedCapturing - then - parent1 & tp2 - else - tp1.derivedCapturingType(parent1 & tp2, refs1) + then (parent1 & tp2).capturing(refs2) + else tp1.derivedCapturingType(parent1 & tp2, refs1) case tp1: AnnotatedType if !tp1.isRefining => tp1.underlying & tp2 case _ => diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 9e84ca547b47..79b89598abd2 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1940,7 +1940,7 @@ object Types { * the two capture sets are combined. */ def capturing(cs: CaptureSet)(using Context): Type = - if cs.isConst && cs.subCaptures(captureSet, frozen = true).isOK then this + if cs.isAlwaysEmpty || cs.isConst && cs.subCaptures(captureSet, frozen = true).isOK then this else this match case CapturingType(parent, cs1) => parent.capturing(cs1 ++ cs) case _ => CapturingType(this, cs) diff --git a/tests/neg-custom-args/captures/cc-glb.check b/tests/neg-custom-args/captures/cc-glb.check new file mode 100644 index 000000000000..7e0d2ff85691 --- /dev/null +++ b/tests/neg-custom-args/captures/cc-glb.check @@ -0,0 +1,7 @@ +-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/cc-glb.scala:7:19 ---------------------------------------- +7 | val x2: Foo[T] = x1 // error + | ^^ + | Found: (x1 : (Foo[T]^) & (Foo[Any]^{io})) + | Required: Foo[T] + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg-custom-args/captures/cc-glb.scala b/tests/neg-custom-args/captures/cc-glb.scala new file mode 100644 index 000000000000..c22f1a36a300 --- /dev/null +++ b/tests/neg-custom-args/captures/cc-glb.scala @@ -0,0 +1,8 @@ +import language.experimental.captureChecking +trait Cap +trait Foo[+T] + +def magic[T](io: Cap^, x: Foo[T]^{io}): Foo[T]^{} = + val x1: Foo[T]^{cap} & Foo[Any]^{io} = x + val x2: Foo[T] = x1 // error + x2 // boom, an impure value becomes pure