@@ -114,88 +114,6 @@ extends tpd.TreeTraverser:
114114 case _ => tp
115115 case _ => tp
116116
117- private def superTypeIsImpure (tp : Type ): Boolean = {
118- tp.dealias match
119- case CapturingType (_, refs) =>
120- ! refs.isAlwaysEmpty
121- case tp : (TypeRef | AppliedType ) =>
122- val sym = tp.typeSymbol
123- if sym.isClass then
124- sym == defn.AnyClass
125- // we assume Any is a shorthand of {cap} Any, so if Any is an upper
126- // bound, the type is taken to be impure.
127- else superTypeIsImpure(tp.superType)
128- case tp : (RefinedOrRecType | MatchType ) =>
129- superTypeIsImpure(tp.underlying)
130- case tp : AndType =>
131- superTypeIsImpure(tp.tp1) || needsVariable(tp.tp2)
132- case tp : OrType =>
133- superTypeIsImpure(tp.tp1) && superTypeIsImpure(tp.tp2)
134- case _ =>
135- false
136- }.showing(i " super type is impure $tp = $result" , capt)
137-
138- /** Should a capture set variable be added on type `tp`? */
139- def needsVariable (tp : Type ): Boolean = {
140- tp.typeParams.isEmpty && tp.match
141- case tp : (TypeRef | AppliedType ) =>
142- val tp1 = tp.dealias
143- if tp1 ne tp then needsVariable(tp1)
144- else
145- val sym = tp1.typeSymbol
146- if sym.isClass then
147- ! sym.isPureClass && sym != defn.AnyClass
148- else superTypeIsImpure(tp1)
149- case tp : (RefinedOrRecType | MatchType ) =>
150- needsVariable(tp.underlying)
151- case tp : AndType =>
152- needsVariable(tp.tp1) && needsVariable(tp.tp2)
153- case tp : OrType =>
154- needsVariable(tp.tp1) || needsVariable(tp.tp2)
155- case CapturingType (parent, refs) =>
156- needsVariable(parent)
157- && refs.isConst // if refs is a variable, no need to add another
158- && ! refs.isUniversal // if refs is {cap}, an added variable would not change anything
159- case _ =>
160- false
161- }.showing(i " can have inferred capture $tp = $result" , capt)
162-
163- /** Add a capture set variable to `tp` if necessary, or maybe pull out
164- * an embedded capture set variable from a part of `tp`.
165- */
166- def addVar (tp : Type ) = tp match
167- case tp @ RefinedType (parent @ CapturingType (parent1, refs), rname, rinfo) =>
168- CapturingType (tp.derivedRefinedType(parent1, rname, rinfo), refs, parent.isBoxed)
169- case tp : RecType =>
170- tp.parent match
171- case parent @ CapturingType (parent1, refs) =>
172- CapturingType (tp.derivedRecType(parent1), refs, parent.isBoxed)
173- case _ =>
174- tp // can return `tp` here since unlike RefinedTypes, RecTypes are never created
175- // by `mapInferred`. Hence if the underlying type admits capture variables
176- // a variable was already added, and the first case above would apply.
177- case AndType (tp1 @ CapturingType (parent1, refs1), tp2 @ CapturingType (parent2, refs2)) =>
178- assert(refs1.asVar.elems.isEmpty)
179- assert(refs2.asVar.elems.isEmpty)
180- assert(tp1.isBoxed == tp2.isBoxed)
181- CapturingType (AndType (parent1, parent2), refs1 ** refs2, tp1.isBoxed)
182- case tp @ OrType (tp1 @ CapturingType (parent1, refs1), tp2 @ CapturingType (parent2, refs2)) =>
183- assert(refs1.asVar.elems.isEmpty)
184- assert(refs2.asVar.elems.isEmpty)
185- assert(tp1.isBoxed == tp2.isBoxed)
186- CapturingType (OrType (parent1, parent2, tp.isSoft), refs1 ++ refs2, tp1.isBoxed)
187- case tp @ OrType (tp1 @ CapturingType (parent1, refs1), tp2) =>
188- CapturingType (OrType (parent1, tp2, tp.isSoft), refs1, tp1.isBoxed)
189- case tp @ OrType (tp1, tp2 @ CapturingType (parent2, refs2)) =>
190- CapturingType (OrType (tp1, parent2, tp.isSoft), refs2, tp2.isBoxed)
191- case _ if needsVariable(tp) =>
192- val cs = tp.dealias match
193- case CapturingType (_, refs) => CaptureSet .Var (refs.elems)
194- case _ => CaptureSet .Var ()
195- CapturingType (tp, cs)
196- case _ =>
197- tp
198-
199117 private var isTopLevel = true
200118
201119 private def mapNested (ts : List [Type ]): List [Type ] =
@@ -246,7 +164,7 @@ extends tpd.TreeTraverser:
246164 resType = this (tp.resType))
247165 case _ =>
248166 mapOver(tp)
249- addVar(addCaptureRefinements(tp1))
167+ Setup . addVar(addCaptureRefinements(tp1))
250168 end apply
251169 end mapInferred
252170
@@ -385,9 +303,9 @@ extends tpd.TreeTraverser:
385303 val polyType = fn.tpe.widen.asInstanceOf [TypeLambda ]
386304 for case (arg : TypeTree , pinfo, pname) <- args.lazyZip(polyType.paramInfos).lazyZip((polyType.paramNames)) do
387305 if pinfo.bounds.hi.hasAnnotation(defn.Caps_SealedAnnot ) then
388- def where = if fn.symbol.exists then i " in the body of ${fn.symbol}" else " "
306+ def where = if fn.symbol.exists then i " in an argument of ${fn.symbol}" else " "
389307 CheckCaptures .disallowRootCapabilitiesIn(arg.knownType,
390- i " Sealed type variable $pname" , " be instantiated to" ,
308+ i " Sealed type variable $pname" , " be instantiated to" ,
391309 i " This is often caused by a local capability $where\n leaking as part of its result. " ,
392310 tree.srcPos)
393311 case _ =>
@@ -428,7 +346,7 @@ extends tpd.TreeTraverser:
428346 if prevLambdas.isEmpty then restp
429347 else SubstParams (prevPsymss, prevLambdas)(restp)
430348
431- if tree.tpt.hasRememberedType && ! sym.isConstructor then
349+ if sym.exists && tree.tpt.hasRememberedType && ! sym.isConstructor then
432350 val newInfo = integrateRT(sym.info, sym.paramSymss, Nil , Nil )
433351 .showing(i " update info $sym: ${sym.info} --> $result" , capt)
434352 if newInfo ne sym.info then
@@ -474,4 +392,97 @@ object Setup:
474392
475393 def isDuringSetup (using Context ): Boolean =
476394 ctx.property(IsDuringSetupKey ).isDefined
395+
396+ private def superTypeIsImpure (tp : Type )(using Context ): Boolean = {
397+ tp.dealias match
398+ case CapturingType (_, refs) =>
399+ ! refs.isAlwaysEmpty
400+ case tp : (TypeRef | AppliedType ) =>
401+ val sym = tp.typeSymbol
402+ if sym.isClass then
403+ sym == defn.AnyClass
404+ // we assume Any is a shorthand of {cap} Any, so if Any is an upper
405+ // bound, the type is taken to be impure.
406+ else superTypeIsImpure(tp.superType)
407+ case tp : (RefinedOrRecType | MatchType ) =>
408+ superTypeIsImpure(tp.underlying)
409+ case tp : AndType =>
410+ superTypeIsImpure(tp.tp1) || needsVariable(tp.tp2)
411+ case tp : OrType =>
412+ superTypeIsImpure(tp.tp1) && superTypeIsImpure(tp.tp2)
413+ case _ =>
414+ false
415+ }.showing(i " super type is impure $tp = $result" , capt)
416+
417+ /** Should a capture set variable be added on type `tp`? */
418+ def needsVariable (tp : Type )(using Context ): Boolean = {
419+ tp.typeParams.isEmpty && tp.match
420+ case tp : (TypeRef | AppliedType ) =>
421+ val sym = tp.typeSymbol
422+ if sym.isClass then
423+ ! sym.isPureClass && sym != defn.AnyClass
424+ else
425+ sym != defn.FromJavaObjectSymbol
426+ // For capture checking, we assume Object from Java is the same as Any
427+ && {
428+ val tp1 = tp.dealias
429+ if tp1 ne tp then needsVariable(tp1)
430+ else superTypeIsImpure(tp1)
431+ }
432+ case tp : (RefinedOrRecType | MatchType ) =>
433+ needsVariable(tp.underlying)
434+ case tp : AndType =>
435+ needsVariable(tp.tp1) && needsVariable(tp.tp2)
436+ case tp : OrType =>
437+ needsVariable(tp.tp1) || needsVariable(tp.tp2)
438+ case CapturingType (parent, refs) =>
439+ needsVariable(parent)
440+ && refs.isConst // if refs is a variable, no need to add another
441+ && ! refs.isUniversal // if refs is {cap}, an added variable would not change anything
442+ case _ =>
443+ false
444+ }.showing(i " can have inferred capture $tp = $result" , capt)
445+
446+ /** Add a capture set variable to `tp` if necessary, or maybe pull out
447+ * an embedded capture set variable from a part of `tp`.
448+ */
449+ def decorate (tp : Type , addedSet : Type => CaptureSet )(using Context ): Type = tp match
450+ case tp @ RefinedType (parent @ CapturingType (parent1, refs), rname, rinfo) =>
451+ CapturingType (tp.derivedRefinedType(parent1, rname, rinfo), refs, parent.isBoxed)
452+ case tp : RecType =>
453+ tp.parent match
454+ case parent @ CapturingType (parent1, refs) =>
455+ CapturingType (tp.derivedRecType(parent1), refs, parent.isBoxed)
456+ case _ =>
457+ tp // can return `tp` here since unlike RefinedTypes, RecTypes are never created
458+ // by `mapInferred`. Hence if the underlying type admits capture variables
459+ // a variable was already added, and the first case above would apply.
460+ case AndType (tp1 @ CapturingType (parent1, refs1), tp2 @ CapturingType (parent2, refs2)) =>
461+ assert(refs1.elems.isEmpty)
462+ assert(refs2.elems.isEmpty)
463+ assert(tp1.isBoxed == tp2.isBoxed)
464+ CapturingType (AndType (parent1, parent2), refs1 ** refs2, tp1.isBoxed)
465+ case tp @ OrType (tp1 @ CapturingType (parent1, refs1), tp2 @ CapturingType (parent2, refs2)) =>
466+ assert(refs1.elems.isEmpty)
467+ assert(refs2.elems.isEmpty)
468+ assert(tp1.isBoxed == tp2.isBoxed)
469+ CapturingType (OrType (parent1, parent2, tp.isSoft), refs1 ++ refs2, tp1.isBoxed)
470+ case tp @ OrType (tp1 @ CapturingType (parent1, refs1), tp2) =>
471+ CapturingType (OrType (parent1, tp2, tp.isSoft), refs1, tp1.isBoxed)
472+ case tp @ OrType (tp1, tp2 @ CapturingType (parent2, refs2)) =>
473+ CapturingType (OrType (tp1, parent2, tp.isSoft), refs2, tp2.isBoxed)
474+ case _ if needsVariable(tp) =>
475+ CapturingType (tp, addedSet(tp))
476+ case _ =>
477+ tp
478+
479+ /** Add a capture set variable to `tp` if necessary, or maybe pull out
480+ * an embedded capture set variable from a part of `tp`.
481+ */
482+ def addVar (tp : Type )(using Context ): Type =
483+ decorate(tp,
484+ addedSet = _.dealias.match
485+ case CapturingType (_, refs) => CaptureSet .Var (refs.elems)
486+ case _ => CaptureSet .Var ())
487+
477488end Setup
0 commit comments