Skip to content

Commit 728831b

Browse files
committed
[GSB] Infer requirements from uses of generic typealiases.
Generic typealiases can add requirements that aren't used by their underlying type. For example, CountableRange in the standard library: public typealias CountableRange<Bound: Comparable> = Range<Bound> Perform requirement inference based on uses of generic typealiases, such that a generic function like this: func f<T>(_: CountableRange<T>) { } will infer T: Bound from the use of CountableRange. Note that this does not yet work for extensions.
1 parent b66c1a0 commit 728831b

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5430,9 +5430,25 @@ class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker {
54305430
}
54315431

54325432
Action walkToTypePost(Type ty) override {
5433-
auto decl = ty->getAnyNominal();
5434-
if (!decl)
5433+
// Infer from generic typealiases.
5434+
if (auto boundNameAlias = dyn_cast<BoundNameAliasType>(ty.getPointer())) {
5435+
auto decl = boundNameAlias->getDecl();
5436+
auto genericSig = decl->getGenericSignature();
5437+
if (!genericSig)
5438+
return Action::Continue;
5439+
5440+
auto subMap = boundNameAlias->getSubstitutionMap();
5441+
for (const auto &rawReq : genericSig->getRequirements()) {
5442+
if (auto req = rawReq.subst(subMap))
5443+
Builder.addRequirement(*req, source, nullptr);
5444+
}
5445+
54355446
return Action::Continue;
5447+
}
5448+
5449+
// Infer from generic nominal types.
5450+
auto decl = ty->getAnyNominal();
5451+
if (!decl) return Action::Continue;
54365452

54375453
auto genericSig = decl->getGenericSignature();
54385454
if (!genericSig)

test/Generics/requirement_inference.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,3 +460,30 @@ func conditionalNested1<U>(_: [ConditionalNested<U>.Inner?]) {}
460460
// CHECK: Generic signature: <U where U : P35, U : P36>
461461
// CHECK: Canonical generic signature: <τ_0_0 where τ_0_0 : P35, τ_0_0 : P36>
462462
func conditionalNested2<U>(_: [ConditionalNested<U>.Inner.Inner2?]) {}
463+
464+
//
465+
// Generate typalias adds requirements that can be inferred
466+
//
467+
typealias X1WithP2<T: P2> = X1<T>
468+
469+
// Inferred requirement T: P2 from the typealias
470+
func testX1WithP2<T>(_: X1WithP2<T>) {
471+
_ = X5<T>() // requires P2
472+
}
473+
474+
// Overload based on the inferred requirement.
475+
func testX1WithP2Overloading<T>(_: X1<T>) {
476+
_ = X5<T>() // expected-error{{type 'T' does not conform to protocol 'P2'}}
477+
}
478+
479+
func testX1WithP2Overloading<T>(_: X1WithP2<T>) {
480+
_ = X5<T>() // requires P2
481+
}
482+
483+
// Extend using the inferred requirement.
484+
// FIXME: Currently broken.
485+
extension X1WithP2 {
486+
func f() {
487+
_ = X5<T>() // FIXME: expected-error{{type 'T' does not conform to protocol 'P2'}}
488+
}
489+
}

0 commit comments

Comments
 (0)