Skip to content

Commit b690056

Browse files
Merge pull request #42004 from AnthonyLatsis/type-witness-system-flagged
TypeWitnessSystem: Disable by default
2 parents 048e41e + f37ac3e commit b690056

File tree

8 files changed

+1152
-336
lines changed

8 files changed

+1152
-336
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,10 @@ namespace swift {
352352
/// Enable variadic generics.
353353
bool EnableExperimentalVariadicGenerics = false;
354354

355+
/// Enable experimental associated type inference using type witness
356+
/// systems.
357+
bool EnableExperimentalAssociatedTypeInference = false;
358+
355359
/// Disable the implicit import of the _Concurrency module.
356360
bool DisableImplicitConcurrencyModuleImport =
357361
!SWIFT_IMPLICIT_CONCURRENCY_IMPORT;

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,10 @@ def enable_experimental_variadic_generics :
556556
Flag<["-"], "enable-experimental-variadic-generics">,
557557
HelpText<"Enable experimental support for variadic generic types">;
558558

559+
def enable_experimental_associated_type_inference :
560+
Flag<["-"], "enable-experimental-associated-type-inference">,
561+
HelpText<"Enable experimental associated type inference via type witness systems">;
562+
559563
def disable_availability_checking : Flag<["-"],
560564
"disable-availability-checking">,
561565
HelpText<"Disable checking for potentially unavailable APIs">;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
459459
Opts.EnableExperimentalVariadicGenerics |=
460460
Args.hasArg(OPT_enable_experimental_variadic_generics);
461461

462+
Opts.EnableExperimentalAssociatedTypeInference |=
463+
Args.hasArg(OPT_enable_experimental_associated_type_inference);
464+
462465
Opts.EnableExperimentalMoveOnly |=
463466
Args.hasArg(OPT_enable_experimental_move_only);
464467

lib/Sema/TypeCheckProtocol.h

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,35 @@ CheckTypeWitnessResult checkTypeWitness(Type type,
100100
const NormalProtocolConformance *Conf,
101101
SubstOptions options = None);
102102

103+
/// A type witness inferred without the aid of a specific potential
104+
/// value witness.
105+
class AbstractTypeWitness {
106+
AssociatedTypeDecl *AssocType;
107+
Type TheType;
108+
109+
/// The defaulted associated type that was used to infer this type witness.
110+
/// Need not necessarilly match \c AssocType, but their names must.
111+
AssociatedTypeDecl *DefaultedAssocType;
112+
113+
public:
114+
AbstractTypeWitness(AssociatedTypeDecl *AssocType, Type TheType,
115+
AssociatedTypeDecl *DefaultedAssocType = nullptr)
116+
: AssocType(AssocType), TheType(TheType),
117+
DefaultedAssocType(DefaultedAssocType) {
118+
assert(AssocType && TheType);
119+
assert(!DefaultedAssocType ||
120+
(AssocType->getName() == DefaultedAssocType->getName()));
121+
}
122+
123+
AssociatedTypeDecl *getAssocType() const { return AssocType; }
124+
125+
Type getType() const { return TheType; }
126+
127+
AssociatedTypeDecl *getDefaultedAssocType() const {
128+
return DefaultedAssocType;
129+
}
130+
};
131+
103132
/// The set of associated types that have been inferred by matching
104133
/// the given value witness to its corresponding requirement.
105134
struct InferredAssociatedTypesByWitness {
@@ -916,7 +945,7 @@ class TypeWitnessSystem final {
916945
struct TypeWitnessCandidate final {
917946
/// The defaulted associated type declaration correlating with this
918947
/// candidate, if present.
919-
const AssociatedTypeDecl *DefaultedAssocType;
948+
AssociatedTypeDecl *DefaultedAssocType;
920949

921950
/// The equivalence class of this candidate.
922951
EquivalenceClass *EquivClass;
@@ -944,7 +973,7 @@ class TypeWitnessSystem final {
944973

945974
/// Get the defaulted associated type relating to the resolved type witness
946975
/// for the associated type with the given name, if present.
947-
const AssociatedTypeDecl *getDefaultedAssocType(Identifier name) const;
976+
AssociatedTypeDecl *getDefaultedAssocType(Identifier name) const;
948977

949978
/// Record a type witness for the given associated type name.
950979
///
@@ -958,8 +987,7 @@ class TypeWitnessSystem final {
958987
/// defines the given default type.
959988
///
960989
/// \note This need not lead to the resolution of a type witness.
961-
void addDefaultTypeWitness(Type type,
962-
const AssociatedTypeDecl *defaultedAssocType);
990+
void addDefaultTypeWitness(Type type, AssociatedTypeDecl *defaultedAssocType);
963991

964992
/// Record the given same-type requirement, if regarded of interest to
965993
/// the system.
@@ -1076,16 +1104,24 @@ class AssociatedTypeInference {
10761104
ConformanceChecker &checker,
10771105
const llvm::SetVector<AssociatedTypeDecl *> &assocTypes);
10781106

1107+
/// Compute a "fixed" type witness for an associated type, e.g.,
1108+
/// if the refined protocol requires it to be equivalent to some other type.
1109+
Type computeFixedTypeWitness(AssociatedTypeDecl *assocType);
1110+
10791111
/// Compute the default type witness from an associated type default,
10801112
/// if there is one.
1081-
Optional<std::pair<AssociatedTypeDecl *, Type>>
1113+
Optional<AbstractTypeWitness>
10821114
computeDefaultTypeWitness(AssociatedTypeDecl *assocType) const;
10831115

10841116
/// Compute the "derived" type witness for an associated type that is
10851117
/// known to the compiler.
10861118
std::pair<Type, TypeDecl *>
10871119
computeDerivedTypeWitness(AssociatedTypeDecl *assocType);
10881120

1121+
/// Compute a type witness without using a specific potential witness.
1122+
Optional<AbstractTypeWitness>
1123+
computeAbstractTypeWitness(AssociatedTypeDecl *assocType);
1124+
10891125
/// Collect abstract type witnesses and feed them to the given system.
10901126
void collectAbstractTypeWitnesses(
10911127
TypeWitnessSystem &system,

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 134 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,56 @@ AssociatedTypeDecl *AssociatedTypeInference::findDefaultedAssociatedType(
798798
return results.size() == 1 ? results.front() : nullptr;
799799
}
800800

801-
Optional<std::pair<AssociatedTypeDecl *, Type>>
801+
Type AssociatedTypeInference::computeFixedTypeWitness(
802+
AssociatedTypeDecl *assocType) {
803+
Type resultType;
804+
805+
// Look at all of the inherited protocols to determine whether they
806+
// require a fixed type for this associated type.
807+
for (auto conformedProto : adoptee->getAnyNominal()->getAllProtocols()) {
808+
if (conformedProto != assocType->getProtocol() &&
809+
!conformedProto->inheritsFrom(assocType->getProtocol()))
810+
continue;
811+
812+
auto sig = conformedProto->getGenericSignature();
813+
814+
// FIXME: The RequirementMachine will assert on re-entrant construction.
815+
// We should find a more principled way of breaking this cycle.
816+
if (ctx.isRecursivelyConstructingRequirementMachine(sig.getCanonicalSignature()) ||
817+
ctx.isRecursivelyConstructingRequirementMachine(conformedProto) ||
818+
conformedProto->isComputingRequirementSignature())
819+
continue;
820+
821+
auto selfTy = conformedProto->getSelfInterfaceType();
822+
if (!sig->requiresProtocol(selfTy, assocType->getProtocol()))
823+
continue;
824+
825+
auto structuralTy = DependentMemberType::get(selfTy, assocType->getName());
826+
const auto ty = sig.getCanonicalTypeInContext(structuralTy);
827+
828+
// A dependent member type with an identical base and name indicates that
829+
// the protocol does not same-type constrain it in any way; move on to
830+
// the next protocol.
831+
if (auto *const memberTy = ty->getAs<DependentMemberType>()) {
832+
if (memberTy->getBase()->isEqual(selfTy) &&
833+
memberTy->getName() == assocType->getName())
834+
continue;
835+
}
836+
837+
if (!resultType) {
838+
resultType = ty;
839+
continue;
840+
}
841+
842+
// FIXME: Bailing out on ambiguity.
843+
if (!resultType->isEqual(ty))
844+
return Type();
845+
}
846+
847+
return resultType;
848+
}
849+
850+
Optional<AbstractTypeWitness>
802851
AssociatedTypeInference::computeDefaultTypeWitness(
803852
AssociatedTypeDecl *assocType) const {
804853
// Go find a default definition.
@@ -814,7 +863,7 @@ AssociatedTypeInference::computeDefaultTypeWitness(
814863
if (defaultType->hasError())
815864
return None;
816865

817-
return std::make_pair(defaultedAssocType, defaultType);
866+
return AbstractTypeWitness(assocType, defaultType, defaultedAssocType);
818867
}
819868

820869
std::pair<Type, TypeDecl *>
@@ -845,6 +894,29 @@ AssociatedTypeInference::computeDerivedTypeWitness(
845894
return result;
846895
}
847896

897+
Optional<AbstractTypeWitness>
898+
AssociatedTypeInference::computeAbstractTypeWitness(
899+
AssociatedTypeDecl *assocType) {
900+
// We don't have a type witness for this associated type, so go
901+
// looking for more options.
902+
if (Type concreteType = computeFixedTypeWitness(assocType))
903+
return AbstractTypeWitness(assocType, concreteType);
904+
905+
// If we can form a default type, do so.
906+
if (const auto &typeWitness = computeDefaultTypeWitness(assocType))
907+
return typeWitness;
908+
909+
// If there is a generic parameter of the named type, use that.
910+
if (auto genericSig = dc->getGenericSignatureOfContext()) {
911+
for (auto gp : genericSig.getInnermostGenericParams()) {
912+
if (gp->getName() == assocType->getName())
913+
return AbstractTypeWitness(assocType, gp);
914+
}
915+
}
916+
917+
return None;
918+
}
919+
848920
void AssociatedTypeInference::collectAbstractTypeWitnesses(
849921
TypeWitnessSystem &system,
850922
ArrayRef<AssociatedTypeDecl *> unresolvedAssocTypes) const {
@@ -878,8 +950,9 @@ void AssociatedTypeInference::collectAbstractTypeWitnesses(
878950
}
879951

880952
// If we find a default type definition, feed it to the system.
881-
if (const auto declAndType = computeDefaultTypeWitness(assocType)) {
882-
system.addDefaultTypeWitness(declAndType->second, declAndType->first);
953+
if (const auto &typeWitness = computeDefaultTypeWitness(assocType)) {
954+
system.addDefaultTypeWitness(typeWitness->getType(),
955+
typeWitness->getDefaultedAssocType());
883956
} else {
884957
// As a last resort, look for a generic parameter that matches the name
885958
// of the associated type.
@@ -1128,26 +1201,56 @@ AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses(
11281201
return nullptr;
11291202
}
11301203

1131-
TypeWitnessSystem system(unresolvedAssocTypes);
1132-
collectAbstractTypeWitnesses(system, unresolvedAssocTypes);
1204+
// Attempt to compute abstract type witnesses for associated types that could
1205+
// not resolve otherwise.
1206+
llvm::SmallVector<AbstractTypeWitness, 2> abstractTypeWitnesses;
11331207

1134-
if (ctx.LangOpts.DumpTypeWitnessSystems) {
1135-
system.dump(llvm::dbgs(), conformance);
1136-
}
1208+
if (ctx.LangOpts.EnableExperimentalAssociatedTypeInference) {
1209+
TypeWitnessSystem system(unresolvedAssocTypes);
1210+
collectAbstractTypeWitnesses(system, unresolvedAssocTypes);
11371211

1138-
// If we couldn't resolve an associated type, bail out.
1139-
for (auto *assocType : unresolvedAssocTypes) {
1140-
if (!system.hasResolvedTypeWitness(assocType->getName())) {
1141-
return assocType;
1212+
if (ctx.LangOpts.DumpTypeWitnessSystems) {
1213+
system.dump(llvm::dbgs(), conformance);
11421214
}
1143-
}
11441215

1145-
// Record the tentative type witnesses to make them available during
1146-
// substitutions.
1147-
for (auto *assocType : unresolvedAssocTypes) {
1148-
typeWitnesses.insert(
1149-
assocType,
1150-
{system.getResolvedTypeWitness(assocType->getName()), reqDepth});
1216+
// If we couldn't resolve an associated type, bail out.
1217+
for (auto *assocType : unresolvedAssocTypes) {
1218+
if (!system.hasResolvedTypeWitness(assocType->getName())) {
1219+
return assocType;
1220+
}
1221+
}
1222+
1223+
// Record the tentative type witnesses to make them available during
1224+
// substitutions.
1225+
for (auto *assocType : unresolvedAssocTypes) {
1226+
auto resolvedTy = system.getResolvedTypeWitness(assocType->getName());
1227+
1228+
typeWitnesses.insert(assocType, {resolvedTy, reqDepth});
1229+
1230+
if (auto *defaultedAssocType =
1231+
system.getDefaultedAssocType(assocType->getName())) {
1232+
abstractTypeWitnesses.emplace_back(assocType, resolvedTy,
1233+
defaultedAssocType);
1234+
} else {
1235+
abstractTypeWitnesses.emplace_back(assocType, resolvedTy);
1236+
}
1237+
}
1238+
} else {
1239+
for (auto *const assocType : unresolvedAssocTypes) {
1240+
// Try to compute the type without the aid of a specific potential
1241+
// witness.
1242+
if (const auto &typeWitness = computeAbstractTypeWitness(assocType)) {
1243+
// Record the type witness immediately to make it available
1244+
// for substitutions into other tentative type witnesses.
1245+
typeWitnesses.insert(assocType, {typeWitness->getType(), reqDepth});
1246+
1247+
abstractTypeWitnesses.push_back(std::move(typeWitness.getValue()));
1248+
continue;
1249+
}
1250+
1251+
// The solution is incomplete.
1252+
return assocType;
1253+
}
11511254
}
11521255

11531256
// Check each abstract type witness against the generic requirements on the
@@ -1164,8 +1267,10 @@ AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses(
11641267
// associatedtype B: Sequence = Never
11651268
// }
11661269
const auto substOptions = getSubstOptionsWithCurrentTypeWitnesses();
1167-
for (auto *const assocType : unresolvedAssocTypes) {
1168-
Type type = system.getResolvedTypeWitness(assocType->getName());
1270+
for (const auto &witness : abstractTypeWitnesses) {
1271+
auto *const assocType = witness.getAssocType();
1272+
Type type = witness.getType();
1273+
11691274
// Replace type parameters with other known or tentative type witnesses.
11701275
if (type->hasTypeParameter()) {
11711276
// FIXME: We should find a better way to detect and reason about these
@@ -1177,7 +1282,10 @@ AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses(
11771282
std::function<Type(Type)> substCurrentTypeWitnesses;
11781283
substCurrentTypeWitnesses = [&](Type ty) -> Type {
11791284
if (auto *gp = ty->getAs<GenericTypeParamType>()) {
1180-
if (isa<ProtocolDecl>(gp->getDecl()->getDeclContext()->getAsDecl())) {
1285+
// FIXME: 'computeFixedTypeWitness' uses 'getCanonicalTypeInContext',
1286+
// so if a generic parameter is canonical here, it's 'Self'.
1287+
if (gp->isCanonical() ||
1288+
isa<ProtocolDecl>(gp->getDecl()->getDeclContext()->getAsDecl())) {
11811289
return adoptee;
11821290
}
11831291

@@ -1282,8 +1390,7 @@ AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses(
12821390
checkTypeWitness(type, assocType, conformance, substOptions)) {
12831391
// We failed to satisfy a requirement. If this is a default type
12841392
// witness failure and we haven't seen one already, write it down.
1285-
auto *defaultedAssocType =
1286-
system.getDefaultedAssocType(assocType->getName());
1393+
auto *defaultedAssocType = witness.getDefaultedAssocType();
12871394
if (defaultedAssocType && !failedDefaultedAssocType &&
12881395
!failed.isError()) {
12891396
failedDefaultedAssocType = defaultedAssocType;
@@ -2187,7 +2294,7 @@ Type TypeWitnessSystem::getResolvedTypeWitness(Identifier name) const {
21872294
return Type();
21882295
}
21892296

2190-
const AssociatedTypeDecl *
2297+
AssociatedTypeDecl *
21912298
TypeWitnessSystem::getDefaultedAssocType(Identifier name) const {
21922299
assert(this->TypeWitnesses.count(name));
21932300

@@ -2268,7 +2375,7 @@ void TypeWitnessSystem::addTypeWitness(Identifier name, Type type) {
22682375
}
22692376

22702377
void TypeWitnessSystem::addDefaultTypeWitness(
2271-
Type type, const AssociatedTypeDecl *defaultedAssocType) {
2378+
Type type, AssociatedTypeDecl *defaultedAssocType) {
22722379
const auto name = defaultedAssocType->getName();
22732380
assert(this->TypeWitnesses.count(name));
22742381

0 commit comments

Comments
 (0)