Skip to content

Commit f247447

Browse files
committed
Iterative type checker: compute inherited protocols of a protocol.
Introduce a type check request for computing inherited protocols and start using it in a few places. Swift SVN r32562
1 parent 68604e6 commit f247447

File tree

9 files changed

+108
-10
lines changed

9 files changed

+108
-10
lines changed

include/swift/Sema/IterativeTypeChecker.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#define SWIFT_SEMA_ITERATIVE_TYPE_CHECKER_H
2121

2222
#include "swift/Sema/TypeCheckRequest.h"
23+
#include "swift/AST/DiagnosticEngine.h"
2324
#include "swift/Basic/LLVM.h"
2425
#include "llvm/ADT/STLExtras.h"
2526

@@ -54,6 +55,15 @@ class IterativeTypeChecker {
5455
public:
5556
IterativeTypeChecker(TypeChecker &tc) : TC(tc) { }
5657

58+
ASTContext &getASTContext() const;
59+
60+
DiagnosticEngine &getDiags() const;
61+
62+
template<typename ...ArgTypes>
63+
InFlightDiagnostic diagnose(ArgTypes &&...Args) {
64+
return getDiags().diagnose(std::forward<ArgTypes>(Args)...);
65+
}
66+
5767
/// Determine whether the given request has already been satisfied.
5868
bool isSatisfied(TypeCheckRequest request);
5969

include/swift/Sema/TypeCheckRequest.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace swift {
2828
class ClassDecl;
2929
class EnumDecl;
3030
class ExtensionDecl;
31+
class ProtocolDecl;
3132
class TypeDecl;
3233

3334
/// A request to the type checker to compute some particular kind of

include/swift/Sema/TypeCheckRequestKinds.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
TYPE_CHECK_REQUEST_PAYLOAD(Class, ClassDecl *)
3838
TYPE_CHECK_REQUEST_PAYLOAD(Enum, EnumDecl *)
3939
TYPE_CHECK_REQUEST_PAYLOAD(InheritedClauseEntry, std::pair<llvm::PointerUnion<TypeDecl *, ExtensionDecl *>, unsigned>)
40+
TYPE_CHECK_REQUEST_PAYLOAD(Protocol, ProtocolDecl *)
4041

4142
/// Perform type checking on an entry in the inherited clause of a
4243
/// type or extension.
@@ -48,5 +49,8 @@ TYPE_CHECK_REQUEST(TypeCheckSuperclass, Class)
4849
/// Perform type checking on the raw type of a particular enum.
4950
TYPE_CHECK_REQUEST(TypeCheckRawType, Enum)
5051

52+
/// Compute the set of inherited protocols for a given protocl
53+
TYPE_CHECK_REQUEST(InheritedProtocols, Protocol)
54+
5155
#undef TYPE_CHECK_REQUEST_PAYLOAD
5256
#undef TYPE_CHECK_REQUEST

lib/AST/Decl.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1722,7 +1722,10 @@ Type ValueDecl::getInterfaceType() const {
17221722
if (auto assocType = dyn_cast<AssociatedTypeDecl>(this)) {
17231723
auto proto = cast<ProtocolDecl>(getDeclContext());
17241724
(void)proto->getType(); // make sure we've computed the type.
1725-
auto selfTy = proto->getGenericParamTypes().back();
1725+
// FIXME: the generic parameter types list should never be empty.
1726+
auto selfTy = proto->getGenericParamTypes().empty()
1727+
? proto->getProtocolSelf()->getType()
1728+
: proto->getGenericParamTypes().back();
17261729
auto &ctx = getASTContext();
17271730
InterfaceTy = DependentMemberType::get(
17281731
selfTy,

lib/Sema/ITCDecl.cpp

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ using namespace swift;
2525
//----------------------------------------------------------------------------//
2626
// Inheritance clause handling
2727
//----------------------------------------------------------------------------//
28-
static std::tuple<TypeResolutionOptions, DeclContext *, MutableArrayRef<TypeLoc>>
28+
static std::tuple<TypeResolutionOptions, DeclContext *,
29+
MutableArrayRef<TypeLoc>>
2930
decomposeInheritedClauseDecl(
3031
llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl) {
3132
TypeResolutionOptions options;
@@ -110,7 +111,7 @@ void IterativeTypeChecker::satisfyTypeCheckInheritedClauseEntry(
110111
// FIXME: Recursion into existing type checker.
111112
PartialGenericTypeToArchetypeResolver resolver(TC);
112113
if (TC.validateType(*inherited, dc, options, &resolver)) {
113-
inherited->setInvalidType(TC.Context);
114+
inherited->setInvalidType(getASTContext());
114115
}
115116
}
116117

@@ -212,3 +213,71 @@ void IterativeTypeChecker::satisfyTypeCheckRawType(EnumDecl *enumDecl) {
212213
// Set the raw type.
213214
enumDecl->setRawType(rawType);
214215
}
216+
217+
//----------------------------------------------------------------------------//
218+
// Inherited protocols
219+
//----------------------------------------------------------------------------//
220+
bool IterativeTypeChecker::isInheritedProtocolsSatisfied(ProtocolDecl *payload){
221+
return payload->isInheritedProtocolsValid();
222+
}
223+
224+
void IterativeTypeChecker::enumerateDependenciesOfInheritedProtocols(
225+
ProtocolDecl *payload,
226+
llvm::function_ref<void(TypeCheckRequest)> fn) {
227+
// Computing the set of inherited protocols depends on the complete
228+
// inheritance clause.
229+
// FIXME: Technically, we only need very basic name binding.
230+
auto inheritedClause = payload->getInherited();
231+
for (unsigned i = 0, n = inheritedClause.size(); i != n; ++i) {
232+
TypeLoc &inherited = inheritedClause[i];
233+
234+
// If this inherited type has not been resolved, we depend on it.
235+
if (!inherited.getType()) {
236+
fn(TypeCheckRequest(TypeCheckRequest::TypeCheckInheritedClauseEntry,
237+
{ payload, i }));
238+
}
239+
}
240+
}
241+
242+
void IterativeTypeChecker::satisfyInheritedProtocols(ProtocolDecl *protocol) {
243+
// Gather all of the existential types in the inherited list.
244+
// Loop through the inheritance clause looking for a non-existential
245+
// nominal type.
246+
llvm::SmallSetVector<ProtocolDecl *, 4> allProtocols;
247+
for (const auto &inherited : protocol->getInherited()) {
248+
if (!inherited.getType()) continue;
249+
250+
// Collect existential types.
251+
// FIXME: We'd prefer to keep what the user wrote here.
252+
SmallVector<ProtocolDecl *, 4> protocols;
253+
if (inherited.getType()->isExistentialType(protocols)) {
254+
allProtocols.insert(protocols.begin(), protocols.end());
255+
}
256+
}
257+
258+
// FIXME: Hack to deal with recursion elsewhere.
259+
if (protocol->isInheritedProtocolsValid())
260+
return;
261+
262+
// Check for circular inheritance.
263+
// FIXME: The diagnostics here should be improved.
264+
bool diagnosedCircularity = false;
265+
for (unsigned i = 0, n = allProtocols.size(); i != n; /*in loop*/) {
266+
if (allProtocols[i] == protocol ||
267+
allProtocols[i]->inheritsFrom(protocol)) {
268+
if (!diagnosedCircularity) {
269+
diagnose(protocol,
270+
diag::circular_protocol_def, protocol->getName().str());
271+
diagnosedCircularity = true;
272+
}
273+
274+
allProtocols.remove(allProtocols[i]);
275+
--n;
276+
continue;
277+
}
278+
279+
++i;
280+
}
281+
282+
protocol->setInheritedProtocols(getASTContext().AllocateCopy(allProtocols));
283+
}

lib/Sema/IterativeTypeChecker.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,19 @@
1616
//
1717
//===----------------------------------------------------------------------===//
1818

19+
#include "TypeChecker.h"
1920
#include "swift/Sema/IterativeTypeChecker.h"
2021
#include "swift/AST/Decl.h"
2122
using namespace swift;
2223

24+
ASTContext &IterativeTypeChecker::getASTContext() const {
25+
return TC.Context;
26+
}
27+
28+
DiagnosticEngine &IterativeTypeChecker::getDiags() const {
29+
return getASTContext().Diags;
30+
}
31+
2332
/// Determine whether the given request has already been satisfied.
2433
bool IterativeTypeChecker::isSatisfied(TypeCheckRequest request) {
2534
switch (request.getKind()) {

lib/Sema/TypeCheckDecl.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3171,9 +3171,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
31713171
// need to propagate recursive properties now.
31723172
TAD->getAliasType()->setRecursiveProperties(
31733173
TAD->getUnderlyingType()->getRecursiveProperties());
3174-
3175-
if (!isa<ProtocolDecl>(TAD->getDeclContext()))
3176-
TC.checkInheritanceClause(TAD);
31773174
}
31783175

31793176
if (IsSecondPass)
@@ -3537,6 +3534,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
35373534
checkAccessibility(TC, PD);
35383535
for (auto member : PD->getMembers())
35393536
checkAccessibility(TC, member);
3537+
TC.checkInheritanceClause(PD);
35403538
return;
35413539
}
35423540

@@ -5871,7 +5869,10 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) {
58715869
checkGenericParamList(&builder, gp, proto->getDeclContext());
58725870
finalizeGenericParamList(builder, gp, proto, *this);
58735871

5874-
checkInheritanceClause(D);
5872+
// Record inherited protocols.
5873+
IterativeTypeChecker ITC(*this);
5874+
ITC.satisfy(TypeCheckRequest(TypeCheckRequest::InheritedProtocols, proto));
5875+
58755876
validateAttributes(*this, D);
58765877

58775878
// Set the underlying type of each of the associated types to the
@@ -6362,7 +6363,8 @@ void TypeChecker::validateExtension(ExtensionDecl *ext) {
63626363

63636364
ArrayRef<ProtocolDecl *>
63646365
TypeChecker::getDirectConformsTo(ProtocolDecl *proto) {
6365-
checkInheritanceClause(proto);
6366+
IterativeTypeChecker ITC(*this);
6367+
ITC.satisfy(TypeCheckRequest(TypeCheckRequest::InheritedProtocols, proto));
63666368
return proto->getInheritedProtocols(nullptr);
63676369
}
63686370

validation-test/compiler_crashers/1843-llvm-bitstreamcursor-readrecord.swift renamed to validation-test/compiler_crashers_fixed/1843-llvm-bitstreamcursor-readrecord.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not --crash %target-swift-frontend %s -parse
1+
// RUN: not %target-swift-frontend %s -parse
22

33
// Distributed under the terms of the MIT license
44
// Test case submitted to project by https://github.com/practicalswift (practicalswift)

validation-test/compiler_crashers/26570-swift-valuedecl-getinterfacetype.swift renamed to validation-test/compiler_crashers_fixed/26570-swift-valuedecl-getinterfacetype.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not --crash %target-swift-frontend %s -parse
1+
// RUN: not %target-swift-frontend %s -parse
22
// Distributed under the terms of the MIT license
33
// Test case submitted to project by https://github.com/practicalswift (practicalswift)
44
// Test case found by fuzzing

0 commit comments

Comments
 (0)