Skip to content

Commit e6d1ef9

Browse files
authored
Merge pull request #41868 from slavapestov/rqm-opaque-archetypes
RequirementMachine: Opaque archetype support (sort of)
2 parents 61da992 + 2f727d6 commit e6d1ef9

13 files changed

+213
-55
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,11 @@ namespace swift {
549549
/// if you have a testcase which requires this, please submit a bug report.
550550
bool EnableRequirementMachineLoopNormalization = false;
551551

552+
/// Enable experimental, more correct support for opaque result types as
553+
/// concrete types. This will sometimes fail to produce a convergent
554+
/// rewrite system.
555+
bool EnableRequirementMachineOpaqueArchetypes = false;
556+
552557
/// Enables dumping type witness systems from associated type inference.
553558
bool DumpTypeWitnessSystems = false;
554559

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,9 @@ def disable_requirement_machine_concrete_contraction : Flag<["-"], "disable-requ
362362
def enable_requirement_machine_loop_normalization : Flag<["-"], "enable-requirement-machine-loop-normalization">,
363363
HelpText<"Enable stronger minimization algorithm, for debugging only">;
364364

365+
def enable_requirement_machine_opaque_archetypes : Flag<["-"], "enable-requirement-machine-opaque-archetypes">,
366+
HelpText<"Enable more correct opaque archetype support, which is off by default because it might fail to produce a convergent rewrite system">;
367+
365368
def dump_type_witness_systems : Flag<["-"], "dump-type-witness-systems">,
366369
HelpText<"Enables dumping type witness systems from associated type inference">;
367370

lib/AST/RequirementMachine/ConcreteContraction.cpp

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -235,19 +235,10 @@ Optional<Type> ConcreteContraction::substTypeParameter(
235235
->substBaseType(module, *substBaseType);
236236
}
237237

238-
auto *decl = (*substBaseType)->getAnyNominal();
239-
if (decl == nullptr) {
240-
if (Debug) {
241-
llvm::dbgs() << "@@@ Not a nominal type: " << *substBaseType << "\n";
242-
}
243-
244-
return None;
245-
}
246-
247238
// An unresolved DependentMemberType stores an identifier. Handle this
248239
// by performing a name lookup into the base type.
249240
SmallVector<TypeDecl *> concreteDecls;
250-
lookupConcreteNestedType(decl, memberType->getName(), concreteDecls);
241+
lookupConcreteNestedType(*substBaseType, memberType->getName(), concreteDecls);
251242

252243
auto *typeDecl = findBestConcreteNestedType(concreteDecls);
253244
if (typeDecl == nullptr) {
@@ -261,8 +252,9 @@ Optional<Type> ConcreteContraction::substTypeParameter(
261252
}
262253

263254
// Substitute the base type into the member type.
255+
auto *dc = typeDecl->getDeclContext();
264256
auto subMap = (*substBaseType)->getContextSubstitutionMap(
265-
decl->getParentModule(), typeDecl->getDeclContext());
257+
dc->getParentModule(), dc);
266258
return typeDecl->getDeclaredInterfaceType().subst(subMap);
267259
}
268260

lib/AST/RequirementMachine/ConcreteTypeWitness.cpp

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,7 @@ void PropertyMap::concretizeNestedTypesFromConcreteParent(
132132
//
133133
// This occurs when a pair of rules are inherited from the property map
134134
// entry for this key's suffix.
135-
auto pair = std::make_pair(concreteRuleID, conformanceRuleID);
136-
auto found = ConcreteConformances.find(pair);
137-
if (found != ConcreteConformances.end())
135+
if (!checkRulePairOnce(concreteRuleID, conformanceRuleID))
138136
continue;
139137

140138
// FIXME: Either remove the ModuleDecl entirely from conformance lookup,
@@ -164,40 +162,44 @@ void PropertyMap::concretizeNestedTypesFromConcreteParent(
164162
continue;
165163
}
166164

167-
// FIXME: Maybe this can happen if the concrete type is an
168-
// opaque result type?
169-
assert(!conformance.isAbstract());
170-
171-
// Save this conformance for later.
172-
auto *concrete = conformance.getConcrete();
173-
auto inserted = ConcreteConformances.insert(
174-
std::make_pair(pair, concrete));
175-
assert(inserted.second);
176-
(void) inserted;
177-
178165
auto concreteConformanceSymbol = Symbol::forConcreteConformance(
179166
concreteType, substitutions, proto, Context);
180167

181168
recordConcreteConformanceRule(concreteRuleID, conformanceRuleID,
182169
requirementKind, concreteConformanceSymbol);
183170

171+
// This is disabled by default because we fail to produce a convergent
172+
// rewrite system if the opaque archetype has infinitely-recursive
173+
// nested types. Fixing this requires a better representation for
174+
// concrete conformances in the rewrite system.
175+
if (conformance.isAbstract() &&
176+
!Context.getASTContext().LangOpts.EnableRequirementMachineOpaqueArchetypes) {
177+
if (Debug.contains(DebugFlags::ConcretizeNestedTypes)) {
178+
llvm::dbgs() << "^^ " << "Skipping abstract conformance of "
179+
<< concreteType << " to " << proto->getName() << "\n";
180+
}
181+
182+
continue;
183+
}
184+
184185
for (auto *assocType : proto->getAssociatedTypeMembers()) {
185186
concretizeTypeWitnessInConformance(key, requirementKind,
186187
concreteConformanceSymbol,
187-
concrete, assocType);
188+
conformance, assocType);
188189
}
189190

190191
// We only infer conditional requirements in top-level generic signatures,
191192
// not in protocol requirement signatures.
192-
if (key.getRootProtocol() == nullptr)
193-
inferConditionalRequirements(concrete, substitutions);
193+
if (conformance.isConcrete() &&
194+
key.getRootProtocol() == nullptr)
195+
inferConditionalRequirements(conformance.getConcrete(), substitutions);
194196
}
195197
}
196198

197199
void PropertyMap::concretizeTypeWitnessInConformance(
198200
Term key, RequirementKind requirementKind,
199201
Symbol concreteConformanceSymbol,
200-
ProtocolConformance *concrete,
202+
ProtocolConformanceRef conformance,
201203
AssociatedTypeDecl *assocType) const {
202204
auto concreteType = concreteConformanceSymbol.getConcreteType();
203205
auto substitutions = concreteConformanceSymbol.getSubstitutions();
@@ -211,17 +213,35 @@ void PropertyMap::concretizeTypeWitnessInConformance(
211213
<< " on " << concreteType << "\n";
212214
}
213215

214-
auto t = concrete->getTypeWitness(assocType);
215-
if (!t) {
216-
if (Debug.contains(DebugFlags::ConcretizeNestedTypes)) {
217-
llvm::dbgs() << "^^ " << "Type witness for " << assocType->getName()
218-
<< " of " << concreteType << " could not be inferred\n";
216+
CanType typeWitness;
217+
if (conformance.isConcrete()) {
218+
auto t = conformance.getConcrete()->getTypeWitness(assocType);
219+
220+
if (!t) {
221+
if (Debug.contains(DebugFlags::ConcretizeNestedTypes)) {
222+
llvm::dbgs() << "^^ " << "Type witness for " << assocType->getName()
223+
<< " of " << concreteType << " could not be inferred\n";
224+
}
225+
226+
t = ErrorType::get(concreteType);
219227
}
220228

221-
t = ErrorType::get(concreteType);
222-
}
229+
typeWitness = t->getCanonicalType();
230+
} else if (conformance.isAbstract()) {
231+
auto archetype = concreteType->getAs<OpaqueTypeArchetypeType>();
232+
if (archetype == nullptr) {
233+
llvm::errs() << "Should only have an abstract conformance with an "
234+
<< "opaque archetype type\n";
235+
llvm::errs() << "Symbol: " << concreteConformanceSymbol << "\n";
236+
llvm::errs() << "Term: " << key << "\n";
237+
dump(llvm::errs());
238+
abort();
239+
}
223240

224-
auto typeWitness = t->getCanonicalType();
241+
typeWitness = archetype->getNestedType(assocType)->getCanonicalType();
242+
} else if (conformance.isInvalid()) {
243+
typeWitness = CanType(ErrorType::get(Context.getASTContext()));
244+
}
225245

226246
if (Debug.contains(DebugFlags::ConcretizeNestedTypes)) {
227247
llvm::dbgs() << "^^ " << "Type witness for " << assocType->getName()

lib/AST/RequirementMachine/GenericSignatureQueries.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "swift/AST/ASTContext.h"
1919
#include "swift/AST/Decl.h"
20+
#include "swift/AST/GenericEnvironment.h"
2021
#include "swift/AST/GenericSignature.h"
2122
#include "swift/AST/Module.h"
2223
#include <vector>
@@ -659,8 +660,7 @@ RequirementMachine::lookupNestedType(Type depType, Identifier name) const {
659660
typeToSearch = props->getSuperclassBound();
660661

661662
if (typeToSearch)
662-
if (auto *decl = typeToSearch->getAnyNominal())
663-
lookupConcreteNestedType(decl, name, concreteDecls);
663+
lookupConcreteNestedType(typeToSearch, name, concreteDecls);
664664
}
665665

666666
if (bestAssocType) {

lib/AST/RequirementMachine/NameLookup.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,33 @@
1212

1313
#include "NameLookup.h"
1414
#include "swift/AST/Decl.h"
15+
#include "swift/AST/GenericEnvironment.h"
1516
#include "swift/AST/Module.h"
17+
#include "swift/AST/Types.h"
1618
#include "llvm/ADT/SmallVector.h"
1719
#include <algorithm>
1820

1921
using namespace swift;
2022
using namespace rewriting;
2123

24+
void
25+
swift::rewriting::lookupConcreteNestedType(
26+
Type baseType,
27+
Identifier name,
28+
SmallVectorImpl<TypeDecl *> &concreteDecls) {
29+
if (auto *decl = baseType->getAnyNominal())
30+
lookupConcreteNestedType(decl, name, concreteDecls);
31+
else if (auto *archetype = baseType->getAs<OpaqueTypeArchetypeType>()) {
32+
// If our concrete type is an opaque result archetype, look into its
33+
// generic environment recursively.
34+
auto *genericEnv = archetype->getGenericEnvironment();
35+
auto genericSig = genericEnv->getGenericSignature();
36+
37+
concreteDecls.push_back(
38+
genericSig->lookupNestedType(archetype->getInterfaceType(), name));
39+
}
40+
}
41+
2242
void
2343
swift::rewriting::lookupConcreteNestedType(
2444
NominalTypeDecl *decl,

lib/AST/RequirementMachine/NameLookup.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,16 @@ namespace swift {
1919

2020
class Identifier;
2121
class NominalTypeDecl;
22+
class Type;
2223
class TypeDecl;
2324

2425
namespace rewriting {
2526

27+
void lookupConcreteNestedType(
28+
Type baseType,
29+
Identifier name,
30+
llvm::SmallVectorImpl<TypeDecl *> &concreteDecls);
31+
2632
void lookupConcreteNestedType(
2733
NominalTypeDecl *decl,
2834
Identifier name,

lib/AST/RequirementMachine/PropertyMap.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,6 @@ class PropertyMap {
174174
// To avoid wasted work from re-introducing the same induced rules,
175175
// we track the rules we've seen already on previous builds.
176176

177-
/// Maps a pair of rules where the first is a conformance rule and the
178-
/// second is a superclass or concrete type rule, to a concrete
179-
/// conformance.
180-
llvm::DenseMap<std::pair<unsigned, unsigned>, ProtocolConformance *>
181-
ConcreteConformances;
182-
183177
/// Superclass requirements always imply a layout requirement, and
184178
/// concrete type requirements where the type is a class imply a
185179
/// superclass requirement.
@@ -291,7 +285,7 @@ class PropertyMap {
291285
void concretizeTypeWitnessInConformance(
292286
Term key, RequirementKind requirementKind,
293287
Symbol concreteConformanceSymbol,
294-
ProtocolConformance *concrete,
288+
ProtocolConformanceRef conformance,
295289
AssociatedTypeDecl *assocType) const;
296290

297291
void inferConditionalRequirements(

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,13 @@ static void desugarConformanceRequirement(Type subjectType, Type constraintType,
168168
errors.push_back(RequirementError::forRedundantRequirement(
169169
{RequirementKind::Conformance, subjectType, constraintType}, loc));
170170

171-
assert(conformance.isConcrete());
172-
auto *concrete = conformance.getConcrete();
173-
174-
// Introduce conditional requirements if the subject type is concrete.
175-
for (auto req : concrete->getConditionalRequirements()) {
176-
desugarRequirement(req, result, errors);
171+
if (conformance.isConcrete()) {
172+
// Introduce conditional requirements if the conformance is concrete.
173+
for (auto req : conformance.getConcrete()->getConditionalRequirements()) {
174+
desugarRequirement(req, result, errors);
175+
}
177176
}
177+
178178
return;
179179
}
180180

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
10071007
if (Args.hasArg(OPT_enable_requirement_machine_loop_normalization))
10081008
Opts.EnableRequirementMachineLoopNormalization = true;
10091009

1010+
if (Args.hasArg(OPT_enable_requirement_machine_opaque_archetypes))
1011+
Opts.EnableRequirementMachineOpaqueArchetypes = true;
1012+
10101013
Opts.DumpTypeWitnessSystems = Args.hasArg(OPT_dump_type_witness_systems);
10111014

10121015
return HadError || UnsupportedOS || UnsupportedArch;

0 commit comments

Comments
 (0)