Skip to content

Sema: fill-protocol-stub fixits should include those missing witnesses that are handed by delayed diagnostics. #8011

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 10 commits into from
Mar 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,15 @@ class ASTContext {
std::vector<DelayedConformanceDiag>
takeDelayedConformanceDiags(NormalProtocolConformance *conformance);

/// Add delayed missing witnesses for the given normal protocol conformance.
void addDelayedMissingWitnesses(NormalProtocolConformance *conformance,
ArrayRef<ValueDecl*> witnesses);

/// Retrieve the delayed missing witnesses for the given normal protocol
/// conformance.
std::vector<ValueDecl*>
takeDelayedMissingWitnesses(NormalProtocolConformance *conformance);

/// \brief Produce a specialized conformance, which takes a generic
/// conformance and substitutions written in terms of the generic
/// conformance's signature.
Expand Down
24 changes: 24 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,12 @@ struct ASTContext::Implementation {
std::vector<ASTContext::DelayedConformanceDiag>>
DelayedConformanceDiags;

/// Map from normal protocol conformances to missing witnesses that have
/// been delayed until the conformance is fully checked, so that we can
/// issue a fixit that fills the entire protocol stub.
llvm::DenseMap<NormalProtocolConformance *, std::vector<ValueDecl*>>
DelayedMissingWitnesses;

/// Stores information about lazy deserialization of various declarations.
llvm::DenseMap<const DeclContext *, LazyContextData *> LazyContexts;

Expand Down Expand Up @@ -1491,6 +1497,24 @@ void ASTContext::addDelayedConformanceDiag(
Impl.DelayedConformanceDiags[conformance].push_back(std::move(fn));
}

void ASTContext::
addDelayedMissingWitnesses(NormalProtocolConformance *conformance,
ArrayRef<ValueDecl*> witnesses) {
auto &bucket = Impl.DelayedMissingWitnesses[conformance];
bucket.insert(bucket.end(), witnesses.begin(), witnesses.end());
}

std::vector<ValueDecl*> ASTContext::
takeDelayedMissingWitnesses(NormalProtocolConformance *conformance) {
std::vector<ValueDecl*> result;
auto known = Impl.DelayedMissingWitnesses.find(conformance);
if (known != Impl.DelayedMissingWitnesses.end()) {
result = std::move(known->second);
Impl.DelayedMissingWitnesses.erase(known);
}
return result;
}

std::vector<ASTContext::DelayedConformanceDiag>
ASTContext::takeDelayedConformanceDiags(NormalProtocolConformance *conformance){
std::vector<ASTContext::DelayedConformanceDiag> result;
Expand Down
37 changes: 33 additions & 4 deletions lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1945,12 +1945,21 @@ namespace {
ProtocolConformance *MultiConformanceChecker::
checkIndividualConformance(NormalProtocolConformance *conformance,
bool issueFixit) {
std::vector<ValueDecl*> revivedMissingWitnesses;
switch (conformance->getState()) {
case ProtocolConformanceState::Incomplete:
if (conformance->isInvalid()) {
// Emit any delayed diagnostics and return.
ConformanceChecker(TC, conformance, MissingWitnesses, false).
emitDelayedDiags();
// Revive registered missing witnesses to handle it below.
revivedMissingWitnesses = TC.Context.
takeDelayedMissingWitnesses(conformance);

// If we have no missing witnesses for this invalid conformance, the
// conformance is invalid for other reasons, so emit diagnosis now.
if (revivedMissingWitnesses.empty()) {
// Emit any delayed diagnostics.
ConformanceChecker(TC, conformance, MissingWitnesses, false).
emitDelayedDiags();
}
}

// Check the rest of the conformance below.
Expand Down Expand Up @@ -2051,6 +2060,8 @@ namespace {

// The conformance checker we're using.
AllUsedCheckers.emplace_back(TC, conformance, MissingWitnesses);
MissingWitnesses.insert(revivedMissingWitnesses.begin(),
revivedMissingWitnesses.end());
AllUsedCheckers.back().checkConformance(issueFixit ?
MissingWitnessDiagnosisKind::ErrorFixIt :
MissingWitnessDiagnosisKind::ErrorOnly);
Expand Down Expand Up @@ -2618,6 +2629,7 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
}

PrintOptions Options = PrintOptions::printForDiagnostics();
Options.PrintDocumentationComments = false;
Options.AccessibilityFilter = Accessibility::Private;
Options.PrintAccessibility = false;
Options.FunctionBody = [](const ValueDecl *VD) { return "<#code#>"; };
Expand Down Expand Up @@ -2721,7 +2733,15 @@ diagnoseMissingWitnesses(MissingWitnessDiagnosisKind Kind) {

switch (Kind) {
case MissingWitnessDiagnosisKind::ErrorFixIt: {
diagnoseOrDefer(LocalMissing[0], true, InsertFixitCallback);
if (SuppressDiagnostics) {
// If the diagnostics are suppressed, we register these missing witnesses
// for later revisiting.
Conformance->setInvalid();
TC.Context.addDelayedMissingWitnesses(Conformance,
MissingWitnesses.getArrayRef());
} else {
diagnoseOrDefer(LocalMissing[0], true, InsertFixitCallback);
}
clearGlobalMissingWitnesses();
return;
}
Expand Down Expand Up @@ -4875,6 +4895,15 @@ void ConformanceChecker::checkConformance(MissingWitnessDiagnosisKind Kind) {
// FIXME: Caller checks that this type conforms to all of the
// inherited protocols.

// Emit known diags for this conformance.
emitDelayedDiags();

// If delayed diags have already complained, return.
if (AlreadyComplained) {
Conformance->setInvalid();
return;
}

// Resolve all of the type witnesses.
resolveTypeWitnesses();

Expand Down
14 changes: 14 additions & 0 deletions test/decl/protocol/conforms/fixit_stub_editor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,17 @@ protocol P2 {
}

class C1 : P1, P2 {} // expected-error{{type 'C1' does not conform to protocol 'P1'}} expected-error{{type 'C1' does not conform to protocol 'P2'}} expected-note{{do you want to add protocol stubs?}}{{20-20=\n func foo1() {\n <#code#>\n \}\n\n func foo2() {\n <#code#>\n \}\n\n func bar1() {\n <#code#>\n \}\n\n func bar2() {\n <#code#>\n \}\n}}

protocol P3 {
associatedtype T1
associatedtype T2
associatedtype T3
}

protocol P4 : P3 {
associatedtype T4 = T1
associatedtype T5 = T2
associatedtype T6 = T3
}

class C2 : P4 {} // expected-error{{type 'C2' does not conform to protocol 'P4'}} expected-error{{type 'C2' does not conform to protocol 'P3'}} expected-note{{do you want to add protocol stubs?}}{{16-16=\n typealias T4 = <#type#>\n\n typealias T5 = <#type#>\n\n typealias T6 = <#type#>\n\n typealias T1 = <#type#>\n\n typealias T2 = <#type#>\n\n typealias T3 = <#type#>\n}}