Skip to content

Commit 464aab6

Browse files
committed
Define InterfaceTypeRequest
The moment you've all been waiting for... Define InterfaceTypeRequest and use it to, well, compute the interface type. This naturally widens the few cycles that we pick up with the request evaluator. There is still a lot of work to get done here, mostly around scaling back all of the ad-hoc circularity checks around the interface type computation. It would also be great to improve the circularity diagnostics.
1 parent eabce73 commit 464aab6

File tree

8 files changed

+128
-76
lines changed

8 files changed

+128
-76
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2467,6 +2467,7 @@ class ValueDecl : public Decl {
24672467
friend class IsFinalRequest;
24682468
friend class IsDynamicRequest;
24692469
friend class IsImplicitlyUnwrappedOptionalRequest;
2470+
friend class InterfaceTypeRequest;
24702471
friend class Decl;
24712472
SourceLoc getLocFromSource() const { return NameLoc; }
24722473
protected:

include/swift/AST/LazyResolver.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,6 @@ class LazyResolver {
5353
virtual void resolveWitness(const NormalProtocolConformance *conformance,
5454
ValueDecl *requirement) = 0;
5555

56-
/// Resolve the type and declaration attributes of a value.
57-
///
58-
/// This can be called when the type or signature of a value is needed.
59-
/// It does not perform full type-checking, only checks for basic
60-
/// consistency and provides the value a type.
61-
virtual void resolveDeclSignature(ValueDecl *VD) = 0;
62-
6356
/// Resolve any implicitly-declared constructors within the given nominal.
6457
virtual void resolveImplicitConstructors(NominalTypeDecl *nominal) = 0;
6558

include/swift/AST/TypeCheckRequests.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,6 +1427,27 @@ class NamingPatternRequest
14271427
void cacheResult(NamedPattern *P) const;
14281428
};
14291429

1430+
class InterfaceTypeRequest :
1431+
public SimpleRequest<InterfaceTypeRequest,
1432+
Type (ValueDecl *),
1433+
CacheKind::SeparatelyCached> {
1434+
public:
1435+
using SimpleRequest::SimpleRequest;
1436+
1437+
private:
1438+
friend SimpleRequest;
1439+
1440+
// Evaluation.
1441+
llvm::Expected<Type>
1442+
evaluate(Evaluator &evaluator, ValueDecl *decl) const;
1443+
1444+
public:
1445+
// Separate caching.
1446+
bool isCached() const { return true; }
1447+
Optional<Type> getCachedResult() const;
1448+
void cacheResult(Type value) const;
1449+
};
1450+
14301451
// Allow AnyValue to compare two Type values, even though Type doesn't
14311452
// support ==.
14321453
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ SWIFT_REQUEST(TypeChecker, InheritedTypeRequest,
6767
SeparatelyCached, HasNearestLocation)
6868
SWIFT_REQUEST(TypeChecker, InitKindRequest,
6969
CtorInitializerKind(ConstructorDecl *), Cached, NoLocationInfo)
70+
SWIFT_REQUEST(TypeChecker, InterfaceTypeRequest,
71+
Type(ValueDecl *), SeparatelyCached, NoLocationInfo)
7072
SWIFT_REQUEST(TypeChecker, IsAccessorTransparentRequest, bool(AccessorDecl *),
7173
SeparatelyCached, NoLocationInfo)
7274
SWIFT_REQUEST(TypeChecker, IsDynamicRequest, bool(ValueDecl *),

lib/AST/Decl.cpp

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2805,30 +2805,23 @@ bool ValueDecl::isRecursiveValidation() const {
28052805
}
28062806

28072807
Type ValueDecl::getInterfaceType() const {
2808-
if (!hasInterfaceType()) {
2809-
// Our clients that don't register the lazy resolver are relying on the
2810-
// fact that they can't pull an interface type out to avoid doing work.
2811-
// This is a necessary evil until we can wean them off.
2812-
if (auto resolver = getASTContext().getLazyResolver()) {
2813-
resolver->resolveDeclSignature(const_cast<ValueDecl *>(this));
2814-
if (!hasInterfaceType())
2815-
return ErrorType::get(getASTContext());
2816-
}
2808+
// Our clients that don't register the lazy resolver are relying on the
2809+
// fact that they can't pull an interface type out to avoid doing work.
2810+
// This is a necessary evil until we can wean them off.
2811+
if (!getASTContext().getLazyResolver()) {
2812+
return TypeAndAccess.getPointer();
28172813
}
2818-
return TypeAndAccess.getPointer();
2814+
2815+
auto ty =
2816+
evaluateOrDefault(getASTContext().evaluator,
2817+
InterfaceTypeRequest{const_cast<ValueDecl *>(this)},
2818+
ErrorType::get(getASTContext()));
2819+
return ty ?: ErrorType::get(getASTContext());
28192820
}
28202821

28212822
void ValueDecl::setInterfaceType(Type type) {
2822-
if (type) {
2823-
assert(!type->hasTypeVariable() && "Type variable in interface type");
2824-
assert(!type->is<InOutType>() && "Interface type must be materializable");
2825-
assert(!type->hasArchetype() && "Archetype in interface type");
2826-
2827-
if (type->hasError())
2828-
setInvalid();
2829-
}
2830-
2831-
TypeAndAccess.setPointer(type);
2823+
getASTContext().evaluator.cacheOutput(InterfaceTypeRequest{this},
2824+
std::move(type));
28322825
}
28332826

28342827
Optional<ObjCSelector> ValueDecl::getObjCRuntimeName(
@@ -4001,7 +3994,7 @@ ClassAncestryFlagsRequest::evaluate(Evaluator &evaluator, ClassDecl *value) cons
40013994
do {
40023995
// If we hit circularity, we will diagnose at some point in typeCheckDecl().
40033996
// However we have to explicitly guard against that here because we get
4004-
// called as part of validateDecl().
3997+
// called as part of the interface type request.
40053998
if (!visited.insert(CD).second)
40063999
break;
40074000

lib/AST/TypeCheckRequests.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,3 +1001,28 @@ void NamingPatternRequest::cacheResult(NamedPattern *value) const {
10011001
auto *VD = std::get<0>(getStorage());
10021002
VD->NamingPattern = value;
10031003
}
1004+
1005+
//----------------------------------------------------------------------------//
1006+
// InterfaceTypeRequest computation.
1007+
//----------------------------------------------------------------------------//
1008+
1009+
Optional<Type> InterfaceTypeRequest::getCachedResult() const {
1010+
auto *decl = std::get<0>(getStorage());
1011+
if (auto Ty = decl->TypeAndAccess.getPointer()) {
1012+
return Ty;
1013+
}
1014+
return None;
1015+
}
1016+
1017+
void InterfaceTypeRequest::cacheResult(Type type) const {
1018+
auto *decl = std::get<0>(getStorage());
1019+
if (type) {
1020+
assert(!type->hasTypeVariable() && "Type variable in interface type");
1021+
assert(!type->is<InOutType>() && "Interface type must be materializable");
1022+
assert(!type->hasArchetype() && "Archetype in interface type");
1023+
1024+
if (type->hasError())
1025+
decl->setInvalid();
1026+
}
1027+
decl->TypeAndAccess.setPointer(type);
1028+
}

lib/Sema/TypeCheckDecl.cpp

Lines changed: 65 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2287,9 +2287,9 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
22872287
// WARNING: Anything you put in this function will only be run when the
22882288
// VarDecl is fully type-checked within its own file. It will NOT be run
22892289
// when the VarDecl is merely used from another file.
2290-
TC.validateDecl(VD);
22912290

22922291
// Compute these requests in case they emit diagnostics.
2292+
(void) VD->getInterfaceType();
22932293
(void) VD->isGetterMutating();
22942294
(void) VD->isSetterMutating();
22952295
(void) VD->getPropertyWrapperBackingProperty();
@@ -4091,15 +4091,9 @@ static Type validateParameterType(ParamDecl *decl) {
40914091
return TL.getType();
40924092
}
40934093

4094-
void TypeChecker::validateDecl(ValueDecl *D) {
4095-
// Handling validation failure due to re-entrancy is left
4096-
// up to the caller, who must call hasInterfaceType() to
4097-
// check that validateDecl() returned a fully-formed decl.
4098-
if (D->isBeingValidated() || D->hasInterfaceType())
4099-
return;
4100-
4101-
PrettyStackTraceDecl StackTrace("validating", D);
4102-
FrontendStatsTracer StatsTracer(Context.Stats, "validate-decl", D);
4094+
llvm::Expected<Type>
4095+
InterfaceTypeRequest::evaluate(Evaluator &eval, ValueDecl *D) const {
4096+
auto &Context = D->getASTContext();
41034097

41044098
TypeChecker::checkForForbiddenPrefix(Context, D->getBaseName());
41054099

@@ -4123,13 +4117,12 @@ void TypeChecker::validateDecl(ValueDecl *D) {
41234117
case DeclKind::OpaqueType:
41244118
case DeclKind::GenericTypeParam:
41254119
llvm_unreachable("should not get here");
4126-
return;
4120+
return Type();
41274121

41284122
case DeclKind::AssociatedType: {
41294123
auto assocType = cast<AssociatedTypeDecl>(D);
41304124
auto interfaceTy = assocType->getDeclaredInterfaceType();
4131-
assocType->setInterfaceType(MetatypeType::get(interfaceTy, Context));
4132-
break;
4125+
return MetatypeType::get(interfaceTy, Context);
41334126
}
41344127

41354128
case DeclKind::TypeAlias: {
@@ -4146,8 +4139,7 @@ void TypeChecker::validateDecl(ValueDecl *D) {
41464139
parent = parentDC->getSelfInterfaceType();
41474140
auto sugaredType = TypeAliasType::get(typeAlias, parent, subs,
41484141
typeAlias->getUnderlyingType());
4149-
typeAlias->setInterfaceType(MetatypeType::get(sugaredType, Context));
4150-
break;
4142+
return MetatypeType::get(sugaredType, Context);
41514143
}
41524144

41534145
case DeclKind::Enum:
@@ -4156,8 +4148,7 @@ void TypeChecker::validateDecl(ValueDecl *D) {
41564148
case DeclKind::Protocol: {
41574149
auto nominal = cast<NominalTypeDecl>(D);
41584150
Type declaredInterfaceTy = nominal->getDeclaredInterfaceType();
4159-
nominal->setInterfaceType(MetatypeType::get(declaredInterfaceTy, Context));
4160-
break;
4151+
return MetatypeType::get(declaredInterfaceTy, Context);
41614152
}
41624153

41634154
case DeclKind::Param: {
@@ -4167,40 +4158,33 @@ void TypeChecker::validateDecl(ValueDecl *D) {
41674158
auto selfParam = computeSelfParam(AFD,
41684159
/*isInitializingCtor*/true,
41694160
/*wantDynamicSelf*/true);
4170-
PD->setInterfaceType(selfParam.getPlainType());
4171-
break;
4161+
return selfParam.getPlainType();
41724162
}
41734163

41744164
if (auto *accessor = dyn_cast<AccessorDecl>(PD->getDeclContext())) {
41754165
auto *storage = accessor->getStorage();
41764166
auto *originalParam = getOriginalParamFromAccessor(
41774167
storage, accessor, PD);
41784168
if (originalParam == nullptr) {
4179-
auto type = storage->getValueInterfaceType();
4180-
PD->setInterfaceType(type);
4181-
break;
4169+
return storage->getValueInterfaceType();
41824170
}
41834171

41844172
if (originalParam != PD) {
4185-
PD->setInterfaceType(originalParam->getInterfaceType());
4186-
break;
4173+
return originalParam->getInterfaceType();
41874174
}
41884175
}
41894176

41904177
if (!PD->getTypeRepr())
4191-
return;
4178+
return Type();
41924179

4193-
auto ty = validateParameterType(PD);
4194-
PD->setInterfaceType(ty);
4195-
break;
4180+
return validateParameterType(PD);
41964181
}
41974182

41984183
case DeclKind::Var: {
41994184
auto *VD = cast<VarDecl>(D);
42004185
auto *namingPattern = VD->getNamingPattern();
42014186
if (!namingPattern) {
4202-
VD->setInterfaceType(ErrorType::get(Context));
4203-
break;
4187+
return ErrorType::get(Context);
42044188
}
42054189

42064190
Type interfaceType = namingPattern->getType();
@@ -4213,9 +4197,8 @@ void TypeChecker::validateDecl(ValueDecl *D) {
42134197
interfaceType =
42144198
TypeChecker::checkReferenceOwnershipAttr(VD, interfaceType, attr);
42154199
}
4216-
VD->setInterfaceType(interfaceType);
42174200

4218-
break;
4201+
return interfaceType;
42194202
}
42204203

42214204
case DeclKind::Func:
@@ -4224,8 +4207,54 @@ void TypeChecker::validateDecl(ValueDecl *D) {
42244207
case DeclKind::Destructor: {
42254208
auto *AFD = cast<AbstractFunctionDecl>(D);
42264209
DeclValidationRAII IBV(AFD);
4227-
AFD->computeType();
4228-
break;
4210+
4211+
auto sig = AFD->getGenericSignature();
4212+
bool hasSelf = AFD->hasImplicitSelfDecl();
4213+
4214+
AnyFunctionType::ExtInfo info;
4215+
4216+
// Result
4217+
Type resultTy;
4218+
if (auto fn = dyn_cast<FuncDecl>(D)) {
4219+
resultTy = fn->getResultInterfaceType();
4220+
} else if (auto ctor = dyn_cast<ConstructorDecl>(D)) {
4221+
resultTy = ctor->getResultInterfaceType();
4222+
} else {
4223+
assert(isa<DestructorDecl>(D));
4224+
resultTy = TupleType::getEmpty(AFD->getASTContext());
4225+
}
4226+
4227+
// (Args...) -> Result
4228+
Type funcTy;
4229+
4230+
{
4231+
SmallVector<AnyFunctionType::Param, 4> argTy;
4232+
AFD->getParameters()->getParams(argTy);
4233+
4234+
// 'throws' only applies to the innermost function.
4235+
info = info.withThrows(AFD->hasThrows());
4236+
// Defer bodies must not escape.
4237+
if (auto fd = dyn_cast<FuncDecl>(D))
4238+
info = info.withNoEscape(fd->isDeferBody());
4239+
4240+
if (sig && !hasSelf) {
4241+
funcTy = GenericFunctionType::get(sig, argTy, resultTy, info);
4242+
} else {
4243+
funcTy = FunctionType::get(argTy, resultTy, info);
4244+
}
4245+
}
4246+
4247+
// (Self) -> (Args...) -> Result
4248+
if (hasSelf) {
4249+
// Substitute in our own 'self' parameter.
4250+
auto selfParam = computeSelfParam(AFD);
4251+
if (sig)
4252+
funcTy = GenericFunctionType::get(sig, {selfParam}, funcTy);
4253+
else
4254+
funcTy = FunctionType::get({selfParam}, funcTy);
4255+
}
4256+
4257+
return funcTy;
42294258
}
42304259

42314260
case DeclKind::Subscript: {
@@ -4243,9 +4272,7 @@ void TypeChecker::validateDecl(ValueDecl *D) {
42434272
else
42444273
funcTy = FunctionType::get(argTy, elementTy);
42454274

4246-
// Record the interface type.
4247-
SD->setInterfaceType(funcTy);
4248-
break;
4275+
return funcTy;
42494276
}
42504277

42514278
case DeclKind::EnumElement: {
@@ -4272,13 +4299,9 @@ void TypeChecker::validateDecl(ValueDecl *D) {
42724299
else
42734300
resultTy = FunctionType::get({selfTy}, resultTy);
42744301

4275-
// Record the interface type.
4276-
EED->setInterfaceType(resultTy);
4277-
break;
4302+
return resultTy;
42784303
}
42794304
}
4280-
4281-
assert(D->hasInterfaceType());
42824305
}
42834306

42844307
llvm::Expected<NamedPattern *>

lib/Sema/TypeChecker.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -798,8 +798,6 @@ class TypeChecker final : public LazyResolver {
798798
GenericEnvironment *handleSILGenericParams(GenericParamList *genericParams,
799799
DeclContext *DC);
800800

801-
void validateDecl(ValueDecl *D);
802-
803801
/// Resolve a reference to the given type declaration within a particular
804802
/// context.
805803
///
@@ -1019,10 +1017,6 @@ class TypeChecker final : public LazyResolver {
10191017
static Type checkReferenceOwnershipAttr(VarDecl *D, Type interfaceType,
10201018
ReferenceOwnershipAttr *attr);
10211019

1022-
virtual void resolveDeclSignature(ValueDecl *VD) override {
1023-
validateDecl(VD);
1024-
}
1025-
10261020
virtual void resolveImplicitConstructors(NominalTypeDecl *nominal) override {
10271021
addImplicitConstructors(nominal);
10281022
}

0 commit comments

Comments
 (0)