@@ -198,7 +198,7 @@ object Capabilities:
198
198
i " a fresh root capability $classifierStr$originStr"
199
199
200
200
object FreshCap :
201
- def apply (origin : Origin )(using Context ): FreshCap | GlobalCap . type =
201
+ def apply (origin : Origin )(using Context ): FreshCap =
202
202
FreshCap (ctx.owner, origin)
203
203
204
204
/** A root capability associated with a function type. These are conceptually
@@ -837,6 +837,7 @@ object Capabilities:
837
837
case Formal (pref : ParamRef , app : tpd.Apply )
838
838
case ResultInstance (methType : Type , meth : Symbol )
839
839
case UnapplyInstance (info : MethodType )
840
+ case LocalInstance (restpe : Type )
840
841
case NewMutable (tp : Type )
841
842
case NewCapability (tp : Type )
842
843
case LambdaExpected (respt : Type )
@@ -865,6 +866,8 @@ object Capabilities:
865
866
i " when instantiating $methDescr$mt"
866
867
case UnapplyInstance (info) =>
867
868
i " when instantiating argument of unapply with type $info"
869
+ case LocalInstance (restpe) =>
870
+ i " when instantiating expected result type $restpe of function literal "
868
871
case NewMutable (tp) =>
869
872
i " when constructing mutable $tp"
870
873
case NewCapability (tp) =>
@@ -948,6 +951,69 @@ object Capabilities:
948
951
def freshToCap (param : Symbol , tp : Type )(using Context ): Type =
949
952
CapToFresh (Origin .Parameter (param)).inverse(tp)
950
953
954
+ /** The local dual of a result type of a closure type.
955
+ * @param binder the method type of the anonymous function whose result is mapped
956
+ * @pre the context's owner is the anonymous function
957
+ */
958
+ class Internalize (binder : MethodType )(using Context ) extends BiTypeMap :
959
+ thisMap =>
960
+
961
+ val sym = ctx.owner
962
+ assert(sym.isAnonymousFunction)
963
+ val paramSyms = atPhase(ctx.phase.prev):
964
+ // We need to ask one phase before since `sym` should not be completed as a side effect.
965
+ // The result of Internalize is used to se the result type of an anonymous function, and
966
+ // the new info of that function is built with the result.
967
+ sym.paramSymss.head
968
+ val resultToFresh = EqHashMap [ResultCap , FreshCap ]()
969
+ val freshToResult = EqHashMap [FreshCap , ResultCap ]()
970
+
971
+ override def apply (t : Type ) =
972
+ if variance < 0 then t
973
+ else t match
974
+ case t : ParamRef =>
975
+ if t.binder == this .binder then paramSyms(t.paramNum).termRef else t
976
+ case _ => mapOver(t)
977
+
978
+ override def mapCapability (c : Capability , deep : Boolean ): Capability = c match
979
+ case r : ResultCap if r.binder == this .binder =>
980
+ resultToFresh.get(r) match
981
+ case Some (f) => f
982
+ case None =>
983
+ val f = FreshCap (Origin .LocalInstance (binder.resType))
984
+ resultToFresh(r) = f
985
+ freshToResult(f) = r
986
+ f
987
+ case _ =>
988
+ super .mapCapability(c, deep)
989
+
990
+ class Inverse extends BiTypeMap :
991
+ def apply (t : Type ): Type =
992
+ if variance < 0 then t
993
+ else t match
994
+ case t : TermRef if paramSyms.contains(t) =>
995
+ binder.paramRefs(paramSyms.indexOf(t.symbol))
996
+ case _ => mapOver(t)
997
+
998
+ override def mapCapability (c : Capability , deep : Boolean ): Capability = c match
999
+ case f : FreshCap if f.owner == sym =>
1000
+ freshToResult.get(f) match
1001
+ case Some (r) => r
1002
+ case None =>
1003
+ val r = ResultCap (binder)
1004
+ resultToFresh(r) = f
1005
+ freshToResult(f) = r
1006
+ r
1007
+ case _ => super .mapCapability(c, deep)
1008
+
1009
+ def inverse = thisMap
1010
+ override def toString = thisMap.toString + " .inverse"
1011
+ end Inverse
1012
+
1013
+ override def toString = " InternalizeClosureResult"
1014
+ def inverse = Inverse ()
1015
+ end Internalize
1016
+
951
1017
/** Map top-level free existential variables one-to-one to Fresh instances */
952
1018
def resultToFresh (tp : Type , origin : Origin )(using Context ): Type =
953
1019
val subst = new TypeMap :
@@ -977,78 +1043,76 @@ object Capabilities:
977
1043
subst(tp)
978
1044
end resultToFresh
979
1045
980
- /** Replace all occurrences of `cap` (or fresh) in parts of this type by an existentially bound
981
- * variable bound by `mt`.
982
- * Stop at function or method types since these have been mapped before.
983
- */
984
- def toResult (tp : Type , mt : MethodicType , fail : Message => Unit )(using Context ): Type =
985
-
986
- abstract class CapMap extends BiTypeMap :
987
- override def mapOver (t : Type ): Type = t match
988
- case t @ FunctionOrMethod (args, res) if variance > 0 && ! t.isAliasFun =>
989
- t // `t` should be mapped in this case by a different call to `toResult`. See [[toResultInResults]].
990
- case t : (LazyRef | TypeVar ) =>
991
- mapConserveSuper(t)
992
- case _ =>
993
- super .mapOver(t)
1046
+ abstract class CapMap (using Context ) extends BiTypeMap :
1047
+ override def mapOver (t : Type ): Type = t match
1048
+ case t @ FunctionOrMethod (args, res) if variance > 0 && ! t.isAliasFun =>
1049
+ t // `t` should be mapped in this case by a different call to `toResult`. See [[toResultInResults]].
1050
+ case t : (LazyRef | TypeVar ) =>
1051
+ mapConserveSuper(t)
1052
+ case _ =>
1053
+ super .mapOver(t)
1054
+
1055
+ class ToResult (localResType : Type , mt : MethodicType , fail : Message => Unit )(using Context ) extends CapMap :
1056
+
1057
+ def apply (t : Type ) = t match
1058
+ case defn.FunctionNOf (args, res, contextual) if t.typeSymbol.name.isImpureFunction =>
1059
+ if variance > 0 then
1060
+ super .mapOver:
1061
+ defn.FunctionNOf (args, res, contextual)
1062
+ .capturing(ResultCap (mt).singletonCaptureSet)
1063
+ else mapOver(t)
1064
+ case _ =>
1065
+ mapOver(t)
1066
+
1067
+ override def mapCapability (c : Capability , deep : Boolean ) = c match
1068
+ case c : (FreshCap | GlobalCap .type ) =>
1069
+ if variance > 0 then
1070
+ val res = ResultCap (mt)
1071
+ c match
1072
+ case c : FreshCap => res.setOrigin(c)
1073
+ case _ =>
1074
+ res
1075
+ else
1076
+ if variance == 0 then
1077
+ fail(em """ $localResType captures the root capability `cap` in invariant position.
1078
+ |This capability cannot be converted to an existential in the result type of a function. """ )
1079
+ // we accept variance < 0, and leave the cap as it is
1080
+ c
1081
+ case _ =>
1082
+ super .mapCapability(c, deep)
994
1083
995
- object toVar extends CapMap :
1084
+ // .showing(i"mapcap $t = $result")
1085
+ override def toString = " toVar"
996
1086
997
- def apply (t : Type ) = t match
998
- case defn.FunctionNOf (args, res, contextual) if t.typeSymbol.name.isImpureFunction =>
999
- if variance > 0 then
1000
- super .mapOver:
1001
- defn.FunctionNOf (args, res, contextual)
1002
- .capturing(ResultCap (mt).singletonCaptureSet)
1003
- else mapOver(t)
1004
- case _ =>
1005
- mapOver(t)
1087
+ object inverse extends BiTypeMap :
1088
+ def apply (t : Type ) = mapOver(t)
1006
1089
1007
1090
override def mapCapability (c : Capability , deep : Boolean ) = c match
1008
- case c : (FreshCap | GlobalCap .type ) =>
1009
- if variance > 0 then
1010
- val res = ResultCap (mt)
1011
- c match
1012
- case c : FreshCap => res.setOrigin(c)
1013
- case _ =>
1014
- res
1015
- else
1016
- if variance == 0 then
1017
- fail(em """ $tp captures the root capability `cap` in invariant position.
1018
- |This capability cannot be converted to an existential in the result type of a function. """ )
1019
- // we accept variance < 0, and leave the cap as it is
1020
- c
1091
+ case c @ ResultCap (`mt`) =>
1092
+ // do a reverse getOrElseUpdate on `seen` to produce the
1093
+ // `Fresh` assosicated with `t`
1094
+ val primary = c.primaryResultCap
1095
+ primary.origin match
1096
+ case GlobalCap =>
1097
+ val fresh = FreshCap (Origin .LocalInstance (mt.resType))
1098
+ primary.setOrigin(fresh)
1099
+ fresh
1100
+ case origin : FreshCap =>
1101
+ origin
1021
1102
case _ =>
1022
1103
super .mapCapability(c, deep)
1023
1104
1024
- // .showing(i"mapcap $t = $result")
1025
- override def toString = " toVar"
1026
-
1027
- object inverse extends BiTypeMap :
1028
- def apply (t : Type ) = mapOver(t)
1029
-
1030
- override def mapCapability (c : Capability , deep : Boolean ) = c match
1031
- case c @ ResultCap (`mt`) =>
1032
- // do a reverse getOrElseUpdate on `seen` to produce the
1033
- // `Fresh` assosicated with `t`
1034
- val primary = c.primaryResultCap
1035
- primary.origin match
1036
- case GlobalCap =>
1037
- val fresh = FreshCap (Origin .Unknown )
1038
- primary.setOrigin(fresh)
1039
- fresh
1040
- case origin : FreshCap =>
1041
- origin
1042
- case _ =>
1043
- super .mapCapability(c, deep)
1044
-
1045
- def inverse = toVar.this
1046
- override def toString = " toVar.inverse"
1047
- end inverse
1048
- end toVar
1105
+ def inverse = ToResult .this
1106
+ override def toString = " toVar.inverse"
1107
+ end inverse
1108
+ end ToResult
1049
1109
1050
- toVar(tp)
1051
- end toResult
1110
+ /** Replace all occurrences of `cap` (or fresh) in parts of this type by an existentially bound
1111
+ * variable bound by `mt`.
1112
+ * Stop at function or method types since these have been mapped before.
1113
+ */
1114
+ def toResult (tp : Type , mt : MethodicType , fail : Message => Unit )(using Context ): Type =
1115
+ ToResult (tp, mt, fail)(tp)
1052
1116
1053
1117
/** Map global roots in function results to result roots. Also,
1054
1118
* map roots in the types of def methods that are parameterless
0 commit comments