Skip to content

Sema: Fix crash when defining an extension of a nested type with constrains #7356

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/swift/AST/ArchetypeBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ class ArchetypeBuilder {
/// where \c Dictionary requires that its key type be \c Hashable,
/// the requirement \c K : Hashable is inferred from the parameter type,
/// because the type \c Dictionary<K,V> cannot be formed without it.
void inferRequirements(TypeLoc type, GenericParamList *genericParams);
void inferRequirements(TypeLoc type, unsigned minDepth, unsigned maxDepth);

/// Infer requirements from the given pattern, recursively.
///
Expand Down
26 changes: 15 additions & 11 deletions lib/AST/ArchetypeBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1654,21 +1654,23 @@ void ArchetypeBuilder::addRequirement(const Requirement &req,
class ArchetypeBuilder::InferRequirementsWalker : public TypeWalker {
ArchetypeBuilder &Builder;
SourceLoc Loc;
unsigned Depth;
unsigned MinDepth;
unsigned MaxDepth;

/// We cannot add requirements to archetypes from outer generic parameter
/// lists.
bool isOuterArchetype(PotentialArchetype *PA) {
unsigned ParamDepth = PA->getRootGenericParamKey().Depth;
assert(ParamDepth <= Depth);
return ParamDepth < Depth;
assert(ParamDepth <= MaxDepth);
return ParamDepth < MinDepth;
}

public:
InferRequirementsWalker(ArchetypeBuilder &builder,
SourceLoc loc,
unsigned Depth)
: Builder(builder), Loc(loc), Depth(Depth) { }
unsigned MinDepth,
unsigned MaxDepth)
: Builder(builder), Loc(loc), MinDepth(MinDepth), MaxDepth(MaxDepth) { }

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

void ArchetypeBuilder::inferRequirements(TypeLoc type,
GenericParamList *genericParams) {
unsigned minDepth,
unsigned maxDepth) {
if (!type.getType())
return;
if (genericParams == nullptr)
return;
// FIXME: Crummy source-location information.
InferRequirementsWalker walker(*this, type.getSourceRange().Start,
genericParams->getDepth());
minDepth, maxDepth);
type.getType().walk(walker);
}

void ArchetypeBuilder::inferRequirements(ParameterList *params,
GenericParamList *genericParams) {
if (genericParams == nullptr)
return;


unsigned depth = genericParams->getDepth();
for (auto P : *params)
inferRequirements(P->getTypeLoc(), genericParams);
inferRequirements(P->getTypeLoc(),
/*minDepth=*/depth,
/*maxDepth=*/depth);
}

/// Perform typo correction on the given nested type, producing the
Expand Down
17 changes: 7 additions & 10 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4822,7 +4822,10 @@ class DeclChecker : public DeclVisitor<DeclChecker> {

// Infer requirements from the result type.
if (!FD->getBodyResultTypeLoc().isNull()) {
builder.inferRequirements(FD->getBodyResultTypeLoc(), gp);
unsigned depth = gp->getDepth();
builder.inferRequirements(FD->getBodyResultTypeLoc(),
/*minDepth=*/depth,
/*maxDepth=*/depth);
}

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

// Local function used to infer requirements from the extended type.
auto inferExtendedTypeReqs = [&](ArchetypeBuilder &builder) {
// Find the outermost generic parameter list. This tricks the inference
// into performing inference for all levels of generic parameters.
// FIXME: This is a hack. The inference shouldn't arbitrarily limit what it
// can infer.
GenericParamList *outermostList = genericParams;
while (auto next = outermostList->getOuterParameters())
outermostList = next;

builder.inferRequirements(TypeLoc::withoutLoc(extInterfaceType), outermostList);
builder.inferRequirements(TypeLoc::withoutLoc(extInterfaceType),
/*minDepth=*/0,
/*maxDepth=*/genericParams->getDepth());
};

// Validate the generic type signature.
Expand Down
14 changes: 11 additions & 3 deletions lib/Sema/TypeCheckGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ void TypeChecker::checkGenericParamList(ArchetypeBuilder *builder,
builder->addGenericParameter(param);
}

unsigned depth = genericParams->getDepth();

// Now, check the inheritance clauses of each parameter.
for (auto param : *genericParams) {
checkInheritanceClause(param, resolver);
Expand All @@ -276,7 +278,9 @@ void TypeChecker::checkGenericParamList(ArchetypeBuilder *builder,

// Infer requirements from the inherited types.
for (const auto &inherited : param->getInherited()) {
builder->inferRequirements(inherited, genericParams);
builder->inferRequirements(inherited,
/*minDepth=*/depth,
/*maxDepth=*/depth);
}
}
}
Expand Down Expand Up @@ -393,8 +397,12 @@ static bool checkGenericFuncSignature(TypeChecker &tc,
}

// Infer requirements from it.
if (builder && fn->getBodyResultTypeLoc().getTypeRepr()) {
builder->inferRequirements(fn->getBodyResultTypeLoc(), genericParams);
if (builder && genericParams &&
fn->getBodyResultTypeLoc().getTypeRepr()) {
unsigned depth = genericParams->getDepth();
builder->inferRequirements(fn->getBodyResultTypeLoc(),
/*minDepth=*/depth,
/*maxDepth=*/depth);
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions test/decl/nested/type_in_type.swift
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,13 @@ extension OuterNonGenericClass.InnerNonGenericBase {
extension OuterNonGenericClass.InnerNonGenericClass1 {
static let anotherPropUsingMember = originalValue
}

// rdar://problem/30353095: Extensions of nested types with generic
// requirements placed on type parameters
struct OuterWithConstraint<T : HasAssocType> {
struct InnerWithConstraint<U : HasAssocType> { }
}

extension OuterWithConstraint.InnerWithConstraint {
func foo<V>(v: V) where T.FirstAssocType == U.SecondAssocType {}
}