@@ -11,6 +11,7 @@ import CaptureSet.{Refs, emptySet, HiddenSet}
11
11
import config .Printers .capt
12
12
import StdNames .nme
13
13
import util .{SimpleIdentitySet , EqHashMap , SrcPos }
14
+ import tpd .*
14
15
15
16
object SepChecker :
16
17
@@ -31,15 +32,14 @@ object SepChecker:
31
32
/** The kind of checked type, used for composing error messages */
32
33
enum TypeKind :
33
34
case Result (sym : Symbol , inferred : Boolean )
34
- case Argument
35
+ case Argument ( arg : Tree )
35
36
36
37
def dclSym = this match
37
38
case Result (sym, _) => sym
38
39
case _ => NoSymbol
39
40
end TypeKind
40
41
41
42
class SepChecker (checker : CheckCaptures .CheckerAPI ) extends tpd.TreeTraverser :
42
- import tpd .*
43
43
import checker .*
44
44
import SepChecker .*
45
45
@@ -214,7 +214,7 @@ class SepChecker(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
214
214
for (arg, idx) <- indexedArgs do
215
215
if arg.needsSepCheck then
216
216
val ac = formalCaptures(arg)
217
- checkType(arg.formalType, arg.srcPos, TypeKind .Argument )
217
+ checkType(arg.formalType, arg.srcPos, TypeKind .Argument (arg) )
218
218
val hiddenInArg = ac.hidden.footprint
219
219
// println(i"check sep $arg: $ac, footprint so far = $footprint, hidden = $hiddenInArg")
220
220
val overlap = hiddenInArg.overlapWith(footprint).deductCapturesOf(deps(arg))
@@ -252,9 +252,9 @@ class SepChecker(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
252
252
case TypeKind .Result (sym, inferred) =>
253
253
def inferredStr = if inferred then " inferred" else " "
254
254
def resultStr = if sym.info.isInstanceOf [MethodicType ] then " result" else " "
255
- i " $sym's $inferredStr$resultStr"
256
- case TypeKind .Argument =>
257
- " the argument's adapted type "
255
+ i " $sym's $inferredStr$resultStr"
256
+ case TypeKind .Argument (_) =>
257
+ " the argument's adapted"
258
258
259
259
def explicitRefs (tp : Type ): Refs = tp match
260
260
case tp : (TermRef | ThisType ) => SimpleIdentitySet (tp)
@@ -292,7 +292,7 @@ class SepChecker(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
292
292
.nextOption
293
293
.getOrElse((" " , current, globalOverlap))
294
294
report.error(
295
- em """ Separation failure in $typeDescr type $tpe.
295
+ em """ Separation failure in $typeDescr type $tpe.
296
296
|One part, $part , $nextRel ${CaptureSet (next)}.
297
297
|A previous part $prevStr $prevRel ${CaptureSet (prevRefs)}.
298
298
|The two sets overlap at ${CaptureSet (overlap)}. """ ,
@@ -346,10 +346,10 @@ class SepChecker(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
346
346
case t =>
347
347
foldOver(c, t)
348
348
349
- def checkParameters ( ) =
349
+ def checkParams ( refsToCheck : Refs , descr : => String ) =
350
350
val badParams = mutable.ListBuffer [Symbol ]()
351
351
def currentOwner = kind.dclSym.orElse(ctx.owner)
352
- for hiddenRef <- prune(tpe.deepCaptureSet.elems.hidden .footprint) do
352
+ for hiddenRef <- prune(refsToCheck .footprint) do
353
353
val refSym = hiddenRef.termSymbol
354
354
if refSym.is(TermParam )
355
355
&& ! refSym.hasAnnotation(defn.ConsumeAnnot )
@@ -364,25 +364,29 @@ class SepChecker(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
364
364
case p :: ps => i " ${p.name}, ${paramsStr(ps)}"
365
365
val (pluralS, singleS) = if badParams.tail.isEmpty then (" " , " s" ) else (" s" , " " )
366
366
report.error(
367
- em """ Separation failure: $typeDescr type $tpe hides parameter $pluralS ${paramsStr(badParams.toList)}
367
+ em """ Separation failure: $descr parameter $pluralS ${paramsStr(badParams.toList)}.
368
368
|The parameter $pluralS need $singleS to be annotated with @consume to allow this. """ ,
369
369
pos)
370
370
371
- def flagHiddenParams =
372
- kind match
373
- case TypeKind .Result (sym, _) =>
374
- ! sym.isAnonymousFunction // we don't check return types of anonymous functions
375
- && ! sym.is(Case ) // We don't check so far binders in patterns since they
376
- // have inferred universal types. TODO come back to this;
377
- // either infer more precise types for such binders or
378
- // "see through them" when we look at hidden sets.
379
- case TypeKind .Argument =>
380
- false
371
+ def checkParameters () = kind match
372
+ case TypeKind .Result (sym, _) =>
373
+ if ! sym.isAnonymousFunction // we don't check return types of anonymous functions
374
+ && ! sym.is(Case ) // We don't check so far binders in patterns since they
375
+ // have inferred universal types. TODO come back to this;
376
+ // either infer more precise types for such binders or
377
+ // "see through them" when we look at hidden sets.
378
+ then checkParams(tpe.deepCaptureSet.elems.hidden, i " $typeDescr type $tpe hides " )
379
+ case TypeKind .Argument (arg) =>
380
+ if tpe.hasAnnotation(defn.ConsumeAnnot ) then
381
+ val capts = captures(arg)
382
+ def descr (verb : String ) = i " argument to @consume parameter with type ${arg.nuType} $verb"
383
+ checkParams(capts, descr(" refers to" ))
384
+ checkParams(capts.hidden, descr(" hides" ))
381
385
382
386
if ! tpe.hasAnnotation(defn.UntrackedCapturesAnnot ) then
383
387
traverse(Captures .None , tpe)
384
388
traverse.toCheck.foreach(checkParts)
385
- if flagHiddenParams then checkParameters()
389
+ checkParameters()
386
390
end checkType
387
391
388
392
private def collectMethodTypes (tp : Type ): List [TermLambda ] = tp match
0 commit comments