Skip to content

Commit 14d0be2

Browse files
committed
Revert "Sema: Clean up resolveTypeInContext() and generalize typealiases in protocols"
This reverts commit 5862883. It broke tests: Swift :: IDE/complete_override_access_control.swift Swift :: IDE/complete_value_expr.swift Swift :: SourceKit/DocSupport/doc_swift_module.swift Swift :: decl/typealias/associated_types.swift Swift :: decl/typealias/typealias.swift
1 parent a1a2344 commit 14d0be2

14 files changed

+157
-120
lines changed

lib/AST/Type.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2917,8 +2917,15 @@ TypeSubstitutionMap TypeBase::getMemberSubstitutions(const DeclContext *dc) {
29172917
// If the member is part of a protocol or extension thereof, we need
29182918
// to substitute in the type of Self.
29192919
if (dc->getAsProtocolOrProtocolExtensionContext()) {
2920+
// We only substitute into archetypes for now for protocols.
2921+
// FIXME: This seems like an odd restriction. Whatever is depending on
2922+
// this, shouldn't.
2923+
if (!baseTy->is<ArchetypeType>() && isa<ProtocolDecl>(dc))
2924+
return substitutions;
2925+
29202926
// FIXME: This feels painfully inefficient. We're creating a dense map
29212927
// for a single substitution.
2928+
substitutions[dc->getProtocolSelf()->getArchetype()] = baseTy;
29222929
substitutions[dc->getProtocolSelf()->getDeclaredType()
29232930
->getCanonicalType()->castTo<GenericTypeParamType>()]
29242931
= baseTy;

lib/Sema/TypeCheckType.cpp

Lines changed: 134 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,23 @@ void TypeChecker::forceExternalDeclMembers(NominalTypeDecl *nominalDecl) {
193193
}
194194
}
195195

196+
static Optional<Type>
197+
resolveAssociatedTypeInContext(TypeChecker &TC, AssociatedTypeDecl *assocType,
198+
DeclContext *DC, GenericTypeResolver *resolver) {
199+
auto protoSelf = DC->getProtocolSelf();
200+
auto selfTy = protoSelf->getDeclaredType()->castTo<GenericTypeParamType>();
201+
auto baseTy = resolver->resolveGenericTypeParamType(selfTy);
202+
203+
if (baseTy->isTypeParameter())
204+
return resolver->resolveSelfAssociatedType(baseTy, DC, assocType);
205+
206+
if (assocType->getDeclContext() != DC)
207+
return TC.substMemberTypeWithBase(DC->getParentModule(), assocType,
208+
protoSelf->getArchetype(),
209+
/*isTypeReference=*/true);
210+
return None;
211+
}
212+
196213
Type TypeChecker::resolveTypeInContext(
197214
TypeDecl *typeDecl,
198215
DeclContext *fromDC,
@@ -222,12 +239,15 @@ Type TypeChecker::resolveTypeInContext(
222239
nominalType = nullptr;
223240
}
224241

225-
// Walk up through the type scopes to find the context containing the type
226-
// being resolved.
242+
// Walk up through the type scopes to find the context where the type
243+
// declaration was found. When we find it, substitute the appropriate base
244+
// type.
227245
auto ownerDC = typeDecl->getDeclContext();
228246
bool nonTypeOwner = !ownerDC->isTypeContext();
229247
auto ownerNominal = ownerDC->getAsNominalTypeOrNominalTypeExtensionContext();
230248
auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl);
249+
auto alias = dyn_cast<TypeAliasDecl>(typeDecl);
250+
DeclContext *typeParent = nullptr;
231251
assert((ownerNominal || nonTypeOwner) &&
232252
"Owner must be a nominal type or a non type context");
233253

@@ -253,126 +273,140 @@ Type TypeChecker::resolveTypeInContext(
253273
return typeDecl->getDeclaredType();
254274

255275
// For the next steps we need our parentDC to be a type context
256-
if (!parentDC->isTypeContext())
276+
if (!parentDC->isTypeContext()) {
257277
continue;
258-
259-
// Search the type of this context and its supertypes (if its a
260-
// class) or refined protocols (if its a protocol).
261-
llvm::SmallPtrSet<const NominalTypeDecl *, 8> visited;
262-
llvm::SmallVector<Type, 8> stack;
263-
264-
// Start with the type of the current context.
265-
if (auto fromType = resolver->resolveTypeOfContext(parentDC))
266-
stack.push_back(fromType);
267-
268-
// If we are in a protocol extension there might be other type aliases and
269-
// nominal types brought into the context through requirements on Self,
270-
// for example:
271-
//
272-
// extension MyProtocol where Self : YourProtocol { ... }
273-
if (parentDC->getAsProtocolExtensionContext()) {
274-
auto ED = cast<ExtensionDecl>(parentDC);
275-
if (auto genericParams = ED->getGenericParams()) {
276-
for (auto req : genericParams->getTrailingRequirements()) {
277-
// We might be resolving 'req.getSubject()' itself.
278-
// This whole case feels like a hack -- there should be a
279-
// more principled way to represent extensions of protocol
280-
// compositions.
281-
if (req.getKind() == RequirementReprKind::TypeConstraint) {
282-
if (!req.getSubject() ||
283-
!req.getSubject()->is<ArchetypeType>() ||
284-
!req.getSubject()->castTo<ArchetypeType>()->getSelfProtocol())
278+
} else if (!typeParent) {
279+
// Remember the first type decl context in the hierarchy for later use
280+
typeParent = parentDC;
281+
}
282+
283+
// If we found an associated type in an inherited protocol, the base for our
284+
// reference to this associated type is our own `Self`. If we can't resolve
285+
// the associated type during this iteration, try again on the next.
286+
if (assocType) {
287+
if (auto proto = parentDC->getAsProtocolOrProtocolExtensionContext()) {
288+
auto assocProto = assocType->getProtocol();
289+
if (proto == assocProto || proto->inheritsFrom(assocProto)) {
290+
// If the associated type is from our own protocol or we inherit from
291+
// the associated type's protocol, resolve it
292+
if (auto resolved = resolveAssociatedTypeInContext(
293+
*this, assocType, parentDC, resolver))
294+
return *resolved;
295+
296+
} else if (auto ED = dyn_cast<ExtensionDecl>(parentDC)) {
297+
// Otherwise, if we are in an extension there might be other
298+
// associated types brought into the context through
299+
// `extension ... where Self : SomeProtocol`
300+
for (auto req : ED->getGenericParams()->getTrailingRequirements()) {
301+
// Reject requirements other than constraints with an subject other
302+
// than `Self`
303+
if (req.getKind() != RequirementReprKind::TypeConstraint ||
304+
!req.getSubject()->castTo<ArchetypeType>()->isSelfDerived())
285305
continue;
286306

287-
stack.push_back(req.getConstraint());
307+
// If the associated type is defined in the same protocol which is
308+
// required for this extension, or if the required protocol inherits
309+
// from the protocol the associated type is declared in, we can
310+
// resolve the associated type with our `Self` as the reference
311+
// point.
312+
auto reqProto =
313+
req.getConstraint()->castTo<ProtocolType>()->getDecl();
314+
if (reqProto == assocProto || reqProto->inheritsFrom(assocProto)) {
315+
if (auto resolved = resolveAssociatedTypeInContext(
316+
*this, assocType, parentDC, resolver))
317+
return *resolved;
318+
break;
319+
}
288320
}
289321
}
290322
}
291323
}
324+
325+
// If we found an alias type in an inherited protocol, resolve it based on our
326+
// own `Self`.
327+
if (alias && alias->hasInterfaceType()) {
328+
auto metaType = alias->getInterfaceType()->getAs<MetatypeType>();
329+
auto memberType = metaType ? metaType->getInstanceType()->getAs<DependentMemberType>() :
330+
nullptr;
331+
332+
if (memberType && parentDC->getAsProtocolOrProtocolExtensionContext()) {
333+
auto protoSelf = parentDC->getProtocolSelf();
334+
auto selfTy = protoSelf->getDeclaredType()->castTo<GenericTypeParamType>();
335+
auto baseTy = resolver->resolveGenericTypeParamType(selfTy);
336+
337+
SmallVector<DependentMemberType *, 4> memberTypes;
338+
do {
339+
memberTypes.push_back(memberType);
340+
memberType = memberType->getBase()->getAs<DependentMemberType>();
341+
} while (memberType);
342+
343+
auto module = parentDC->getParentModule();
344+
while (memberTypes.size()) {
345+
baseTy = memberTypes.back()->substBaseType(module, baseTy, nullptr);
346+
memberTypes.pop_back();
347+
}
348+
return baseTy;
349+
}
350+
}
292351

293-
while (!stack.empty()) {
294-
auto fromType = stack.back();
295-
auto *fromProto = parentDC->getAsProtocolOrProtocolExtensionContext();
296-
297-
stack.pop_back();
298-
352+
// Search the type of this context and its supertypes.
353+
llvm::SmallPtrSet<const NominalTypeDecl *, 8> visited;
354+
for (auto fromType = resolver->resolveTypeOfContext(parentDC);
355+
fromType;
356+
fromType = getSuperClassOf(fromType)) {
299357
// If we hit circularity, we will diagnose at some point in typeCheckDecl().
300358
// However we have to explicitly guard against that here because we get
301359
// called as part of validateDecl().
302360
if (!visited.insert(fromType->getAnyNominal()).second)
303-
continue;
304-
305-
// Handle this case:
306-
// - Current context: concrete type
307-
// - Nested type: associated type
308-
// - Nested type's context: protocol or protocol extension
309-
//
310-
if (assocType && fromProto == nullptr) {
311-
ProtocolConformance *conformance = nullptr;
312-
313-
// If the conformance check failed, the associated type is for a
314-
// conformance of an outer context.
315-
if (!options.contains(TR_InheritanceClause) &&
316-
conformsToProtocol(fromType,
317-
cast<ProtocolDecl>(ownerNominal),
318-
parentDC, ConformanceCheckFlags::Used,
319-
&conformance) &&
320-
conformance) {
321-
return conformance->getTypeWitness(assocType, this).getReplacement();
322-
}
323-
}
361+
break;
324362

325-
// Handle these cases:
326-
// - Current context: concrete type
327-
// - Nested type: concrete type or type alias
328-
// - Nested type's context: concrete type
329-
//
330-
// - Current context: protocol or protocol extension
331-
// - Nested type: type alias
332-
// - Nested type's context: protocol or protocol extension
333-
//
334-
// Note: this is not supported yet, FIXME:
335-
// - Current context: concrete type
336-
// - Nested type: type alias
337-
// - Nested type's context: protocol or protocol extension
338-
//
363+
// If the nominal type declaration of the context type we're looking at
364+
// matches the owner's nominal type declaration, this is how we found
365+
// the member type declaration. Substitute the type we're coming from as
366+
// the base of the member type to produce the projected type result.
339367
if (fromType->getAnyNominal() == ownerNominal) {
340-
if (fromProto &&
341-
ownerNominal->getAsProtocolOrProtocolExtensionContext()) {
342-
// If we are looking up an associated type or a protocol's type alias
343-
// from a protocol or protocol extension, use the archetype for 'Self'
344-
// instead of the existential type.
345-
assert(fromType->is<ProtocolType>());
346-
347-
auto protoSelf = parentDC->getProtocolSelf();
348-
auto selfType = protoSelf
349-
->getDeclaredType()
350-
->castTo<GenericTypeParamType>();
351-
fromType = resolver->resolveGenericTypeParamType(selfType);
352-
353-
if (assocType) {
354-
// Odd special case, ask Doug to explain it over pizza one day
355-
if (fromType->isTypeParameter())
356-
return resolver->resolveSelfAssociatedType(
357-
fromType, parentDC, assocType);
358-
}
368+
// If we are referring into a protocol or extension thereof,
369+
// the base type is the 'Self'.
370+
if (ownerDC->getAsProtocolOrProtocolExtensionContext()) {
371+
auto selfTy = ownerDC->getProtocolSelf()->getDeclaredType()
372+
->castTo<GenericTypeParamType>();
373+
fromType = resolver->resolveGenericTypeParamType(selfTy);
359374
}
360375

376+
// Perform the substitution.
361377
return substMemberTypeWithBase(parentDC->getParentModule(), typeDecl,
362378
fromType, /*isTypeReference=*/true);
363379
}
364380

365-
if (auto superclassTy = getSuperClassOf(fromType))
366-
stack.push_back(superclassTy);
367-
else if (auto protoTy = fromType->getAs<ProtocolType>()) {
368-
for (auto *proto : protoTy->getDecl()->getInheritedProtocols(this))
369-
if (auto refinedTy = proto->getDeclaredTypeInContext())
370-
stack.push_back(refinedTy);
381+
ProtocolConformance *conformance = nullptr;
382+
if (assocType &&
383+
!options.contains(TR_InheritanceClause) &&
384+
conformsToProtocol(fromType,
385+
cast<ProtocolDecl>(assocType->getDeclContext()),
386+
parentDC, ConformanceCheckFlags::Used,
387+
&conformance) &&
388+
conformance) {
389+
return conformance->getTypeWitness(assocType, this).getReplacement();
371390
}
372391
}
373392
}
374393

375-
llvm_unreachable("Cannot resolve type");
394+
// At this point by iterating through the decl context hierarchy we should
395+
// have encountered the first type context in the stack.
396+
assert(typeParent && "incomplete iteration");
397+
assert(!typeParent->isModuleContext());
398+
399+
// Substitute in the appropriate type for 'Self'.
400+
// FIXME: We shouldn't have to guess here; the caller should tell us.
401+
Type fromType;
402+
if (typeParent->getAsProtocolOrProtocolExtensionContext())
403+
fromType = typeParent->getProtocolSelf()->getArchetype();
404+
else
405+
fromType = resolver->resolveTypeOfContext(typeParent);
406+
407+
// Perform the substitution.
408+
return substMemberTypeWithBase(typeParent->getParentModule(), typeDecl,
409+
fromType, /*isTypeReference=*/true);
376410
}
377411

378412
Type TypeChecker::applyGenericArguments(Type type, SourceLoc loc,
@@ -503,8 +537,7 @@ Type TypeChecker::applyUnboundGenericArguments(
503537

504538
// Check the generic arguments against the generic signature.
505539
auto genericSig = unbound->getDecl()->getGenericSignature();
506-
if (!unbound->getDecl()->hasType() ||
507-
unbound->getDecl()->isValidatingGenericSignature()) {
540+
if (unbound->getDecl()->isValidatingGenericSignature()) {
508541
diagnose(loc, diag::recursive_requirement_reference);
509542
return nullptr;
510543
}
@@ -2441,6 +2474,7 @@ Type TypeChecker::substMemberTypeWithBase(Module *module,
24412474
Type memberType = isTypeReference
24422475
? cast<TypeDecl>(member)->getDeclaredInterfaceType()
24432476
: member->getInterfaceType();
2477+
24442478
if (isTypeReference) {
24452479
// The declared interface type for a generic type will have the type
24462480
// arguments; strip them off.

test/decl/typealias/typealias.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,12 +158,8 @@ protocol Col {
158158
protocol CB {
159159
associatedtype C : Col
160160
typealias E = C.Elem
161-
typealias OE = C.Elem?
162-
typealias FE = (C) -> (C.Elem) -> Self
163161

164162
func setIt(_ element: E)
165-
func setItMaybe(_ element: OE)
166-
func teleport(_ fn: FE)
167163
}
168164

169165
func go1<T : CB, U : Col where U.Elem == T.E>(_ col: U, builder: T) { // OK
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// RUN: not --crash %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s
2+
{class T{protocol b{#^A^#associatedtype b:B<T>struct B<b
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// RUN: not --crash %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s
2+
protocol c{func a:P
3+
protocol P{#^A^#func a:b
4+
associatedtype b:a
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// RUN: not --crash %target-swift-ide-test -code-completion -code-completion-token=A -source-filename=%s
2+
protocol A{protocol A{
3+
associatedtype e:a
4+
func a<T:e
5+
enum b{func a{#^A^#

validation-test/IDE/crashers_fixed/021-swift-typechecker-resolveidentifiertype.swift

Lines changed: 0 additions & 2 deletions
This file was deleted.

validation-test/IDE/crashers_fixed/024-swift-archetypebuilder-potentialarchetype-getrepresentative.swift

Lines changed: 0 additions & 4 deletions
This file was deleted.

validation-test/IDE/crashers_fixed/044-swift-dependentgenerictyperesolver-resolveselfassociatedtype.swift

Lines changed: 0 additions & 5 deletions
This file was deleted.

validation-test/compiler_crashers_fixed/01766-swift-typechecker-validatedecl.swift renamed to validation-test/compiler_crashers/01766-swift-typechecker-validatedecl.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// See http://swift.org/LICENSE.txt for license information
66
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
77

8-
// RUN: not %target-swift-frontend %s -parse
8+
// RUN: not --crash %target-swift-frontend %s -parse
99
protocol a {
1010
protocol A {
1111
}

validation-test/compiler_crashers_fixed/26083-std-function-func-swift-type-subst.swift renamed to validation-test/compiler_crashers/26083-std-function-func-swift-type-subst.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
77

88
// DUPLICATE-OF: 01766-swift-typechecker-validatedecl.swift
9-
// RUN: not %target-swift-frontend %s -parse
9+
// RUN: not --crash %target-swift-frontend %s -parse
1010
protocol e:A{protocol e:A class A}protocol A{enum A}protocol B:e

validation-test/compiler_crashers_fixed/27156-swift-typechecker-applygenericarguments.swift renamed to validation-test/compiler_crashers/27156-swift-typechecker-applygenericarguments.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// See http://swift.org/LICENSE.txt for license information
66
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
77

8-
// RUN: not %target-swift-frontend %s -parse
8+
// RUN: not --crash %target-swift-frontend %s -parse
99
struct B<T{protocol A{
1010
class B<T
1111
associatedtype e:B<T>

validation-test/compiler_crashers_fixed/28193-swift-typechecker-lookupmembertype.swift renamed to validation-test/compiler_crashers/28193-swift-typechecker-lookupmembertype.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
// See http://swift.org/LICENSE.txt for license information
66
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
77

8-
// RUN: not %target-swift-frontend %s -parse
8+
// RUN: not --crash %target-swift-frontend %s -parse
99
// REQUIRES: asserts
1010
var d:Collection{for c d in

validation-test/compiler_crashers_fixed/28233-swift-typebase-getmembersubstitutions.swift renamed to validation-test/compiler_crashers/28233-swift-typebase-getmembersubstitutions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
77

88
// DUPLICATE-OF: 01766-swift-typechecker-validatedecl.swift
9-
// RUN: not %target-swift-frontend %s -parse
9+
// RUN: not --crash %target-swift-frontend %s -parse
1010
protocol A{class A}protocol a:A{protocol P{associatedtype e:A}}a

0 commit comments

Comments
 (0)