Skip to content

Fix mutating method calls on class existentials #9573

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

Merged

Conversation

slavapestov
Copy link
Contributor

@slavapestov slavapestov commented May 13, 2017

This builds upon #9625 and #9637 to address miscompiles and assertions with a peculiar corner case -- performing a mutating method call on a class existential.

This can manifest in one of two ways:

  1. A class-constrained protocol inherits from a non-class-constrained protocol, and the latter has mutating methods.
  2. A protocol composition type contains both a class-constrained and a non-class-constrained protocol, or a superclass constraint and a non-class-constrained protocol.

The root cause is that mutating methods take the opened self value as an inout parameter, but we had no way to model an inout access of the payload inside a class existential at the SIL level. I've decided to model it as a logical lvalue component where the "get" strips the existential witness tables to produce a reference, and the "set" adds the witness tables back to the reference to form a new existential.

Note that this miscompile was occurring irrespective of whether the mutating method was defined in an extension, or in the class itself. The problem was that incorrect code was being generated at the call site, where it is not known how the method is implemented, and self has to be passed as an inout value.

Fixes rdar://problem/31858378.

@slavapestov slavapestov changed the title Fix mutating method calls on class existentials [WIP] Fix mutating method calls on class existentials May 13, 2017
@@ -223,6 +223,63 @@ ManagedValue LogicalPathComponent::getMaterialized(SILGenFunction &SGF,
SILLocation loc,
ManagedValue base,
AccessKind kind) && {
if (getTypeOfRValue().getSwiftRValueType()->hasOpenedExistential()) {
Copy link
Contributor Author

@slavapestov slavapestov May 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jckarter @gottesmm This part is really awkward because it's mostly duplicating the code below. I don't really have a good feel for how to write idiomatic code with Initializations and the FormalEvaluationScope (which seems new, haven't seen it before). Can you think of a better way to address this problem?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FormalEvaluationScope is just a writeback scope that can also handle borrows.

@slavapestov slavapestov requested a review from rjmccall May 13, 2017 09:50
Now that SILGen can correctly lower lvalue accesses of
class existential payloads, remove a hack in Sema that
was simply doing the wrong thing.

Fixes <rdar://problem/31858378>.
@slavapestov slavapestov changed the title [WIP] Fix mutating method calls on class existentials Fix mutating method calls on class existentials May 16, 2017
@slavapestov slavapestov force-pushed the class-existential-payload-lvalue branch from 13c0d7a to 03ebba5 Compare May 16, 2017 03:16
@slavapestov
Copy link
Contributor Author

@swift-ci Please smoke test

@slavapestov slavapestov merged commit 7ce86c0 into swiftlang:master May 16, 2017
jansvoboda11 added a commit that referenced this pull request Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants