Skip to content

Commit 1221bd8

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 bd02831 commit 1221bd8

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
@@ -2403,14 +2403,19 @@ void TypeAliasDecl::setUnderlyingType(Type underlying) {
24032403
underlying = mapTypeOutOfContext(underlying);
24042404
UnderlyingTy.setType(underlying);
24052405

2406-
// Create a NameAliasType which will resolve to the underlying type.
2407-
ASTContext &Ctx = getASTContext();
2408-
auto aliasTy = new (Ctx, AllocationArena::Permanent) NameAliasType(this);
2409-
aliasTy->setRecursiveProperties(getUnderlyingTypeLoc().getType()
2410-
->getRecursiveProperties());
2411-
2412-
// Set the interface type of this declaration.
2413-
setInterfaceType(MetatypeType::get(aliasTy, Ctx));
2406+
// FIXME -- if we already have an interface type, we're changing the
2407+
// underlying type. See the comment in the ProtocolDecl case of
2408+
// validateDecl().
2409+
if (!hasInterfaceType()) {
2410+
// Create a NameAliasType which will resolve to the underlying type.
2411+
ASTContext &Ctx = getASTContext();
2412+
auto aliasTy = new (Ctx, AllocationArena::Permanent) NameAliasType(this);
2413+
aliasTy->setRecursiveProperties(getUnderlyingTypeLoc().getType()
2414+
->getRecursiveProperties());
2415+
2416+
// Set the interface type of this declaration.
2417+
setInterfaceType(MetatypeType::get(aliasTy, Ctx));
2418+
}
24142419
}
24152420

24162421
UnboundGenericType *TypeAliasDecl::getUnboundGenericType() const {

lib/Sema/TypeCheckType.cpp

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

30243024
if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(member)) {
3025+
// FIXME: If this is a protocol typealias and we haven't built the
3026+
// protocol's generic environment yet, do so now, to ensure the
3027+
// typealias's underlying type has fully resoved dependent
3028+
// member types.
3029+
if (auto *protoDecl = dyn_cast<ProtocolDecl>(aliasDecl->getDeclContext()))
3030+
if (protoDecl->getGenericEnvironment() == nullptr)
3031+
validateDecl(protoDecl);
3032+
30253033
if (aliasDecl->getGenericParams()) {
30263034
return UnboundGenericType::get(
30273035
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)