-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[IDE] Teach type checker about conditional conformance extensions. #14554
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
No point in getting rid of the sugar so early.
@DougGregor thoughts on the safety of this for the swift-*-branches? It's kinda huge (but, fortunately, 300 lines of the net 400 increase are from the expected output of a test case), and fiddly. :( |
@swift-ci please smoke test |
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 looking great. It's definitely fine for the Swift 5.0 branch. And although it's quite a bit of code churn... the changes are fairly clear and you've made the code fairly defensive, so I think on balance it's safe for the 4.1 branch. Thank you!
lib/IDE/IDETypeChecking.cpp
Outdated
if (!Ext->isConstrainedExtension()) { | ||
auto conformanceIsConditional = | ||
Conf && !Conf->getConditionalRequirements().empty(); | ||
if (!Ext->isConstrainedExtension() && !conformanceIsConditional) { |
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.
It seems to me that one cannot have a conditional conformance without also having a constrained extension?
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.
It's confusing (took me 10 minutes to remember why I had to have this... will add a comment), but they're referring to two different extensions:
protocol Foo {}
extension Foo { ... } // Ext
struct Bar<T> {}
extension Bar : Foo where T: Foo {} // Conf
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.
Oh, of course! Ext
is the protocol extension we're considering, and Conf
is referring to a nominal type's conditional conformance to the corresponding protocol.
|
||
// FIXME: Could do something here | ||
if (Kind == RequirementKind::Layout) | ||
continue; |
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 know this isn't your new code, but it'd be so nice to at least check for class constraints here. I guess we'll wait for the isApplicable
rewrite.
First = First.subst(subMap); | ||
Second = Second.subst(subMap); | ||
|
||
if (!First || !Second) { |
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.
Random: should we move this safety code out of the if
? This particular code path is known to be a bit crashy, and maybe that would help somewhat...
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 think that can probably become Req.subst(subMap)
too, but I was keeping everything the same to reduce risk as much as possible, since this patch is large enough. (And similarly for the class constraints.)
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.
Okay.
lib/IDE/ModuleInterfacePrinting.cpp
Outdated
Printer << "\n"; | ||
} | ||
}); | ||
// For top-level decls, only constraint extensions are to print; |
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.
If you're revising stuff, could you clean up the comment grammar here?
NominalTypeDecl *SynthesizedTargetNTD = nullptr; | ||
if (SynthesizedTarget) { | ||
SynthesizedTargetNTD = SynthesizedTarget.dyn_cast<NominalTypeDecl *>(); | ||
if (!SynthesizedTargetNTD) |
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'd appreciate some curly braces for the 3-line body here.
DocInfoConsumer &Consumer) { | ||
if (!D || isa<ParamDecl>(D)) | ||
return; | ||
if (const auto *ED = dyn_cast<ExtensionDecl>(D)) { | ||
if (SynthesizedTarget) { | ||
passExtends((const ValueDecl*)SynthesizedTarget, Consumer); | ||
auto Extends = SynthesizedTarget.dyn_cast<NominalTypeDecl *>(); | ||
if (!Extends) |
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.
You have this same "figure out the nominal type declaration to which SynthesizedTarget
refers" pattern in two places; can you pull it out into a function somewhere?
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.
Oh, yeah, bit embarrassing that I missed that. I've made TypeOrExtensionDecl
a wrapper struct with some convenience methods like getBaseNominal
.
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.
Although, it is in a somewhat clunky place: PrintOptions.h
. Any thoughts for where something like that should go? Decl.h
seems wrong to me.
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 suspect that TypeOrExtensionDecl
could be more widely used, if we were to search around for pointer unions similar to the one you're replacing. It's fine to put it in Decl.h
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.
FWIW, I couldn't find any other NominalTypeDecl, ExtensionDecl pointer unions.
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.
Ugh, moving it to Decl.h is rather ugly: PrintOptions.h doesn't/can't include that file, so everything has to be indirected...
Optional<BracketOptions> Bracket) override { | ||
// When we start print a synthesized extension, record the target's USR. | ||
llvm::SmallString<64> Buf; | ||
llvm::raw_svector_ostream OS(Buf); | ||
if (!SwiftLangSupport::printUSR(Target, OS)) { | ||
auto TargetNTD = Target.dyn_cast<NominalTypeDecl *>(); | ||
if (!TargetNTD) |
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.
Another copy of this pattern
if (TargetToAnalyzerMap.count(Target) == 0) { | ||
NominalTypeDecl *TargetNTD = Target.dyn_cast<NominalTypeDecl *>(); | ||
if (!TargetNTD) | ||
TargetNTD = Target.get<ExtensionDecl *>() |
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.
Another one :)
b4cfd93
to
da7b9d6
Compare
@swift-ci please test |
@swift-ci test. |
1 similar comment
@swift-ci test. |
@swift-ci test |
Build failed |
Build failed |
Before conditional conformances, the archetypes in conformance extensions (i.e. extension Foo: SomeProtocol) were equivalent to those in the type decl, with the same protocol bounds and so on. The code for printing "synthesized" members relied on this fact. This commit teaches that code to deal with archetypes in the conditional conformance extension when required. Fixes rdar://problem/36553066 and SR-6930.
da7b9d6
to
cb60dbe
Compare
@swift-ci please smoke test and merge |
3 similar comments
@swift-ci please smoke test and merge |
@swift-ci please smoke test and merge |
@swift-ci please smoke test and merge |
@swift-ci please smoke test |
Before conditional conformances, the archetypes in conformance
extensions (i.e. extension Foo: SomeProtocol) were equivalent to those
in the type decl, with the same protocol bounds and so on. The code for
printing "synthesized" members relied on this fact. This commit teaches
that code to deal with archetypes in the conditional conformance
extension when required.
Fixes rdar://problem/36553066 and SR-6930.