Skip to content

Commit b37b3ba

Browse files
authored
Merge pull request #10950 from rudkx/revert-recursive-protocol-constraints-changes
Revert recursive protocol constraints changes
2 parents 7fd5a82 + 5acc140 commit b37b3ba

File tree

9 files changed

+74
-50
lines changed

9 files changed

+74
-50
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,6 +1666,8 @@ ERROR(requires_generic_param_made_equal_to_concrete,none,
16661666
(Type))
16671667
ERROR(recursive_type_reference,none,
16681668
"%0 %1 references itself", (DescriptiveDeclKind, Identifier))
1669+
ERROR(recursive_requirement_reference,none,
1670+
"type may not reference itself as a requirement",())
16691671
ERROR(recursive_same_type_constraint,none,
16701672
"same-type constraint %0 == %1 is recursive", (Type, Type))
16711673
ERROR(recursive_superclass_constraint,none,

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,10 @@ class GenericSignatureBuilder {
417417
template<typename F>
418418
void visitPotentialArchetypes(F f);
419419

420+
void markPotentialArchetypeRecursive(PotentialArchetype *pa,
421+
ProtocolDecl *proto,
422+
const RequirementSource *source);
423+
420424
public:
421425
/// Construct a new generic signature builder.
422426
///
@@ -1328,28 +1332,32 @@ class GenericSignatureBuilder::PotentialArchetype {
13281332
/// that share a name.
13291333
llvm::MapVector<Identifier, StoredNestedType> NestedTypes;
13301334

1335+
/// \brief Recursively conforms to itself.
1336+
unsigned IsRecursive : 1;
1337+
13311338
/// \brief Construct a new potential archetype for an unresolved
13321339
/// associated type.
13331340
PotentialArchetype(PotentialArchetype *parent, Identifier name);
13341341

13351342
/// \brief Construct a new potential archetype for an associated type.
13361343
PotentialArchetype(PotentialArchetype *parent, AssociatedTypeDecl *assocType)
1337-
: parentOrBuilder(parent), identifier(assocType)
1344+
: parentOrBuilder(parent), identifier(assocType), IsRecursive(false)
13381345
{
13391346
assert(parent != nullptr && "Not an associated type?");
13401347
}
13411348

13421349
/// \brief Construct a new potential archetype for a concrete declaration.
13431350
PotentialArchetype(PotentialArchetype *parent, TypeDecl *concreteDecl)
1344-
: parentOrBuilder(parent), identifier(concreteDecl)
1351+
: parentOrBuilder(parent), identifier(concreteDecl), IsRecursive(false)
13451352
{
13461353
assert(parent != nullptr && "Not an associated type?");
13471354
}
13481355

13491356
/// \brief Construct a new potential archetype for a generic parameter.
13501357
PotentialArchetype(GenericSignatureBuilder *builder,
13511358
GenericParamKey genericParam)
1352-
: parentOrBuilder(builder), identifier(genericParam)
1359+
: parentOrBuilder(builder), identifier(genericParam),
1360+
IsRecursive(false)
13531361
{
13541362
}
13551363

@@ -1592,6 +1600,9 @@ class GenericSignatureBuilder::PotentialArchetype {
15921600
return Type();
15931601
}
15941602

1603+
void setIsRecursive() { IsRecursive = true; }
1604+
bool isRecursive() const { return IsRecursive; }
1605+
15951606
LLVM_ATTRIBUTE_DEPRECATED(
15961607
void dump() const,
15971608
"only for use within the debugger");

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ namespace swift {
206206
/// Should we use \c ASTScope-based resolution for unqualified name lookup?
207207
bool EnableASTScopeLookup = false;
208208

209+
/// Enable SE-0157: Recursive Protocol Constraints.
210+
bool EnableRecursiveConstraints = false;
211+
209212
/// Whether to use the import as member inference system
210213
///
211214
/// When importing a global, try to infer whether we can import it as a

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ def disable_target_os_checking :
109109
def enable_astscope_lookup : Flag<["-"], "enable-astscope-lookup">,
110110
HelpText<"Enable ASTScope-based unqualified name lookup">;
111111

112+
def enable_recursive_constraints : Flag<["-"], "enable-recursive-constraints">,
113+
HelpText<"Enable SE-0157: Recursive Protocol Constraints">;
114+
112115
def print_clang_stats : Flag<["-"], "print-clang-stats">,
113116
HelpText<"Print Clang importer statistics">;
114117

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,6 @@ struct GenericSignatureBuilder::Implementation {
9090
/// The set of requirements that have been delayed for some reason.
9191
SmallVector<DelayedRequirement, 4> DelayedRequirements;
9292

93-
/// The generation number, which is incremented whenever we successfully
94-
/// introduce a new constraint.
95-
unsigned Generation = 0;
96-
97-
/// The generation at which we last processed all of the delayed requirements.
98-
unsigned LastProcessedGeneration = 0;
99-
10093
#ifndef NDEBUG
10194
/// Whether we've already finalized the builder.
10295
bool finalized = false;
@@ -1406,9 +1399,6 @@ bool PotentialArchetype::addConformance(ProtocolDecl *proto,
14061399
return false;
14071400
}
14081401

1409-
// Bump the generation.
1410-
++builder.Impl->Generation;
1411-
14121402
// Add the conformance along with this constraint.
14131403
equivClass->conformsTo[proto].push_back({this, proto, source});
14141404
++NumConformanceConstraints;
@@ -1876,12 +1866,6 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
18761866
if (!assocType && !concreteDecl)
18771867
return nullptr;
18781868

1879-
// If we were asked for a complete, well-formed archetype, make sure we
1880-
// process delayed requirements if anything changed.
1881-
SWIFT_DEFER {
1882-
getBuilder()->processDelayedRequirements();
1883-
};
1884-
18851869
Identifier name = assocType ? assocType->getName() : concreteDecl->getName();
18861870
ProtocolDecl *proto =
18871871
assocType ? assocType->getProtocol()
@@ -1916,9 +1900,6 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
19161900
switch (kind) {
19171901
case ArchetypeResolutionKind::CompleteWellFormed:
19181902
case ArchetypeResolutionKind::WellFormed: {
1919-
// Bump the generation count, because we created a new archetype.
1920-
++getBuilder()->Impl->Generation;
1921-
19221903
if (assocType)
19231904
resultPA = new PotentialArchetype(this, assocType);
19241905
else
@@ -2837,9 +2818,6 @@ ConstraintResult GenericSignatureBuilder::addLayoutRequirement(
28372818
return ConstraintResult::Resolved;
28382819
}
28392820

2840-
// Bump the generation.
2841-
++Impl->Generation;
2842-
28432821
auto pa = resolvedSubject->getPotentialArchetype();
28442822
return addLayoutRequirementDirect(pa, layout, source.getSource(pa));
28452823
}
@@ -2924,9 +2902,6 @@ ConstraintResult GenericSignatureBuilder::addSuperclassRequirementDirect(
29242902
.push_back(ConcreteConstraint{T, superclass, source});
29252903
++NumSuperclassConstraints;
29262904

2927-
// Bump the generation.
2928-
++Impl->Generation;
2929-
29302905
// Update the equivalence class with the constraint.
29312906
updateSuperclass(T, superclass, source);
29322907
return ConstraintResult::Resolved;
@@ -3086,9 +3061,6 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
30863061
if (T1 == T2)
30873062
return ConstraintResult::Resolved;
30883063

3089-
// Bump the generation.
3090-
++Impl->Generation;
3091-
30923064
unsigned nestingDepth1 = T1->getNestingDepth();
30933065
unsigned nestingDepth2 = T2->getNestingDepth();
30943066

@@ -3224,9 +3196,6 @@ ConstraintResult GenericSignatureBuilder::addSameTypeRequirementToConcrete(
32243196
ConcreteConstraint{T, Concrete, Source});
32253197
++NumConcreteTypeConstraints;
32263198

3227-
// Bump the generation.
3228-
++Impl->Generation;
3229-
32303199
// If we've already been bound to a type, match that type.
32313200
if (equivClass->concreteType) {
32323201
return addSameTypeRequirement(equivClass->concreteType, Concrete, Source,
@@ -3357,6 +3326,28 @@ ConstraintResult GenericSignatureBuilder::addSameTypeRequirementDirect(
33573326
}
33583327
}
33593328

3329+
// Local function to mark the given associated type as recursive,
3330+
// diagnosing it if this is the first such occurrence.
3331+
void GenericSignatureBuilder::markPotentialArchetypeRecursive(
3332+
PotentialArchetype *pa, ProtocolDecl *proto, const RequirementSource *source) {
3333+
if (pa->isRecursive())
3334+
return;
3335+
pa->setIsRecursive();
3336+
3337+
pa->addConformance(proto, source, *this);
3338+
if (!pa->getParent())
3339+
return;
3340+
3341+
auto assocType = pa->getResolvedAssociatedType();
3342+
if (!assocType || assocType->isInvalid())
3343+
return;
3344+
3345+
Diags.diagnose(assocType->getLoc(), diag::recursive_requirement_reference);
3346+
3347+
// Silence downstream errors referencing this associated type.
3348+
assocType->setInvalid();
3349+
}
3350+
33603351
ConstraintResult GenericSignatureBuilder::addInheritedRequirements(
33613352
TypeDecl *decl,
33623353
UnresolvedType type,
@@ -3407,6 +3398,26 @@ ConstraintResult GenericSignatureBuilder::addInheritedRequirements(
34073398
getFloatingSource(typeRepr, /*forInferred=*/true));
34083399
}
34093400

3401+
if (!decl->getASTContext().LangOpts.EnableRecursiveConstraints) {
3402+
// Check for direct recursion.
3403+
if (auto assocType = dyn_cast<AssociatedTypeDecl>(decl)) {
3404+
auto proto = assocType->getProtocol();
3405+
if (auto inheritedProto = inheritedType->getAs<ProtocolType>()) {
3406+
if (inheritedProto->getDecl() == proto ||
3407+
inheritedProto->getDecl()->inheritsFrom(proto)) {
3408+
auto source = getFloatingSource(typeRepr, /*forInferred=*/false);
3409+
if (auto resolved = resolve(type, source)) {
3410+
if (auto pa = resolved->getPotentialArchetype()) {
3411+
markPotentialArchetypeRecursive(pa, proto,
3412+
source.getSource(pa));
3413+
return ConstraintResult::Conflicting;
3414+
}
3415+
}
3416+
}
3417+
}
3418+
}
3419+
}
3420+
34103421
return addTypeRequirement(type, inheritedType,
34113422
getFloatingSource(typeRepr,
34123423
/*forInferred=*/false),
@@ -3967,13 +3978,6 @@ static GenericSignatureBuilder::UnresolvedType asUnresolvedType(
39673978
}
39683979

39693980
void GenericSignatureBuilder::processDelayedRequirements() {
3970-
// If we're already up-to-date, do nothing.
3971-
if (Impl->Generation == Impl->LastProcessedGeneration) return;
3972-
3973-
SWIFT_DEFER {
3974-
Impl->LastProcessedGeneration = Impl->Generation;
3975-
};
3976-
39773981
bool anySolved = !Impl->DelayedRequirements.empty();
39783982
while (anySolved) {
39793983
// Steal the delayed requirements so we can reprocess them.

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
10071007
}
10081008

10091009
Opts.EnableASTScopeLookup |= Args.hasArg(OPT_enable_astscope_lookup);
1010+
Opts.EnableRecursiveConstraints |=
1011+
Args.hasArg(OPT_enable_recursive_constraints);
10101012
Opts.DebugConstraintSolver |= Args.hasArg(OPT_debug_constraints);
10111013
Opts.EnableConstraintPropagation |= Args.hasArg(OPT_propagate_constraints);
10121014
Opts.IterativeTypeChecker |= Args.hasArg(OPT_iterative_type_checker);

test/Generics/same_type_constraints.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ extension Dictionary {
154154

155155
// rdar://problem/19245317
156156
protocol P {
157-
associatedtype T: P
157+
associatedtype T: P // expected-error{{type may not reference itself as a requirement}}
158158
}
159159

160160
struct S<A: P> {

test/decl/protocol/recursive_requirement.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// -----
44

55
protocol Foo {
6-
associatedtype Bar : Foo
6+
associatedtype Bar : Foo // expected-error{{type may not reference itself as a requirement}}
77
}
88

99
struct Oroborous : Foo {
@@ -13,7 +13,7 @@ struct Oroborous : Foo {
1313
// -----
1414

1515
protocol P {
16-
associatedtype A : P
16+
associatedtype A : P // expected-error{{type may not reference itself as a requirement}}
1717
}
1818

1919
struct X<T: P> {
@@ -26,7 +26,7 @@ func f<T : P>(_ z: T) {
2626
// -----
2727

2828
protocol PP2 {
29-
associatedtype A : P2 = Self
29+
associatedtype A : P2 = Self // expected-error{{type may not reference itself as a requirement}}
3030
}
3131

3232
protocol P2 : PP2 {
@@ -41,13 +41,13 @@ struct Y2 : P2 {
4141
}
4242

4343
func f<T : P2>(_ z: T) {
44-
_ = X2<T.A>()
44+
_ = X2<T.A>() // expected-error{{type 'T.A' does not conform to protocol 'P2'}}
4545
}
4646

4747
// -----
4848

4949
protocol P3 {
50-
associatedtype A: P4 = Self
50+
associatedtype A: P4 = Self // expected-error{{type may not reference itself as a requirement}}
5151
}
5252

5353
protocol P4 : P3 {}
Lines changed: 2 additions & 3 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 -enable-recursive-constraints
22

33
protocol P {
44
associatedtype Assoc : P
@@ -9,6 +9,5 @@ protocol P {
99
func testP<T: P>(_ t: T) {
1010
testP(t.assoc)
1111
testP(t.assoc.assoc)
12-
testP(t.assoc.assoc.assoc)
13-
testP(t.assoc.assoc.assoc.assoc.assoc.assoc.assoc)
12+
testP(t.assoc.assoc.assoc) // FIXME: expected-error{{argument type 'T.Assoc.Assoc.Assoc' does not conform to expected type 'P'}}
1413
}

0 commit comments

Comments
 (0)