@@ -14,6 +14,7 @@ import NameOps.isImpureFunction
1414import reporting .Message
1515import util .{SimpleIdentitySet , EqHashMap }
1616import util .Spans .NoSpan
17+ import ast .tpd
1718import annotation .constructorOnly
1819
1920/** A module defining three kinds of root capabilities
@@ -59,9 +60,58 @@ import annotation.constructorOnly
5960 */
6061object root :
6162
63+ enum Origin :
64+ case InDecl (sym : Symbol )
65+ case TypeArg (tp : Type )
66+ case UnsafeAssumePure
67+ case Formal (pref : ParamRef , app : tpd.Apply )
68+ case ResultInstance (methType : Type , meth : Symbol )
69+ case UnapplyInstance (info : MethodType )
70+ case NewMutable (tp : Type )
71+ case NewCapability (tp : Type )
72+ case LambdaExpected (respt : Type )
73+ case LambdaActual (restp : Type )
74+ case OverriddenType (member : Symbol )
75+ case DeepCS (ref : TypeRef )
76+ case Unknown
77+
78+ def explanation (using Context ): String = this match
79+ case InDecl (sym : Symbol ) =>
80+ if sym.is(Method ) then i " in the result type of $sym"
81+ else if sym.exists then i " in the type of $sym"
82+ else " "
83+ case TypeArg (tp : Type ) =>
84+ i " of type argument $tp"
85+ case UnsafeAssumePure =>
86+ " when instantiating argument of unsafeAssumePure"
87+ case Formal (pref, app) =>
88+ val meth = app.symbol
89+ if meth.exists
90+ then i " when checking argument to parameter ${pref.paramName} of $meth"
91+ else " "
92+ case ResultInstance (mt, meth) =>
93+ val methDescr = if meth.exists then i " $meth's type " else " "
94+ i " when instantiating $methDescr$mt"
95+ case UnapplyInstance (info) =>
96+ i " when instantiating argument of unapply with type $info"
97+ case NewMutable (tp) =>
98+ i " when constructing mutable $tp"
99+ case NewCapability (tp) =>
100+ i " when constructing Capability instance $tp"
101+ case LambdaExpected (respt) =>
102+ i " when instantiating expected result type $respt of lambda "
103+ case LambdaActual (restp : Type ) =>
104+ i " when instantiating result type $restp of lambda "
105+ case OverriddenType (member : Symbol ) =>
106+ i " when instantiating upper bound of member overridden by $member"
107+ case DeepCS (ref : TypeRef ) =>
108+ i " when computing deep capture set of $ref"
109+ case Unknown =>
110+ " "
111+
62112 enum Kind :
63113 case Result (binder : MethodType )
64- case Fresh (hidden : CaptureSet .HiddenSet )(val purpose : () => String )
114+ case Fresh (hidden : CaptureSet .HiddenSet )(val origin : Origin )
65115 case Global
66116
67117 override def equals (other : Any ): Boolean =
@@ -129,10 +179,10 @@ object root:
129179
130180 /** Constructor and extractor methods for "fresh" capabilities */
131181 object Fresh :
132- def apply (using Context )(purpose : => String , owner : Symbol = ctx.owner): CaptureRef =
182+ def apply (using Context )(origin : Origin , owner : Symbol = ctx.owner): CaptureRef =
133183 if ccConfig.useSepChecks then
134184 val hiddenSet = CaptureSet .HiddenSet (owner)
135- val res = AnnotatedType (cap, Annot (Kind .Fresh (hiddenSet)(() => purpose )))
185+ val res = AnnotatedType (cap, Annot (Kind .Fresh (hiddenSet)(origin )))
136186 hiddenSet.owningCap = res
137187 // assert(hiddenSet.id != 3)
138188 res
@@ -167,14 +217,14 @@ object root:
167217 /** Map each occurrence of cap to a different Fresh instance
168218 * Exception: CapSet^ stays as it is.
169219 */
170- class CapToFresh (purpose : => String )(using Context ) extends BiTypeMap , FollowAliasesMap :
220+ class CapToFresh (origin : Origin )(using Context ) extends BiTypeMap , FollowAliasesMap :
171221 thisMap =>
172222
173223 override def apply (t : Type ) =
174224 if variance <= 0 then t
175225 else t match
176226 case t : CaptureRef if t.isCap =>
177- Fresh (purpose )
227+ Fresh (origin )
178228 case t @ CapturingType (parent : TypeRef , _) if parent.symbol == defn.Caps_CapSet =>
179229 t
180230 case t @ CapturingType (_, _) =>
@@ -212,23 +262,23 @@ object root:
212262 end CapToFresh
213263
214264 /** Maps cap to fresh */
215- def capToFresh (tp : Type , purpose : => String )(using Context ): Type =
216- if ccConfig.useSepChecks then CapToFresh (purpose )(tp) else tp
265+ def capToFresh (tp : Type , origin : Origin )(using Context ): Type =
266+ if ccConfig.useSepChecks then CapToFresh (origin )(tp) else tp
217267
218268 /** Maps fresh to cap */
219269 def freshToCap (tp : Type )(using Context ): Type =
220- if ccConfig.useSepChecks then CapToFresh (" " ).inverse(tp) else tp
270+ if ccConfig.useSepChecks then CapToFresh (Origin . Unknown ).inverse(tp) else tp
221271
222272 /** Map top-level free existential variables one-to-one to Fresh instances */
223- def resultToFresh (tp : Type , purpose : => String )(using Context ): Type =
273+ def resultToFresh (tp : Type , origin : Origin )(using Context ): Type =
224274 val subst = new TypeMap :
225275 val seen = EqHashMap [Annotation , CaptureRef ]()
226276 var localBinders : SimpleIdentitySet [MethodType ] = SimpleIdentitySet .empty
227277
228278 def apply (t : Type ): Type = t match
229279 case t @ Result (binder) =>
230280 if localBinders.contains(binder) then t // keep bound references
231- else seen.getOrElseUpdate(t.annot, Fresh (purpose )) // map free references to Fresh()
281+ else seen.getOrElseUpdate(t.annot, Fresh (origin )) // map free references to Fresh()
232282 case t : MethodType =>
233283 // skip parameters
234284 val saved = localBinders
@@ -294,7 +344,7 @@ object root:
294344 val (k, v) = it.next
295345 if v.annot eq t.annot then ref = k
296346 if ref == null then
297- ref = Fresh (" " )
347+ ref = Fresh (Origin . Unknown )
298348 seen(ref) = t
299349 ref
300350 case _ => mapOver(t)
0 commit comments