Skip to content

Commit d699de6

Browse files
committed
Sema: Properly handle inference for abstract fixed type witnesses
1 parent 17169fc commit d699de6

7 files changed

+106
-38
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,9 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
334334
bool isConcreteType(Type type);
335335

336336
/// Return the concrete type that the given dependent type is constrained to,
337-
/// or the null Type if it is not the subject of a concrete same-type
338-
/// constraint.
339-
Type getConcreteType(Type type);
337+
/// the null Type if it is not the subject of a concrete same-type
338+
/// constraint, or None if the equivalence class failed to resolve.
339+
Optional<Type> maybeGetConcreteType(Type type);
340340

341341
/// Return the layout constraint that the given dependent type is constrained
342342
/// to, or the null LayoutConstraint if it is not the subject of layout

lib/AST/GenericSignature.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -467,21 +467,18 @@ bool GenericSignatureImpl::conformsToProtocol(Type type, ProtocolDecl *proto) {
467467

468468
/// Determine whether the given dependent type is equal to a concrete type.
469469
bool GenericSignatureImpl::isConcreteType(Type type) {
470-
return bool(getConcreteType(type));
470+
return bool(maybeGetConcreteType(type).getValueOr(Type()));
471471
}
472472

473-
/// Return the concrete type that the given dependent type is constrained to,
474-
/// or the null Type if it is not the subject of a concrete same-type
475-
/// constraint.
476-
Type GenericSignatureImpl::getConcreteType(Type type) {
473+
Optional<Type> GenericSignatureImpl::maybeGetConcreteType(Type type) {
477474
if (!type->isTypeParameter()) return Type();
478475

479476
auto &builder = *getGenericSignatureBuilder();
480477
auto equivClass =
481478
builder.resolveEquivalenceClass(
482479
type,
483480
ArchetypeResolutionKind::CompleteWellFormed);
484-
if (!equivClass) return Type();
481+
if (!equivClass) return None;
485482

486483
return equivClass->concreteType;
487484
}

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2165,6 +2165,18 @@ void EquivalenceClass::dump(llvm::raw_ostream &out,
21652165
}, [&] {
21662166
out << ", ";
21672167
});
2168+
if (!concreteTypeConstraints.empty()) {
2169+
out << "\nConcrete-type constraints:";
2170+
interleave(concreteTypeConstraints, [&](const Constraint<Type> &c) {
2171+
out << "\n " << c.getSubjectDependentType({ })
2172+
<< " == " << c.value;
2173+
2174+
if (c.source->isDerivedRequirement())
2175+
out << " [derived]";
2176+
}, [&] {
2177+
out << ", ";
2178+
});
2179+
}
21682180
if (concreteType)
21692181
out << "\nConcrete type: " << concreteType.getString();
21702182
if (superclass)

lib/AST/SubstitutionMap.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,8 @@ Type SubstitutionMap::lookupSubstitution(CanSubstitutableType type) const {
266266

267267
// The generic parameter may have been made concrete by the generic signature,
268268
// substitute into the concrete type.
269-
if (auto concreteType = genericSig->getConcreteType(genericParam)){
269+
if (auto concreteType = genericSig
270+
->maybeGetConcreteType(genericParam).getValueOr(Type())) {
270271
// Set the replacement type to an error, to block infinite recursion.
271272
replacementType = ErrorType::get(concreteType);
272273

lib/SIL/TypeLowering.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,9 @@ namespace {
256256
if (auto genericSig = getGenericSignature()) {
257257
if (genericSig->requiresClass(type)) {
258258
return asImpl().handleReference(type);
259-
} else if (genericSig->isConcreteType(type)) {
260-
return asImpl().visit(genericSig->getConcreteType(type)
261-
->getCanonicalType());
259+
} else if (auto concreteTy = genericSig
260+
->maybeGetConcreteType(type).getValueOr(Type())) {
261+
return asImpl().visit(concreteTy->getCanonicalType());
262262
} else {
263263
return asImpl().handleAddressOnly(type,
264264
RecursiveProperties::forOpaque());
@@ -281,7 +281,8 @@ namespace {
281281
auto signature = getGenericSignature();
282282
assert(signature && "dependent type without generic signature?!");
283283

284-
if (auto concreteType = signature->getConcreteType(type))
284+
if (auto concreteType = signature
285+
->maybeGetConcreteType(type).getValueOr(Type()))
285286
return concreteType->getCanonicalType();
286287

287288
assert(signature->requiresClass(type));

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -794,8 +794,22 @@ Type AssociatedTypeInference::computeFixedTypeWitness(
794794
auto genericSig = conformedProto->getGenericSignature();
795795
if (!genericSig) return Type();
796796

797-
Type concreteType = genericSig->getConcreteType(dependentType);
798-
if (!concreteType) continue;
797+
Type concreteType;
798+
if (auto optType = genericSig->maybeGetConcreteType(dependentType)) {
799+
if (optType.getValue()) {
800+
concreteType = optType.getValue();
801+
802+
// If this associated type has a same-type constraint
803+
// with Self, the fixed type is the adoptee.
804+
} else if (genericSig->areSameTypeParameterInContext(
805+
dependentType, proto->getSelfInterfaceType())) {
806+
concreteType = adoptee;
807+
} else {
808+
continue;
809+
}
810+
} else {
811+
continue;
812+
}
799813

800814
if (!resultType) {
801815
resultType = concreteType;
@@ -936,9 +950,16 @@ Type AssociatedTypeInference::substCurrentTypeWitnesses(Type type) {
936950
llvm::DenseSet<AssociatedTypeDecl *> recursionCheck;
937951
foldDependentMemberTypes = [&](Type type) -> Type {
938952
if (auto depMemTy = type->getAs<DependentMemberType>()) {
939-
auto baseTy = depMemTy->getBase().transform(foldDependentMemberTypes);
940-
if (baseTy.isNull() || baseTy->hasTypeParameter())
941-
return nullptr;
953+
Type baseTy;
954+
if (depMemTy->getBase()->is<GenericTypeParamType>()) {
955+
// The base type is Self.
956+
baseTy = depMemTy->getBase();
957+
} else {
958+
baseTy = depMemTy->getBase().transform(foldDependentMemberTypes);
959+
960+
if (baseTy.isNull() || baseTy->hasTypeParameter())
961+
return nullptr;
962+
}
942963

943964
auto assocType = depMemTy->getAssocType();
944965
if (!assocType)
@@ -949,21 +970,26 @@ Type AssociatedTypeInference::substCurrentTypeWitnesses(Type type) {
949970

950971
SWIFT_DEFER { recursionCheck.erase(assocType); };
951972

952-
// Try to substitute into the base type.
953-
Type result = depMemTy->substBaseType(dc->getParentModule(), baseTy);
954-
if (!result->hasError())
955-
return result;
956-
957-
// If that failed, check whether it's because of the conformance we're
958-
// evaluating.
959-
auto localConformance
960-
= TypeChecker::conformsToProtocol(
961-
baseTy, assocType->getProtocol(), dc,
962-
ConformanceCheckFlags::SkipConditionalRequirements);
963-
if (localConformance.isInvalid() || localConformance.isAbstract() ||
964-
(localConformance.getConcrete()->getRootConformance() !=
965-
conformance)) {
966-
return nullptr;
973+
// If the base type is Self, we are folding a fixed type witness, which
974+
// is to say, a witness through same-type constraints on protocols;
975+
// substituting into the base and conformance lookup are irrelevant.
976+
if (!baseTy->is<GenericTypeParamType>()) {
977+
// Try to substitute into the base type.
978+
Type result = depMemTy->substBaseType(dc->getParentModule(), baseTy);
979+
if (!result->hasError())
980+
return result;
981+
982+
// If that failed, check whether it's because of the conformance we're
983+
// evaluating.
984+
auto localConformance
985+
= TypeChecker::conformsToProtocol(
986+
baseTy, assocType->getProtocol(), dc,
987+
ConformanceCheckFlags::SkipConditionalRequirements);
988+
if (localConformance.isInvalid() || localConformance.isAbstract() ||
989+
(localConformance.getConcrete()->getRootConformance() !=
990+
conformance)) {
991+
return nullptr;
992+
}
967993
}
968994

969995
// Find the tentative type witness for this associated type.
@@ -974,10 +1000,13 @@ Type AssociatedTypeInference::substCurrentTypeWitnesses(Type type) {
9741000
return known->first.transform(foldDependentMemberTypes);
9751001
}
9761002

977-
// The presence of a generic type parameter indicates that we
978-
// cannot use this type binding.
979-
if (type->is<GenericTypeParamType>()) {
980-
return nullptr;
1003+
if (const auto genParam = type->getAs<GenericTypeParamType>()) {
1004+
bool isProtocolSelf = true;
1005+
if (const auto gpDecl = genParam->getDecl())
1006+
if (adoptee->getAnyNominal() == gpDecl->getDeclContext())
1007+
isProtocolSelf = false;
1008+
if (isProtocolSelf)
1009+
return adoptee;
9811010
}
9821011

9831012
return type;

test/Generics/protocol_where_clause.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,31 @@ protocol P2 {
7777
associatedtype AT
7878
}
7979
protocol P3: P2 where AT == Y<X> {}
80+
81+
82+
// SR-10831:
83+
struct G<T> {}
84+
85+
protocol SR10831_P1 {
86+
associatedtype A
87+
associatedtype B
88+
associatedtype C
89+
}
90+
91+
protocol SR10831_P2: SR10831_P1 where A == G<G<C?>> {}
92+
protocol SR10831_P3: SR10831_P2 where B == Int, C == G<B> {}
93+
94+
struct SR10831: SR10831_P3 {} // OK
95+
96+
97+
// SR-11671:
98+
protocol SR11671_P1 {
99+
associatedtype A
100+
associatedtype B
101+
}
102+
protocol SR11671_P2: SR11671_P1 where A == Self {}
103+
protocol SR11671_P3: SR11671_P2 where B == G<Self?> {}
104+
105+
struct SR11671_S1: SR11671_P3 {} // OK
106+
107+
struct SR11671_S2<T, U>: SR11671_P3 {} // OK

0 commit comments

Comments
 (0)