Skip to content

Commit 2206b1c

Browse files
committed
RequirementMachine: Split up equivalence classes with inferred concrete type
I'll clean this up, comment it and generalize it to work with protocol requirement signatures soon. Landing this now to unblock the Linux corelibs-foundation build. Fixes rdar://problem/89791117.
1 parent 058190e commit 2206b1c

File tree

2 files changed

+102
-3
lines changed

2 files changed

+102
-3
lines changed

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,59 @@ static bool isCanonicalRequest(GenericSignature baseSignature,
243243
return true;
244244
}
245245

246+
/// Hack for GenericSignatureBuilder compatibility. We might end up with a
247+
/// same-type requirement between type parameters where one of them has an
248+
/// implied concrete type requirement. In this case, split it up into two
249+
/// concrete type requirements.
250+
static bool shouldSplitConcreteEquivalenceClass(Requirement req,
251+
GenericSignature sig) {
252+
return (req.getKind() == RequirementKind::SameType &&
253+
req.getSecondType()->isTypeParameter() &&
254+
sig->isConcreteType(req.getSecondType()));
255+
}
256+
257+
static bool shouldSplitConcreteEquivalenceClasses(GenericSignature sig) {
258+
for (auto req : sig.getRequirements()) {
259+
if (shouldSplitConcreteEquivalenceClass(req, sig))
260+
return true;
261+
}
262+
263+
return false;
264+
}
265+
266+
static GenericSignature splitConcreteEquivalenceClasses(
267+
GenericSignature sig, ASTContext &ctx) {
268+
SmallVector<Requirement, 2> reqs;
269+
270+
for (auto req : sig.getRequirements()) {
271+
if (shouldSplitConcreteEquivalenceClass(req, sig)) {
272+
auto canType = sig->getSugaredType(
273+
sig.getCanonicalTypeInContext(
274+
req.getSecondType()));
275+
276+
reqs.emplace_back(RequirementKind::SameType,
277+
req.getFirstType(),
278+
canType);
279+
reqs.emplace_back(RequirementKind::SameType,
280+
req.getSecondType(),
281+
canType);
282+
} else {
283+
reqs.push_back(req);
284+
}
285+
}
286+
287+
SmallVector<GenericTypeParamType *, 2> genericParams;
288+
genericParams.append(sig.getGenericParams().begin(),
289+
sig.getGenericParams().end());
290+
291+
return evaluateOrDefault(
292+
ctx.evaluator,
293+
AbstractGenericSignatureRequestRQM{
294+
/*baseSignature=*/nullptr,
295+
genericParams, reqs},
296+
GenericSignatureWithError()).getPointer();
297+
}
298+
246299
GenericSignatureWithError
247300
AbstractGenericSignatureRequestRQM::evaluate(
248301
Evaluator &evaluator,
@@ -391,8 +444,13 @@ AbstractGenericSignatureRequestRQM::evaluate(
391444
auto result = GenericSignature::get(genericParams, minimalRequirements);
392445
auto errorFlags = machine->getErrors();
393446

394-
if (!errorFlags)
447+
if (!errorFlags) {
448+
if (shouldSplitConcreteEquivalenceClasses(result))
449+
result = splitConcreteEquivalenceClasses(result, ctx);
450+
451+
// Check invariants.
395452
result.verify();
453+
}
396454

397455
return GenericSignatureWithError(result, errorFlags);
398456
}
@@ -543,9 +601,13 @@ InferredGenericSignatureRequestRQM::evaluate(
543601

544602
// FIXME: Handle allowConcreteGenericParams
545603

546-
// Check invariants.
547-
if (!errorFlags)
604+
if (!errorFlags) {
605+
if (shouldSplitConcreteEquivalenceClasses(result))
606+
result = splitConcreteEquivalenceClasses(result, ctx);
607+
608+
// Check invariants.
548609
result.verify();
610+
}
549611

550612
return GenericSignatureWithError(result, errorFlags);
551613
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %target-swift-frontend -typecheck %s -debug-generic-signatures -requirement-machine-inferred-signatures=on 2>&1 | %FileCheck %s
2+
3+
// CHECK-LABEL: split_concrete_equivalence_class.(file).f01@
4+
// CHECK-NEXT: Generic signature: <C, R where C : Collection, R : Collection, C.[Collection]SubSequence == Substring, R.[Sequence]Element == Character>
5+
func f01<C : Collection, R : Collection>(_: C, _: R) where C.SubSequence == Substring, C.Element == R.Element {}
6+
7+
// CHECK-LABEL: split_concrete_equivalence_class.(file).f02@
8+
// CHECK-NEXT: Generic signature: <C, R where C : Collection, R : Collection, C.[Sequence]Element == Character, R.[Collection]SubSequence == Substring>
9+
func f02<C : Collection, R : Collection>(_: C, _: R) where R.SubSequence == Substring, C.Element == R.Element {}
10+
11+
// CHECK-LABEL: split_concrete_equivalence_class.(file).f03@
12+
// CHECK-NEXT: Generic signature: <C, R where C : Collection, R : Collection, C.[Collection]SubSequence == Substring, R.[Sequence]Element == Character>
13+
func f03<C : Collection, R : Collection>(_: C, _: R) where C.SubSequence == Substring, C.Element == R.Element, C.Element == Character {}
14+
15+
// CHECK-LABEL: split_concrete_equivalence_class.(file).f04@
16+
// CHECK-NEXT: Generic signature: <C, R where C : Collection, R : Collection, C.[Sequence]Element == Character, R.[Collection]SubSequence == Substring>
17+
func f04<C : Collection, R : Collection>(_: C, _: R) where R.SubSequence == Substring, C.Element == R.Element, C.Element == Character {}
18+
19+
// CHECK-LABEL: split_concrete_equivalence_class.(file).f05@
20+
// CHECK-NEXT: Generic signature: <C, R where C : Collection, R : Collection, C.[Collection]SubSequence == Substring, R.[Sequence]Element == Character>
21+
func f05<C : Collection, R : Collection>(_: C, _: R) where C.SubSequence == Substring, C.Element == R.Element, R.Element == Character {}
22+
23+
// CHECK-LABEL: split_concrete_equivalence_class.(file).f06@
24+
// CHECK-NEXT: Generic signature: <C, R where C : Collection, R : Collection, C.[Sequence]Element == Character, R.[Collection]SubSequence == Substring>
25+
func f06<C : Collection, R : Collection>(_: C, _: R) where R.SubSequence == Substring, C.Element == R.Element, R.Element == Character {}
26+
27+
// CHECK-LABEL: split_concrete_equivalence_class.(file).f07@
28+
// CHECK-NEXT: Generic signature: <C, R where C : Collection, R : Collection, C.[Collection]SubSequence == Substring, R.[Collection]SubSequence == Substring>
29+
func f07<C : Collection, R : Collection>(_: C, _: R) where C.SubSequence == Substring, R.SubSequence == Substring, C.Element == R.Element {}
30+
31+
// CHECK-LABEL: split_concrete_equivalence_class.(file).f08@
32+
// CHECK-NEXT: Generic signature: <C, R where C : Collection, R : Collection, C.[Collection]SubSequence == Substring, R.[Collection]SubSequence == Substring>
33+
func f08<C : Collection, R : Collection>(_: C, _: R) where C.SubSequence == Substring, R.SubSequence == Substring, C.Element == R.Element, C.Element == Character {}
34+
35+
// CHECK-LABEL: split_concrete_equivalence_class.(file).f09@
36+
// CHECK-NEXT: Generic signature: <C, R where C : Collection, R : Collection, C.[Collection]SubSequence == Substring, R.[Collection]SubSequence == Substring>
37+
func f09<C : Collection, R : Collection>(_: C, _: R) where C.SubSequence == Substring, R.SubSequence == Substring, C.Element == R.Element, R.Element == Character {}

0 commit comments

Comments
 (0)