Skip to content

Commit cb1685c

Browse files
committed
Sema/AST: Fix a couple of protocol typealias validation order bugs
We break name lookup circularities by special-casing validation of type aliases, resolving the underlying type of the type alias before building the generic environment of the protocol that contains the type alias. However doing this gives the type alias an underlying type written in terms of unresolved DependentMemberTypes which do not map to associated types. Attempting to substitute such a type fails. We worked around this by re-validating type alias members of protocols when we finally got around to building the protocol's generic environment. Force this to happen earlier in substMemberTypeWithBase(), because we need the fully resolved underlying type in order to perform the substitution. Also, fix TypeAliasDecl::setUnderlyingType() to only create a new NameAliasType the first time it is called. In this special case where it can be called twice with a resolved underlying type the second time, we should not be creating a new NameAliasType. There are better fixes possible here, requiring various levels of refactoring. I'll investigate this soon, but for now this narrow fix should address the problem with minimal risk. Fixes <rdar://problem/33189068>.
1 parent 7c8958f commit cb1685c

File tree

3 files changed

+40
-8
lines changed

3 files changed

+40
-8
lines changed

lib/AST/Decl.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2421,14 +2421,19 @@ void TypeAliasDecl::setUnderlyingType(Type underlying) {
24212421
underlying = mapTypeOutOfContext(underlying);
24222422
UnderlyingTy.setType(underlying);
24232423

2424-
// Create a NameAliasType which will resolve to the underlying type.
2425-
ASTContext &Ctx = getASTContext();
2426-
auto aliasTy = new (Ctx, AllocationArena::Permanent) NameAliasType(this);
2427-
aliasTy->setRecursiveProperties(getUnderlyingTypeLoc().getType()
2428-
->getRecursiveProperties());
2429-
2430-
// Set the interface type of this declaration.
2431-
setInterfaceType(MetatypeType::get(aliasTy, Ctx));
2424+
// FIXME -- if we already have an interface type, we're changing the
2425+
// underlying type. See the comment in the ProtocolDecl case of
2426+
// validateDecl().
2427+
if (!hasInterfaceType()) {
2428+
// Create a NameAliasType which will resolve to the underlying type.
2429+
ASTContext &Ctx = getASTContext();
2430+
auto aliasTy = new (Ctx, AllocationArena::Permanent) NameAliasType(this);
2431+
aliasTy->setRecursiveProperties(getUnderlyingTypeLoc().getType()
2432+
->getRecursiveProperties());
2433+
2434+
// Set the interface type of this declaration.
2435+
setInterfaceType(MetatypeType::get(aliasTy, Ctx));
2436+
}
24322437
}
24332438

24342439
UnboundGenericType *TypeAliasDecl::getUnboundGenericType() const {

lib/Sema/TypeCheckType.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3183,6 +3183,14 @@ Type TypeChecker::substMemberTypeWithBase(ModuleDecl *module,
31833183
}
31843184

31853185
if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(member)) {
3186+
// FIXME: If this is a protocol typealias and we haven't built the
3187+
// protocol's generic environment yet, do so now, to ensure the
3188+
// typealias's underlying type has fully resoved dependent
3189+
// member types.
3190+
if (auto *protoDecl = dyn_cast<ProtocolDecl>(aliasDecl->getDeclContext()))
3191+
if (protoDecl->getGenericEnvironment() == nullptr)
3192+
validateDecl(protoDecl);
3193+
31863194
if (aliasDecl->getGenericParams()) {
31873195
return UnboundGenericType::get(
31883196
aliasDecl, baseTy,
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %target-swift-frontend %s -typecheck
2+
3+
struct Bar : BarProtocol {
4+
typealias Element = Int
5+
}
6+
7+
struct Foo: FooProtocol {
8+
typealias Things = Bar
9+
func thing() -> Thing {}
10+
}
11+
12+
protocol BarProtocol {
13+
associatedtype Element
14+
}
15+
16+
protocol FooProtocol {
17+
associatedtype Things: BarProtocol
18+
typealias Thing = Things.Element
19+
}

0 commit comments

Comments
 (0)