Skip to content

Commit 2172c0a

Browse files
committed
[NFC] Provide a more generator-like interface for traversing orig+subst function parameters
This is necessary because the use patterns in SILGenPoly require walking two orig+subst sequences in parallel, which poses problems for a callback-centric design like the one I addded before. An inversion of control is necessary; this is basically a manual coroutine. But frankly it's a nicer interface than the callback design, too; I switched the implementation of forEachFunctionParam to use the generator just to avoid code duplication, but I might try to remove it and switch all the clients over to the generator. The main problems with the callback design are that (1) I wasn't sure which values clients would want, and the result is that there are a *lot* of parameters and (2) (relatedly) the types of those parameters have to be written out explicitly, and some of them are quite large. The generator code is just much nicer. Maybe I can still give the generator a little unparameterized callback to keep lexical loops simple. I'll need to do this same thing for tuples. One at a time.
1 parent 79cbb2e commit 2172c0a

File tree

2 files changed

+191
-31
lines changed

2 files changed

+191
-31
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
//===--- AbstractionPatternGenerators.h -------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 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 defines "generators" that can be used with an AbstractionPattern
14+
// to do certain kinds of traversal without using callbacks.
15+
// This can be useful when a traversal is required in parallel with
16+
// some other traversal.
17+
//
18+
//===----------------------------------------------------------------------===//
19+
20+
#ifndef SWIFT_SIL_ABSTRACTIONPATTERNGENERATORS_H
21+
#define SWIFT_SIL_ABSTRACTIONPATTERNGENERATORS_H
22+
23+
#include "swift/SIL/AbstractionPattern.h"
24+
25+
namespace swift {
26+
namespace Lowering {
27+
28+
/// A generator for traversing the formal function parameters of a type
29+
/// while properly respecting variadic generics.
30+
class FunctionParamGenerator {
31+
// The steady state of the generator.
32+
33+
/// The abstraction pattern of the entire function type. Set once
34+
/// during construction.
35+
AbstractionPattern origFunctionType;
36+
37+
/// The list of all substituted parameters to traverse. Set once
38+
/// during construction.
39+
AnyFunctionType::CanParamArrayRef allSubstParams;
40+
41+
/// The number of orig parameters to traverse. Set once during
42+
/// construction.
43+
unsigned numOrigParams;
44+
45+
/// The index of the current orig parameter.
46+
/// Incremented during advance().
47+
unsigned origParamIndex = 0;
48+
49+
/// The (start) index of the current subst parameters.
50+
/// Incremented during advance().
51+
unsigned substParamIndex = 0;
52+
53+
/// The number of subst parameters corresponding to the current
54+
/// subst parameter.
55+
unsigned numSubstParamsForOrigParam;
56+
57+
/// Whether the orig function type is opaque, i.e. does not permit us to
58+
/// call getNumFunctionParams() and similar accessors. Set once during
59+
/// construction.
60+
bool origFunctionTypeIsOpaque;
61+
62+
/// Whether the current orig parameter is a pack expansion.
63+
bool origParamIsExpansion;
64+
65+
/// The abstraction pattern of the current orig parameter.
66+
/// If it is a pack expansion, this is the expansion type, not the
67+
/// pattern type.
68+
AbstractionPattern origParamType = AbstractionPattern::getInvalid();
69+
70+
/// Load the informaton for the current orig parameter into the
71+
/// fields above for it.
72+
void loadParameter() {
73+
origParamType = origFunctionType.getFunctionParamType(origParamIndex);
74+
origParamIsExpansion = origParamType.isPackExpansion();
75+
numSubstParamsForOrigParam =
76+
(origParamIsExpansion
77+
? origParamType.getNumPackExpandedComponents()
78+
: 1);
79+
}
80+
81+
public:
82+
FunctionParamGenerator(AbstractionPattern origFunctionType,
83+
AnyFunctionType::CanParamArrayRef substParams,
84+
bool ignoreFinalParam);
85+
86+
/// Is the traversal finished? If so, none of the getters below
87+
/// are allowed to be called.
88+
bool isFinished() const {
89+
return origParamIndex == numOrigParams;
90+
}
91+
92+
/// Advance to the next orig parameter.
93+
void advance() {
94+
assert(!isFinished());
95+
origParamIndex++;
96+
substParamIndex += numSubstParamsForOrigParam;
97+
if (!isFinished()) loadParameter();
98+
}
99+
100+
/// Return the index of the current orig parameter.
101+
unsigned getOrigIndex() const {
102+
assert(!isFinished());
103+
return origParamIndex;
104+
}
105+
106+
/// Return the index of the (first) subst parameter corresponding
107+
/// to the current orig parameter.
108+
unsigned getSubstIndex() const {
109+
assert(!isFinished());
110+
return origParamIndex;
111+
}
112+
113+
/// Return the parameter flags for the current orig parameter.
114+
ParameterTypeFlags getOrigFlags() const {
115+
assert(!isFinished());
116+
return (origFunctionTypeIsOpaque
117+
? allSubstParams[substParamIndex].getParameterFlags()
118+
: origFunctionType.getFunctionParamFlags(origParamIndex));
119+
}
120+
121+
/// Return the type of the current orig parameter.
122+
const AbstractionPattern &getOrigType() const {
123+
assert(!isFinished());
124+
return origParamType;
125+
}
126+
127+
/// Return whether the current orig parameter type is a pack expansion.
128+
bool isPackExpansion() const {
129+
assert(!isFinished());
130+
return origParamIsExpansion;
131+
}
132+
133+
/// Return the substituted parameters corresponding to the current
134+
/// orig parameter type. If the current orig parameter is not a
135+
/// pack expansion, this will have exactly one element.
136+
AnyFunctionType::CanParamArrayRef getSubstParams() const {
137+
assert(!isFinished());
138+
return allSubstParams.slice(substParamIndex, numSubstParamsForOrigParam);
139+
}
140+
141+
/// Call this to finalize the traversal and assert that it was done
142+
/// properly.
143+
void finish() {
144+
assert(isFinished() && "didn't finish the traversal");
145+
assert(substParamIndex == allSubstParams.size() &&
146+
"didn't exhaust subst parameters; possible missing subs on "
147+
"orig function type");
148+
}
149+
};
150+
151+
} // end namespace Lowering
152+
} // end namespace swift
153+
154+
#endif

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "swift/AST/TypeCheckRequests.h"
2727
#include "swift/AST/CanTypeVisitor.h"
2828
#include "swift/SIL/TypeLowering.h"
29+
#include "swift/SIL/AbstractionPatternGenerators.h"
2930
#include "clang/AST/ASTContext.h"
3031
#include "clang/AST/Attr.h"
3132
#include "clang/AST/DeclCXX.h"
@@ -1215,42 +1216,47 @@ forEachFunctionParam(AnyFunctionType::CanParamArrayRef substParams,
12151216
AbstractionPattern origExpansionType,
12161217
AnyFunctionType::CanParamArrayRef substParams)>
12171218
handleExpansion) const {
1218-
// Honor ignoreFinalParam for the substituted parameters on all paths.
1219-
if (ignoreFinalParam) substParams = substParams.drop_back();
1220-
1221-
// If we don't have a function type, use the substituted type.
1222-
if (isTypeParameterOrOpaqueArchetype() ||
1223-
getKind() == Kind::OpaqueFunction ||
1224-
getKind() == Kind::OpaqueDerivativeFunction) {
1225-
for (auto substParamIndex : indices(substParams)) {
1226-
handleScalar(substParamIndex, substParamIndex,
1227-
substParams[substParamIndex].getParameterFlags(),
1228-
AbstractionPattern::getOpaque(),
1229-
substParams[substParamIndex]);
1219+
FunctionParamGenerator generator(*this, substParams, ignoreFinalParam);
1220+
1221+
for (; !generator.isFinished(); generator.advance()) {
1222+
if (generator.isPackExpansion()) {
1223+
handleExpansion(generator.getOrigIndex(),
1224+
generator.getSubstIndex(),
1225+
generator.getOrigFlags(),
1226+
generator.getOrigType(),
1227+
generator.getSubstParams());
1228+
} else {
1229+
handleScalar(generator.getOrigIndex(),
1230+
generator.getSubstIndex(),
1231+
generator.getOrigFlags(),
1232+
generator.getOrigType(),
1233+
generator.getSubstParams()[0]);
12301234
}
1231-
return;
12321235
}
1236+
generator.finish();
1237+
}
12331238

1234-
size_t numOrigParams = getNumFunctionParams();
1235-
if (ignoreFinalParam) numOrigParams--;
1239+
FunctionParamGenerator::FunctionParamGenerator(
1240+
AbstractionPattern origFunctionType,
1241+
AnyFunctionType::CanParamArrayRef substParams,
1242+
bool ignoreFinalParam)
1243+
: origFunctionType(origFunctionType), allSubstParams(substParams) {
1244+
origFunctionTypeIsOpaque =
1245+
(origFunctionType.isTypeParameterOrOpaqueArchetype() ||
1246+
origFunctionType.isOpaqueFunctionOrOpaqueDerivativeFunction());
12361247

1237-
size_t substParamIndex = 0;
1238-
for (auto origParamIndex : range(numOrigParams)) {
1239-
auto origParamType = getFunctionParamType(origParamIndex);
1240-
if (origParamType.isPackExpansion()) {
1241-
unsigned numComponents = origParamType.getNumPackExpandedComponents();
1242-
handleExpansion(origParamIndex, substParamIndex,
1243-
getFunctionParamFlags(origParamIndex), origParamType,
1244-
substParams.slice(substParamIndex, numComponents));
1245-
substParamIndex += numComponents;
1246-
} else {
1247-
handleScalar(origParamIndex, substParamIndex,
1248-
getFunctionParamFlags(origParamIndex), origParamType,
1249-
substParams[substParamIndex]);
1250-
substParamIndex++;
1251-
}
1248+
if (origFunctionTypeIsOpaque) {
1249+
numOrigParams = allSubstParams.size();
1250+
} else {
1251+
numOrigParams = origFunctionType.getNumFunctionParams();
1252+
}
1253+
1254+
if (ignoreFinalParam) {
1255+
allSubstParams = allSubstParams.drop_back();
1256+
numOrigParams--;
12521257
}
1253-
assert(substParamIndex == substParams.size());
1258+
1259+
if (!isFinished()) loadParameter();
12541260
}
12551261

12561262
static CanType getOptionalObjectType(CanType type) {

0 commit comments

Comments
 (0)