Skip to content

Commit 3367fdd

Browse files
committed
SmallProjectionPath: add mayOverlap(with:)
"Overlapping" means that both paths may project the same field.
1 parent 9c4bd12 commit 3367fdd

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

SwiftCompilerSources/Sources/SIL/SmallProjectionPath.swift

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,37 @@ public struct SmallProjectionPath : CustomStringConvertible, CustomReflectable,
373373
}
374374
return Self(.anything)
375375
}
376+
377+
/// Returns true if this path may overlap with `rhs`.
378+
///
379+
/// "Overlapping" means that both paths may project the same field.
380+
/// For example:
381+
/// `s0.s1` and `s0.s1` overlap (the paths are identical)
382+
/// `s0.s1` and `s0.s2` don't overlap
383+
/// `s0.s1` and `s0` overlap (the second path is a sub-path of the first one)
384+
/// `s0.v**` and `s0.s1` overlap
385+
public func mayOverlap(with rhs: SmallProjectionPath) -> Bool {
386+
if isEmpty || rhs.isEmpty {
387+
return true
388+
}
376389

390+
let (lhsKind, lhsIdx, lhsBits) = top
391+
let (rhsKind, rhsIdx, rhsBits) = rhs.top
392+
393+
if lhsKind == .anything || rhsKind == .anything {
394+
return true
395+
}
396+
if lhsKind == .anyValueFields || rhsKind == .anyValueFields {
397+
return popAllValueFields().mayOverlap(with: rhs.popAllValueFields())
398+
}
399+
if (lhsKind == rhsKind && lhsIdx == rhsIdx) ||
400+
(lhsKind == .anyClassField && rhsKind.isClassField) ||
401+
(lhsKind.isClassField && rhsKind == .anyClassField) {
402+
return pop(numBits: lhsBits).mayOverlap(with: rhs.pop(numBits: rhsBits))
403+
}
404+
return false
405+
}
406+
377407
public var customMirror: Mirror { Mirror(self, children: []) }
378408
}
379409

@@ -505,6 +535,7 @@ extension SmallProjectionPath {
505535
parsing()
506536
merging()
507537
matching()
538+
overlapping()
508539
predicates()
509540
path2path()
510541

@@ -617,6 +648,38 @@ extension SmallProjectionPath {
617648
precondition(result == expect)
618649
}
619650

651+
func overlapping() {
652+
testOverlap("s0.s1.s2", "s0.s1.s2", expect: true)
653+
testOverlap("s0.s1.s2", "s0.s2.s2", expect: false)
654+
testOverlap("s0.s1.s2", "s0.e1.s2", expect: false)
655+
testOverlap("s0.s1.s2", "s0.s1", expect: true)
656+
testOverlap("s0.s1.s2", "s1.s2", expect: false)
657+
658+
testOverlap("s0.c*.s2", "s0.ct.s2", expect: true)
659+
testOverlap("s0.c*.s2", "s0.c1.s2", expect: true)
660+
testOverlap("s0.c*.s2", "s0.c1.c2.s2", expect: false)
661+
testOverlap("s0.c*.s2", "s0.s2", expect: false)
662+
663+
testOverlap("s0.v**.s2", "s0.s3", expect: true)
664+
testOverlap("s0.v**.s2.c2", "s0.s3.c1", expect: false)
665+
testOverlap("s0.v**.s2", "s1.s3", expect: false)
666+
testOverlap("s0.v**.s2", "s0.v**.s3", expect: true)
667+
668+
testOverlap("s0.**", "s0.s3.c1", expect: true)
669+
testOverlap("**", "s0.s3.c1", expect: true)
670+
}
671+
672+
func testOverlap(_ lhsStr: String, _ rhsStr: String, expect: Bool) {
673+
var lhsParser = StringParser(lhsStr)
674+
let lhs = try! lhsParser.parseProjectionPathFromSIL()
675+
var rhsParser = StringParser(rhsStr)
676+
let rhs = try! rhsParser.parseProjectionPathFromSIL()
677+
let result = lhs.mayOverlap(with: rhs)
678+
precondition(result == expect)
679+
let reversedResult = rhs.mayOverlap(with: lhs)
680+
precondition(reversedResult == expect)
681+
}
682+
620683
func predicates() {
621684
testPredicate("v**", \.hasNoClassProjection, expect: true)
622685
testPredicate("c0", \.hasNoClassProjection, expect: false)

0 commit comments

Comments
 (0)