Skip to content

Commit 4d53b5e

Browse files
committed
AST: Requestify unique underlying type substitutions.
Introduce a request that computes the unique underlying type substitution of an opaque type declaration. This ensures that the type substitution is available on-demand when generating SIL in lazy typechecking mode. Resolves rdar://117439760
1 parent d2e2214 commit 4d53b5e

File tree

6 files changed

+185
-3
lines changed

6 files changed

+185
-3
lines changed

include/swift/AST/Decl.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3214,6 +3214,7 @@ class OpaqueTypeDecl final :
32143214
public GenericTypeDecl,
32153215
private llvm::TrailingObjects<OpaqueTypeDecl, TypeRepr *> {
32163216
friend TrailingObjects;
3217+
friend class UniqueUnderlyingTypeSubstitutionsRequest;
32173218

32183219
public:
32193220
/// A set of substitutions that represents a possible underlying type iff
@@ -3253,6 +3254,10 @@ class OpaqueTypeDecl final :
32533254

32543255
mutable Identifier OpaqueReturnTypeIdentifier;
32553256

3257+
struct {
3258+
unsigned UniqueUnderlyingTypeComputed : 1;
3259+
} LazySemanticInfo = { };
3260+
32563261
OpaqueTypeDecl(ValueDecl *NamingDecl, GenericParamList *GenericParams,
32573262
DeclContext *DC,
32583263
GenericSignature OpaqueInterfaceGenericSignature,
@@ -3329,9 +3334,7 @@ class OpaqueTypeDecl final :
33293334

33303335
/// The substitutions that map the generic parameters of the opaque type to
33313336
/// the unique underlying types, when that information is known.
3332-
llvm::Optional<SubstitutionMap> getUniqueUnderlyingTypeSubstitutions() const {
3333-
return UniqueUnderlyingType;
3334-
}
3337+
llvm::Optional<SubstitutionMap> getUniqueUnderlyingTypeSubstitutions() const;
33353338

33363339
void setUniqueUnderlyingTypeSubstitutions(SubstitutionMap subs) {
33373340
assert(!UniqueUnderlyingType.has_value() && "resetting underlying type?!");

include/swift/AST/TypeCheckRequests.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4620,6 +4620,27 @@ class SemanticDeclAttrsRequest
46204620
void cacheResult(DeclAttributes) const;
46214621
};
46224622

4623+
class UniqueUnderlyingTypeSubstitutionsRequest
4624+
: public SimpleRequest<UniqueUnderlyingTypeSubstitutionsRequest,
4625+
llvm::Optional<SubstitutionMap>(
4626+
const OpaqueTypeDecl *),
4627+
RequestFlags::SeparatelyCached> {
4628+
public:
4629+
using SimpleRequest::SimpleRequest;
4630+
4631+
private:
4632+
friend SimpleRequest;
4633+
4634+
llvm::Optional<SubstitutionMap> evaluate(Evaluator &evaluator,
4635+
const OpaqueTypeDecl *) const;
4636+
4637+
public:
4638+
// Separate caching.
4639+
bool isCached() const { return true; }
4640+
llvm::Optional<llvm::Optional<SubstitutionMap>> getCachedResult() const;
4641+
void cacheResult(llvm::Optional<SubstitutionMap>) const;
4642+
};
4643+
46234644
#define SWIFT_TYPEID_ZONE TypeChecker
46244645
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"
46254646
#include "swift/Basic/DefineTypeIDZone.h"

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,3 +527,6 @@ SWIFT_REQUEST(TypeChecker, IsCCompatibleFuncDeclRequest,
527527
SWIFT_REQUEST(TypeChecker, SemanticDeclAttrsRequest,
528528
DeclAttributes(const Decl *),
529529
Cached, NoLocationInfo)
530+
SWIFT_REQUEST(TypeChecker, UniqueUnderlyingTypeSubstitutionsRequest,
531+
llvm::Optional<SubstitutionMap>(const Decl *),
532+
SeparatelyCached, NoLocationInfo)

lib/AST/Decl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9608,6 +9608,12 @@ bool OpaqueTypeDecl::exportUnderlyingType() const {
96089608
llvm_unreachable("The naming decl is expected to be either an AFD or ASD");
96099609
}
96109610

9611+
llvm::Optional<SubstitutionMap>
9612+
OpaqueTypeDecl::getUniqueUnderlyingTypeSubstitutions() const {
9613+
return evaluateOrDefault(getASTContext().evaluator,
9614+
UniqueUnderlyingTypeSubstitutionsRequest{this}, {});
9615+
}
9616+
96119617
llvm::Optional<unsigned>
96129618
OpaqueTypeDecl::getAnonymousOpaqueParamOrdinal(TypeRepr *repr) const {
96139619
assert(NamingDeclAndHasOpaqueReturnTypeRepr.getInt() &&

lib/AST/TypeCheckRequests.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2075,3 +2075,59 @@ void SemanticDeclAttrsRequest::cacheResult(DeclAttributes attrs) const {
20752075
auto decl = std::get<0>(getStorage());
20762076
const_cast<Decl *>(decl)->setSemanticAttrsComputed(true);
20772077
}
2078+
2079+
//----------------------------------------------------------------------------//
2080+
// UniqueUnderlyingTypeSubstitutionsRequest computation.
2081+
//----------------------------------------------------------------------------//
2082+
2083+
static bool
2084+
shouldTypecheckFunctionBodyForUniqueUnderlyingType(AbstractFunctionDecl *afd) {
2085+
auto mod = afd->getModuleContext();
2086+
if (!mod->isMainModule())
2087+
return true;
2088+
2089+
// If the main module has no primary source files then the compilation is a
2090+
// whole module build and all source files can be typechecked.
2091+
if (mod->getPrimarySourceFiles().size() == 0)
2092+
return true;
2093+
2094+
auto sf = afd->getParentSourceFile();
2095+
if (sf->getKind() != FileUnitKind::Source)
2096+
return true;
2097+
2098+
if (sf->isPrimary())
2099+
return true;
2100+
2101+
return false;
2102+
}
2103+
2104+
llvm::Optional<SubstitutionMap>
2105+
UniqueUnderlyingTypeSubstitutionsRequest::evaluate(
2106+
Evaluator &evaluator, const OpaqueTypeDecl *decl) const {
2107+
auto namingDecl = decl->getNamingDecl();
2108+
2109+
// If the naming declaration is a function, typecheck its body. This will
2110+
// have a side-effect of setting UniqueUnderlyingType on the opaque type.
2111+
if (auto afd = dyn_cast<AbstractFunctionDecl>(namingDecl)) {
2112+
if (shouldTypecheckFunctionBodyForUniqueUnderlyingType(afd))
2113+
(void)afd->getTypecheckedBody();
2114+
}
2115+
2116+
return decl->UniqueUnderlyingType;
2117+
}
2118+
2119+
llvm::Optional<llvm::Optional<SubstitutionMap>>
2120+
UniqueUnderlyingTypeSubstitutionsRequest::getCachedResult() const {
2121+
auto decl = std::get<0>(getStorage());
2122+
if (decl->LazySemanticInfo.UniqueUnderlyingTypeComputed)
2123+
return decl->UniqueUnderlyingType;
2124+
return llvm::None;
2125+
}
2126+
2127+
void UniqueUnderlyingTypeSubstitutionsRequest::cacheResult(
2128+
llvm::Optional<SubstitutionMap> subs) const {
2129+
auto decl = std::get<0>(getStorage());
2130+
assert(subs == decl->UniqueUnderlyingType);
2131+
const_cast<OpaqueTypeDecl *>(decl)
2132+
->LazySemanticInfo.UniqueUnderlyingTypeComputed = true;
2133+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
// RUN: %target-swift-frontend -emit-module %t/Library.swift -parse-as-library -module-name Library -enable-library-evolution -emit-module-path %t/Library.swiftmodule
4+
// RUN: %target-swift-frontend -emit-silgen -primary-file %t/Primary.swift %t/Other.swift -parse-as-library -module-name Test -I %t | %FileCheck %s --check-prefixes CHECK,CHECK-PRIMARY,CHECK-COMMON
5+
// RUN: %target-swift-frontend -emit-silgen %t/Primary.swift %t/Other.swift -parse-as-library -module-name Test -I %t | %FileCheck %s --check-prefixes CHECK,CHECK-WHOLE-MODULE,CHECK-COMMON
6+
// RUN: %target-swift-frontend -emit-silgen -primary-file %t/Primary.swift %t/Other.swift -parse-as-library -module-name Test -I %t -experimental-lazy-typecheck | %FileCheck %s --check-prefixes CHECK,CHECK-PRIMARY,CHECK-COMMON
7+
// RUN: %target-swift-frontend -emit-silgen -primary-file %t/Primary.swift %t/Other.swift -parse-as-library -module-name Test -I %t -experimental-skip-non-inlinable-function-bodies | %FileCheck %s --check-prefixes CHECK-SKIP,CHECK-COMMON
8+
9+
//--- Library.swift
10+
11+
public protocol P {}
12+
13+
@usableFromInline struct LibraryStruct: P {
14+
@usableFromInline init() {}
15+
}
16+
17+
public func returnsLibraryStruct() -> some P {
18+
return LibraryStruct()
19+
}
20+
21+
@inlinable public func inlinableReturnsLibraryStruct() -> some P {
22+
return LibraryStruct()
23+
}
24+
25+
//--- Other.swift
26+
27+
import Library
28+
29+
struct OtherStruct: P {}
30+
31+
public func returnsOtherStruct() -> some P {
32+
return OtherStruct()
33+
}
34+
35+
//--- Primary.swift
36+
37+
import Library
38+
39+
public struct PrimaryStruct: P {
40+
public init() {}
41+
}
42+
43+
// CHECK-LABEL: sil{{.*}} @$s4Test20returnsPrimaryStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test20returnsPrimaryStructQryF", 0) __> {
44+
// CHECK: bb0(%0 : $*PrimaryStruct):
45+
// CHECK: } // end sil function '$s4Test20returnsPrimaryStructQryF'
46+
public func returnsPrimaryStruct() -> some P {
47+
return PrimaryStruct()
48+
}
49+
50+
// CHECK-COMMON-LABEL: sil{{.*}} @$s4Test024inlinableReturnsResultOfC13PrimaryStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test024inlinableReturnsResultOfC13PrimaryStructQryF", 0) __> {
51+
// CHECK: bb0(%0 : $*PrimaryStruct):
52+
// CHECK-SKIP: bb0(%0 : $*@_opaqueReturnTypeOf("$s4Test20returnsPrimaryStructQryF", 0) __):
53+
// CHECK-COMMON: } // end sil function '$s4Test024inlinableReturnsResultOfC13PrimaryStructQryF'
54+
@inlinable public func inlinableReturnsResultOfReturnsPrimaryStruct() -> some P {
55+
return returnsPrimaryStruct()
56+
}
57+
58+
// CHECK-LABEL: sil{{.*}} @$s4Test19returnsNestedStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test19returnsNestedStructQryF", 0) __> {
59+
// CHECK: bb0(%0 : $*NestedStruct):
60+
// CHECK: } // end sil function '$s4Test19returnsNestedStructQryF'
61+
public func returnsNestedStruct() -> some P {
62+
struct NestedStruct: P {}
63+
return NestedStruct()
64+
}
65+
66+
// CHECK-LABEL: sil{{.*}} @$s4Test34returnsResultOfReturnsNestedStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test34returnsResultOfReturnsNestedStructQryF", 0) __> {
67+
// CHECK: bb0(%0 : $*NestedStruct):
68+
// CHECK: } // end sil function '$s4Test34returnsResultOfReturnsNestedStructQryF'
69+
public func returnsResultOfReturnsNestedStruct() -> some P {
70+
return returnsNestedStruct()
71+
}
72+
73+
// CHECK-LABEL: sil{{.*}} @$s4Test33returnsResultOfReturnsOtherStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test33returnsResultOfReturnsOtherStructQryF", 0) __> {
74+
// CHECK-PRIMARY: bb0(%0 : $*@_opaqueReturnTypeOf("$s4Test18returnsOtherStructQryF", 0) __):
75+
// CHECK-WHOLE-MODULE: bb0(%0 : $*OtherStruct):
76+
// CHECK: } // end sil function '$s4Test33returnsResultOfReturnsOtherStructQryF'
77+
public func returnsResultOfReturnsOtherStruct() -> some P {
78+
return returnsOtherStruct()
79+
}
80+
81+
// CHECK-LABEL: sil{{.*}} @$s4Test35returnsResultOfReturnsLibraryStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test35returnsResultOfReturnsLibraryStructQryF", 0) __> {
82+
// CHECK: bb0(%0 : $*@_opaqueReturnTypeOf("$s7Library07returnsA6StructQryF", 0) __):
83+
// CHECK: } // end sil function '$s4Test35returnsResultOfReturnsLibraryStructQryF'
84+
public func returnsResultOfReturnsLibraryStruct() -> some P {
85+
return returnsLibraryStruct()
86+
}
87+
88+
// CHECK-LABEL: sil{{.*}} @$s4Test44returnsResulfOfInlinableReturnsLibraryStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test44returnsResulfOfInlinableReturnsLibraryStructQryF", 0) __> {
89+
// CHECK: bb0(%0 : $*LibraryStruct):
90+
// CHECK: } // end sil function '$s4Test44returnsResulfOfInlinableReturnsLibraryStructQryF'
91+
public func returnsResulfOfInlinableReturnsLibraryStruct() -> some P {
92+
return inlinableReturnsLibraryStruct()
93+
}

0 commit comments

Comments
 (0)