Skip to content

Commit 8c65333

Browse files
committed
Sema: Fix failure to emit a diagnostic when a protocol witness is being validated already
Validating a declaration can trigger conformance checking. If the conformance checker comes across the same declaration as a candidate witness, it would fail to emit a diagnostic. As a result we would then go onto SILGen, which would crash while emitting a witness table with a missing entry. Fixes <rdar://problem/45151902>.
1 parent e160b85 commit 8c65333

File tree

7 files changed

+38
-14
lines changed

7 files changed

+38
-14
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,6 +1875,9 @@ NOTE(protocol_witness_nonconform_type,none,
18751875
"possibly intended match %0 does not "
18761876
"%select{inherit from|conform to}2 %1", (Type, Type, bool))
18771877

1878+
NOTE(protocol_witness_circularity,none,
1879+
"candidate references itself", ())
1880+
18781881
NOTE(protocol_conformance_here,none,
18791882
"%select{|class }0%1 declares conformance to protocol %2 here",
18801883
(bool, DeclName, DeclName))
@@ -1982,8 +1985,8 @@ ERROR(requires_generic_params_made_equal,none,
19821985
ERROR(requires_generic_param_made_equal_to_concrete,none,
19831986
"same-type requirement makes generic parameter %0 non-generic",
19841987
(Type))
1985-
ERROR(recursive_type_reference,none,
1986-
"%0 %1 references itself", (DescriptiveDeclKind, Identifier))
1988+
ERROR(recursive_decl_reference,none,
1989+
"%0 %1 references itself", (DescriptiveDeclKind, DeclBaseName))
19871990
ERROR(recursive_same_type_constraint,none,
19881991
"same-type constraint %0 == %1 is recursive", (Type, Type))
19891992
ERROR(recursive_superclass_constraint,none,

lib/Sema/TypeCheckDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3918,7 +3918,7 @@ void TypeChecker::validateDecl(ValueDecl *D) {
39183918
});
39193919

39203920
if (mentionsItself) {
3921-
diagnose(defaultDefinition.getLoc(), diag::recursive_type_reference,
3921+
diagnose(defaultDefinition.getLoc(), diag::recursive_decl_reference,
39223922
assocType->getDescriptiveKind(), assocType->getName());
39233923
diagnose(assocType, diag::kind_declared_here, DescriptiveDeclKind::Type);
39243924
}

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,7 @@ bool swift::isRepresentableInObjC(const VarDecl *VD, ObjCReason Reason) {
760760
VD->getASTContext().getLazyResolver()->resolveDeclSignature(
761761
const_cast<VarDecl *>(VD));
762762
if (!VD->hasInterfaceType()) {
763-
VD->diagnose(diag::recursive_type_reference, VD->getDescriptiveKind(),
763+
VD->diagnose(diag::recursive_decl_reference, VD->getDescriptiveKind(),
764764
VD->getName());
765765
return false;
766766
}

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -440,9 +440,12 @@ swift::matchWitness(
440440
return RequirementMatch(witness, MatchKind::KindConflict);
441441

442442
// If the witness is invalid, record that and stop now.
443-
if (witness->isInvalid() || !witness->hasValidSignature())
443+
if (witness->isInvalid())
444444
return RequirementMatch(witness, MatchKind::WitnessInvalid);
445445

446+
if (!witness->hasValidSignature())
447+
return RequirementMatch(witness, MatchKind::Circularity);
448+
446449
// Get the requirement and witness attributes.
447450
const auto &reqAttrs = req->getAttrs();
448451
const auto &witnessAttrs = witness->getAttrs();
@@ -1146,15 +1149,9 @@ bool WitnessChecker::findBestWitness(
11461149
continue;
11471150
}
11481151

1149-
if (!witness->hasValidSignature()) {
1152+
if (!witness->hasValidSignature())
11501153
TC.validateDecl(witness);
11511154

1152-
if (!witness->hasValidSignature()) {
1153-
doNotDiagnoseMatches = true;
1154-
continue;
1155-
}
1156-
}
1157-
11581155
auto match = matchWitness(TC, ReqEnvironmentCache, Proto, conformance, DC,
11591156
requirement, witness);
11601157
if (match.isViable()) {
@@ -2130,6 +2127,10 @@ diagnoseMatch(ModuleDecl *module, NormalProtocolConformance *conformance,
21302127
// about them.
21312128
break;
21322129

2130+
case MatchKind::Circularity:
2131+
diags.diagnose(match.Witness, diag::protocol_witness_circularity);
2132+
break;
2133+
21332134
case MatchKind::TypeConflict: {
21342135
auto diag = diags.diagnose(match.Witness,
21352136
diag::protocol_witness_type_conflict,

lib/Sema/TypeCheckProtocol.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ enum class MatchKind : uint8_t {
166166
/// The witness is invalid or has an invalid type.
167167
WitnessInvalid,
168168

169+
/// The witness is currently being type checked and this type checking in turn
170+
/// triggered conformance checking, so the witness cannot be considered as a
171+
/// candidate.
172+
Circularity,
173+
169174
/// The kind of the witness and requirement differ, e.g., one
170175
/// is a function and the other is a variable.
171176
KindConflict,
@@ -405,6 +410,7 @@ struct RequirementMatch {
405410
return true;
406411

407412
case MatchKind::WitnessInvalid:
413+
case MatchKind::Circularity:
408414
case MatchKind::KindConflict:
409415
case MatchKind::TypeConflict:
410416
case MatchKind::MissingRequirement:
@@ -435,6 +441,7 @@ struct RequirementMatch {
435441
return true;
436442

437443
case MatchKind::WitnessInvalid:
444+
case MatchKind::Circularity:
438445
case MatchKind::KindConflict:
439446
case MatchKind::StaticNonStaticConflict:
440447
case MatchKind::SettableConflict:

lib/Sema/TypeCheckType.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ Type TypeChecker::applyGenericArguments(Type type,
700700

701701
// FIXME: More principled handling of circularity.
702702
if (!genericDecl->hasValidSignature()) {
703-
diags.diagnose(loc, diag::recursive_type_reference,
703+
diags.diagnose(loc, diag::recursive_decl_reference,
704704
genericDecl->getDescriptiveKind(), genericDecl->getName());
705705
genericDecl->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type);
706706
return ErrorType::get(ctx);
@@ -922,7 +922,7 @@ static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc,
922922

923923
// If we were not able to validate recursively, bail out.
924924
if (!typeDecl->hasInterfaceType()) {
925-
diags.diagnose(loc, diag::recursive_type_reference,
925+
diags.diagnose(loc, diag::recursive_decl_reference,
926926
typeDecl->getDescriptiveKind(), typeDecl->getName());
927927
typeDecl->diagnose(diag::kind_declared_here,
928928
DescriptiveDeclKind::Type);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
// With a bit of effort, we could make this work -- but for now, let's just
4+
// not crash.
5+
6+
protocol P {
7+
var x: Int { get set } // expected-note {{protocol requires property 'x' with type 'Int'; do you want to add a stub?}}
8+
}
9+
10+
struct S : P { // expected-error {{type 'S' does not conform to protocol 'P'}}
11+
static var x = 0 // expected-note {{candidate operates on a type, not an instance as required}}
12+
var x = S.x // expected-note {{candidate references itself}}
13+
}

0 commit comments

Comments
 (0)