Skip to content

Commit b44f24d

Browse files
committed
[Type checker] Re-validate typealiases in protocols after protocol validation.
Validation for typealiases in protocols is... odd. It needs to avoid depending on the whole protocol being validated, so it does an initial validation that can leave nested types of Self (and other associated types) somewhat unresolved. In these cases, do something icky but partially effective: when we resolve the protocol, go back and clean up the types of these typealiases. A better solution would allow us to use the types of these typealiases within the Generic Signature Builder without recording them in the AST as "the interface type", so there's no way unresolved nested types could be found (and, therefore, nothing to "fix up" later). Howwever, that's a more significant undertaking. Fixes rdar://problem/32287795.
1 parent 7b56977 commit b44f24d

File tree

4 files changed

+73
-20
lines changed

4 files changed

+73
-20
lines changed

lib/AST/Type.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3623,6 +3623,9 @@ case TypeKind::Id:
36233623
case TypeKind::NameAlias: {
36243624
auto alias = cast<NameAliasType>(base);
36253625
auto underlyingTy = Type(alias->getSinglyDesugaredType());
3626+
if (!underlyingTy)
3627+
return Type();
3628+
36263629
auto transformedTy = underlyingTy.transformRec(fn);
36273630
if (!transformedTy)
36283631
return Type();

lib/Sema/TypeCheckDecl.cpp

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6954,6 +6954,18 @@ bool swift::checkOverrides(TypeChecker &TC, ValueDecl *decl) {
69546954
return DeclChecker::checkOverrides(TC, decl);
69556955
}
69566956

6957+
/// Determine whether the given type contains an unresolved dependent member
6958+
/// type.
6959+
static bool hasUnresolvedDependentMemberType(Type type) {
6960+
return type.findIf([](Type type) {
6961+
if (auto depMemTy = type->getAs<DependentMemberType>()) {
6962+
if (!depMemTy->getAssocType()) return true;
6963+
}
6964+
6965+
return false;
6966+
});
6967+
}
6968+
69576969
bool TypeChecker::isAvailabilitySafeForOverride(ValueDecl *override,
69586970
ValueDecl *base) {
69596971
// API availability ranges are contravariant: make sure the version range
@@ -7054,6 +7066,27 @@ static Optional<ObjCReason> shouldMarkClassAsObjC(TypeChecker &TC,
70547066
return None;
70557067
}
70567068

7069+
/// Validate the underlying type of the given typealias.
7070+
static void validateTypealiasType(TypeChecker &tc, TypeAliasDecl *typeAlias) {
7071+
TypeResolutionOptions options = TR_TypeAliasUnderlyingType;
7072+
if (typeAlias->getFormalAccess() <= Accessibility::FilePrivate)
7073+
options |= TR_KnownNonCascadingDependency;
7074+
7075+
if (typeAlias->getDeclContext()->isModuleScopeContext() &&
7076+
typeAlias->getGenericParams() == nullptr) {
7077+
IterativeTypeChecker ITC(tc);
7078+
ITC.satisfy(requestResolveTypeDecl(typeAlias));
7079+
} else {
7080+
if (tc.validateType(typeAlias->getUnderlyingTypeLoc(),
7081+
typeAlias, options)) {
7082+
typeAlias->setInvalid();
7083+
typeAlias->getUnderlyingTypeLoc().setInvalidType(tc.Context);
7084+
}
7085+
7086+
typeAlias->setUnderlyingType(typeAlias->getUnderlyingTypeLoc().getType());
7087+
}
7088+
}
7089+
70577090
void TypeChecker::validateDecl(ValueDecl *D) {
70587091
// Generic parameters are validated as part of their context.
70597092
if (isa<GenericTypeParamDecl>(D))
@@ -7161,25 +7194,7 @@ void TypeChecker::validateDecl(ValueDecl *D) {
71617194
SWIFT_DEFER { typeAlias->setIsBeingValidated(false); };
71627195

71637196
validateGenericTypeSignature(typeAlias);
7164-
7165-
TypeResolutionOptions options = TR_TypeAliasUnderlyingType;
7166-
if (typeAlias->getFormalAccess() <= Accessibility::FilePrivate)
7167-
options |= TR_KnownNonCascadingDependency;
7168-
7169-
if (typeAlias->getDeclContext()->isModuleScopeContext() &&
7170-
typeAlias->getGenericParams() == nullptr) {
7171-
IterativeTypeChecker ITC(*this);
7172-
ITC.satisfy(requestResolveTypeDecl(typeAlias));
7173-
} else {
7174-
if (validateType(typeAlias->getUnderlyingTypeLoc(),
7175-
typeAlias, options)) {
7176-
typeAlias->setInvalid();
7177-
typeAlias->getUnderlyingTypeLoc().setInvalidType(Context);
7178-
}
7179-
7180-
typeAlias->setUnderlyingType(typeAlias->getUnderlyingTypeLoc().getType());
7181-
}
7182-
7197+
validateTypealiasType(*this, typeAlias);
71837198
break;
71847199
}
71857200

@@ -7246,8 +7261,28 @@ void TypeChecker::validateDecl(ValueDecl *D) {
72467261
// FIXME: Hopefully this can all go away with the ITC.
72477262
for (auto member : proto->getMembers()) {
72487263
if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(member)) {
7249-
if (!aliasDecl->isGeneric())
7264+
if (!aliasDecl->isGeneric()) {
72507265
aliasDecl->setGenericEnvironment(proto->getGenericEnvironment());
7266+
7267+
// If the underlying alias declaration has a type parameter,
7268+
// we have unresolved dependent member types we will need to deal
7269+
// with. Wipe out the types and validate them again.
7270+
// FIXME: We never should have recorded such a type in the first
7271+
// place.
7272+
if (!aliasDecl->getUnderlyingTypeLoc().getType() ||
7273+
hasUnresolvedDependentMemberType(
7274+
aliasDecl->getUnderlyingTypeLoc().getType())) {
7275+
aliasDecl->getUnderlyingTypeLoc().setType(Type(),
7276+
/*validated=*/false);
7277+
validateAccessibility(aliasDecl);
7278+
7279+
// Check generic parameters, if needed.
7280+
aliasDecl->setIsBeingValidated();
7281+
SWIFT_DEFER { aliasDecl->setIsBeingValidated(false); };
7282+
7283+
validateTypealiasType(*this, aliasDecl);
7284+
}
7285+
}
72517286
}
72527287
}
72537288

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType(
218218
if (auto proto =
219219
concrete->getDeclContext()
220220
->getAsProtocolOrProtocolExtensionContext()) {
221+
TC.validateDecl(proto);
221222
auto subMap = SubstitutionMap::getProtocolSubstitutions(
222223
proto, baseTy, ProtocolConformanceRef(proto));
223224
return concrete->getDeclaredInterfaceType().subst(subMap);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %target-swift-frontend %s -emit-ir
2+
struct X<T: Q> {
3+
func f(_: T.Z) { }
4+
}
5+
6+
protocol P {
7+
associatedtype A
8+
associatedtype B
9+
}
10+
11+
protocol Q {
12+
associatedtype C: P
13+
typealias Z = (C.A, C.B)
14+
}

0 commit comments

Comments
 (0)