Skip to content

Commit b73143a

Browse files
authored
Merge pull request #64578 from rjmccall/in-flight-substitution
Substitute pack expansions by repeatedly substituting the pattern type
2 parents 4e14288 + 251c089 commit b73143a

21 files changed

+1267
-1220
lines changed
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
//===--- InFlightSubstitution.h - In-flight substitution data ---*- 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 the InFlightSubstitution structure, which captures
14+
// all the information about a type substitution that's currently in
15+
// progress. For now, this is meant to be an internal implementation
16+
// detail of the substitution system, and other systems should not use
17+
// it (unless they are part of the extended substitution system, such as
18+
// the SIL type substituter)
19+
//
20+
//===----------------------------------------------------------------------===//
21+
22+
#ifndef SWIFT_AST_INFLIGHTSUBSTITUTION_H
23+
#define SWIFT_AST_INFLIGHTSUBSTITUTION_H
24+
25+
#include "swift/AST/SubstitutionMap.h"
26+
27+
namespace swift {
28+
class SubstitutionMap;
29+
30+
class InFlightSubstitution {
31+
SubstOptions Options;
32+
TypeSubstitutionFn BaselineSubstType;
33+
LookupConformanceFn BaselineLookupConformance;
34+
35+
struct ActivePackExpansion {
36+
bool isSubstExpansion = false;
37+
unsigned expansionIndex = 0;
38+
};
39+
SmallVector<ActivePackExpansion, 4> ActivePackExpansions;
40+
41+
public:
42+
InFlightSubstitution(TypeSubstitutionFn substType,
43+
LookupConformanceFn lookupConformance,
44+
SubstOptions options)
45+
: Options(options),
46+
BaselineSubstType(substType),
47+
BaselineLookupConformance(lookupConformance) {}
48+
49+
InFlightSubstitution(const InFlightSubstitution &) = delete;
50+
InFlightSubstitution &operator=(const InFlightSubstitution &) = delete;
51+
52+
// TODO: when we add PackElementType, we should recognize it during
53+
// substitution and either call different methods on this class or
54+
// pass an extra argument for the pack-expansion depth D. We should
55+
// be able to rely on that to mark a pack-element reference instead
56+
// of checking whether the original type was a pack. Substitution
57+
// should use the D'th entry from the end of ActivePackExpansions to
58+
// guide the element substitution:
59+
// - project the given index of the pack substitution
60+
// - wrap it in a PackElementType if it's a subst expansion
61+
// - the depth of that PackElementType is the number of subst
62+
// expansions between the depth entry and the end of
63+
// ActivePackExpansions
64+
65+
/// Perform primitive substitution on the given type. Returns Type()
66+
/// if the type should not be substituted as a whole.
67+
Type substType(SubstitutableType *origType);
68+
69+
/// Perform primitive conformance lookup on the given type.
70+
ProtocolConformanceRef lookupConformance(CanType dependentType,
71+
Type conformingReplacementType,
72+
ProtocolDecl *conformedProtocol);
73+
74+
/// Given the shape type of a pack expansion, invoke the given callback
75+
/// for each expanded component of it. If the substituted component
76+
/// is an expansion component, the desired shape of that expansion
77+
/// is passed as the argument; otherwise, the argument is Type().
78+
/// In either case, an active expansion is entered on this IFS for
79+
/// the duration of the call to handleComponent, and subsequent
80+
/// pack-element type references will substitute to the corresponding
81+
/// element of the substitution of the pack.
82+
void expandPackExpansionShape(Type origShape,
83+
llvm::function_ref<void(Type substComponentShape)> handleComponent);
84+
85+
/// Call the given function for each expanded component type of the
86+
/// given pack expansion type. The function will be invoked with the
87+
/// active expansion still active.
88+
void expandPackExpansionType(PackExpansionType *origExpansionType,
89+
llvm::function_ref<void(Type substType)> handleComponentType) {
90+
expandPackExpansionShape(origExpansionType->getCountType(),
91+
[&](Type substComponentShape) {
92+
auto origPatternType = origExpansionType->getPatternType();
93+
auto substEltType = origPatternType.subst(*this);
94+
95+
auto substComponentType =
96+
(substComponentShape
97+
? PackExpansionType::get(substEltType, substComponentShape)
98+
: substEltType);
99+
handleComponentType(substComponentType);
100+
});
101+
}
102+
103+
/// Return a list of component types that the pack expansion expands to.
104+
SmallVector<Type, 8>
105+
expandPackExpansionType(PackExpansionType *origExpansionType) {
106+
SmallVector<Type, 8> substComponentTypes;
107+
expandPackExpansionType(origExpansionType, substComponentTypes);
108+
return substComponentTypes;
109+
}
110+
111+
/// Expand the list of component types that the pack expansion expands
112+
/// to into the given array.
113+
void expandPackExpansionType(PackExpansionType *origExpansionType,
114+
SmallVectorImpl<Type> &substComponentTypes) {
115+
expandPackExpansionType(origExpansionType, [&](Type substComponentType) {
116+
substComponentTypes.push_back(substComponentType);
117+
});
118+
}
119+
120+
class OptionsAdjustmentScope {
121+
InFlightSubstitution &IFS;
122+
SubstOptions SavedOptions;
123+
124+
public:
125+
OptionsAdjustmentScope(InFlightSubstitution &IFS, SubstOptions newOptions)
126+
: IFS(IFS), SavedOptions(IFS.Options) {
127+
IFS.Options = newOptions;
128+
}
129+
130+
OptionsAdjustmentScope(const OptionsAdjustmentScope &) = delete;
131+
OptionsAdjustmentScope &operator=(const OptionsAdjustmentScope &) = delete;
132+
133+
~OptionsAdjustmentScope() {
134+
IFS.Options = SavedOptions;
135+
}
136+
};
137+
138+
template <class Fn>
139+
auto withNewOptions(SubstOptions options, Fn &&fn)
140+
-> decltype(std::forward<Fn>(fn)()) {
141+
OptionsAdjustmentScope scope(*this, options);
142+
return std::forward<Fn>(fn)();
143+
}
144+
145+
SubstOptions getOptions() const {
146+
return Options;
147+
}
148+
149+
bool shouldSubstituteOpaqueArchetypes() const {
150+
return Options.contains(SubstFlags::SubstituteOpaqueArchetypes);
151+
}
152+
153+
/// Is the given type invariant to substitution?
154+
bool isInvariant(Type type) const;
155+
};
156+
157+
/// A helper classes that provides stable storage for the query
158+
/// functions against a SubstitutionMap.
159+
struct InFlightSubstitutionViaSubMapHelper {
160+
QuerySubstitutionMap QueryType;
161+
LookUpConformanceInSubstitutionMap QueryConformance;
162+
163+
InFlightSubstitutionViaSubMapHelper(SubstitutionMap subMap)
164+
: QueryType{subMap}, QueryConformance(subMap) {}
165+
};
166+
class InFlightSubstitutionViaSubMap :
167+
private InFlightSubstitutionViaSubMapHelper,
168+
public InFlightSubstitution {
169+
170+
public:
171+
InFlightSubstitutionViaSubMap(SubstitutionMap subMap,
172+
SubstOptions options)
173+
: InFlightSubstitutionViaSubMapHelper(subMap),
174+
InFlightSubstitution(QueryType, QueryConformance, options) {}
175+
};
176+
177+
} // end namespace swift
178+
179+
#endif

include/swift/AST/PackConformance.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ class alignas(1 << DeclAlignInBits) PackConformance final
8888
LookupConformanceFn conformances,
8989
SubstOptions options=None) const;
9090

91+
/// Apply an in-flight substitution to the conformances in this
92+
/// protocol conformance ref.
93+
///
94+
/// This function should generally not be used outside of the
95+
/// substitution subsystem.
96+
ProtocolConformanceRef subst(InFlightSubstitution &IFS) const;
97+
9198
SWIFT_DEBUG_DUMP;
9299
void dump(llvm::raw_ostream &out, unsigned indent = 0) const;
93100
};

include/swift/AST/ProtocolConformance.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,13 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance
309309
LookupConformanceFn conformances,
310310
SubstOptions options=None) const;
311311

312+
/// Substitute the conforming type and produce a ProtocolConformance that
313+
/// applies to the substituted type.
314+
///
315+
/// This function should generally not be used outside of the substitution
316+
/// subsystem.
317+
ProtocolConformance *subst(InFlightSubstitution &IFS) const;
318+
312319
SWIFT_DEBUG_DUMP;
313320
void dump(llvm::raw_ostream &out, unsigned indent = 0) const;
314321
};

include/swift/AST/ProtocolConformanceRef.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ class ProtocolConformanceRef {
164164
LookupConformanceFn conformances,
165165
SubstOptions options=None) const;
166166

167+
/// Apply a substitution to the conforming type.
168+
///
169+
/// This function should generally not be used outside of the substitution
170+
/// subsystem.
171+
ProtocolConformanceRef subst(Type origType,
172+
InFlightSubstitution &IFS) const;
173+
167174
/// Map contextual types to interface types in the conformance.
168175
ProtocolConformanceRef mapConformanceOutOfContext() const;
169176

include/swift/AST/SubstitutionMap.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ class SubstitutionMap {
121121
TypeSubstitutionFn subs,
122122
LookupConformanceFn lookupConformance);
123123

124+
/// Build a substitution map from the substitutions represented by
125+
/// the given in-flight substitution.
126+
///
127+
/// This function should generally only be used by the substitution
128+
/// subsystem.
129+
static SubstitutionMap get(GenericSignature genericSig,
130+
InFlightSubstitution &IFS);
131+
124132
/// Retrieve the generic signature describing the environment in which
125133
/// substitutions occur.
126134
GenericSignature getGenericSignature() const;
@@ -182,6 +190,13 @@ class SubstitutionMap {
182190
LookupConformanceFn conformances,
183191
SubstOptions options=None) const;
184192

193+
/// Apply an in-flight substitution to all replacement types in the map.
194+
/// Does not change keys.
195+
///
196+
/// This should generally not be used outside of the substitution
197+
/// subsystem.
198+
SubstitutionMap subst(InFlightSubstitution &subs) const;
199+
185200
/// Apply type expansion lowering to all types in the substitution map. Opaque
186201
/// archetypes will be lowered to their underlying types if the type expansion
187202
/// context allows.

include/swift/AST/Type.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class ClassDecl;
4343
class CanType;
4444
class EnumDecl;
4545
class GenericSignatureImpl;
46+
class InFlightSubstitution;
4647
class ModuleDecl;
4748
class NominalTypeDecl;
4849
class GenericTypeDecl;
@@ -343,6 +344,12 @@ class Type {
343344
LookupConformanceFn conformances,
344345
SubstOptions options=None) const;
345346

347+
/// Apply an in-flight substitution to this type.
348+
///
349+
/// This should generally not be used outside of the substitution
350+
/// subsystem.
351+
Type subst(InFlightSubstitution &subs) const;
352+
346353
bool isPrivateStdlibType(bool treatNonBuiltinProtocolsAsPublic = true) const;
347354

348355
SWIFT_DEBUG_DUMP;

include/swift/AST/Types.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2449,8 +2449,6 @@ class TupleType final : public TypeBase, public llvm::FoldingSetNode,
24492449

24502450
bool containsPackExpansionType() const;
24512451

2452-
Type flattenPackTypes();
2453-
24542452
private:
24552453
TupleType(ArrayRef<TupleTypeElt> elements, const ASTContext *CanCtx,
24562454
RecursiveTypeProperties properties)
@@ -3520,8 +3518,6 @@ class AnyFunctionType : public TypeBase {
35203518

35213519
static bool containsPackExpansionType(ArrayRef<Param> params);
35223520

3523-
AnyFunctionType *flattenPackTypes();
3524-
35253521
static void printParams(ArrayRef<Param> Params, raw_ostream &OS,
35263522
const PrintOptions &PO = PrintOptions());
35273523
static void printParams(ArrayRef<Param> Params, ASTPrinter &Printer,
@@ -5168,6 +5164,9 @@ class SILFunctionType final
51685164
TypeSubstitutionFn subs,
51695165
LookupConformanceFn conformances,
51705166
TypeExpansionContext context);
5167+
CanSILFunctionType substGenericArgs(SILModule &silModule,
5168+
InFlightSubstitution &IFS,
5169+
TypeExpansionContext context);
51715170
CanSILFunctionType substituteOpaqueArchetypes(Lowering::TypeConverter &TC,
51725171
TypeExpansionContext context);
51735172

@@ -6839,8 +6838,6 @@ class PackType final : public TypeBase, public llvm::FoldingSetNode,
68396838

68406839
bool containsPackExpansionType() const;
68416840

6842-
PackType *flattenPackTypes();
6843-
68446841
CanTypeWrapper<PackType> getReducedShape();
68456842

68466843
public:
@@ -6935,8 +6932,6 @@ class PackExpansionType : public TypeBase, public llvm::FoldingSetNode {
69356932
/// Retrieves the count type of this pack expansion.
69366933
Type getCountType() const { return countType; }
69376934

6938-
PackExpansionType *expand();
6939-
69406935
CanType getReducedShape();
69416936

69426937
public:

include/swift/SIL/SILType.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,10 @@ class SILType {
651651
CanGenericSignature genericSig = CanGenericSignature(),
652652
bool shouldSubstituteOpaqueArchetypes = false) const;
653653

654+
SILType subst(Lowering::TypeConverter &tc,
655+
InFlightSubstitution &IFS,
656+
CanGenericSignature genericSig) const;
657+
654658
SILType subst(Lowering::TypeConverter &tc, SubstitutionMap subs) const;
655659

656660
SILType subst(SILModule &M, SubstitutionMap subs) const;

lib/AST/ASTContext.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3257,6 +3257,12 @@ CanPackExpansionType::get(CanType patternType, CanType countType) {
32573257
}
32583258

32593259
PackExpansionType *PackExpansionType::get(Type patternType, Type countType) {
3260+
assert(!patternType->is<PackExpansionType>());
3261+
assert(!countType->is<PackExpansionType>());
3262+
// FIXME: stop doing this deliberately in PackExpansionMatcher
3263+
//assert(!patternType->is<PackType>());
3264+
//assert(!countType->is<PackType>());
3265+
32603266
auto properties = patternType->getRecursiveProperties();
32613267
properties |= countType->getRecursiveProperties();
32623268

@@ -3272,8 +3278,19 @@ PackExpansionType *PackExpansionType::get(Type patternType, Type countType) {
32723278
.PackExpansionTypes.FindNodeOrInsertPos(id, insertPos))
32733279
return expType;
32743280

3281+
// The canonical pack expansion type uses the canonical shape.
3282+
// For interface types, we'd need a signature to do this properly,
3283+
// but for archetypes we can do it directly.
3284+
bool countIsCanonical = countType->isCanonical();
3285+
if (countIsCanonical) {
3286+
if (auto archetype = dyn_cast<PackArchetypeType>(countType.getPointer())) {
3287+
auto reducedShape = archetype->getReducedShape();
3288+
countIsCanonical = (reducedShape.getPointer() == archetype);
3289+
}
3290+
}
3291+
32753292
const ASTContext *canCtx =
3276-
(patternType->isCanonical() && countType->isCanonical())
3293+
(patternType->isCanonical() && countIsCanonical)
32773294
? &context : nullptr;
32783295
PackExpansionType *expansionType =
32793296
new (context, arena) PackExpansionType(patternType, countType, properties,

0 commit comments

Comments
 (0)