@@ -113,13 +113,17 @@ STATISTIC(NumRewriteRhsSimplified,
113
113
" # of rewrite rule right-hand sides simplified" );
114
114
STATISTIC (NumRewriteRhsSimplifiedToLhs,
115
115
" # of rewrite rule right-hand sides simplified to lhs (and removed)" );
116
+ STATISTIC (NumRewriteRulesRedundant,
117
+ " # of rewrite rules that are redundant (and removed)" );
116
118
117
119
namespace {
118
120
119
121
// / A purely-relative rewrite path consisting of a (possibly empty)
120
122
// / sequence of associated type references.
121
123
using RelativeRewritePath = ArrayRef<AssociatedTypeDecl *>;
122
124
125
+ class AnchorPathCache ;
126
+
123
127
// / Describes a rewrite path, which contains an optional base (generic
124
128
// / parameter) followed by a sequence of associated type references.
125
129
class RewritePath {
@@ -179,8 +183,10 @@ class RewritePath {
179
183
180
184
// / Form a canonical, dependent type.
181
185
// /
182
- // / This requires that the rewrite path have a base.
183
- CanType formDependentType (ASTContext &ctx) const ;
186
+ // / This requires that either the rewrite path have a base, or the
187
+ // / \c baseEquivClass to be non-null (which substitutes in a base).
188
+ CanType formDependentType (ASTContext &ctx,
189
+ AnchorPathCache *anchorPathCache = nullptr ) const ;
184
190
185
191
// / Compare the given rewrite paths.
186
192
int compare (const RewritePath &other) const ;
@@ -198,6 +204,26 @@ class RewritePath {
198
204
}
199
205
};
200
206
207
+ // / A cache that lazily computes the anchor path for the given equivalence
208
+ // / class.
209
+ class AnchorPathCache {
210
+ GenericSignatureBuilder &builder;
211
+ EquivalenceClass &equivClass;
212
+ Optional<RewritePath> anchorPath;
213
+
214
+ public:
215
+ AnchorPathCache (GenericSignatureBuilder &builder,
216
+ EquivalenceClass &equivClass)
217
+ : builder(builder), equivClass(equivClass) { }
218
+
219
+ Optional<RewritePath> getAnchorPath () {
220
+ if (anchorPath) return anchorPath;
221
+
222
+ anchorPath = RewritePath::createPath (equivClass.getAnchor (builder, { }));
223
+ return anchorPath;
224
+ }
225
+ };
226
+
201
227
// / A node within the prefix tree that is used to match associated type
202
228
// / references.
203
229
class RewriteTreeNode {
@@ -262,11 +288,17 @@ class RewriteTreeNode {
262
288
}
263
289
264
290
// / Retrieve the path to which this node will be rewritten.
265
- const RewritePath &getRewriteRule () const {
291
+ const RewritePath &getRewriteRule () const & {
266
292
assert (hasRewriteRule ());
267
293
return rewrite;
268
294
}
269
295
296
+ // / Retrieve the path to which this node will be rewritten.
297
+ RewritePath &&getRewriteRule() && {
298
+ assert (hasRewriteRule ());
299
+ return std::move (rewrite);
300
+ }
301
+
270
302
// / Add a new rewrite rule to this tree node.
271
303
// /
272
304
// / \param matchPath The path of associated type declarations that must
@@ -359,9 +391,10 @@ class RewriteTreeNode {
359
391
// / right-hand sides of each rule.
360
392
// /
361
393
// / \returns true if the action function returned \c Stop at any point.
362
- bool enumerateRules (llvm::function_ref<EnumerateCallback> fn) {
394
+ bool enumerateRules (llvm::function_ref<EnumerateCallback> fn,
395
+ bool temporarilyDisableVisitedRule = false ) {
363
396
SmallVector<AssociatedTypeDecl *, 4 > lhs;
364
- return enumerateRulesRec (fn, lhs);
397
+ return enumerateRulesRec (fn, temporarilyDisableVisitedRule, lhs);
365
398
}
366
399
367
400
LLVM_ATTRIBUTE_DEPRECATED (void dump () const LLVM_ATTRIBUTE_USED,
@@ -376,6 +409,7 @@ class RewriteTreeNode {
376
409
// /
377
410
// / \returns true if the action function returned \c Stop at any point.
378
411
bool enumerateRulesRec (llvm::function_ref<EnumerateCallback> &fn,
412
+ bool temporarilyDisableVisitedRule,
379
413
llvm::SmallVectorImpl<AssociatedTypeDecl *> &lhs);
380
414
};
381
415
}
@@ -459,14 +493,19 @@ struct GenericSignatureBuilder::Implementation {
459
493
const EquivalenceClass *equivClass);
460
494
461
495
// / Minimize the rewrite tree by minimizing the right-hand sides and
462
- // / (TBD) removing redundant rules.
496
+ // / removing redundant rules.
463
497
void minimizeRewriteTree (GenericSignatureBuilder &builder);
464
498
465
499
private:
466
500
// / Minimize the right-hand sides of the rewrite tree, simplifying them
467
501
// / as far as possible and removing any changes that result in trivial
468
502
// / rules.
469
503
void minimizeRewriteTreeRhs (GenericSignatureBuilder &builder);
504
+
505
+ // / Minimize the right-hand sides of the rewrite tree, simplifying them
506
+ // / as far as possible and removing any changes that result in trivial
507
+ // / rules.
508
+ void removeRewriteTreeRedundancies (GenericSignatureBuilder &builder);
470
509
};
471
510
472
511
#pragma mark Memory management
@@ -2250,6 +2289,9 @@ Type EquivalenceClass::getAnchor(
2250
2289
return substAnchor ();
2251
2290
}
2252
2291
2292
+ // Always work with a minimized term-rewriting system.
2293
+ builder.Impl ->minimizeRewriteTree (builder);
2294
+
2253
2295
// Form the anchor.
2254
2296
bool updatedAnchor = false ;
2255
2297
for (auto member : members) {
@@ -3198,9 +3240,24 @@ static Type formDependentType(ASTContext &ctx, GenericParamKey genericParam,
3198
3240
path);
3199
3241
}
3200
3242
3201
- CanType RewritePath::formDependentType (ASTContext &ctx) const {
3202
- assert (getBase ());
3203
- return CanType (::formDependentType (ctx, *getBase (), getPath ()));
3243
+ CanType RewritePath::formDependentType (
3244
+ ASTContext &ctx,
3245
+ AnchorPathCache *anchorPathCache) const {
3246
+ if (auto base = getBase ())
3247
+ return CanType (::formDependentType (ctx, *base, getPath ()));
3248
+
3249
+ assert (anchorPathCache && " Need an anchor path cache" );
3250
+ Optional<RewritePath> anchorPath = anchorPathCache->getAnchorPath ();
3251
+ if (!anchorPath) return CanType ();
3252
+
3253
+ // Add the relative path to the anchor path.
3254
+ SmallVector<AssociatedTypeDecl *, 4 > absolutePath;
3255
+ absolutePath.append (anchorPath->getPath ().begin (),
3256
+ anchorPath->getPath ().end ());
3257
+ absolutePath.append (getPath ().begin (), getPath ().end ());
3258
+ return CanType (::formDependentType (ctx, *anchorPath->getBase (),
3259
+ absolutePath));
3260
+
3204
3261
}
3205
3262
3206
3263
int RewritePath::compare (const RewritePath &other) const {
@@ -3391,6 +3448,7 @@ bool RewriteTreeNode::mergeInto(RewriteTreeNode *other) {
3391
3448
3392
3449
bool RewriteTreeNode::enumerateRulesRec (
3393
3450
llvm::function_ref<EnumerateCallback> &fn,
3451
+ bool temporarilyDisableVisitedRule,
3394
3452
llvm::SmallVectorImpl<AssociatedTypeDecl *> &lhs) {
3395
3453
if (auto assocType = getMatch ())
3396
3454
lhs.push_back (assocType);
@@ -3402,27 +3460,50 @@ bool RewriteTreeNode::enumerateRulesRec(
3402
3460
3403
3461
// If there is a rewrite rule, invoke the callback.
3404
3462
if (hasRewriteRule ()) {
3405
- switch (RuleAction action = fn (lhs, getRewriteRule ())) {
3463
+ // If we're supposed to temporarily disabled the visited rule, do so
3464
+ // now.
3465
+ Optional<RewritePath> rewriteRule;
3466
+ if (temporarilyDisableVisitedRule) {
3467
+ rewriteRule = std::move (*this ).getRewriteRule ();
3468
+ removeRewriteRule ();
3469
+ }
3470
+
3471
+ // Make sure that we put the rewrite rule back in place if we moved it
3472
+ // aside.
3473
+ SWIFT_DEFER {
3474
+ if (temporarilyDisableVisitedRule && rewriteRule)
3475
+ setRewriteRule (*std::move (rewriteRule));
3476
+ };
3477
+
3478
+ switch (auto action =
3479
+ fn (lhs, rewriteRule ? *rewriteRule : getRewriteRule ())) {
3406
3480
case RuleAction::None:
3407
3481
break ;
3408
3482
3409
3483
case RuleAction::Stop:
3410
3484
return true ;
3411
3485
3412
3486
case RuleAction::Remove:
3413
- removeRewriteRule ();
3487
+ if (temporarilyDisableVisitedRule)
3488
+ rewriteRule = None;
3489
+ else
3490
+ removeRewriteRule ();
3414
3491
break ;
3415
3492
3416
3493
case RuleAction::Replace:
3417
- removeRewriteRule ();
3418
- setRewriteRule (action.path );
3494
+ if (temporarilyDisableVisitedRule) {
3495
+ rewriteRule = std::move (action.path );
3496
+ } else {
3497
+ removeRewriteRule ();
3498
+ setRewriteRule (action.path );
3499
+ }
3419
3500
break ;
3420
3501
}
3421
3502
}
3422
3503
3423
3504
// Recurse into the child nodes.
3424
3505
for (auto child : children) {
3425
- if (child->enumerateRulesRec (fn, lhs))
3506
+ if (child->enumerateRulesRec (fn, temporarilyDisableVisitedRule, lhs))
3426
3507
return true ;
3427
3508
}
3428
3509
@@ -3506,6 +3587,7 @@ void GenericSignatureBuilder::Implementation::minimizeRewriteTree(
3506
3587
};
3507
3588
3508
3589
minimizeRewriteTreeRhs (builder);
3590
+ removeRewriteTreeRedundancies (builder);
3509
3591
}
3510
3592
3511
3593
void GenericSignatureBuilder::Implementation::minimizeRewriteTreeRhs (
@@ -3517,40 +3599,14 @@ void GenericSignatureBuilder::Implementation::minimizeRewriteTreeRhs(
3517
3599
auto root = RewriteTreeRoots.find (&equivClass);
3518
3600
if (root == RewriteTreeRoots.end ()) continue ;
3519
3601
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
- };
3602
+ AnchorPathCache anchorPathCache (builder, equivClass);
3533
3603
3534
3604
ASTContext &ctx = builder.getASTContext ();
3535
3605
root->second ->enumerateRules ([&](RelativeRewritePath lhs,
3536
3606
const RewritePath &rhs) {
3537
3607
// 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
- }
3608
+ Type rhsType = rhs.formDependentType (ctx, &anchorPathCache);
3609
+ if (!rhsType) return RewriteTreeNode::RuleAction::none ();
3554
3610
3555
3611
// Compute the canonical type for the right-hand side.
3556
3612
Type canonicalRhsType = builder.getCanonicalTypeParameter (rhsType);
@@ -3566,7 +3622,7 @@ void GenericSignatureBuilder::Implementation::minimizeRewriteTreeRhs(
3566
3622
3567
3623
// Determine replacement path, which might be relative to the anchor.
3568
3624
auto canonicalRhsPath = *RewritePath::createPath (canonicalRhsType);
3569
- populateAnchor ();
3625
+ auto anchorPath = anchorPathCache. getAnchorPath ();
3570
3626
if (auto prefix = anchorPath->commonPath (canonicalRhsPath)) {
3571
3627
unsigned prefixLength = prefix.getPath ().size ();
3572
3628
RelativeRewritePath replacementRhsPath =
@@ -3589,6 +3645,44 @@ void GenericSignatureBuilder::Implementation::minimizeRewriteTreeRhs(
3589
3645
}
3590
3646
}
3591
3647
3648
+ void GenericSignatureBuilder::Implementation::removeRewriteTreeRedundancies (
3649
+ GenericSignatureBuilder &builder) {
3650
+ assert (MinimizingRewriteSystem);
3651
+
3652
+ // Minimize the right-hand sides of each rule in the tree.
3653
+ for (auto &equivClass : EquivalenceClasses) {
3654
+ auto root = RewriteTreeRoots.find (&equivClass);
3655
+ if (root == RewriteTreeRoots.end ()) continue ;
3656
+
3657
+ AnchorPathCache anchorPathCache (builder, equivClass);
3658
+
3659
+ ASTContext &ctx = builder.getASTContext ();
3660
+ root->second ->enumerateRules ([&](RelativeRewritePath lhs,
3661
+ const RewritePath &rhs) {
3662
+ // / Left-hand side type.
3663
+ Type lhsType = RewritePath (None, lhs, RewritePath::Forward)
3664
+ .formDependentType (ctx, &anchorPathCache);
3665
+ if (!lhsType) return RewriteTreeNode::RuleAction::none ();
3666
+
3667
+ // Simplify the left-hand type.
3668
+ Type simplifiedLhsType = builder.getCanonicalTypeParameter (lhsType);
3669
+ if (!simplifiedLhsType) return RewriteTreeNode::RuleAction::none ();
3670
+
3671
+ // Compute the type of the right-hand side.
3672
+ Type rhsType = rhs.formDependentType (ctx, &anchorPathCache);
3673
+ if (!rhsType) return RewriteTreeNode::RuleAction::none ();
3674
+
3675
+ if (simplifiedLhsType->isEqual (rhsType)) {
3676
+ ++NumRewriteRulesRedundant;
3677
+ return RewriteTreeNode::RuleAction::remove ();
3678
+ }
3679
+
3680
+ return RewriteTreeNode::RuleAction::none ();
3681
+ },
3682
+ /* temporarilyDisableVisitedRule=*/ true );
3683
+ }
3684
+ }
3685
+
3592
3686
bool GenericSignatureBuilder::addSameTypeRewriteRule (
3593
3687
EquivalenceClass *equivClass,
3594
3688
PotentialArchetype *otherPA){
0 commit comments