@@ -73,7 +73,6 @@ object CheckCaptures:
73
73
74
74
/** Similar normal substParams, but this is an approximating type map that
75
75
* maps parameters in contravariant capture sets to the empty set.
76
- * TODO: check what happens with non-variant.
77
76
*/
78
77
final class SubstParamsMap (from : BindingType , to : List [Type ])(using Context )
79
78
extends ApproximatingTypeMap , IdempotentCaptRefMap :
@@ -96,6 +95,36 @@ object CheckCaptures:
96
95
mapOver(tp)
97
96
end SubstParamsMap
98
97
98
+ final class SubstParamsBiMap (from : LambdaType , to : List [Type ])(using Context )
99
+ extends BiTypeMap :
100
+
101
+ def apply (tp : Type ): Type = tp match
102
+ case tp : ParamRef =>
103
+ if tp.binder == from then to(tp.paramNum) else tp
104
+ case tp : NamedType =>
105
+ if tp.prefix `eq` NoPrefix then tp
106
+ else tp.derivedSelect(apply(tp.prefix))
107
+ case _ : ThisType =>
108
+ tp
109
+ case _ =>
110
+ mapOver(tp)
111
+
112
+ def inverse (tp : Type ): Type = tp match
113
+ case tp : NamedType =>
114
+ var idx = 0
115
+ var to1 = to
116
+ while idx < to.length && (tp ne to(idx)) do
117
+ idx += 1
118
+ to1 = to1.tail
119
+ if idx < to.length then from.paramRefs(idx)
120
+ else if tp.prefix `eq` NoPrefix then tp
121
+ else tp.derivedSelect(apply(tp.prefix))
122
+ case _ : ThisType =>
123
+ tp
124
+ case _ =>
125
+ mapOver(tp)
126
+ end SubstParamsBiMap
127
+
99
128
/** Check that a @retains annotation only mentions references that can be tracked.
100
129
* This check is performed at Typer.
101
130
*/
@@ -437,18 +466,34 @@ class CheckCaptures extends Recheck, SymTransformer:
437
466
case appType => appType
438
467
end recheckApply
439
468
469
+ private def isDistinct (xs : List [Type ]): Boolean = xs match
470
+ case x :: xs1 => xs1.isEmpty || ! xs1.contains(x) && isDistinct(xs1)
471
+ case Nil => true
472
+
473
+ private def isTrackable (tp : Type )(using Context ) = tp match
474
+ case tp : CaptureRef => tp.canBeTracked
475
+ case _ => false
476
+
440
477
/** Handle an application of method `sym` with type `mt` to arguments of types `argTypes`.
441
478
* This means:
442
479
* - Instantiate result type with actual arguments
443
480
* - If call is to a constructor:
444
481
* - remember types of arguments corresponding to tracked
445
482
* parameters in refinements.
446
483
* - add capture set of instantiated class to capture set of result type.
484
+ * If all argument types are mutually disfferent trackable capture references, use a BiTypeMap,
485
+ * since that is more precise. Otherwise use a normal idempotent map, which might lose information
486
+ * in the case where the result type contains captureset variables that are further
487
+ * constrained afterwards.
447
488
*/
448
489
override def instantiate (mt : MethodType , argTypes : List [Type ], sym : Symbol )(using Context ): Type =
449
490
val ownType =
450
- if mt.isResultDependent then SubstParamsMap (mt, argTypes)(mt.resType)
451
- else mt.resType
491
+ if ! mt.isResultDependent then
492
+ mt.resType
493
+ else if argTypes.forall(isTrackable) && isDistinct(argTypes) then
494
+ SubstParamsBiMap (mt, argTypes)(mt.resType)
495
+ else
496
+ SubstParamsMap (mt, argTypes)(mt.resType)
452
497
453
498
if sym.isConstructor then
454
499
val cls = sym.owner.asClass
0 commit comments