Skip to content

Commit d385b73

Browse files
committed
RequirementMachine: Plumb source locations through concrete contraction
1 parent 0e297b0 commit d385b73

10 files changed

+72
-90
lines changed

lib/AST/RequirementMachine/ConcreteContraction.cpp

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ class ConcreteContraction {
182182

183183
bool performConcreteContraction(
184184
ArrayRef<StructuralRequirement> requirements,
185-
SmallVectorImpl<StructuralRequirement> &result);
185+
SmallVectorImpl<StructuralRequirement> &result,
186+
SmallVectorImpl<RequirementError> &errors);
186187
};
187188

188189
} // end namespace
@@ -464,7 +465,8 @@ bool ConcreteContraction::preserveSameTypeRequirement(
464465
/// original \p requirements.
465466
bool ConcreteContraction::performConcreteContraction(
466467
ArrayRef<StructuralRequirement> requirements,
467-
SmallVectorImpl<StructuralRequirement> &result) {
468+
SmallVectorImpl<StructuralRequirement> &result,
469+
SmallVectorImpl<RequirementError> &errors) {
468470

469471
// Phase 1 - collect concrete type and superclass requirements where the
470472
// subject type is a generic parameter.
@@ -577,47 +579,19 @@ bool ConcreteContraction::performConcreteContraction(
577579
llvm::dbgs() << "\n";
578580
}
579581

580-
if (preserveSameTypeRequirement(req.req)) {
581-
if (Debug) {
582-
llvm::dbgs() << "@ Preserving original requirement: ";
583-
req.req.dump(llvm::dbgs());
584-
llvm::dbgs() << "\n";
585-
}
586-
587-
// Make the duplicated requirement 'inferred' so that we don't diagnose
588-
// it as redundant.
589-
result.push_back({req.req, SourceLoc(), /*inferred=*/true});
590-
}
591-
592582
// Substitute the requirement.
593-
Optional<Requirement> substReq = substRequirement(req.req);
594-
595-
// If substitution failed, we have a conflict; bail out here so that we can
596-
// diagnose the conflict later.
597-
if (!substReq) {
598-
if (Debug) {
599-
llvm::dbgs() << "@ Concrete contraction cannot proceed; requirement ";
600-
llvm::dbgs() << "substitution failed:\n";
601-
req.req.dump(llvm::dbgs());
602-
llvm::dbgs() << "\n";
603-
}
604-
605-
continue;
606-
}
583+
auto substReq = substRequirement(req.req);
607584

608585
if (Debug) {
609586
llvm::dbgs() << "@ Substituted requirement: ";
610-
substReq->dump(llvm::dbgs());
587+
substReq.dump(llvm::dbgs());
611588
llvm::dbgs() << "\n";
612589
}
613590

614591
// Otherwise, desugar the requirement again, since we might now have a
615592
// requirement where the left hand side is not a type parameter.
616-
//
617-
// FIXME: Do we need to check for errors? Right now they're just ignored.
618593
SmallVector<Requirement, 4> reqs;
619-
SmallVector<RequirementError, 1> errors;
620-
desugarRequirement(*substReq, reqs, errors);
594+
desugarRequirement(substReq, req.loc, reqs, errors);
621595
for (auto desugaredReq : reqs) {
622596
if (Debug) {
623597
llvm::dbgs() << "@@ Desugared requirement: ";
@@ -626,6 +600,20 @@ bool ConcreteContraction::performConcreteContraction(
626600
}
627601
result.push_back({desugaredReq, req.loc, req.inferred});
628602
}
603+
604+
if (preserveSameTypeRequirement(req.req) &&
605+
(!req.req.getFirstType()->isEqual(substReq.getFirstType()) ||
606+
!req.req.getSecondType()->isEqual(substReq.getSecondType()))) {
607+
if (Debug) {
608+
llvm::dbgs() << "@ Preserving original requirement: ";
609+
req.req.dump(llvm::dbgs());
610+
llvm::dbgs() << "\n";
611+
}
612+
613+
// Make the duplicated requirement 'inferred' so that we don't diagnose
614+
// it as redundant.
615+
result.push_back({req.req, SourceLoc(), /*inferred=*/true});
616+
}
629617
}
630618

631619
if (Debug) {
@@ -647,7 +635,9 @@ bool ConcreteContraction::performConcreteContraction(
647635
bool swift::rewriting::performConcreteContraction(
648636
ArrayRef<StructuralRequirement> requirements,
649637
SmallVectorImpl<StructuralRequirement> &result,
638+
SmallVectorImpl<RequirementError> &errors,
650639
bool debug) {
651640
ConcreteContraction concreteContraction(debug);
652-
return concreteContraction.performConcreteContraction(requirements, result);
641+
return concreteContraction.performConcreteContraction(
642+
requirements, result, errors);
653643
}

lib/AST/RequirementMachine/ConcreteTypeWitness.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ void PropertyMap::inferConditionalRequirements(
568568
llvm::dbgs() << "\n";
569569
}
570570

571-
desugarRequirement(req, desugaredRequirements, errors);
571+
desugarRequirement(req, SourceLoc(), desugaredRequirements, errors);
572572
}
573573

574574
// Now, convert desugared conditional requirements to rules.

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ static void desugarConformanceRequirement(Type subjectType, Type constraintType,
304304
if (conformance.isConcrete()) {
305305
// Introduce conditional requirements if the conformance is concrete.
306306
for (auto req : conformance.getConcrete()->getConditionalRequirements()) {
307-
desugarRequirement(req, result, errors);
307+
desugarRequirement(req, loc, result, errors);
308308
}
309309
}
310310

@@ -324,7 +324,7 @@ static void desugarConformanceRequirement(Type subjectType, Type constraintType,
324324
paramType->getRequirements(subjectType, reqs);
325325

326326
for (const auto &req : reqs)
327-
desugarRequirement(req, result, errors);
327+
desugarRequirement(req, loc, result, errors);
328328

329329
return;
330330
}
@@ -352,30 +352,30 @@ static void desugarConformanceRequirement(Type subjectType, Type constraintType,
352352
/// composition, into zero or more "proper" requirements which can then be
353353
/// converted into rewrite rules by the RuleBuilder.
354354
void
355-
swift::rewriting::desugarRequirement(Requirement req,
355+
swift::rewriting::desugarRequirement(Requirement req, SourceLoc loc,
356356
SmallVectorImpl<Requirement> &result,
357357
SmallVectorImpl<RequirementError> &errors) {
358358
auto firstType = req.getFirstType();
359359

360360
switch (req.getKind()) {
361361
case RequirementKind::Conformance:
362362
desugarConformanceRequirement(firstType, req.getSecondType(),
363-
SourceLoc(), result, errors);
363+
loc, result, errors);
364364
break;
365365

366366
case RequirementKind::Superclass:
367367
desugarSuperclassRequirement(firstType, req.getSecondType(),
368-
SourceLoc(), result, errors);
368+
loc, result, errors);
369369
break;
370370

371371
case RequirementKind::Layout:
372372
desugarLayoutRequirement(firstType, req.getLayoutConstraint(),
373-
SourceLoc(), result, errors);
373+
loc, result, errors);
374374
break;
375375

376376
case RequirementKind::SameType:
377377
desugarSameTypeRequirement(firstType, req.getSecondType(),
378-
SourceLoc(), result, errors);
378+
loc, result, errors);
379379
break;
380380
}
381381
}
@@ -435,7 +435,7 @@ struct InferRequirementsWalker : public TypeWalker {
435435
auto subMap = typeAlias->getSubstitutionMap();
436436
for (const auto &rawReq : decl->getGenericSignature().getRequirements()) {
437437
if (auto req = rawReq.subst(subMap))
438-
desugarRequirement(*req, reqs, errors);
438+
desugarRequirement(*req, SourceLoc(), reqs, errors);
439439
}
440440

441441
return Action::Continue;
@@ -455,15 +455,15 @@ struct InferRequirementsWalker : public TypeWalker {
455455
auto addConformanceConstraint = [&](Type type, ProtocolDecl *protocol) {
456456
Requirement req(RequirementKind::Conformance, type,
457457
protocol->getDeclaredInterfaceType());
458-
desugarRequirement(req, reqs, errors);
458+
desugarRequirement(req, SourceLoc(), reqs, errors);
459459
};
460460
auto addSameTypeConstraint = [&](Type firstType,
461461
AssociatedTypeDecl *assocType) {
462462
auto secondType = assocType->getDeclaredInterfaceType()
463463
->castTo<DependentMemberType>()
464464
->substBaseType(module, firstType);
465465
Requirement req(RequirementKind::SameType, firstType, secondType);
466-
desugarRequirement(req, reqs, errors);
466+
desugarRequirement(req, SourceLoc(), reqs, errors);
467467
};
468468
auto *tangentVectorAssocType =
469469
differentiableProtocol->getAssociatedType(ctx.Id_TangentVector);
@@ -502,7 +502,7 @@ struct InferRequirementsWalker : public TypeWalker {
502502
// FIXME: Inaccurate TypeReprs.
503503
for (const auto &rawReq : genericSig.getRequirements()) {
504504
if (auto req = rawReq.subst(subMap))
505-
desugarRequirement(*req, reqs, errors);
505+
desugarRequirement(*req, SourceLoc(), reqs, errors);
506506
}
507507

508508
return Action::Continue;

lib/AST/RequirementMachine/RequirementLowering.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ namespace rewriting {
3838
// documentation
3939
// comments.
4040

41-
void desugarRequirement(Requirement req,
41+
void desugarRequirement(Requirement req, SourceLoc loc,
4242
SmallVectorImpl<Requirement> &result,
4343
SmallVectorImpl<RequirementError> &errors);
4444

@@ -78,6 +78,7 @@ bool diagnoseRequirementErrors(ASTContext &ctx,
7878
bool performConcreteContraction(
7979
ArrayRef<StructuralRequirement> requirements,
8080
SmallVectorImpl<StructuralRequirement> &result,
81+
SmallVectorImpl<RequirementError> &errors,
8182
bool debug);
8283

8384
} // end namespace rewriting

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ AbstractGenericSignatureRequestRQM::evaluate(
603603
// which is what the RuleBuilder expects.
604604
for (auto req : addedRequirements) {
605605
SmallVector<Requirement, 2> reqs;
606-
desugarRequirement(req, reqs, errors);
606+
desugarRequirement(req, SourceLoc(), reqs, errors);
607607
for (auto req : reqs)
608608
requirements.push_back({req, SourceLoc(), /*wasInferred=*/false});
609609
}
@@ -619,9 +619,10 @@ AbstractGenericSignatureRequestRQM::evaluate(
619619
// which are made concrete.
620620
if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) {
621621
SmallVector<StructuralRequirement, 4> contractedRequirements;
622+
bool debug = rewriteCtx.getDebugOptions()
623+
.contains(DebugFlags::ConcreteContraction);
622624
if (performConcreteContraction(requirements, contractedRequirements,
623-
rewriteCtx.getDebugOptions()
624-
.contains(DebugFlags::ConcreteContraction))) {
625+
errors, debug)) {
625626
std::swap(contractedRequirements, requirements);
626627
}
627628
}
@@ -795,9 +796,10 @@ InferredGenericSignatureRequestRQM::evaluate(
795796
// which are made concrete.
796797
if (ctx.LangOpts.EnableRequirementMachineConcreteContraction) {
797798
SmallVector<StructuralRequirement, 4> contractedRequirements;
799+
bool debug = rewriteCtx.getDebugOptions()
800+
.contains(DebugFlags::ConcreteContraction);
798801
if (performConcreteContraction(requirements, contractedRequirements,
799-
rewriteCtx.getDebugOptions()
800-
.contains(DebugFlags::ConcreteContraction))) {
802+
errors, debug)) {
801803
std::swap(contractedRequirements, requirements);
802804
}
803805
}

test/Generics/derived_via_concrete.swift

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -requirement-machine-inferred-signatures=on
22
// RUN: %target-swift-frontend -typecheck %s -debug-generic-signatures -requirement-machine-inferred-signatures=on 2>&1 | %FileCheck %s
33

44
protocol P {}
@@ -24,43 +24,37 @@ protocol W {
2424
// CHECK-NEXT: Generic signature: <A, B where A : X<B>, B : P>
2525
func derivedViaConcreteX1<A, B>(_: A, _: B)
2626
where A : U, A : X<B> {}
27-
// expected-warning@-1 {{redundant conformance constraint 'A' : 'U'}}
28-
// expected-note@-2 {{conformance constraint 'A' : 'U' implied here}}
27+
// expected-warning@-1 {{redundant conformance constraint 'X<B>' : 'U'}}
2928

3029
// CHECK-LABEL: .derivedViaConcreteX2@
3130
// CHECK-NEXT: Generic signature: <A, B where A : X<B>, B : P>
3231
func derivedViaConcreteX2<A, B>(_: A, _: B)
3332
where A : U, B : P, A : X<B> {}
34-
// expected-warning@-1 {{redundant conformance constraint 'A' : 'U'}}
35-
// expected-note@-2 {{conformance constraint 'A' : 'U' implied here}}
33+
// expected-warning@-1 {{redundant conformance constraint 'X<B>' : 'U'}}
3634

3735
// CHECK-LABEL: .derivedViaConcreteY1@
3836
// CHECK-NEXT: Generic signature: <A, B where A : Y<B>, B : C>
3937
func derivedViaConcreteY1<A, B>(_: A, _: B)
4038
where A : V, A : Y<B> {}
41-
// expected-warning@-1 {{redundant conformance constraint 'A' : 'V'}}
42-
// expected-note@-2 {{conformance constraint 'A' : 'V' implied here}}
39+
// expected-warning@-1 {{redundant conformance constraint 'Y<B>' : 'V'}}
4340

4441
// CHECK-LABEL: .derivedViaConcreteY2@
4542
// CHECK-NEXT: Generic signature: <A, B where A : Y<B>, B : C>
4643
func derivedViaConcreteY2<A, B>(_: A, _: B)
4744
where A : V, B : C, A : Y<B> {}
48-
// expected-warning@-1 {{redundant conformance constraint 'A' : 'V'}}
49-
// expected-note@-2 {{conformance constraint 'A' : 'V' implied here}}
45+
// expected-warning@-1 {{redundant conformance constraint 'Y<B>' : 'V'}}
5046

5147
// CHECK-LABEL: .derivedViaConcreteZ1@
5248
// CHECK-NEXT: Generic signature: <A, B where A : Z<B>, B : AnyObject>
5349
func derivedViaConcreteZ1<A, B>(_: A, _: B)
5450
where A : W, A : Z<B> {}
55-
// expected-warning@-1 {{redundant conformance constraint 'A' : 'W'}}
56-
// expected-note@-2 {{conformance constraint 'A' : 'W' implied here}}
51+
// expected-warning@-1 {{redundant conformance constraint 'Z<B>' : 'W'}}
5752

5853
// CHECK-LABEL: .derivedViaConcreteZ2@
5954
// CHECK-NEXT: Generic signature: <A, B where A : Z<B>, B : AnyObject>
6055
func derivedViaConcreteZ2<A, B>(_: A, _: B)
6156
where A : W, B : AnyObject, A : Z<B> {}
62-
// expected-warning@-1 {{redundant conformance constraint 'A' : 'W'}}
63-
// expected-note@-2 {{conformance constraint 'A' : 'W' implied here}}
57+
// expected-warning@-1 {{redundant conformance constraint 'Z<B>' : 'W'}}
6458

6559
class Base {}
6660
class Derived<T : C> : Base, V {}

test/Generics/non_final_class_conforms_same_type_requirement_on_self.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ public class FinalD : Q {
4242

4343
// CHECK-LABEL: Generic signature: <T where T : C>
4444
public func takesBoth1<T>(_: T) where T : P, T : C {}
45+
// expected-warning@-1 {{redundant conformance constraint 'C' : 'P'}}
4546

4647
// CHECK-LABEL: Generic signature: <U where U : C>
4748
public func takesBoth2<U>(_: U) where U : C, U : P {}
49+
// expected-warning@-1 {{redundant conformance constraint 'C' : 'P'}}
4850

4951
// 'Self' can also occur inside of a concrete type or superclass requirement.
5052
public class G<T> {}

test/Generics/rdar65263302.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures %s -requirement-machine-inferred-signatures=verify 2>&1 | %FileCheck %s
2-
// RUN: %target-swift-frontend -verify -emit-ir -requirement-machine-inferred-signatures=verify %s
1+
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures %s -requirement-machine-inferred-signatures=on 2>&1 | %FileCheck %s
2+
// RUN: %target-swift-frontend -verify -emit-ir %s -requirement-machine-inferred-signatures=on
33

44
public protocol P {
55
associatedtype Element
@@ -11,10 +11,10 @@ public class C<O: P>: P {
1111

1212
// CHECK: Generic signature: <T, O, E where T : C<E>, O : P, E : P, O.[P]Element == E.[P]Element>
1313
public func toe1<T, O, E>(_: T, _: O, _: E, _: T.Element)
14-
where T : P, // expected-warning {{redundant conformance constraint 'T' : 'P'}}
14+
where T : P, // expected-warning {{redundant conformance constraint 'C<E>' : 'P'}}
1515
O : P,
1616
O.Element == T.Element,
17-
T : C<E> {} // expected-note {{conformance constraint 'T' : 'P' implied here}}
17+
T : C<E> {}
1818

1919
// CHECK: Generic signature: <T, O, E where T : C<E>, O : P, E : P, O.[P]Element == E.[P]Element>
2020
public func toe2<T, O, E>(_: T, _: O, _: E, _: T.Element)
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
// RUN: %target-typecheck-verify-swift
2-
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures %s 2>&1 | %FileCheck %s
1+
// RUN: %target-typecheck-verify-swift -requirement-machine-inferred-signatures=on
2+
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures %s -requirement-machine-inferred-signatures=on 2>&1 | %FileCheck %s
33

44
struct G<T> {}
55

66
// CHECK-LABEL: Generic signature: <T where T == Error>
77
extension G where T : Error, T == Error {}
8-
// expected-warning@-1 {{redundant conformance constraint 'T' : 'Error'}}
9-
// expected-note@-2 {{conformance constraint 'T' : 'Error' implied here}}
8+
// expected-warning@-1 {{redundant conformance constraint 'any Error' : 'Error'}}

0 commit comments

Comments
 (0)