@@ -107,6 +107,12 @@ STATISTIC(NumDelayedRequirementUnresolved,
107
107
" Delayed requirements left unresolved" );
108
108
STATISTIC (NumConditionalRequirementsAdded,
109
109
" # of conditional requirements added" );
110
+ STATISTIC (NumRewriteMinimizations,
111
+ " # of rewrite system minimizations performed" );
112
+ STATISTIC (NumRewriteRhsSimplified,
113
+ " # of rewrite rule right-hand sides simplified" );
114
+ STATISTIC (NumRewriteRhsSimplifiedToLhs,
115
+ " # of rewrite rule right-hand sides simplified to lhs (and removed)" );
110
116
111
117
namespace {
112
118
@@ -158,6 +164,16 @@ class RewritePath {
158
164
// / types.
159
165
Optional<RewritePath> static createPath (Type type);
160
166
167
+ // / Decompose a type into a path.
168
+ // /
169
+ // / \param path Will be filled in with the components of the path, in
170
+ // / reverse order.
171
+ // /
172
+ // / \returns the generic parameter at the start of the path, or \c None if
173
+ // /
174
+ Optional<GenericParamKey>
175
+ static createPath (Type type, SmallVectorImpl<AssociatedTypeDecl *> &path);
176
+
161
177
// / Compute the longer common prefix between this path and \c other.
162
178
RewritePath commonPath (const RewritePath &other) const ;
163
179
@@ -258,7 +274,10 @@ class RewriteTreeNode {
258
274
// /
259
275
// / \param replacementPath The sequence of associated type declarations
260
276
// / with which a match will be replaced.
261
- void addRewriteRule (RelativeRewritePath matchPath,
277
+ // /
278
+ // / \returns true if a rewrite rule was added, and false if it already
279
+ // / existed.
280
+ bool addRewriteRule (RelativeRewritePath matchPath,
262
281
RewritePath replacementPath);
263
282
264
283
// / Enumerate all of the paths to which the given matched path can be
@@ -293,7 +312,9 @@ class RewriteTreeNode {
293
312
unsigned prefixLength);
294
313
295
314
// / Merge the given rewrite tree into \c other.
296
- void mergeInto (RewriteTreeNode *other);
315
+ // /
316
+ // / \returns true if any rules were created by this merge.
317
+ bool mergeInto (RewriteTreeNode *other);
297
318
298
319
// / An action to perform for the given rule
299
320
class RuleAction {
@@ -386,6 +407,13 @@ struct GenericSignatureBuilder::Implementation {
386
407
DenseMap<const EquivalenceClass *, std::unique_ptr<RewriteTreeNode>>
387
408
RewriteTreeRoots;
388
409
410
+ // / The generation number for the term-rewriting system, which is
411
+ // / increased every time a new rule gets added.
412
+ unsigned RewriteGeneration = 0 ;
413
+
414
+ // / The generation at which the term-rewriting system was last minimized.
415
+ unsigned LastRewriteMinimizedGeneration = 0 ;
416
+
389
417
// / The generation number, which is incremented whenever we successfully
390
418
// / introduce a new constraint.
391
419
unsigned Generation = 0 ;
@@ -396,6 +424,9 @@ struct GenericSignatureBuilder::Implementation {
396
424
// / Whether we are currently processing delayed requirements.
397
425
bool ProcessingDelayedRequirements = false ;
398
426
427
+ // / Whether we are currently minimizing the term-rewriting system.
428
+ bool MinimizingRewriteSystem = false ;
429
+
399
430
// / Whether there were any errors.
400
431
bool HadAnyError = false ;
401
432
@@ -426,6 +457,16 @@ struct GenericSignatureBuilder::Implementation {
426
457
// / creating it if needed.
427
458
RewriteTreeNode *getOrCreateRewriteTreeRoot (
428
459
const EquivalenceClass *equivClass);
460
+
461
+ // / Minimize the rewrite tree by minimizing the right-hand sides and
462
+ // / (TBD) removing redundant rules.
463
+ void minimizeRewriteTree (GenericSignatureBuilder &builder);
464
+
465
+ private:
466
+ // / Minimize the right-hand sides of the rewrite tree, simplifying them
467
+ // / as far as possible and removing any changes that result in trivial
468
+ // / rules.
469
+ void minimizeRewriteTreeRhs (GenericSignatureBuilder &builder);
429
470
};
430
471
431
472
#pragma mark Memory management
@@ -3095,6 +3136,16 @@ RewritePath::RewritePath(Optional<GenericParamKey> base,
3095
3136
3096
3137
Optional<RewritePath> RewritePath::createPath (Type type) {
3097
3138
SmallVector<AssociatedTypeDecl *, 4 > path;
3139
+ if (auto genericParam = createPath (type, path)) {
3140
+ return RewritePath (*genericParam, path, Reverse);
3141
+ }
3142
+
3143
+ return None;
3144
+ }
3145
+
3146
+ Optional<GenericParamKey>
3147
+ RewritePath::createPath (Type type,
3148
+ SmallVectorImpl<AssociatedTypeDecl *> &path) {
3098
3149
while (auto depMemTy = type->getAs <DependentMemberType>()) {
3099
3150
auto assocType = depMemTy->getAssocType ();
3100
3151
if (!assocType) return None;
@@ -3106,7 +3157,7 @@ Optional<RewritePath> RewritePath::createPath(Type type) {
3106
3157
auto genericParam = type->getAs <GenericTypeParamType>();
3107
3158
if (!genericParam) return None;
3108
3159
3109
- return RewritePath ( GenericParamKey (genericParam), path, Reverse );
3160
+ return GenericParamKey (genericParam);
3110
3161
}
3111
3162
3112
3163
RewritePath RewritePath::commonPath (const RewritePath &other) const {
@@ -3219,25 +3270,25 @@ class OrderTreeRewriteNode {
3219
3270
};
3220
3271
}
3221
3272
3222
- void RewriteTreeNode::addRewriteRule (RelativeRewritePath matchPath,
3273
+ bool RewriteTreeNode::addRewriteRule (RelativeRewritePath matchPath,
3223
3274
RewritePath replacementPath) {
3224
3275
// If the match path is empty, we're adding the rewrite rule to this node.
3225
3276
if (matchPath.empty ()) {
3226
3277
// If we don't already have a rewrite rule, add it.
3227
3278
if (!hasRewriteRule ()) {
3228
3279
setRewriteRule (replacementPath);
3229
- return ;
3280
+ return true ;
3230
3281
}
3231
3282
3232
3283
// If we already have this rewrite rule, we're done.
3233
- if (getRewriteRule () == replacementPath) return ;
3284
+ if (getRewriteRule () == replacementPath) return false ;
3234
3285
3235
3286
// Check whether any of the continuation children matches.
3236
3287
auto insertPos = children.begin ();
3237
3288
while (insertPos != children.end () && !(*insertPos)->getMatch ()) {
3238
3289
if ((*insertPos)->hasRewriteRule () &&
3239
3290
(*insertPos)->getRewriteRule () == replacementPath)
3240
- return ;
3291
+ return false ;
3241
3292
3242
3293
++insertPos;
3243
3294
}
@@ -3247,7 +3298,7 @@ void RewriteTreeNode::addRewriteRule(RelativeRewritePath matchPath,
3247
3298
auto newChild = new RewriteTreeNode (nullptr );
3248
3299
newChild->setRewriteRule (replacementPath);
3249
3300
children.insert (insertPos, newChild);
3250
- return ;
3301
+ return true ;
3251
3302
}
3252
3303
3253
3304
// Find (or create) a child node describing the next step in the match.
@@ -3260,7 +3311,7 @@ void RewriteTreeNode::addRewriteRule(RelativeRewritePath matchPath,
3260
3311
}
3261
3312
3262
3313
// Add the rewrite rule to the child.
3263
- (*childPos)->addRewriteRule (matchPath.slice (1 ), replacementPath);
3314
+ return (*childPos)->addRewriteRule (matchPath.slice (1 ), replacementPath);
3264
3315
}
3265
3316
3266
3317
void RewriteTreeNode::enumerateRewritePathsImpl (
@@ -3324,14 +3375,18 @@ RewriteTreeNode::bestRewritePath(GenericParamKey base, RelativeRewritePath path,
3324
3375
return best;
3325
3376
}
3326
3377
3327
- void RewriteTreeNode::mergeInto (RewriteTreeNode *other) {
3378
+ bool RewriteTreeNode::mergeInto (RewriteTreeNode *other) {
3328
3379
// FIXME: A destructive version of this operation would be more efficient,
3329
3380
// since we generally don't care about \c other after doing this.
3330
- (void )enumerateRules ([other](RelativeRewritePath lhs,
3331
- const RewritePath &rhs) {
3332
- other->addRewriteRule (lhs, rhs);
3381
+ bool anyAdded = false ;
3382
+ (void )enumerateRules ([other, &anyAdded](RelativeRewritePath lhs,
3383
+ const RewritePath &rhs) {
3384
+ if (other->addRewriteRule (lhs, rhs))
3385
+ anyAdded = true ;
3333
3386
return RuleAction::none ();
3334
3387
});
3388
+
3389
+ return anyAdded;
3335
3390
}
3336
3391
3337
3392
bool RewriteTreeNode::enumerateRulesRec (
@@ -3436,22 +3491,120 @@ GenericSignatureBuilder::Implementation::getOrCreateRewriteTreeRoot(
3436
3491
return root.get ();
3437
3492
}
3438
3493
3439
- void GenericSignatureBuilder::addSameTypeRewriteRule (
3494
+ void GenericSignatureBuilder::Implementation::minimizeRewriteTree (
3495
+ GenericSignatureBuilder &builder) {
3496
+ // Only perform minimization if the term-rewriting tree has changed.
3497
+ if (LastRewriteMinimizedGeneration == RewriteGeneration
3498
+ || MinimizingRewriteSystem)
3499
+ return ;
3500
+
3501
+ ++NumRewriteMinimizations;
3502
+ llvm::SaveAndRestore<bool > minimizingRewriteSystem (MinimizingRewriteSystem,
3503
+ true );
3504
+ SWIFT_DEFER {
3505
+ LastRewriteMinimizedGeneration = RewriteGeneration;
3506
+ };
3507
+
3508
+ minimizeRewriteTreeRhs (builder);
3509
+ }
3510
+
3511
+ void GenericSignatureBuilder::Implementation::minimizeRewriteTreeRhs (
3512
+ GenericSignatureBuilder &builder) {
3513
+ assert (MinimizingRewriteSystem);
3514
+
3515
+ // Minimize the right-hand sides of each rule in the tree.
3516
+ for (auto &equivClass : EquivalenceClasses) {
3517
+ auto root = RewriteTreeRoots.find (&equivClass);
3518
+ if (root == RewriteTreeRoots.end ()) continue ;
3519
+
3520
+ // Stores the anchor base and path, when we've computed it.
3521
+ Optional<RewritePath> anchorPath;
3522
+
3523
+ // Make sure that anchorBase/anchorPath are populated.
3524
+ auto populateAnchor = [&] {
3525
+ if (anchorPath) return false ;
3526
+
3527
+ // Get the pieces of the path for the anchor.
3528
+ anchorPath = RewritePath::createPath (equivClass.getAnchor (builder, { }));
3529
+ if (!anchorPath) return true ;
3530
+
3531
+ return false ;
3532
+ };
3533
+
3534
+ ASTContext &ctx = builder.getASTContext ();
3535
+ root->second ->enumerateRules ([&](RelativeRewritePath lhs,
3536
+ const RewritePath &rhs) {
3537
+ // Compute the type of the right-hand side.
3538
+ Type rhsType;
3539
+ if (rhs.getBase ()) {
3540
+ rhsType = rhs.formDependentType (ctx);
3541
+ } else {
3542
+ // We need the anchor of this equivalence class.
3543
+ if (populateAnchor ())
3544
+ return RewriteTreeNode::RuleAction::none ();
3545
+
3546
+ // Add the right-hand side to the anchor path we have.
3547
+ SmallVector<AssociatedTypeDecl *, 4 > absoluteRhsPath;
3548
+ absoluteRhsPath.append (anchorPath->getPath ().begin (),
3549
+ anchorPath->getPath ().end ());
3550
+ absoluteRhsPath.append (rhs.getPath ().begin (), rhs.getPath ().end ());
3551
+ rhsType = formDependentType (ctx, *anchorPath->getBase (),
3552
+ absoluteRhsPath);
3553
+ }
3554
+
3555
+ // Compute the canonical type for the right-hand side.
3556
+ Type canonicalRhsType = builder.getCanonicalTypeParameter (rhsType);
3557
+
3558
+ // If the canonicalized result is equivalent to the right-hand side we
3559
+ // had, there's nothing to do.
3560
+ if (rhsType->isEqual (canonicalRhsType))
3561
+ return RewriteTreeNode::RuleAction::none ();
3562
+
3563
+ // We have a canonical replacement path. Determine its encoding and
3564
+ // perform the replacement.
3565
+ ++NumRewriteRhsSimplified;
3566
+
3567
+ // Determine replacement path, which might be relative to the anchor.
3568
+ auto canonicalRhsPath = *RewritePath::createPath (canonicalRhsType);
3569
+ populateAnchor ();
3570
+ if (auto prefix = anchorPath->commonPath (canonicalRhsPath)) {
3571
+ unsigned prefixLength = prefix.getPath ().size ();
3572
+ RelativeRewritePath replacementRhsPath =
3573
+ canonicalRhsPath.getPath ().slice (prefixLength);
3574
+
3575
+ // If the left and right-hand sides are equivalent, just remove the
3576
+ // rule.
3577
+ if (lhs == replacementRhsPath) {
3578
+ ++NumRewriteRhsSimplifiedToLhs;
3579
+ return RewriteTreeNode::RuleAction::remove ();
3580
+ }
3581
+
3582
+ RewritePath replacementRhs (None, replacementRhsPath,
3583
+ RewritePath::Forward);
3584
+ return RewriteTreeNode::RuleAction::replace (std::move (replacementRhs));
3585
+ }
3586
+
3587
+ return RewriteTreeNode::RuleAction::replace (canonicalRhsPath);
3588
+ });
3589
+ }
3590
+ }
3591
+
3592
+ bool GenericSignatureBuilder::addSameTypeRewriteRule (
3440
3593
EquivalenceClass *equivClass,
3441
3594
PotentialArchetype *otherPA){
3442
3595
// Simplify both sides in the hope of uncovering a common path.
3443
3596
Type simplifiedType1 = equivClass->getAnchor (*this , { });
3444
- if (!simplifiedType1) return ;
3597
+ if (!simplifiedType1) return false ;
3445
3598
3446
3599
Type simplifiedType2;
3447
3600
if (auto otherEquivClass = otherPA->getEquivalenceClassIfPresent ())
3448
3601
simplifiedType2 = otherEquivClass->getAnchor (*this , { });
3449
3602
else
3450
3603
simplifiedType2 = getCanonicalTypeParameter (otherPA->getDependentType ({ }));
3451
- if (!simplifiedType2) return ;
3604
+ if (!simplifiedType2) return false ;
3452
3605
3453
3606
// We already effectively have this rewrite rule.
3454
- if (simplifiedType1->isEqual (simplifiedType2)) return ;
3607
+ if (simplifiedType1->isEqual (simplifiedType2)) return false ;
3455
3608
3456
3609
auto path1 = *RewritePath::createPath (simplifiedType1);
3457
3610
auto path2 = *RewritePath::createPath (simplifiedType2);
@@ -3476,10 +3629,9 @@ void GenericSignatureBuilder::addSameTypeRewriteRule(
3476
3629
3477
3630
// Add the rewrite rule.
3478
3631
auto root = Impl->getOrCreateRewriteTreeRoot (equivClass);
3479
- root->addRewriteRule (relPath1,
3480
- RewritePath (None, relPath2, RewritePath::Forward));
3481
-
3482
- return ;
3632
+ return root->addRewriteRule (
3633
+ relPath1,
3634
+ RewritePath (None, relPath2, RewritePath::Forward));
3483
3635
}
3484
3636
3485
3637
// Otherwise, form a rewrite rule with absolute paths.
@@ -3499,7 +3651,7 @@ void GenericSignatureBuilder::addSameTypeRewriteRule(
3499
3651
assert (baseEquivClass && " Base cannot be resolved?" );
3500
3652
3501
3653
auto root = Impl->getOrCreateRewriteTreeRoot (baseEquivClass);
3502
- root->addRewriteRule (path1.getPath (), path2);
3654
+ return root->addRewriteRule (path1.getPath (), path2);
3503
3655
}
3504
3656
3505
3657
Type GenericSignatureBuilder::getCanonicalTypeParameter (Type type) {
@@ -4648,7 +4800,8 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
4648
4800
4649
4801
// Add a rewrite rule to map T2 down to the anchor.
4650
4802
auto equivClass = T1->getOrCreateEquivalenceClass (*this );
4651
- addSameTypeRewriteRule (equivClass, T2);
4803
+ if (addSameTypeRewriteRule (equivClass, T2))
4804
+ ++Impl->RewriteGeneration ;
4652
4805
4653
4806
// Merge the equivalence classes.
4654
4807
equivClass->modified (*this );
@@ -4679,7 +4832,8 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
4679
4832
if (auto rewriteRoot2 = Impl->getOrCreateRewriteTreeRoot (equivClass2)) {
4680
4833
if (auto rewriteRoot1 = Impl->getOrCreateRewriteTreeRoot (equivClass)) {
4681
4834
// Merge the second rewrite tree into the first.
4682
- rewriteRoot2->mergeInto (rewriteRoot1);
4835
+ if (rewriteRoot2->mergeInto (rewriteRoot1))
4836
+ ++Impl->RewriteGeneration ;
4683
4837
Impl->RewriteTreeRoots .erase (equivClass2);
4684
4838
} else {
4685
4839
// Take the second rewrite tree and make it the first.
0 commit comments