Skip to content

Commit b18e815

Browse files
committed
[RequirementMachine] Preserve structural requirements during rule construction,
and diagnose trivially redundant rules in the rewrite system.
1 parent 8df83fe commit b18e815

File tree

8 files changed

+105
-24
lines changed

8 files changed

+105
-24
lines changed

lib/AST/RequirementMachine/ConcreteTypeWitness.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -578,8 +578,11 @@ void PropertyMap::inferConditionalRequirements(
578578
for (const auto &rule : builder.PermanentRules)
579579
System.addPermanentRule(rule.first, rule.second);
580580

581-
for (const auto &rule : builder.RequirementRules)
582-
System.addExplicitRule(rule.first, rule.second);
581+
for (const auto &rule : builder.RequirementRules) {
582+
auto lhs = std::get<0>(rule);
583+
auto rhs = std::get<1>(rule);
584+
System.addExplicitRule(lhs, rhs, /*requirementID=*/None);
585+
}
583586
}
584587
}
585588

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,14 @@ static void desugarSameTypeRequirement(Type lhs, Type rhs, SourceLoc loc,
7777
Type sugaredFirstType) {
7878
if (firstType->isTypeParameter() && secondType->isTypeParameter()) {
7979
result.emplace_back(RequirementKind::SameType,
80-
firstType, secondType);
80+
sugaredFirstType, secondType);
8181
recordedRequirements = true;
8282
return true;
8383
}
8484

8585
if (firstType->isTypeParameter()) {
8686
result.emplace_back(RequirementKind::SameType,
87-
firstType, secondType);
87+
sugaredFirstType, secondType);
8888
recordedRequirements = true;
8989
return true;
9090
}
@@ -530,7 +530,7 @@ void swift::rewriting::realizeInheritedRequirements(
530530
/// \returns true if any errors were emitted, and false otherwise (including
531531
/// when only warnings were emitted).
532532
bool swift::rewriting::diagnoseRequirementErrors(
533-
ASTContext &ctx, SmallVectorImpl<RequirementError> &errors,
533+
ASTContext &ctx, ArrayRef<RequirementError> errors,
534534
bool allowConcreteGenericParams) {
535535
bool diagnosedError = false;
536536

@@ -1034,7 +1034,7 @@ void RuleBuilder::addRequirements(ArrayRef<Requirement> requirements) {
10341034

10351035
// Add rewrite rules for all top-level requirements.
10361036
for (const auto &req : requirements)
1037-
addRequirement(req, /*proto=*/nullptr);
1037+
addRequirement(req, /*proto=*/nullptr, /*requirementID=*/None);
10381038
}
10391039

10401040
void RuleBuilder::addRequirements(ArrayRef<StructuralRequirement> requirements) {
@@ -1184,22 +1184,26 @@ swift::rewriting::getRuleForRequirement(const Requirement &req,
11841184
}
11851185

11861186
void RuleBuilder::addRequirement(const Requirement &req,
1187-
const ProtocolDecl *proto) {
1187+
const ProtocolDecl *proto,
1188+
Optional<unsigned> requirementID) {
11881189
if (Dump) {
11891190
llvm::dbgs() << "+ ";
11901191
req.dump(llvm::dbgs());
11911192
llvm::dbgs() << "\n";
11921193
}
11931194

1194-
RequirementRules.push_back(
1195+
auto rule =
11951196
getRuleForRequirement(req, proto, /*substitutions=*/None,
1196-
Context));
1197+
Context);
1198+
RequirementRules.push_back(
1199+
std::make_tuple(rule.first, rule.second, requirementID));
11971200
}
11981201

11991202
void RuleBuilder::addRequirement(const StructuralRequirement &req,
12001203
const ProtocolDecl *proto) {
1201-
// FIXME: Preserve source location information for diagnostics.
1202-
addRequirement(req.req.getCanonical(), proto);
1204+
WrittenRequirements.push_back(req);
1205+
unsigned requirementID = WrittenRequirements.size() - 1;
1206+
addRequirement(req.req.getCanonical(), proto, requirementID);
12031207
}
12041208

12051209
/// Lowers a protocol typealias to a rewrite rule.
@@ -1231,7 +1235,8 @@ void RuleBuilder::addTypeAlias(const ProtocolTypeAlias &alias,
12311235
constraintTerm.add(Symbol::forConcreteType(concreteType, result, Context));
12321236
}
12331237

1234-
RequirementRules.emplace_back(subjectTerm, constraintTerm);
1238+
RequirementRules.emplace_back(subjectTerm, constraintTerm,
1239+
/*requirementID=*/None);
12351240
}
12361241

12371242
/// Record information about a protocol if we have no seen it yet.
@@ -1292,11 +1297,11 @@ void RuleBuilder::collectRulesFromReferencedProtocols() {
12921297
addRequirement(req, proto);
12931298

12941299
for (auto req : proto->getTypeAliasRequirements())
1295-
addRequirement(req.getCanonical(), proto);
1300+
addRequirement(req.getCanonical(), proto, /*requirementID=*/None);
12961301
} else {
12971302
auto reqs = proto->getRequirementSignature();
12981303
for (auto req : reqs.getRequirements())
1299-
addRequirement(req.getCanonical(), proto);
1304+
addRequirement(req.getCanonical(), proto, /*requirementID=*/None);
13001305
for (auto alias : reqs.getTypeAliases())
13011306
addTypeAlias(alias, proto);
13021307
}

lib/AST/RequirementMachine/RequirementLowering.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ void realizeInheritedRequirements(TypeDecl *decl, Type type,
5959
SmallVectorImpl<RequirementError> &errors);
6060

6161
bool diagnoseRequirementErrors(ASTContext &ctx,
62-
SmallVectorImpl<RequirementError> &errors,
62+
ArrayRef<RequirementError> errors,
6363
bool allowConcreteGenericParams);
6464

6565
std::pair<MutableTerm, MutableTerm>
@@ -104,7 +104,12 @@ struct RuleBuilder {
104104

105105
/// New rules derived from requirements written by the user, which can be
106106
/// eliminated by homotopy reduction.
107-
std::vector<std::pair<MutableTerm, MutableTerm>> RequirementRules;
107+
std::vector<std::tuple<MutableTerm, MutableTerm, Optional<unsigned>>>
108+
RequirementRules;
109+
110+
/// Requirements written in source code. The requirement ID in the above
111+
/// \c RequirementRules vector is an index into this array.
112+
std::vector<StructuralRequirement> WrittenRequirements;
108113

109114
/// Enables debugging output. Controlled by the -dump-requirement-machine
110115
/// frontend flag.
@@ -123,7 +128,8 @@ struct RuleBuilder {
123128
void addAssociatedType(const AssociatedTypeDecl *type,
124129
const ProtocolDecl *proto);
125130
void addRequirement(const Requirement &req,
126-
const ProtocolDecl *proto);
131+
const ProtocolDecl *proto,
132+
Optional<unsigned> requirementID);
127133
void addRequirement(const StructuralRequirement &req,
128134
const ProtocolDecl *proto);
129135
void addTypeAlias(const ProtocolTypeAlias &alias,

lib/AST/RequirementMachine/RequirementMachine.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ RequirementMachine::initWithGenericSignature(CanGenericSignature sig) {
9696
// Add the initial set of rewrite rules to the rewrite system.
9797
System.initialize(/*recordLoops=*/false,
9898
/*protos=*/ArrayRef<const ProtocolDecl *>(),
99+
std::move(builder.WrittenRequirements),
99100
std::move(builder.PermanentRules),
100101
std::move(builder.RequirementRules));
101102

@@ -138,6 +139,7 @@ RequirementMachine::initWithProtocols(ArrayRef<const ProtocolDecl *> protos) {
138139

139140
// Add the initial set of rewrite rules to the rewrite system.
140141
System.initialize(/*recordLoops=*/true, protos,
142+
std::move(builder.WrittenRequirements),
141143
std::move(builder.PermanentRules),
142144
std::move(builder.RequirementRules));
143145

@@ -185,6 +187,7 @@ RequirementMachine::initWithWrittenRequirements(
185187
// Add the initial set of rewrite rules to the rewrite system.
186188
System.initialize(/*recordLoops=*/true,
187189
/*protos=*/ArrayRef<const ProtocolDecl *>(),
190+
std::move(builder.WrittenRequirements),
188191
std::move(builder.PermanentRules),
189192
std::move(builder.RequirementRules));
190193

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,12 @@ RequirementSignatureRequestRQM::evaluate(Evaluator &evaluator,
419419
}
420420
}
421421

422+
if (ctx.LangOpts.RequirementMachineProtocolSignatures ==
423+
RequirementMachineMode::Enabled) {
424+
diagnoseRequirementErrors(ctx, machine->System.getErrors(),
425+
/*allowConcreteGenericParams=*/false);
426+
}
427+
422428
// Return the result for the specific protocol this request was kicked off on.
423429
return *result;
424430
}
@@ -668,6 +674,8 @@ InferredGenericSignatureRequestRQM::evaluate(
668674
if (ctx.LangOpts.RequirementMachineInferredSignatures ==
669675
RequirementMachineMode::Enabled) {
670676
hadError |= diagnoseRequirementErrors(ctx, errors, allowConcreteGenericParams);
677+
hadError |= diagnoseRequirementErrors(ctx, machine->System.getErrors(),
678+
allowConcreteGenericParams);
671679
}
672680

673681
// FIXME: Handle allowConcreteGenericParams

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -276,19 +276,26 @@ RewriteSystem::~RewriteSystem() {
276276

277277
void RewriteSystem::initialize(
278278
bool recordLoops, ArrayRef<const ProtocolDecl *> protos,
279+
ArrayRef<StructuralRequirement> writtenRequirements,
279280
std::vector<std::pair<MutableTerm, MutableTerm>> &&permanentRules,
280-
std::vector<std::pair<MutableTerm, MutableTerm>> &&requirementRules) {
281+
std::vector<std::tuple<MutableTerm, MutableTerm, Optional<unsigned>>>
282+
&&requirementRules) {
281283
assert(!Initialized);
282284
Initialized = 1;
283285

284286
RecordLoops = recordLoops;
285287
Protos = protos;
288+
WrittenRequirements = writtenRequirements;
286289

287290
for (const auto &rule : permanentRules)
288291
addPermanentRule(rule.first, rule.second);
289292

290-
for (const auto &rule : requirementRules)
291-
addExplicitRule(rule.first, rule.second);
293+
for (const auto &rule : requirementRules) {
294+
auto lhs = std::get<0>(rule);
295+
auto rhs = std::get<1>(rule);
296+
auto requirementID = std::get<2>(rule);
297+
addExplicitRule(lhs, rhs, requirementID);
298+
}
292299
}
293300

294301
/// Reduce a term by applying all rewrite rules until fixed point.
@@ -487,10 +494,16 @@ bool RewriteSystem::addPermanentRule(MutableTerm lhs, MutableTerm rhs) {
487494
}
488495

489496
/// Add a new rule, marking it explicit.
490-
bool RewriteSystem::addExplicitRule(MutableTerm lhs, MutableTerm rhs) {
497+
bool RewriteSystem::addExplicitRule(MutableTerm lhs, MutableTerm rhs,
498+
Optional<unsigned> requirementID) {
491499
bool added = addRule(std::move(lhs), std::move(rhs));
492-
if (added)
500+
if (added) {
493501
Rules.back().markExplicit();
502+
} else if (requirementID.hasValue()) {
503+
auto req = WrittenRequirements[requirementID.getValue()];
504+
Errors.push_back(
505+
RequirementError::forRedundantRequirement(req.req, req.loc));
506+
}
494507

495508
return added;
496509
}

lib/AST/RequirementMachine/RewriteSystem.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
#ifndef SWIFT_REWRITESYSTEM_H
1414
#define SWIFT_REWRITESYSTEM_H
1515

16+
#include "swift/AST/Requirement.h"
1617
#include "llvm/ADT/DenseSet.h"
1718
#include "llvm/ADT/PointerUnion.h"
1819

1920
#include "Debug.h"
21+
#include "Diagnostics.h"
2022
#include "RewriteLoop.h"
2123
#include "Symbol.h"
2224
#include "Term.h"
@@ -225,6 +227,12 @@ class RewriteSystem final {
225227
/// top-level generic signature and this array is empty.
226228
ArrayRef<const ProtocolDecl *> Protos;
227229

230+
/// The requirements written in source code.
231+
std::vector<StructuralRequirement> WrittenRequirements;
232+
233+
/// The invalid requirements.
234+
std::vector<RequirementError> Errors;
235+
228236
/// The rules added so far, including rules from our client, as well
229237
/// as rules introduced by the completion procedure.
230238
std::vector<Rule> Rules;
@@ -278,11 +286,16 @@ class RewriteSystem final {
278286
return ProtocolMap;
279287
}
280288

289+
ArrayRef<RequirementError> getErrors() {
290+
return Errors;
291+
}
292+
281293
DebugOptions getDebugOptions() const { return Debug; }
282294

283295
void initialize(bool recordLoops, ArrayRef<const ProtocolDecl *> protos,
296+
ArrayRef<StructuralRequirement> writtenRequirements,
284297
std::vector<std::pair<MutableTerm, MutableTerm>> &&permanentRules,
285-
std::vector<std::pair<MutableTerm, MutableTerm>> &&requirementRules);
298+
std::vector<std::tuple<MutableTerm, MutableTerm, Optional<unsigned>>> &&requirementRules);
286299

287300
ArrayRef<const ProtocolDecl *> getProtocols() const {
288301
return Protos;
@@ -314,7 +327,8 @@ class RewriteSystem final {
314327

315328
bool addPermanentRule(MutableTerm lhs, MutableTerm rhs);
316329

317-
bool addExplicitRule(MutableTerm lhs, MutableTerm rhs);
330+
bool addExplicitRule(MutableTerm lhs, MutableTerm rhs,
331+
Optional<unsigned> requirementID);
318332

319333
bool simplify(MutableTerm &term, RewritePath *path=nullptr) const;
320334

test/Generics/requirement_machine_diagnostics.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,32 @@ func cascadingConflictingRequirement<T>(_: T) where DoesNotExist : EqualComparab
8282

8383
func cascadingInvalidConformance<T>(_: T) where T : DoesNotExist { }
8484
// expected-error@-1 {{cannot find type 'DoesNotExist' in scope}}
85+
86+
func trivialRedundant1<T>(_: T) where T: P, T: P {}
87+
// expected-warning@-1 {{redundant conformance constraint 'T' : 'P'}}
88+
89+
func trivialRedundant2<T>(_: T) where T: AnyObject, T: AnyObject {}
90+
// expected-warning@-1 {{redundant constraint 'T' : 'AnyObject'}}
91+
92+
func trivialRedundant3<T>(_: T) where T: C, T: C {}
93+
// expected-warning@-1 {{redundant superclass constraint 'T' : 'C'}}
94+
95+
func trivialRedundant4<T>(_: T) where T == T {}
96+
// expected-warning@-1 {{redundant same-type constraint 'T' == 'T'}}
97+
98+
protocol TrivialRedundantConformance: P, P {}
99+
// expected-warning@-1 {{redundant conformance constraint 'Self' : 'P'}}
100+
101+
protocol TrivialRedundantLayout: AnyObject, AnyObject {}
102+
// expected-warning@-1 {{redundant constraint 'Self' : 'AnyObject'}}
103+
// expected-error@-2 {{duplicate inheritance from 'AnyObject'}}
104+
105+
protocol TrivialRedundantSuperclass: C, C {}
106+
// expected-warning@-1 {{redundant superclass constraint 'Self' : 'C'}}
107+
// expected-error@-2 {{duplicate inheritance from 'C'}}
108+
109+
protocol TrivialRedundantSameType where Self == Self {
110+
// expected-warning@-1 {{redundant same-type constraint 'Self' == 'Self'}}
111+
associatedtype T where T == T
112+
// expected-warning@-1 {{redundant same-type constraint 'Self.T' == 'Self.T'}}
113+
}

0 commit comments

Comments
 (0)