-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Deserialization] Output a diagnostic when deserializing an invalid decl #36153
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
Conversation
I don't really consider this PR fully complete yet - I'm yet to reduce a test case for when the AccessorDecl is invalid when it is actually valid (after actually deserializing everything). It definitely does happen (reproduces in a whole project build) and I've confirmed it works properly after this PR. It seems to involve some combination of generics, opaque types, and @_implementationOnly that I haven't been able to reduce :(. I've mostly put this up because I'd like some opinions. This is the second hacky-ish branch I've added because of SimpleDidSetRequest typechecking the body (see rdar://70739449 and #34569 for the other). What are your thoughts on not typechecking in the SimpleDidSetRequest, ie. just look for references to This would be incorrect if eg. there was a local The other solution would be to explicitly require specifying |
@swift-ci please test |
Build failed |
Out of curiosity, why does |
I was assuming it was to avoid outputting diagnostics that are because the decl is invalid/a general optimization. Digging into it, the diagnostics produced by this function are:
So after looking at that... I'd be happy to just remove |
Test failure is a different cycle caused by I've done that fix + removed |
The previous change 47b068d was partially reverted (when not allowing errors) as it output diagnostics for valid code. `Decl::isInvalid` had a special case for `AccessorDecl` where if its interface type hadn't already been computed, it would fallback to checking whether its storage (ie. its `VarDecl`) was valid. Since the `VarDecl` isn't fully deserialized when deserializing the `AccessorDecl`, this sometimes causes `isInvalid` to be true, even though it isn't actually invalid. The fallback introduced to `isInvalid` was to prevent a cycle during typechecking caused by `SimpleDidSetRequest` - during `didSet` typechecking, the body would be typechecked, which would then check whether the declaration is valid, calling the typechecking for the declaration again (and so on). This change removes the special case from `isInvalid`. The result of `isInvalid` is then correct for `AccessorDecl`, preventing spurious diagnostics. The `isInvalid` check in `performAbstractFuncDeclDiagnostics` has been removed to prevent the cycle there - it works perfectly fine without it. The unused variable diagnostics are skipped on seeing an error in the body anyway. The opaque type matching diagnostics make sense to keep when the return type is valid. Removing that check exposes another cycle when computing captures in body typechecking caused by `shouldMarkAsObjC` checking `isInvalid` as well. It already checks for `didSet`, so have moved that check above the `isInvalid` check. Resolves rdar://74541834
e8ada42
to
2d9cdb6
Compare
@swift-ci please test |
Build failed |
Build failed |
@swift-ci please test |
Build failed |
Going to close this in favour of another fix (will be up soon). |
Build failed |
The previous change 47b068d was
partially reverted (when not allowing errors) as it output diagnostics
for valid code.
Decl::isInvalid
had a special case forAccessorDecl
where if itsinterface type hadn't already been computed, it would fallback to
checking whether its storage (ie. its
VarDecl
) was valid. Since theVarDecl
isn't fully deserialized when deserializing theAccessorDecl
, this sometimes causesisInvalid
to be true, eventhough it isn't actually invalid.
The fallback introduced to
isInvalid
was to prevent a cycle duringtypechecking caused by
SimpleDidSetRequest
- duringdidSet
typechecking, the body would be typechecked, which would then check
whether the declaration is valid, calling the typechecking for the
declaration again (and so on).
This change removes the special case from
isInvalid
. The result ofisInvalid
is then correct forAccessorDecl
, preventing spuriousdiagnostics.
The
isInvalid
check inperformAbstractFuncDeclDiagnostics
has beenremoved to prevent the cycle there - it works perfectly fine without it.
The unused variable diagnostics are skipped on seeing an error in the
body anyway. The opaque type matching diagnostics make sense to keep
when the return type is valid.
Removing that check exposes another cycle when computing captures in
body typechecking caused by
shouldMarkAsObjC
checkingisInvalid
aswell. It already checks for
didSet
, so have moved that check above theisInvalid
check.Resolves rdar://74541834