Skip to content

Commit 435d66f

Browse files
committed
Sema: Add separate pass for checkConformancesInContext()
I tried doing this directly from typeCheckDecl(), but it breaks associated type inference. We can figure this out later when declaration checking becomes lazier and more incremental. Note that typo correction does not force witnesses of synthesized conformances. This means that a typo correction from a top-level form will no longer pick up synthesized witnesses, and will find the protocol requirement instead. To give a test the same behavior as before, I put the expression in a function body instead of a top-level form. Note that we already had the same behavior with typo correction from pattern binding initializers and other contexts that are type checked before conformances.
1 parent ec42da0 commit 435d66f

File tree

4 files changed

+24
-5
lines changed

4 files changed

+24
-5
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4354,7 +4354,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
43544354
for (Decl *member : ED->getMembers())
43554355
visit(member);
43564356

4357-
TC.checkConformancesInContext(ED, ED);
43584357
return;
43594358
}
43604359

@@ -4387,14 +4386,14 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
43874386
}
43884387

43894388
TC.checkDeclCircularity(ED);
4389+
TC.ConformanceContexts.push_back(ED);
43904390
}
43914391

43924392
void visitStructDecl(StructDecl *SD) {
43934393
if (!IsFirstPass) {
43944394
for (Decl *Member : SD->getMembers())
43954395
visit(Member);
43964396

4397-
TC.checkConformancesInContext(SD, SD);
43984397
return;
43994398
}
44004399

@@ -4415,6 +4414,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
44154414
checkAccessControl(TC, SD);
44164415

44174416
TC.checkDeclCircularity(SD);
4417+
TC.ConformanceContexts.push_back(SD);
44184418
}
44194419

44204420
/// Check whether the given properties can be @NSManaged in this class.
@@ -4525,7 +4525,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
45254525
for (Decl *Member : CD->getMembers())
45264526
visit(Member);
45274527

4528-
TC.checkConformancesInContext(CD, CD);
45294528
return;
45304529
}
45314530

@@ -4649,6 +4648,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
46494648
checkAccessControl(TC, CD);
46504649

46514650
TC.checkDeclCircularity(CD);
4651+
TC.ConformanceContexts.push_back(CD);
46524652
}
46534653

46544654
void visitProtocolDecl(ProtocolDecl *PD) {
@@ -6241,7 +6241,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
62416241
for (Decl *Member : ED->getMembers())
62426242
visit(Member);
62436243

6244-
TC.checkConformancesInContext(ED, ED);
6244+
TC.ConformanceContexts.push_back(ED);
62456245

62466246
if (!ED->isInvalid())
62476247
TC.checkDeclAttributes(ED);

lib/Sema/TypeChecker.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,18 @@ static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC)
442442
unsigned currentExternalDef = TC.Context.LastCheckedExternalDefinition;
443443
unsigned currentSynthesizedDecl = SF.LastCheckedSynthesizedDecl;
444444
do {
445+
// Type check conformance contexts.
446+
for (unsigned i = 0; i != TC.ConformanceContexts.size(); ++i) {
447+
auto decl = TC.ConformanceContexts[i];
448+
if (auto *ext = dyn_cast<ExtensionDecl>(decl))
449+
TC.checkConformancesInContext(ext, ext);
450+
else {
451+
auto *ntd = cast<NominalTypeDecl>(decl);
452+
TC.checkConformancesInContext(ntd, ntd);
453+
}
454+
}
455+
TC.ConformanceContexts.clear();
456+
445457
// Type check the body of each of the function in turn. Note that outside
446458
// functions must be visited before nested functions for type-checking to
447459
// work correctly.
@@ -523,6 +535,7 @@ static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC)
523535
currentExternalDef < TC.Context.ExternalDefinitions.size() ||
524536
currentSynthesizedDecl < SF.SynthesizedDecls.size() ||
525537
!TC.DeclsToFinalize.empty() ||
538+
!TC.ConformanceContexts.empty() ||
526539
!TC.DelayedRequirementSignatures.empty() ||
527540
!TC.UsedConformances.empty() ||
528541
!TC.PartiallyCheckedConformances.empty());

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,9 @@ class TypeChecker final : public LazyResolver {
711711
/// \brief The list of function definitions we've encountered.
712712
std::vector<AbstractFunctionDecl *> definedFunctions;
713713

714+
/// Declarations that need their conformances checked.
715+
llvm::SmallVector<Decl *, 8> ConformanceContexts;
716+
714717
/// The list of protocol conformances that were "used" and will need to be
715718
/// completed before type checking is considered complete.
716719
llvm::SetVector<NormalProtocolConformance *> UsedConformances;

test/decl/enum/enumtest.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,10 @@ print(E21269142.Foo.rawValue) // expected-error {{value of type 'E21269142' has
313313
enum SyntheticMember { // expected-note {{did you mean the implicitly-synthesized property 'hashValue'?}}
314314
case Foo
315315
}
316-
print(SyntheticMember.Foo.hasValue) // expected-error {{value of type 'SyntheticMember' has no member 'hasValue'}}
316+
317+
func useSynthesizedMember() {
318+
print(SyntheticMember.Foo.hasValue) // expected-error {{value of type 'SyntheticMember' has no member 'hasValue'}}
319+
}
317320

318321
// Non-materializable argument type
319322
enum Lens<T> {

0 commit comments

Comments
 (0)