-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Use level checking for Fresh instances #23101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Refactor to avoid generating refsText ahead of time. We need to keep the original capture sets or tree lists so that we can record them as seen.
- Map cap to Result in their original types (was Fresh before) - Map Result to Fresh on access
223b9c6
to
99a4c20
Compare
Turn level checking on under the useFreshLevels config option (which is on by default)
Fall back to previous scheme if there is no recording in Seen. That way, we see what we expect when turning on Ycc-verbose and other printing options.
…bles. The check was not working properly before, which meant that problems went undetected. To make things work again, we need two additional fixes - A more detailed treatment of result mapping for inferred types. In these, we map root.Fresh to root.Result only if the original inferred type was dependent. AppliedType functions are also mapped to RefinedType functions in setup, but this should not count for fresh to result mappings. - A fix in the Fresh to Result mapping of parameterless defs.
When printing types deriving from capability, do print their capture sets even if these are implied. This avoids confusing errors where a capability classes has two different implied Fresh instances which are both elided so the types look the same. Exception: When printing a singleton type (x: T) we do elide in T, since the usually the only part that matters is the `x`. But we don't do the elision under -Ycc-verbose or -explain.
99a4c20
to
d7eb32a
Compare
We had the wrong condition in maxSubsumes before. We need to test for isStaticOwner instead of isStatic. The previous test made all fresh capabilities in global classes slip through the net.
d7eb32a
to
b58327d
Compare
b58327d
to
a178c04
Compare
Most of the added lines in this PR are in the tests. We have more tests and the existing neg tests explain the problem in more detail. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also notice .check
files missing for class-level-attack.scala
and capt-capability.scala
.
Otherwise seems good!
case _ => | ||
NoSymbol | ||
|
||
final def adjustedOwner(using Context): Symbol = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this returning the owner representing the boundary of a level? I found only one use of this method, its name is a bit mysterious
&& !yIsExistential | ||
&& !y.isInstanceOf[TermParamRef] | ||
&& !y.isInstanceOf[ParamRef] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason for the TermParamRef
-> ParamRef
change? I tried changing it back and testCompilation captures
still passes
@@ -183,7 +183,7 @@ sealed abstract class CaptureSet extends Showable: | |||
*/ | |||
def accountsFor(x: CaptureRef)(using ctx: Context)(using vs: VarState = VarState.Separate): Boolean = | |||
|
|||
def debugInfo(using Context) = i"$this accountsFor $x, which has capture set ${x.captureSetOfInfo}" | |||
def debugInfo(using Context) = i"$this accountsFor $x" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intentional removal?
val argType = recheck(arg, freshenedFormal) | ||
.showing(i"recheck arg $arg vs $freshenedFormal = $result", capt) | ||
if formal.hasAnnotation(defn.UseAnnot) || formal.hasAnnotation(defn.ConsumeAnnot) then | ||
// The @use and/or @consume annotation is added to `formal` by `prepareFunction` | ||
// The @use and/or @consume annotation is added to `formal` by `prep areFunction` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unintentional?
@@ -1261,8 +1277,7 @@ class CheckCaptures extends Recheck, SymTransformer: | |||
val msg = note match | |||
case CompareResult.LevelError(cs, ref) => | |||
if ref.stripReadOnly.isCapOrFresh then | |||
def capStr = if ref.isReadOnly then "cap.rd" else "cap" | |||
i"""the universal capability `$capStr` | |||
i"""the universa capability $ref |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i"""the universa capability $ref | |
i"""the universal capability $ref |
typo
pdenot.meet( | ||
new JointRefDenotation(NoSymbol, rinfo, Period.allInRun(ctx.runId), pre, isRefinedMethod), | ||
pre, | ||
safeIntersection = ctx.base.pendingMemberSearches.contains(name)) | ||
pdenot.meet( | ||
new JointRefDenotation(NoSymbol, rinfo, Period.allInRun(ctx.runId), pre, isRefinedMethod), | ||
pre, | ||
safeIntersection = ctx.base.pendingMemberSearches.contains(name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pdenot.meet
called twice, intentional?
| where: => refers to the universal root capability | ||
| cap is the universal root capability |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still quite confusing I think, both are universal root capabilities
def twoRefs3(): Pair[Ref^, Ref^] = // error but should work | ||
val p = Pair(Ref(), Ref()) | ||
p |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO?
This PR changes the way we treat fresh instances. Instead of disallowing all of them when instantiating type parameters (as well as in a number of other situations), we allow them but check that inner fresh instances do not get widened to outer ones. This makes code like this one compile
Previously, that would not work since the
X
andY
variables ofPair
would be instantiated toRef^
, which was not allowed.The PR also implements lots of improvements to error diagnostics.
^
,cap
, or=>
.