Skip to content

Commit 81ceeaf

Browse files
committed
Sema: Source compatibility fix for extensions of type aliases
Referring to a generic type without arguments inside the definition of the type itself or an extension thereof is a shorthand for forwarding the arguments from context: struct Generic<T> {} extension Generic { func makeOne() -> Generic // same as -> Generic<T> } However this didn't work if the type was replaced by a typealias: struct OldGeneric<T> {} typealias Generic<T> = OldGeneric<T> extension Generic { func makeOne() -> OldGeneric // OK func makeOne() -> Generic // error } Add a hack for making this work so that we better cope with the renaming of DictionaryLiteral to KeyValuePairs in Swift 5.0. Fixes <rdar://problem/43955962>.
1 parent dbac940 commit 81ceeaf

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed

lib/Sema/TypeCheckType.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -476,19 +476,18 @@ Type TypeChecker::resolveTypeInContext(
476476
genericParam->getDeclaredInterfaceType());
477477
}
478478

479-
// If we are referring to a type within its own context, and we have either
480-
// a generic type with no generic arguments or a non-generic type, use the
481-
// type within the context.
482-
if (auto nominalType = dyn_cast<NominalTypeDecl>(typeDecl)) {
483-
if (!isa<ProtocolDecl>(nominalType) &&
484-
(!nominalType->getGenericParams() || !isSpecialized)) {
485-
for (auto parentDC = fromDC;
479+
if (!isSpecialized) {
480+
// If we are referring to a type within its own context, and we have either
481+
// a generic type with no generic arguments or a non-generic type, use the
482+
// type within the context.
483+
if (auto *nominalType = dyn_cast<NominalTypeDecl>(typeDecl)) {
484+
for (auto *parentDC = fromDC;
486485
!parentDC->isModuleScopeContext();
487486
parentDC = parentDC->getParent()) {
488487
auto *parentNominal = parentDC->getSelfNominalTypeDecl();
489488
if (parentNominal == nominalType)
490489
return resolution.mapTypeIntoContext(
491-
parentDC->getSelfInterfaceType());
490+
parentDC->getDeclaredInterfaceType());
492491
if (isa<ExtensionDecl>(parentDC)) {
493492
auto *extendedType = parentNominal;
494493
while (extendedType != nullptr) {
@@ -500,6 +499,27 @@ Type TypeChecker::resolveTypeInContext(
500499
}
501500
}
502501
}
502+
503+
// If we're inside an extension of a type alias, allow the type alias to be
504+
// referenced without generic arguments as well.
505+
if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(typeDecl)) {
506+
for (auto *parentDC = fromDC;
507+
!parentDC->isModuleScopeContext();
508+
parentDC = parentDC->getParent()) {
509+
if (auto *ext = dyn_cast<ExtensionDecl>(parentDC)) {
510+
auto extendedType = ext->getExtendedType();
511+
if (auto *aliasType = dyn_cast<NameAliasType>(extendedType.getPointer())) {
512+
if (aliasType->getDecl() == aliasDecl) {
513+
return resolution.mapTypeIntoContext(
514+
aliasDecl->getDeclaredInterfaceType());
515+
}
516+
517+
extendedType = aliasType->getParent();
518+
continue;
519+
}
520+
}
521+
}
522+
}
503523
}
504524

505525
// Simple case -- the type is not nested inside of another type.

test/decl/ext/generic.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,17 @@ extension A.B {
209209
extension A.B.D {
210210
func g() { }
211211
}
212+
213+
// rdar://problem/43955962
214+
struct OldGeneric<T> {}
215+
typealias NewGeneric<T> = OldGeneric<T>
216+
217+
extension NewGeneric {
218+
static func oldMember() -> OldGeneric {
219+
return OldGeneric()
220+
}
221+
222+
static func newMember() -> NewGeneric {
223+
return NewGeneric()
224+
}
225+
}

0 commit comments

Comments
 (0)