Skip to content

Commit 5db9e4d

Browse files
committed
AST: Factor out LocalArchetypeRequirementCollector from SIL
1 parent 1f621ac commit 5db9e4d

File tree

3 files changed

+330
-0
lines changed

3 files changed

+330
-0
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//===--- LocalArchetypeRequirementCollector.h -------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file has utility code for extending a generic signature with opened
14+
// existentials and shape classes.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_AST_LOCAL_ARCHETYPE_REQUIREMENT_COLLECTOR_H
19+
#define SWIFT_AST_LOCAL_ARCHETYPE_REQUIREMENT_COLLECTOR_H
20+
21+
#include "swift/AST/ASTContext.h"
22+
#include "swift/AST/GenericSignature.h"
23+
#include "swift/AST/Requirement.h"
24+
#include "swift/AST/Types.h"
25+
26+
namespace swift {
27+
28+
struct LocalArchetypeRequirementCollector {
29+
const ASTContext &Context;
30+
GenericSignature OuterSig;
31+
unsigned Depth;
32+
33+
/// The lists of new parameters and requirements to add to the signature.
34+
SmallVector<GenericTypeParamType *, 2> Params;
35+
SmallVector<Requirement, 2> Requirements;
36+
37+
LocalArchetypeRequirementCollector(const ASTContext &ctx, GenericSignature sig);
38+
39+
void addOpenedExistential(Type constraint);
40+
void addOpenedElement(CanGenericTypeParamType shapeClass);
41+
42+
GenericTypeParamType *addParameter();
43+
};
44+
45+
struct MapLocalArchetypesOutOfContext {
46+
GenericSignature baseGenericSig;
47+
ArrayRef<GenericEnvironment *> capturedEnvs;
48+
49+
MapLocalArchetypesOutOfContext(GenericSignature baseGenericSig,
50+
ArrayRef<GenericEnvironment *> capturedEnvs)
51+
: baseGenericSig(baseGenericSig), capturedEnvs(capturedEnvs) {}
52+
53+
Type operator()(SubstitutableType *type) const;
54+
};
55+
56+
struct MapIntoLocalArchetypeContext {
57+
GenericEnvironment *baseGenericEnv;
58+
ArrayRef<GenericEnvironment *> capturedEnvs;
59+
60+
MapIntoLocalArchetypeContext(GenericEnvironment *baseGenericEnv,
61+
ArrayRef<GenericEnvironment *> capturedEnvs)
62+
: baseGenericEnv(baseGenericEnv), capturedEnvs(capturedEnvs) {}
63+
64+
Type operator()(SubstitutableType *type) const;
65+
};
66+
67+
GenericSignature buildGenericSignatureWithCapturedEnvironments(
68+
ASTContext &ctx,
69+
GenericSignature sig,
70+
ArrayRef<GenericEnvironment *> capturedEnvs);
71+
72+
SubstitutionMap buildSubstitutionMapWithCapturedEnvironments(
73+
SubstitutionMap baseSubMap,
74+
GenericSignature genericSigWithCaptures,
75+
ArrayRef<GenericEnvironment *> capturedEnvs);
76+
77+
}
78+
79+
#endif // SWIFT_AST_LOCAL_ARCHETYPE_REQUIREMENT_COLLECTOR_H

lib/AST/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ add_swift_host_library(swiftAST STATIC
6161
IndexSubset.cpp
6262
InlinableText.cpp
6363
LayoutConstraint.cpp
64+
LocalArchetypeRequirementCollector.cpp
6465
Module.cpp
6566
ModuleDependencies.cpp
6667
ModuleLoader.cpp
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
//===--- LocalArchetypeRequirementCollector.cpp ---------------------------===//1
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file implements the LocalArchetypeRequirementCollector class.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "swift/AST/LocalArchetypeRequirementCollector.h"
18+
#include "swift/AST/ASTContext.h"
19+
#include "swift/AST/GenericEnvironment.h"
20+
#include "swift/AST/GenericSignature.h"
21+
#include "swift/AST/Requirement.h"
22+
#include "swift/AST/Types.h"
23+
24+
using namespace swift;
25+
26+
LocalArchetypeRequirementCollector::LocalArchetypeRequirementCollector(
27+
const ASTContext &ctx, GenericSignature sig)
28+
: Context(ctx), OuterSig(sig), Depth(sig.getNextDepth()) {}
29+
30+
void LocalArchetypeRequirementCollector::addOpenedExistential(Type constraint) {
31+
assert(constraint->isConstraintType() ||
32+
constraint->getClassOrBoundGenericClass());
33+
assert(OuterSig || !constraint->hasTypeParameter() &&
34+
"Interface type here requires a parent signature");
35+
36+
auto param = addParameter();
37+
38+
Requirements.emplace_back(RequirementKind::Conformance, param, constraint);
39+
40+
++Depth;
41+
}
42+
43+
void LocalArchetypeRequirementCollector::addOpenedElement(
44+
CanGenericTypeParamType shapeClass) {
45+
46+
size_t startingIndex = Params.size();
47+
48+
/// Add a parameter for each of the opened elements in this shape class.
49+
SmallVector<GenericTypeParamType *, 2> packParams;
50+
for (auto paramType : OuterSig.getGenericParams()) {
51+
if (paramType->isParameterPack() &&
52+
OuterSig->haveSameShape(paramType, shapeClass)) {
53+
packParams.push_back(paramType);
54+
addParameter();
55+
}
56+
}
57+
58+
assert(!packParams.empty());
59+
60+
// Clone the element requirements.
61+
62+
// Helper function: replace references to type parameter packs
63+
// with one of the opened element type parameters we just created for this
64+
// shape class.
65+
auto rewriteElementType = [=](Type type) {
66+
return type.transformTypeParameterPacks(
67+
[&](SubstitutableType *t) -> std::optional<Type> {
68+
auto *paramType = cast<GenericTypeParamType>(t);
69+
for (unsigned packElementIndex : indices(packParams)) {
70+
if (paramType == packParams[packElementIndex])
71+
return Params[startingIndex + packElementIndex];
72+
}
73+
74+
return std::nullopt;
75+
});
76+
};
77+
78+
// Clone the pack requirements that apply to this shape class.
79+
for (auto req : OuterSig.getRequirements()) {
80+
switch (req.getKind()) {
81+
case RequirementKind::SameShape:
82+
// These never involve element types.
83+
break;
84+
case RequirementKind::Conformance:
85+
case RequirementKind::Superclass:
86+
case RequirementKind::SameType: {
87+
auto substFirstType = rewriteElementType(req.getFirstType());
88+
auto substSecondType = rewriteElementType(req.getSecondType());
89+
if (!substFirstType->isEqual(req.getFirstType()) ||
90+
!substSecondType->isEqual(req.getSecondType())) {
91+
Requirements.emplace_back(req.getKind(), substFirstType, substSecondType);
92+
}
93+
break;
94+
}
95+
case RequirementKind::Layout: {
96+
auto substFirstType = rewriteElementType(req.getFirstType());
97+
if (!substFirstType->isEqual(req.getFirstType())) {
98+
Requirements.emplace_back(req.getKind(), substFirstType,
99+
req.getLayoutConstraint());
100+
}
101+
break;
102+
}
103+
}
104+
}
105+
106+
++Depth;
107+
}
108+
109+
GenericTypeParamType *LocalArchetypeRequirementCollector::addParameter() {
110+
unsigned index = 0;
111+
if (!Params.empty() &&
112+
Params.back()->getDepth() == Depth) {
113+
index = Params.back()->getIndex() + 1;
114+
}
115+
116+
auto *param = GenericTypeParamType::get(/*pack*/ false, Depth,
117+
index, Context);
118+
Params.push_back(param);
119+
return param;
120+
}
121+
122+
GenericSignature swift::buildGenericSignatureWithCapturedEnvironments(
123+
ASTContext &ctx,
124+
GenericSignature sig,
125+
ArrayRef<GenericEnvironment *> capturedEnvs) {
126+
// Add new generic parameters to replace the local archetypes.
127+
LocalArchetypeRequirementCollector collector(ctx, sig);
128+
129+
for (auto *genericEnv : capturedEnvs) {
130+
switch (genericEnv->getKind()) {
131+
case GenericEnvironment::Kind::Primary:
132+
case GenericEnvironment::Kind::Opaque:
133+
break;
134+
135+
case GenericEnvironment::Kind::OpenedExistential: {
136+
auto constraint = genericEnv->getOpenedExistentialType();
137+
if (auto existential = constraint->getAs<ExistentialType>())
138+
constraint = existential->getConstraintType();
139+
collector.addOpenedExistential(constraint);
140+
continue;
141+
}
142+
case GenericEnvironment::Kind::OpenedElement: {
143+
collector.addOpenedElement(
144+
genericEnv->getOpenedElementShapeClass());
145+
continue;
146+
}
147+
}
148+
149+
llvm_unreachable("Cannot happen");
150+
}
151+
152+
return buildGenericSignature(ctx,
153+
collector.OuterSig,
154+
collector.Params,
155+
collector.Requirements,
156+
/*allowInverses=*/false);
157+
}
158+
159+
Type MapLocalArchetypesOutOfContext::operator()(SubstitutableType *type) const {
160+
auto *archetypeTy = cast<ArchetypeType>(type);
161+
162+
// Primary archetypes just map out of context.
163+
if (isa<PrimaryArchetypeType>(archetypeTy) ||
164+
isa<PackArchetypeType>(archetypeTy)) {
165+
return archetypeTy->getInterfaceType();
166+
}
167+
168+
assert(isa<LocalArchetypeType>(archetypeTy));
169+
170+
// Handle dependent member types recursively in the usual way.
171+
if (!archetypeTy->isRoot())
172+
return Type();
173+
174+
// Root local archetypes change depth.
175+
auto *genericEnv = archetypeTy->getGenericEnvironment();
176+
auto rootParam = archetypeTy->getInterfaceType()
177+
->castTo<GenericTypeParamType>();
178+
assert(!rootParam->isParameterPack());
179+
assert(rootParam->getDepth() == genericEnv->getGenericSignature()->getMaxDepth());
180+
181+
// The new depth is determined by counting how many captured environments
182+
// precede this one.
183+
unsigned depth = baseGenericSig.getNextDepth();
184+
for (auto *capturedEnv : capturedEnvs) {
185+
if (capturedEnv == genericEnv) {
186+
return GenericTypeParamType::get(/*isParameterPack=*/false,
187+
depth, rootParam->getIndex(),
188+
rootParam->getASTContext());
189+
}
190+
191+
++depth;
192+
}
193+
194+
llvm_unreachable("Fell off the end");
195+
}
196+
197+
static Type mapIntoLocalContext(GenericTypeParamType *param, unsigned baseDepth,
198+
ArrayRef<GenericEnvironment *> capturedEnvs) {
199+
assert(!param->isParameterPack());
200+
unsigned envIndex = param->getDepth() - baseDepth;
201+
assert(envIndex < capturedEnvs.size());
202+
auto *capturedEnv = capturedEnvs[envIndex];
203+
auto localInterfaceType = capturedEnv->getGenericSignature()
204+
.getInnermostGenericParams()[param->getIndex()];
205+
assert(localInterfaceType->getIndex() == param->getIndex());
206+
return capturedEnvs[envIndex]->mapTypeIntoContext(localInterfaceType);
207+
}
208+
209+
Type MapIntoLocalArchetypeContext::operator()(SubstitutableType *type) const {
210+
unsigned baseDepth = baseGenericEnv->getGenericSignature().getNextDepth();
211+
212+
auto param = cast<GenericTypeParamType>(type);
213+
if (param->getDepth() >= baseDepth)
214+
return mapIntoLocalContext(param, baseDepth, capturedEnvs);
215+
216+
return baseGenericEnv->mapTypeIntoContext(param);
217+
}
218+
219+
/// Given a substitution map for a call to a local function or closure, extend
220+
/// it to include all captured element archetypes; they become primary archetypes
221+
/// inside the body of the function.
222+
SubstitutionMap
223+
swift::buildSubstitutionMapWithCapturedEnvironments(
224+
SubstitutionMap baseSubMap,
225+
GenericSignature genericSigWithCaptures,
226+
ArrayRef<GenericEnvironment *> capturedEnvs) {
227+
228+
if (capturedEnvs.empty()) {
229+
assert((!baseSubMap && !genericSigWithCaptures) ||
230+
baseSubMap.getGenericSignature()->isEqual(genericSigWithCaptures));
231+
return baseSubMap;
232+
}
233+
234+
unsigned baseDepth = genericSigWithCaptures.getNextDepth() - capturedEnvs.size();
235+
236+
return SubstitutionMap::get(
237+
genericSigWithCaptures,
238+
[&](SubstitutableType *type) -> Type {
239+
auto param = cast<GenericTypeParamType>(type);
240+
if (param->getDepth() >= baseDepth)
241+
return mapIntoLocalContext(param, baseDepth, capturedEnvs);
242+
return Type(type).subst(baseSubMap);
243+
},
244+
[&](CanType origType, Type substType,
245+
ProtocolDecl *proto) -> ProtocolConformanceRef {
246+
if (origType->getRootGenericParam()->getDepth() >= baseDepth)
247+
return ProtocolConformanceRef(proto);
248+
return baseSubMap.lookupConformance(origType, proto);
249+
});
250+
}

0 commit comments

Comments
 (0)