Skip to content

[ParseableInterface] Print conformances inherited via private protos #20169

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
merged 1 commit into from
Nov 8, 2018

Conversation

jrose-apple
Copy link
Contributor

In this code...

private protocol MyProto: Hashable {}
public struct MyStruct: MyProto {}

...being Hashable is part of MyStruct's public API, even though it's not written explicitly. If we're not going to require people to write it explicitly, we need to make sure it gets printed.

rdar://problem/44662501

@jrose-apple
Copy link
Contributor Author

@swift-ci Please test

@@ -400,6 +401,134 @@ static void printImports(raw_ostream &out, ModuleDecl *M) {
}
}

// FIXME: Copied from ASTPrinter.cpp...
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think Harlan's moving these into a header file anyway in another PR. Once that lands, I'll move PrintOptions::printParseableInterfaceFile up to Frontend, and then we'll only need one copy of these helpers.

if (!shouldPrint(NTD))
continue;
if (auto ty = TL.getType()) {
bool foundUnprintable = ty.findIf([shouldPrint](Type subTy) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you factor this out? Especially if it's gonna be reused in #20146.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not exactly the same query, though: the shouldPrint here is an argument to the function the way ASTPrinter is currently written. I suppose Type itself could have an overload of findIf that passes GenericTypeDecls.

return scope.isPublic();
}

static bool isPublicOrUsableFromInline(Type ty) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah! Okay, yes, this copy should probably make its way into the header introduced in #20004 (or whichever PR I land that contains just the cleanup)

}

void
printSynthesizedExtensionIfNeeded(raw_ostream &out,
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a comment here explaining the motivation for why we're printing the empty extensions after the types? I think it's useful to mention that we are printing conformances to public types that are hidden by conformances to private types, and that they're all satisfied by the requirements that have already been printed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops. Yes, this whole scheme deserves commenting.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It kind of stinks to print the extensions at the end of the file rather than next to the type, but I don't see a good way around that.

// NEGATIVE-NOT: typealias Element =
// CHECK: public func inference(_: Int){{$}}
public func inference(_: Int) {}
// CHECK: public typealias Inferred = Swift.Int
} // CHECK: {{^}$}}


public protocol PublicProto {}
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems the CHECKs are missing here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

…right. I was manually inspecting the output but didn't actually write down the CHECK lines I wanted.

@jrose-apple
Copy link
Contributor Author

Most concerns addressed.

@swift-ci Please smoke test

Copy link
Contributor

@slavapestov slavapestov left a comment

Choose a reason for hiding this comment

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

Can you check that it does the right thing with subclass existentials? Eg if P is a private protocol and C is a public class, then I would expect protocol Q : P & C to print as protocol Q : C.

ExistentialLayout layout = inheritedTy->getExistentialLayout();
for (ProtocolType *protoTy : layout.getProtocols())
whichProtocols.push_back(protoTy->getDecl());
// FIXME: This ignores layout constraints, but currently we don't support
Copy link
Contributor

Choose a reason for hiding this comment

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

You're ignoring superclass constraints too.

@slavapestov
Copy link
Contributor

Wait, the example I gave doesn't make sense, but you should still make sure it does something reasonable with subclass existentials.

@jrose-apple
Copy link
Contributor Author

Ooh, you're right, I totally forgot to test those. It's okay to ignore superclass constraints because we're printing the class itself, but…

…oh, no, that's not correct; we allow specifying the superclass like that, don't we. Yikes. Okay, I may do that in a follow-up PR.

@slavapestov
Copy link
Contributor

@jrose-apple It looks like we allow this:

public class Base {}
public protocol P2 {}

public class Derived2 : P2 & Base {}

But not this:

public class Base {}
internal protocol P2 {}

public class Derived2 : P2 & Base {}

Which is a bit weird, but I don't think we intended for subclass existentials to work there at all. So it might be that there's nothing to test.

In this code:

    private protocol MyProto: Hashable {}
    public struct MyStruct: MyProto {}

Being Hashable is part of MyStruct's public API, even though it's not
written explicitly. If we're not going to require people to write it
explicitly, we need to make sure it gets printed.

rdar://problem/44662501
@jrose-apple
Copy link
Contributor Author

I think we allow that for people who make typealiases of subclass existentials, but if we already check them for access then I'm happy. Added two more tests.

@swift-ci Please smoke test

@jrose-apple
Copy link
Contributor Author

@slavapestov @harlanhaskins Ready to go?

@jrose-apple jrose-apple merged commit 4d041a3 into swiftlang:master Nov 8, 2018
@jrose-apple jrose-apple deleted the refinery branch November 8, 2018 18:33
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.

3 participants