Skip to content

Commit 707083d

Browse files
committed
Sema: Fix crash when defining an extension of a nested type with constraints
If the nested type itself has generic constraints, we would hit an assertion in requirement inference. Refactor some code so that we can make the assertion more accurate. Fixes <rdar://problem/30353095>.
1 parent f2d426f commit 707083d

File tree

5 files changed

+44
-25
lines changed

5 files changed

+44
-25
lines changed

include/swift/AST/ArchetypeBuilder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ class ArchetypeBuilder {
270270
/// where \c Dictionary requires that its key type be \c Hashable,
271271
/// the requirement \c K : Hashable is inferred from the parameter type,
272272
/// because the type \c Dictionary<K,V> cannot be formed without it.
273-
void inferRequirements(TypeLoc type, GenericParamList *genericParams);
273+
void inferRequirements(TypeLoc type, unsigned minDepth, unsigned maxDepth);
274274

275275
/// Infer requirements from the given pattern, recursively.
276276
///

lib/AST/ArchetypeBuilder.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,21 +1654,23 @@ void ArchetypeBuilder::addRequirement(const Requirement &req,
16541654
class ArchetypeBuilder::InferRequirementsWalker : public TypeWalker {
16551655
ArchetypeBuilder &Builder;
16561656
SourceLoc Loc;
1657-
unsigned Depth;
1657+
unsigned MinDepth;
1658+
unsigned MaxDepth;
16581659

16591660
/// We cannot add requirements to archetypes from outer generic parameter
16601661
/// lists.
16611662
bool isOuterArchetype(PotentialArchetype *PA) {
16621663
unsigned ParamDepth = PA->getRootGenericParamKey().Depth;
1663-
assert(ParamDepth <= Depth);
1664-
return ParamDepth < Depth;
1664+
assert(ParamDepth <= MaxDepth);
1665+
return ParamDepth < MinDepth;
16651666
}
16661667

16671668
public:
16681669
InferRequirementsWalker(ArchetypeBuilder &builder,
16691670
SourceLoc loc,
1670-
unsigned Depth)
1671-
: Builder(builder), Loc(loc), Depth(Depth) { }
1671+
unsigned MinDepth,
1672+
unsigned MaxDepth)
1673+
: Builder(builder), Loc(loc), MinDepth(MinDepth), MaxDepth(MaxDepth) { }
16721674

16731675
Action walkToTypePost(Type ty) override {
16741676
auto boundGeneric = ty->getAs<BoundGenericType>();
@@ -1776,24 +1778,26 @@ class ArchetypeBuilder::InferRequirementsWalker : public TypeWalker {
17761778
};
17771779

17781780
void ArchetypeBuilder::inferRequirements(TypeLoc type,
1779-
GenericParamList *genericParams) {
1781+
unsigned minDepth,
1782+
unsigned maxDepth) {
17801783
if (!type.getType())
17811784
return;
1782-
if (genericParams == nullptr)
1783-
return;
17841785
// FIXME: Crummy source-location information.
17851786
InferRequirementsWalker walker(*this, type.getSourceRange().Start,
1786-
genericParams->getDepth());
1787+
minDepth, maxDepth);
17871788
type.getType().walk(walker);
17881789
}
17891790

17901791
void ArchetypeBuilder::inferRequirements(ParameterList *params,
17911792
GenericParamList *genericParams) {
17921793
if (genericParams == nullptr)
17931794
return;
1794-
1795+
1796+
unsigned depth = genericParams->getDepth();
17951797
for (auto P : *params)
1796-
inferRequirements(P->getTypeLoc(), genericParams);
1798+
inferRequirements(P->getTypeLoc(),
1799+
/*minDepth=*/depth,
1800+
/*maxDepth=*/depth);
17971801
}
17981802

17991803
/// Perform typo correction on the given nested type, producing the

lib/Sema/TypeCheckDecl.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4822,7 +4822,10 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
48224822

48234823
// Infer requirements from the result type.
48244824
if (!FD->getBodyResultTypeLoc().isNull()) {
4825-
builder.inferRequirements(FD->getBodyResultTypeLoc(), gp);
4825+
unsigned depth = gp->getDepth();
4826+
builder.inferRequirements(FD->getBodyResultTypeLoc(),
4827+
/*minDepth=*/depth,
4828+
/*maxDepth=*/depth);
48264829
}
48274830

48284831
// Revert the types within the signature so it can be type-checked with
@@ -7383,15 +7386,9 @@ checkExtensionGenericParams(TypeChecker &tc, ExtensionDecl *ext, Type type,
73837386

73847387
// Local function used to infer requirements from the extended type.
73857388
auto inferExtendedTypeReqs = [&](ArchetypeBuilder &builder) {
7386-
// Find the outermost generic parameter list. This tricks the inference
7387-
// into performing inference for all levels of generic parameters.
7388-
// FIXME: This is a hack. The inference shouldn't arbitrarily limit what it
7389-
// can infer.
7390-
GenericParamList *outermostList = genericParams;
7391-
while (auto next = outermostList->getOuterParameters())
7392-
outermostList = next;
7393-
7394-
builder.inferRequirements(TypeLoc::withoutLoc(extInterfaceType), outermostList);
7389+
builder.inferRequirements(TypeLoc::withoutLoc(extInterfaceType),
7390+
/*minDepth=*/0,
7391+
/*maxDepth=*/genericParams->getDepth());
73957392
};
73967393

73977394
// Validate the generic type signature.

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,8 @@ void TypeChecker::checkGenericParamList(ArchetypeBuilder *builder,
267267
builder->addGenericParameter(param);
268268
}
269269

270+
unsigned depth = genericParams->getDepth();
271+
270272
// Now, check the inheritance clauses of each parameter.
271273
for (auto param : *genericParams) {
272274
checkInheritanceClause(param, resolver);
@@ -276,7 +278,9 @@ void TypeChecker::checkGenericParamList(ArchetypeBuilder *builder,
276278

277279
// Infer requirements from the inherited types.
278280
for (const auto &inherited : param->getInherited()) {
279-
builder->inferRequirements(inherited, genericParams);
281+
builder->inferRequirements(inherited,
282+
/*minDepth=*/depth,
283+
/*maxDepth=*/depth);
280284
}
281285
}
282286
}
@@ -393,8 +397,12 @@ static bool checkGenericFuncSignature(TypeChecker &tc,
393397
}
394398

395399
// Infer requirements from it.
396-
if (builder && fn->getBodyResultTypeLoc().getTypeRepr()) {
397-
builder->inferRequirements(fn->getBodyResultTypeLoc(), genericParams);
400+
if (builder && genericParams &&
401+
fn->getBodyResultTypeLoc().getTypeRepr()) {
402+
unsigned depth = genericParams->getDepth();
403+
builder->inferRequirements(fn->getBodyResultTypeLoc(),
404+
/*minDepth=*/depth,
405+
/*maxDepth=*/depth);
398406
}
399407
}
400408
}

test/decl/nested/type_in_type.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,13 @@ extension OuterNonGenericClass.InnerNonGenericBase {
351351
extension OuterNonGenericClass.InnerNonGenericClass1 {
352352
static let anotherPropUsingMember = originalValue
353353
}
354+
355+
// rdar://problem/30353095: Extensions of nested types with generic
356+
// requirements placed on type parameters
357+
struct OuterWithConstraint<T : HasAssocType> {
358+
struct InnerWithConstraint<U : HasAssocType> { }
359+
}
360+
361+
extension OuterWithConstraint.InnerWithConstraint {
362+
func foo<V>(v: V) where T.FirstAssocType == U.SecondAssocType {}
363+
}

0 commit comments

Comments
 (0)