Skip to content

Commit e45afd3

Browse files
authored
Merge pull request #69770 from tshortli/requestify-unique-underlying-type-subs
AST: Requestify unique underlying type substitutions
2 parents 51d4cd7 + 7e77241 commit e45afd3

File tree

7 files changed

+257
-4
lines changed

7 files changed

+257
-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
@@ -4623,6 +4623,27 @@ class SemanticDeclAttrsRequest
46234623
void cacheResult(DeclAttributes) const;
46244624
};
46254625

4626+
class UniqueUnderlyingTypeSubstitutionsRequest
4627+
: public SimpleRequest<UniqueUnderlyingTypeSubstitutionsRequest,
4628+
llvm::Optional<SubstitutionMap>(
4629+
const OpaqueTypeDecl *),
4630+
RequestFlags::SeparatelyCached> {
4631+
public:
4632+
using SimpleRequest::SimpleRequest;
4633+
4634+
private:
4635+
friend SimpleRequest;
4636+
4637+
llvm::Optional<SubstitutionMap> evaluate(Evaluator &evaluator,
4638+
const OpaqueTypeDecl *) const;
4639+
4640+
public:
4641+
// Separate caching.
4642+
bool isCached() const { return true; }
4643+
llvm::Optional<llvm::Optional<SubstitutionMap>> getCachedResult() const;
4644+
void cacheResult(llvm::Optional<SubstitutionMap>) const;
4645+
};
4646+
46264647
#define SWIFT_TYPEID_ZONE TypeChecker
46274648
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"
46284649
#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: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2075,3 +2075,84 @@ 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+
llvm::Optional<SubstitutionMap>
2084+
UniqueUnderlyingTypeSubstitutionsRequest::evaluate(
2085+
Evaluator &evaluator, const OpaqueTypeDecl *decl) const {
2086+
// Typechecking the body of a function that is associated with the naming
2087+
// declaration of an opaque type declaration will have the side-effect of
2088+
// setting UniqueUnderlyingType on the opaque type declaration.
2089+
auto typecheckBodyIfNeeded = [](AbstractFunctionDecl *afd) {
2090+
auto shouldTypecheckFunctionBody = [](AbstractFunctionDecl *afd) -> bool {
2091+
auto mod = afd->getModuleContext();
2092+
if (!mod->isMainModule())
2093+
return true;
2094+
2095+
// If the main module has no primary source files then the compilation is
2096+
// a whole module build and all source files can be typechecked.
2097+
if (mod->getPrimarySourceFiles().size() == 0)
2098+
return true;
2099+
2100+
auto sf = afd->getParentSourceFile();
2101+
if (!sf)
2102+
return true;
2103+
2104+
if (sf->isPrimary())
2105+
return true;
2106+
2107+
switch (sf->Kind) {
2108+
case SourceFileKind::Interface:
2109+
case SourceFileKind::MacroExpansion:
2110+
case SourceFileKind::SIL:
2111+
return true;
2112+
case SourceFileKind::Main:
2113+
case SourceFileKind::Library:
2114+
// Don't typecheck bodies in auxiliary source files.
2115+
return false;
2116+
}
2117+
2118+
llvm_unreachable("bad SourceFileKind");
2119+
};
2120+
2121+
if (shouldTypecheckFunctionBody(afd))
2122+
(void)afd->getTypecheckedBody();
2123+
};
2124+
2125+
auto namingDecl = decl->getNamingDecl();
2126+
if (auto afd = dyn_cast<AbstractFunctionDecl>(namingDecl)) {
2127+
typecheckBodyIfNeeded(afd);
2128+
2129+
return decl->UniqueUnderlyingType;
2130+
}
2131+
2132+
if (auto asd = dyn_cast<AbstractStorageDecl>(namingDecl)) {
2133+
asd->visitParsedAccessors([&](AccessorDecl *accessor) {
2134+
typecheckBodyIfNeeded(accessor);
2135+
});
2136+
2137+
return decl->UniqueUnderlyingType;
2138+
}
2139+
2140+
assert(false && "Unexpected kind of naming decl");
2141+
return llvm::None;
2142+
}
2143+
2144+
llvm::Optional<llvm::Optional<SubstitutionMap>>
2145+
UniqueUnderlyingTypeSubstitutionsRequest::getCachedResult() const {
2146+
auto decl = std::get<0>(getStorage());
2147+
if (decl->LazySemanticInfo.UniqueUnderlyingTypeComputed)
2148+
return decl->UniqueUnderlyingType;
2149+
return llvm::None;
2150+
}
2151+
2152+
void UniqueUnderlyingTypeSubstitutionsRequest::cacheResult(
2153+
llvm::Optional<SubstitutionMap> subs) const {
2154+
auto decl = std::get<0>(getStorage());
2155+
assert(subs == decl->UniqueUnderlyingType);
2156+
const_cast<OpaqueTypeDecl *>(decl)
2157+
->LazySemanticInfo.UniqueUnderlyingTypeComputed = true;
2158+
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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-LABEL: sil{{.*}} @$s4Test39globalComputedVarReturningPrimaryStructQrvg : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test39globalComputedVarReturningPrimaryStructQrvp", 0) __> {
55+
// CHECK: bb0(%0 : $*PrimaryStruct):
56+
// CHECK: } // end sil function '$s4Test39globalComputedVarReturningPrimaryStructQrvg'
57+
@available(SwiftStdlib 5.5, *)
58+
public var globalComputedVarReturningPrimaryStruct: some P {
59+
return PrimaryStruct()
60+
}
61+
62+
@available(SwiftStdlib 5.5, *)
63+
public struct S {
64+
private var privatePrimaryStruct: PrimaryStruct
65+
66+
public var computedVarReturningPrimaryStruct: some P {
67+
// CHECK-LABEL: sil{{.*}} @$s4Test1SV33computedVarReturningPrimaryStructQrvg : $@convention(method) (S) -> @out @_opaqueReturnTypeOf("$s4Test1SV33computedVarReturningPrimaryStructQrvp", 0) __ {
68+
// CHECK: bb0(%0 : $*PrimaryStruct, %1 : $S):
69+
// CHECK: } // end sil function '$s4Test1SV33computedVarReturningPrimaryStructQrvg'
70+
get { privatePrimaryStruct }
71+
72+
// CHECK-LABEL: sil{{.*}} @$s4Test1SV33computedVarReturningPrimaryStructQrvs : $@convention(method) (@in @_opaqueReturnTypeOf("$s4Test1SV33computedVarReturningPrimaryStructQrvp", 0) __, @inout S) -> () {
73+
// CHECK: bb0(%0 : $*PrimaryStruct, %1 : $*S):
74+
// CHECK: } // end sil function '$s4Test1SV33computedVarReturningPrimaryStructQrvs'
75+
set {}
76+
}
77+
78+
public subscript(subscriptReturningPrimaryStruct: Void) -> some P {
79+
// CHECK-LABEL: sil{{.*}} @$s4Test1SVyQryt_tcig : $@convention(method) (S) -> @out @_opaqueReturnTypeOf("$s4Test1SVyQryt_tcip", 0) __ {
80+
// CHECK: bb0(%0 : $*PrimaryStruct, %1 : $S):
81+
// CHECK: } // end sil function '$s4Test1SVyQryt_tcig'
82+
get { privatePrimaryStruct }
83+
// CHECK-LABEL: sil{{.*}} @$s4Test1SVyQryt_tcis : $@convention(method) (@in @_opaqueReturnTypeOf("$s4Test1SVyQryt_tcip", 0) __, @inout S) -> () {
84+
// CHECK: bb0(%0 : $*PrimaryStruct, %1 : $*S):
85+
// CHECK: } // end sil function '$s4Test1SVyQryt_tcis'
86+
set {}
87+
}
88+
}
89+
90+
// CHECK-COMMON-LABEL: sil{{.*}} @$s4Test024inlinableReturnsResultOfC13PrimaryStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test024inlinableReturnsResultOfC13PrimaryStructQryF", 0) __> {
91+
// CHECK: bb0(%0 : $*PrimaryStruct):
92+
// CHECK-SKIP: bb0(%0 : $*@_opaqueReturnTypeOf("$s4Test20returnsPrimaryStructQryF", 0) __):
93+
// CHECK-COMMON: } // end sil function '$s4Test024inlinableReturnsResultOfC13PrimaryStructQryF'
94+
@available(SwiftStdlib 5.5, *)
95+
@inlinable public func inlinableReturnsResultOfReturnsPrimaryStruct() -> some P {
96+
return returnsPrimaryStruct()
97+
}
98+
99+
// CHECK-LABEL: sil{{.*}} @$s4Test19returnsNestedStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test19returnsNestedStructQryF", 0) __> {
100+
// CHECK: bb0(%0 : $*NestedStruct):
101+
// CHECK: } // end sil function '$s4Test19returnsNestedStructQryF'
102+
@available(SwiftStdlib 5.5, *)
103+
public func returnsNestedStruct() -> some P {
104+
struct NestedStruct: P {}
105+
return NestedStruct()
106+
}
107+
108+
// CHECK-LABEL: sil{{.*}} @$s4Test34returnsResultOfReturnsNestedStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test34returnsResultOfReturnsNestedStructQryF", 0) __> {
109+
// CHECK: bb0(%0 : $*NestedStruct):
110+
// CHECK: } // end sil function '$s4Test34returnsResultOfReturnsNestedStructQryF'
111+
@available(SwiftStdlib 5.5, *)
112+
public func returnsResultOfReturnsNestedStruct() -> some P {
113+
return returnsNestedStruct()
114+
}
115+
116+
// CHECK-LABEL: sil{{.*}} @$s4Test33returnsResultOfReturnsOtherStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test33returnsResultOfReturnsOtherStructQryF", 0) __> {
117+
// CHECK-PRIMARY: bb0(%0 : $*@_opaqueReturnTypeOf("$s4Test18returnsOtherStructQryF", 0) __):
118+
// CHECK-WHOLE-MODULE: bb0(%0 : $*OtherStruct):
119+
// CHECK: } // end sil function '$s4Test33returnsResultOfReturnsOtherStructQryF'
120+
@available(SwiftStdlib 5.5, *)
121+
public func returnsResultOfReturnsOtherStruct() -> some P {
122+
return returnsOtherStruct()
123+
}
124+
125+
// CHECK-LABEL: sil{{.*}} @$s4Test35returnsResultOfReturnsLibraryStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test35returnsResultOfReturnsLibraryStructQryF", 0) __> {
126+
// CHECK: bb0(%0 : $*@_opaqueReturnTypeOf("$s7Library07returnsA6StructQryF", 0) __):
127+
// CHECK: } // end sil function '$s4Test35returnsResultOfReturnsLibraryStructQryF'
128+
@available(SwiftStdlib 5.5, *)
129+
public func returnsResultOfReturnsLibraryStruct() -> some P {
130+
return returnsLibraryStruct()
131+
}
132+
133+
// CHECK-LABEL: sil{{.*}} @$s4Test44returnsResulfOfInlinableReturnsLibraryStructQryF : $@convention(thin) @substituted <τ_0_0> () -> @out τ_0_0 for <@_opaqueReturnTypeOf("$s4Test44returnsResulfOfInlinableReturnsLibraryStructQryF", 0) __> {
134+
// CHECK: bb0(%0 : $*LibraryStruct):
135+
// CHECK: } // end sil function '$s4Test44returnsResulfOfInlinableReturnsLibraryStructQryF'
136+
@available(SwiftStdlib 5.5, *)
137+
public func returnsResulfOfInlinableReturnsLibraryStruct() -> some P {
138+
return inlinableReturnsLibraryStruct()
139+
}

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)