Skip to content

Commit 5dadfa8

Browse files
authored
Merge pull request #8707 from DougGregor/gsb-delayed-reqs
[GSB] Basic infrastructure for delaying and reprocessing requirements
2 parents 3263d0c + 0f0a590 commit 5dadfa8

File tree

6 files changed

+438
-181
lines changed

6 files changed

+438
-181
lines changed

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 119 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ class GenericSignatureBuilder {
8282

8383
class FloatingRequirementSource;
8484

85+
class DelayedRequirement;
86+
8587
/// Describes a specific constraint on a potential archetype.
8688
template<typename T>
8789
struct Constraint {
@@ -178,6 +180,35 @@ class GenericSignatureBuilder {
178180

179181
friend class RequirementSource;
180182

183+
/// The result of introducing a new constraint.
184+
enum class ConstraintResult {
185+
/// The constraint was resolved and the relative potential archetypes
186+
/// have been updated.
187+
Resolved,
188+
189+
/// The constraint was written directly on a concrete type.
190+
Concrete,
191+
192+
/// The constraint conflicted with existing constraints in some way;
193+
/// the generic signature is ill-formed.
194+
Conflicting,
195+
196+
/// The constraint could not be resolved immediately.
197+
Unresolved,
198+
};
199+
200+
/// Enum used to indicate how we should handle a constraint that cannot be
201+
/// processed immediately for some reason.
202+
enum class UnresolvedHandlingKind : char {
203+
/// Generate a new, unresolved constraint and consider the constraint
204+
/// "resolved" at this point.
205+
GenerateConstraints = 0,
206+
207+
/// Do not generate a new constraint; rather, return
208+
/// \c ConstraintResult::Unresolved and let the caller handle it.
209+
ReturnUnresolved = 1,
210+
};
211+
181212
private:
182213
class InferRequirementsWalker;
183214
friend class InferRequirementsWalker;
@@ -193,13 +224,15 @@ class GenericSignatureBuilder {
193224

194225
/// When a particular requirement cannot be resolved due to, e.g., a
195226
/// currently-unresolvable or nested type, this routine should be
196-
/// called to record the unresolved requirement to be reconsidered later.
227+
/// called to cope with the unresolved requirement.
197228
///
198-
/// \returns false, which is used elsewhere to indicate "no failure".
199-
bool recordUnresolvedRequirement(RequirementKind kind,
229+
/// \returns \c ConstraintResult::Resolved or ConstraintResult::Delayed,
230+
/// as appropriate based on \c unresolvedHandling.
231+
ConstraintResult handleUnresolvedRequirement(RequirementKind kind,
200232
UnresolvedType lhs,
201233
RequirementRHS rhs,
202-
FloatingRequirementSource source);
234+
FloatingRequirementSource source,
235+
UnresolvedHandlingKind unresolvedHandling);
203236

204237
/// Retrieve the constraint source conformance for the superclass constraint
205238
/// of the given potential archetype (if present) to the given protocol.
@@ -214,14 +247,15 @@ class GenericSignatureBuilder {
214247

215248
/// \brief Add a new conformance requirement specifying that the given
216249
/// potential archetype conforms to the given protocol.
217-
bool addConformanceRequirement(PotentialArchetype *T,
218-
ProtocolDecl *Proto,
219-
const RequirementSource *Source);
250+
ConstraintResult addConformanceRequirement(PotentialArchetype *T,
251+
ProtocolDecl *Proto,
252+
const RequirementSource *Source);
220253

221-
bool addConformanceRequirement(PotentialArchetype *T,
222-
ProtocolDecl *Proto,
223-
const RequirementSource *Source,
224-
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
254+
ConstraintResult addConformanceRequirement(
255+
PotentialArchetype *T,
256+
ProtocolDecl *Proto,
257+
const RequirementSource *Source,
258+
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
225259

226260
public:
227261
/// \brief Add a new same-type requirement between two fully resolved types
@@ -231,7 +265,7 @@ class GenericSignatureBuilder {
231265
/// incompatible (e.g. \c Foo<Bar<T>> and \c Foo<Baz>), \c diagnoseMismatch is
232266
/// called with the two types that don't match (\c Bar<T> and \c Baz for the
233267
/// previous example).
234-
bool
268+
ConstraintResult
235269
addSameTypeRequirementDirect(
236270
ResolvedType paOrT1, ResolvedType paOrT2,
237271
FloatingRequirementSource Source,
@@ -241,57 +275,67 @@ class GenericSignatureBuilder {
241275
/// (output of GenericSignatureBuilder::resolve).
242276
///
243277
/// The two types must not be incompatible concrete types.
244-
bool addSameTypeRequirementDirect(ResolvedType paOrT1, ResolvedType paOrT2,
245-
FloatingRequirementSource Source);
278+
ConstraintResult addSameTypeRequirementDirect(
279+
ResolvedType paOrT1,
280+
ResolvedType paOrT2,
281+
FloatingRequirementSource Source);
246282

247283
/// \brief Add a new same-type requirement between two unresolved types.
248284
///
249285
/// The types are resolved with \c GenericSignatureBuilder::resolve, and must
250286
/// not be incompatible concrete types.
251-
bool addSameTypeRequirement(UnresolvedType paOrT1, UnresolvedType paOrT2,
252-
FloatingRequirementSource Source);
287+
ConstraintResult addSameTypeRequirement(
288+
UnresolvedType paOrT1,
289+
UnresolvedType paOrT2,
290+
FloatingRequirementSource Source,
291+
UnresolvedHandlingKind unresolvedHandling);
253292

254293
/// \brief Add a new same-type requirement between two unresolved types.
255294
///
256295
/// The types are resolved with \c GenericSignatureBuilder::resolve. \c
257296
/// diagnoseMismatch is called if the two types refer to incompatible concrete
258297
/// types.
259-
bool
298+
ConstraintResult
260299
addSameTypeRequirement(UnresolvedType paOrT1, UnresolvedType paOrT2,
261300
FloatingRequirementSource Source,
301+
UnresolvedHandlingKind unresolvedHandling,
262302
llvm::function_ref<void(Type, Type)> diagnoseMismatch);
263303

264304
/// Update the superclass for the equivalence class of \c T.
265305
///
266-
/// This assumes that the constraint has already been recorded
267-
bool updateSuperclass(PotentialArchetype *T,
306+
/// This assumes that the constraint has already been recorded.
307+
void updateSuperclass(PotentialArchetype *T,
268308
Type superclass,
269309
const RequirementSource *source);
270310

271311
private:
272312
/// \brief Add a new superclass requirement specifying that the given
273313
/// potential archetype has the given type as an ancestor.
274-
bool addSuperclassRequirementDirect(PotentialArchetype *T,
275-
Type Superclass,
276-
const RequirementSource *Source);
314+
ConstraintResult addSuperclassRequirementDirect(
315+
PotentialArchetype *T,
316+
Type Superclass,
317+
const RequirementSource *Source);
277318

278319
/// \brief Add a new type requirement specifying that the given
279320
/// type conforms-to or is a superclass of the second type.
280-
bool addTypeRequirement(UnresolvedType subject,
321+
ConstraintResult addTypeRequirement(
322+
UnresolvedType subject,
281323
UnresolvedType constraint,
282324
FloatingRequirementSource source,
325+
UnresolvedHandlingKind unresolvedHandling,
283326
llvm::SmallPtrSetImpl<ProtocolDecl *> *visited
284327
= nullptr);
285328

286329
/// \brief Add a new conformance requirement specifying that the given
287330
/// potential archetypes are equivalent.
288-
bool addSameTypeRequirementBetweenArchetypes(PotentialArchetype *T1,
331+
ConstraintResult addSameTypeRequirementBetweenArchetypes(
332+
PotentialArchetype *T1,
289333
PotentialArchetype *T2,
290334
const RequirementSource *Source);
291335

292336
/// \brief Add a new conformance requirement specifying that the given
293337
/// potential archetype is bound to a concrete type.
294-
bool addSameTypeRequirementToConcrete(PotentialArchetype *T,
338+
ConstraintResult addSameTypeRequirementToConcrete(PotentialArchetype *T,
295339
Type Concrete,
296340
const RequirementSource *Source);
297341

@@ -300,26 +344,30 @@ class GenericSignatureBuilder {
300344
///
301345
/// \param diagnoseMismatch Callback invoked when the types in the same-type
302346
/// requirement mismatch.
303-
bool addSameTypeRequirementBetweenConcrete(
347+
ConstraintResult addSameTypeRequirementBetweenConcrete(
304348
Type T1, Type T2, FloatingRequirementSource Source,
305349
llvm::function_ref<void(Type, Type)> diagnoseMismatch);
306350

307351
/// \brief Add a new layout requirement directly on the potential archetype.
308352
///
309353
/// \returns true if this requirement makes the set of requirements
310354
/// inconsistent, in which case a diagnostic will have been issued.
311-
bool addLayoutRequirementDirect(PotentialArchetype *PAT,
312-
LayoutConstraint Layout,
313-
const RequirementSource *Source);
355+
ConstraintResult addLayoutRequirementDirect(PotentialArchetype *PAT,
356+
LayoutConstraint Layout,
357+
const RequirementSource *Source);
314358

315359
/// Add a new layout requirement to the subject.
316-
bool addLayoutRequirement(UnresolvedType subject,
317-
LayoutConstraint layout,
318-
FloatingRequirementSource source);
360+
ConstraintResult addLayoutRequirement(
361+
UnresolvedType subject,
362+
LayoutConstraint layout,
363+
FloatingRequirementSource source,
364+
UnresolvedHandlingKind unresolvedHandling);
319365

320366
/// Add the requirements placed on the given type parameter
321367
/// to the given potential archetype.
322-
bool addInheritedRequirements(TypeDecl *decl, PotentialArchetype *pa,
368+
ConstraintResult addInheritedRequirements(
369+
TypeDecl *decl,
370+
PotentialArchetype *pa,
323371
const RequirementSource *parentSource,
324372
llvm::SmallPtrSetImpl<ProtocolDecl *> &visited);
325373

@@ -379,15 +427,15 @@ class GenericSignatureBuilder {
379427
///
380428
/// \returns true if this requirement makes the set of requirements
381429
/// inconsistent, in which case a diagnostic will have been issued.
382-
bool addRequirement(const RequirementRepr *req);
430+
ConstraintResult addRequirement(const RequirementRepr *req);
383431

384432
/// \brief Add a new requirement.
385433
///
386434
/// \returns true if this requirement makes the set of requirements
387435
/// inconsistent, in which case a diagnostic will have been issued.
388-
bool addRequirement(const RequirementRepr *Req,
389-
FloatingRequirementSource source,
390-
const SubstitutionMap *subMap);
436+
ConstraintResult addRequirement(const RequirementRepr *Req,
437+
FloatingRequirementSource source,
438+
const SubstitutionMap *subMap);
391439

392440
/// \brief Add an already-checked requirement.
393441
///
@@ -396,12 +444,15 @@ class GenericSignatureBuilder {
396444
///
397445
/// \returns true if this requirement makes the set of requirements
398446
/// inconsistent, in which case a diagnostic will have been issued.
399-
bool addRequirement(const Requirement &req, FloatingRequirementSource source,
400-
const SubstitutionMap *subMap = nullptr);
401-
402-
bool addRequirement(const Requirement &req, FloatingRequirementSource source,
403-
const SubstitutionMap *subMap,
404-
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
447+
ConstraintResult addRequirement(const Requirement &req,
448+
FloatingRequirementSource source,
449+
const SubstitutionMap *subMap = nullptr);
450+
451+
ConstraintResult addRequirement(
452+
const Requirement &req,
453+
FloatingRequirementSource source,
454+
const SubstitutionMap *subMap,
455+
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
405456

406457
/// \brief Add all of a generic signature's parameters and requirements.
407458
void addGenericSignature(GenericSignature *sig);
@@ -454,6 +505,9 @@ class GenericSignatureBuilder {
454505
ArrayRef<GenericTypeParamType *> genericParams);
455506

456507
private:
508+
/// Process any delayed requirements that can be handled now.
509+
void processDelayedRequirements();
510+
457511
/// Describes the relationship between a given constraint and
458512
/// the canonical constraint of the equivalence class.
459513
enum class ConstraintRelation {
@@ -1519,6 +1573,28 @@ class GenericSignatureBuilder::PotentialArchetype {
15191573
friend class GenericSignatureBuilder;
15201574
};
15211575

1576+
/// Describes a requirement whose processing has been delayed for some reason.
1577+
class GenericSignatureBuilder::DelayedRequirement {
1578+
public:
1579+
RequirementKind kind;
1580+
UnresolvedType lhs;
1581+
RequirementRHS rhs;
1582+
FloatingRequirementSource source;
1583+
};
1584+
1585+
/// Whether the given constraint result signals an error.
1586+
inline bool isErrorResult(GenericSignatureBuilder::ConstraintResult result) {
1587+
switch (result) {
1588+
case GenericSignatureBuilder::ConstraintResult::Concrete:
1589+
case GenericSignatureBuilder::ConstraintResult::Conflicting:
1590+
return true;
1591+
1592+
case GenericSignatureBuilder::ConstraintResult::Resolved:
1593+
case GenericSignatureBuilder::ConstraintResult::Unresolved:
1594+
return false;
1595+
}
1596+
}
1597+
15221598
} // end namespace swift
15231599

15241600
#endif

lib/AST/ASTContext.cpp

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,9 +1277,50 @@ GenericSignatureBuilder *ASTContext::getOrCreateGenericSignatureBuilder(
12771277
llvm::errs() << "Original generic signature : ";
12781278
sig->print(llvm::errs());
12791279
llvm::errs() << "\nReprocessed generic signature: ";
1280-
builder->getGenericSignature()->getCanonicalSignature()
1281-
->print(llvm::errs());
1280+
auto reprocessedSig =
1281+
builder->getGenericSignature()->getCanonicalSignature();
1282+
1283+
reprocessedSig->print(llvm::errs());
12821284
llvm::errs() << "\n";
1285+
1286+
if (sig->getGenericParams().size() ==
1287+
reprocessedSig->getGenericParams().size() &&
1288+
sig->getRequirements().size() ==
1289+
reprocessedSig->getRequirements().size()) {
1290+
for (unsigned i : indices(sig->getRequirements())) {
1291+
auto sigReq = sig->getRequirements()[i];
1292+
auto reprocessedReq = reprocessedSig->getRequirements()[i];
1293+
if (sigReq.getKind() != reprocessedReq.getKind()) {
1294+
llvm::errs() << "Requirement mismatch:\n";
1295+
llvm::errs() << " Original: ";
1296+
sigReq.print(llvm::errs(), PrintOptions());
1297+
llvm::errs() << "\n Reprocessed: ";
1298+
reprocessedReq.print(llvm::errs(), PrintOptions());
1299+
llvm::errs() << "\n";
1300+
break;
1301+
}
1302+
1303+
if (!sigReq.getFirstType()->isEqual(reprocessedReq.getFirstType())) {
1304+
llvm::errs() << "First type mismatch, original is:\n";
1305+
sigReq.getFirstType().dump(llvm::errs());
1306+
llvm::errs() << "Reprocessed:\n";
1307+
reprocessedReq.getFirstType().dump(llvm::errs());
1308+
llvm::errs() << "\n";
1309+
break;
1310+
}
1311+
1312+
if (sigReq.getKind() == RequirementKind::SameType &&
1313+
!sigReq.getSecondType()->isEqual(reprocessedReq.getSecondType())) {
1314+
llvm::errs() << "Second type mismatch, original is:\n";
1315+
sigReq.getSecondType().dump(llvm::errs());
1316+
llvm::errs() << "Reprocessed:\n";
1317+
reprocessedReq.getSecondType().dump(llvm::errs());
1318+
llvm::errs() << "\n";
1319+
break;
1320+
}
1321+
}
1322+
}
1323+
12831324
llvm_unreachable("idempotency problem with a generic signature");
12841325
}
12851326
#endif

0 commit comments

Comments
 (0)