Skip to content

Commit a75fdba

Browse files
author
Eli Friedman
committed
Fix protocol checking so it happens in the right order. Fixes <rdar://problem/11515674> in -parse-as-library mode.
A refactor of the various visitors in DeclChecker in TypeCheckDecl.cpp is coming up next. Swift SVN r2000
1 parent 2947962 commit a75fdba

File tree

3 files changed

+63
-53
lines changed

3 files changed

+63
-53
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -49,27 +49,19 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
4949
/// \param CheckConformance Will be set true if the caller needs to call
5050
/// checkExplicitConformance() for this declaration once its members have
5151
/// been type-checked. Otherwise, the conformance check can be delayed.
52-
void checkInherited(Decl *D, Type T, MutableArrayRef<Type> Inherited,
53-
bool &CheckConformance) {
52+
void checkInherited(Decl *D, Type T, MutableArrayRef<Type> Inherited) {
5453
// Check the list of inherited protocols.
55-
bool ConformsToProtocols = false;
5654
for (unsigned i = 0, e = Inherited.size(); i != e; ++i) {
5755
if (TC.validateType(Inherited[i], IsFirstPass)) {
5856
Inherited[i] = ErrorType::get(TC.Context);
5957
continue;
6058
}
6159

62-
if (!Inherited[i]->is<ProtocolType>()) {
60+
if (!Inherited[i]->is<ProtocolType>() && !Inherited[i]->is<ErrorType>()) {
6361
// FIXME: Terrible location information.
6462
TC.diagnose(D->getLocStart(), diag::nonprotocol_inherit, Inherited[i]);
65-
} else if (!Inherited[i]->is<ErrorType>()) {
66-
ConformsToProtocols = true;
6763
}
6864
}
69-
70-
CheckConformance = ConformsToProtocols &&
71-
!D->getDeclContext()->isModuleContext() &&
72-
!isa<ProtocolDecl>(D);
7365
}
7466

7567
void checkExplicitConformance(Decl *D, Type T,
@@ -187,28 +179,36 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
187179
}
188180

189181
void visitOneOfDecl(OneOfDecl *OOD) {
190-
if (IsSecondPass)
182+
if (IsSecondPass) {
183+
for (auto elt : OOD->getElements())
184+
visitOneOfElementDecl(elt);
185+
186+
checkExplicitConformance(OOD, OOD->getDeclaredType(),
187+
OOD->getInherited());
191188
return;
189+
}
192190

193-
bool CheckConformance;
194-
checkInherited(OOD, OOD->getDeclaredType(), OOD->getInherited(),
195-
CheckConformance);
191+
checkInherited(OOD, OOD->getDeclaredType(), OOD->getInherited());
196192

197193
for (auto elt : OOD->getElements())
198194
visitOneOfElementDecl(elt);
199195

200-
if (CheckConformance)
196+
if (!IsFirstPass)
201197
checkExplicitConformance(OOD, OOD->getDeclaredType(),
202198
OOD->getInherited());
203199
}
204200

205201
void visitStructDecl(StructDecl *SD) {
206-
if (IsSecondPass)
202+
if (IsSecondPass) {
203+
for (Decl *Member : SD->getMembers())
204+
visit(Member);
205+
206+
checkExplicitConformance(SD, SD->getDeclaredType(),
207+
SD->getInherited());
207208
return;
209+
}
208210

209-
bool CheckConformance;
210-
checkInherited(SD, SD->getDeclaredType(), SD->getInherited(),
211-
CheckConformance);
211+
checkInherited(SD, SD->getDeclaredType(), SD->getInherited());
212212

213213
for (Decl *Member : SD->getMembers()) {
214214
visit(Member);
@@ -226,24 +226,28 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
226226
cast<OneOfElementDecl>(SD->getMembers().back())->setType(CreateTy);
227227
cast<OneOfElementDecl>(SD->getMembers().back())->setArgumentType(TT);
228228

229-
if (CheckConformance)
229+
if (!IsFirstPass)
230230
checkExplicitConformance(SD, SD->getDeclaredType(),
231231
SD->getInherited());
232232
}
233233

234234
void visitClassDecl(ClassDecl *CD) {
235-
if (IsSecondPass)
235+
if (IsSecondPass) {
236+
for (Decl *Member : CD->getMembers())
237+
visit(Member);
238+
239+
checkExplicitConformance(CD, CD->getDeclaredType(),
240+
CD->getInherited());
236241
return;
242+
}
237243

238-
bool CheckConformance;
239-
checkInherited(CD, CD->getDeclaredType(), CD->getInherited(),
240-
CheckConformance);
244+
checkInherited(CD, CD->getDeclaredType(), CD->getInherited());
241245

242246
for (Decl *Member : CD->getMembers()) {
243247
visit(Member);
244248
}
245249

246-
if (CheckConformance)
250+
if (!IsFirstPass)
247251
checkExplicitConformance(CD, CD->getDeclaredType(),
248252
CD->getInherited());
249253
}
@@ -252,9 +256,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
252256
if (IsSecondPass)
253257
return;
254258

255-
bool CheckConformance;
256-
checkInherited(PD, PD->getDeclaredType(), PD->getInherited(),
257-
CheckConformance);
259+
checkInherited(PD, PD->getDeclaredType(), PD->getInherited());
258260

259261
// Assign archetypes each of the associated types.
260262
// FIXME: We need to build equivalence classes of associated types first,
@@ -297,6 +299,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
297299

298300
visitValueDecl(FD);
299301
}
302+
300303
void visitOneOfElementDecl(OneOfElementDecl *ED) {
301304
if (IsSecondPass)
302305
return;
@@ -313,11 +316,19 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
313316
diag::oneof_element_not_materializable);
314317
}
315318
}
319+
316320
void visitExtensionDecl(ExtensionDecl *ED) {
317-
if (IsSecondPass)
321+
if (IsSecondPass) {
322+
for (Decl *Member : ED->getMembers())
323+
// First recursively type check each thing in the extension.
324+
visit(Member);
325+
326+
checkExplicitConformance(ED, ED->getExtendedType(),
327+
ED->getInherited());
318328
return;
329+
}
330+
319331

320-
bool CheckConformance;
321332
if (TC.validateType(ED->getExtendedType(), IsFirstPass)) {
322333
ED->setExtendedType(ErrorType::get(TC.Context));
323334
} else {
@@ -330,13 +341,17 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
330341
// declaration, if any.
331342
}
332343

333-
checkInherited(ED, ExtendedTy, ED->getInherited(), CheckConformance);
344+
checkInherited(ED, ExtendedTy, ED->getInherited());
334345
}
335346

336347
for (Decl *Member : ED->getMembers()) {
337348
// First recursively type check each thing in the extension.
338349
visit(Member);
339350
}
351+
352+
if (!IsFirstPass)
353+
checkExplicitConformance(ED, ED->getExtendedType(),
354+
ED->getInherited());
340355
}
341356

342357
void visitTopLevelCodeDecl(TopLevelCodeDecl *TLCD) {

lib/Sema/TypeCheckStmt.cpp

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -686,15 +686,6 @@ static void REPLCheckPatternBinding(PatternBindingDecl *D, TypeChecker &TC) {
686686
D->setInit(TC.semaApplyExpr(CE));
687687
}
688688

689-
/// \brief Check for explicit protocol conformance.
690-
static void checkExplicitConformance(TypeChecker &TC, Decl *D, Type Ty,
691-
ArrayRef<Type> Inherited) {
692-
for (auto InheritedTy : Inherited) {
693-
if (ProtocolType *Proto = InheritedTy->getAs<ProtocolType>())
694-
TC.conformsToProtocol(Ty, Proto->getDecl(), D->getLocStart());
695-
}
696-
}
697-
698689
/// \brief Check for circular inheritance of protocols.
699690
///
700691
/// \param Path The circular path through the protocol inheritance hierarchy,
@@ -946,21 +937,10 @@ void swift::performTypeChecking(TranslationUnit *TU, unsigned StartElem) {
946937
// Check for explicit conformance to protocols and for circularity in
947938
// protocol definitions.
948939
{
940+
// FIXME: This check should be in TypeCheckDecl.
949941
llvm::SmallPtrSet<ProtocolDecl *, 16> VisitedProtocols;
950942
for (auto D : TU->Decls) {
951-
if (auto Struct = dyn_cast<StructDecl>(D))
952-
checkExplicitConformance(TC, Struct, Struct->getDeclaredType(),
953-
Struct->getInherited());
954-
else if (auto Class = dyn_cast<ClassDecl>(D))
955-
checkExplicitConformance(TC, Class, Class->getDeclaredType(),
956-
Class->getInherited());
957-
else if (auto OneOf = dyn_cast<OneOfDecl>(D))
958-
checkExplicitConformance(TC, OneOf, OneOf->getDeclaredType(),
959-
OneOf->getInherited());
960-
else if (auto Extension = dyn_cast<ExtensionDecl>(D))
961-
checkExplicitConformance(TC, Extension, Extension->getExtendedType(),
962-
Extension->getInherited());
963-
else if (auto Protocol = dyn_cast<ProtocolDecl>(D)) {
943+
if (auto Protocol = dyn_cast<ProtocolDecl>(D)) {
964944
// Check for circular protocol definitions.
965945
llvm::SmallPtrSet<ProtocolDecl *, 16> LocalVisited;
966946
llvm::SmallVector<ProtocolDecl *, 4> Path;

test/protocols_in_library.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %swift -parse %s -verify -parse-as-library
2+
3+
struct X {
4+
struct Inner : Proto {
5+
}
6+
struct Inner2 : Proto2 { // expected-error {{type 'Inner2' does not conform to protocol 'Proto2'}}
7+
}
8+
}
9+
10+
protocol Proto {
11+
}
12+
13+
protocol Proto2 {
14+
func f() // expected-note {{protocol requires function 'f' with type '() -> ()'}}
15+
}

0 commit comments

Comments
 (0)