Skip to content

Commit d84730c

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 d84730c

File tree

7 files changed

+199
-4
lines changed

7 files changed

+199
-4
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: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2075,3 +2075,62 @@ 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)
2096+
return true;
2097+
2098+
if (sf->getKind() != FileUnitKind::Source)
2099+
return true;
2100+
2101+
if (sf->isPrimary())
2102+
return true;
2103+
2104+
return false;
2105+
}
2106+
2107+
llvm::Optional<SubstitutionMap>
2108+
UniqueUnderlyingTypeSubstitutionsRequest::evaluate(
2109+
Evaluator &evaluator, const OpaqueTypeDecl *decl) const {
2110+
auto namingDecl = decl->getNamingDecl();
2111+
2112+
// If the naming declaration is a function, typecheck its body. This will
2113+
// have a side-effect of setting UniqueUnderlyingType on the opaque type.
2114+
if (auto afd = dyn_cast<AbstractFunctionDecl>(namingDecl)) {
2115+
if (shouldTypecheckFunctionBodyForUniqueUnderlyingType(afd))
2116+
(void)afd->getTypecheckedBody();
2117+
}
2118+
2119+
return decl->UniqueUnderlyingType;
2120+
}
2121+
2122+
llvm::Optional<llvm::Optional<SubstitutionMap>>
2123+
UniqueUnderlyingTypeSubstitutionsRequest::getCachedResult() const {
2124+
auto decl = std::get<0>(getStorage());
2125+
if (decl->LazySemanticInfo.UniqueUnderlyingTypeComputed)
2126+
return decl->UniqueUnderlyingType;
2127+
return llvm::None;
2128+
}
2129+
2130+
void UniqueUnderlyingTypeSubstitutionsRequest::cacheResult(
2131+
llvm::Optional<SubstitutionMap> subs) const {
2132+
auto decl = std::get<0>(getStorage());
2133+
assert(subs == decl->UniqueUnderlyingType);
2134+
const_cast<OpaqueTypeDecl *>(decl)
2135+
->LazySemanticInfo.UniqueUnderlyingTypeComputed = true;
2136+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
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+
@available(SwiftStdlib 5.5, *)
18+
public func returnsLibraryStruct() -> some P {
19+
return LibraryStruct()
20+
}
21+
22+
@available(SwiftStdlib 5.5, *)
23+
@inlinable public func inlinableReturnsLibraryStruct() -> some P {
24+
return LibraryStruct()
25+
}
26+
27+
//--- Other.swift
28+
29+
import Library
30+
31+
struct OtherStruct: P {}
32+
33+
@available(SwiftStdlib 5.5, *)
34+
public func returnsOtherStruct() -> some P {
35+
return OtherStruct()
36+
}
37+
38+
//--- Primary.swift
39+
40+
import Library
41+
42+
public struct PrimaryStruct: P {
43+
public init() {}
44+
}
45+
46+
// CHECK-LABEL: sil{{.*}} @$s4Test20returnsPrimaryStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test20returnsPrimaryStructQryF", 0) __> {
47+
// CHECK: bb0(%0 : $*PrimaryStruct):
48+
// CHECK: } // end sil function '$s4Test20returnsPrimaryStructQryF'
49+
@available(SwiftStdlib 5.5, *)
50+
public func returnsPrimaryStruct() -> some P {
51+
return PrimaryStruct()
52+
}
53+
54+
// CHECK-COMMON-LABEL: sil{{.*}} @$s4Test024inlinableReturnsResultOfC13PrimaryStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test024inlinableReturnsResultOfC13PrimaryStructQryF", 0) __> {
55+
// CHECK: bb0(%0 : $*PrimaryStruct):
56+
// CHECK-SKIP: bb0(%0 : $*@_opaqueReturnTypeOf("$s4Test20returnsPrimaryStructQryF", 0) __):
57+
// CHECK-COMMON: } // end sil function '$s4Test024inlinableReturnsResultOfC13PrimaryStructQryF'
58+
@available(SwiftStdlib 5.5, *)
59+
@inlinable public func inlinableReturnsResultOfReturnsPrimaryStruct() -> some P {
60+
return returnsPrimaryStruct()
61+
}
62+
63+
// CHECK-LABEL: sil{{.*}} @$s4Test19returnsNestedStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test19returnsNestedStructQryF", 0) __> {
64+
// CHECK: bb0(%0 : $*NestedStruct):
65+
// CHECK: } // end sil function '$s4Test19returnsNestedStructQryF'
66+
@available(SwiftStdlib 5.5, *)
67+
public func returnsNestedStruct() -> some P {
68+
struct NestedStruct: P {}
69+
return NestedStruct()
70+
}
71+
72+
// CHECK-LABEL: sil{{.*}} @$s4Test34returnsResultOfReturnsNestedStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test34returnsResultOfReturnsNestedStructQryF", 0) __> {
73+
// CHECK: bb0(%0 : $*NestedStruct):
74+
// CHECK: } // end sil function '$s4Test34returnsResultOfReturnsNestedStructQryF'
75+
@available(SwiftStdlib 5.5, *)
76+
public func returnsResultOfReturnsNestedStruct() -> some P {
77+
return returnsNestedStruct()
78+
}
79+
80+
// CHECK-LABEL: sil{{.*}} @$s4Test33returnsResultOfReturnsOtherStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test33returnsResultOfReturnsOtherStructQryF", 0) __> {
81+
// CHECK-PRIMARY: bb0(%0 : $*@_opaqueReturnTypeOf("$s4Test18returnsOtherStructQryF", 0) __):
82+
// CHECK-WHOLE-MODULE: bb0(%0 : $*OtherStruct):
83+
// CHECK: } // end sil function '$s4Test33returnsResultOfReturnsOtherStructQryF'
84+
@available(SwiftStdlib 5.5, *)
85+
public func returnsResultOfReturnsOtherStruct() -> some P {
86+
return returnsOtherStruct()
87+
}
88+
89+
// CHECK-LABEL: sil{{.*}} @$s4Test35returnsResultOfReturnsLibraryStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test35returnsResultOfReturnsLibraryStructQryF", 0) __> {
90+
// CHECK: bb0(%0 : $*@_opaqueReturnTypeOf("$s7Library07returnsA6StructQryF", 0) __):
91+
// CHECK: } // end sil function '$s4Test35returnsResultOfReturnsLibraryStructQryF'
92+
@available(SwiftStdlib 5.5, *)
93+
public func returnsResultOfReturnsLibraryStruct() -> some P {
94+
return returnsLibraryStruct()
95+
}
96+
97+
// CHECK-LABEL: sil{{.*}} @$s4Test44returnsResulfOfInlinableReturnsLibraryStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test44returnsResulfOfInlinableReturnsLibraryStructQryF", 0) __> {
98+
// CHECK: bb0(%0 : $*LibraryStruct):
99+
// CHECK: } // end sil function '$s4Test44returnsResulfOfInlinableReturnsLibraryStructQryF'
100+
@available(SwiftStdlib 5.5, *)
101+
public func returnsResulfOfInlinableReturnsLibraryStruct() -> some P {
102+
return inlinableReturnsLibraryStruct()
103+
}

test/SILOptimizer/specialize_opaque_result_types2.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// RUN: %target-swift-frontend -disable-availability-checking -primary-file %S/Inputs/specialize_opaque_result_types.swift -enable-library-evolution -module-name A -emit-sib -o %t/A.sib
33
// RUN: %target-swift-frontend -emit-sil -primary-file %s -enable-library-evolution -O -module-name A %t/A.sib -o - | %FileCheck %s
44

5-
// REQUIRES: CPU=x86_64
5+
// REQUIRES: CPU=x86_64 || CPU=arm64
66

77
sil_stage canonical
88

0 commit comments

Comments
 (0)