Skip to content

Commit 99051b5

Browse files
authored
Merge pull request #15439 from DougGregor/gsb-infer-generic-typealias
[GSB] Infer requirements from uses of generic typealiases.
2 parents 29681ef + ff5dc60 commit 99051b5

File tree

4 files changed

+76
-7
lines changed

4 files changed

+76
-7
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4171,7 +4171,7 @@ ConstraintResult GenericSignatureBuilder::expandConformanceRequirement(
41714171

41724172
auto inheritedReqResult =
41734173
addInheritedRequirements(proto, selfType.getUnresolvedType(), source,
4174-
/*inferForModule=*/nullptr);
4174+
proto->getModuleContext());
41754175
if (isErrorResult(inheritedReqResult))
41764176
return inheritedReqResult;
41774177
}
@@ -4187,7 +4187,7 @@ ConstraintResult GenericSignatureBuilder::expandConformanceRequirement(
41874187
auto innerSource = FloatingRequirementSource::viaProtocolRequirement(
41884188
source, proto, &req, /*inferred=*/false);
41894189
addRequirement(&req, innerSource, &protocolSubMap,
4190-
/*inferForModule=*/nullptr);
4190+
proto->getModuleContext());
41914191
}
41924192
}
41934193

@@ -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)

lib/Sema/TypeCheckType.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3154,6 +3154,8 @@ Type TypeResolver::buildProtocolType(
31543154
Type TypeChecker::substMemberTypeWithBase(ModuleDecl *module,
31553155
TypeDecl *member,
31563156
Type baseTy) {
3157+
Type sugaredBaseTy = baseTy;
3158+
31573159
// For type members of a base class, make sure we use the right
31583160
// derived class as the parent type.
31593161
if (auto *ownerClass = member->getDeclContext()
@@ -3207,7 +3209,8 @@ Type TypeChecker::substMemberTypeWithBase(ModuleDecl *module,
32073209
// If we're referring to a typealias within a generic context, build
32083210
// a sugared alias type.
32093211
if (aliasDecl && aliasDecl->getGenericSignature()) {
3210-
resultType = BoundNameAliasType::get(aliasDecl, baseTy, subs, resultType);
3212+
resultType = BoundNameAliasType::get(aliasDecl, sugaredBaseTy, subs,
3213+
resultType);
32113214
}
32123215

32133216
return resultType;

test/Generics/requirement_inference.swift

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-typecheck-verify-swift -typecheck %s -verify
2-
// RUN: %target-typecheck-verify-swift -typecheck -debug-generic-signatures %s > %t.dump 2>&1
1+
// RUN: %target-typecheck-verify-swift -typecheck -verify
2+
// RUN: %target-typecheck-verify-swift -typecheck -debug-generic-signatures > %t.dump 2>&1
33
// RUN: %FileCheck %s < %t.dump
44

55
protocol P1 {
@@ -460,3 +460,41 @@ 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+
}
490+
491+
// Inference from protocol inheritance clauses.
492+
typealias ExistentialP4WithP2Assoc<T: P4> = P4 where T.P4Assoc : P2
493+
494+
protocol P37 : ExistentialP4WithP2Assoc<Self> { }
495+
496+
extension P37 {
497+
func f() {
498+
_ = X5<P4Assoc>() // requires P2
499+
}
500+
}

test/decl/typealias/dependent_types.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,15 @@ let _: GenericStruct.MetaAlias = metaFoo()
5858
// ... but if the typealias has a fully concrete underlying type,
5959
// we are OK.
6060
let _: GenericStruct.Concrete = foo()
61+
62+
class SuperG<T, U> {
63+
typealias Composed = (T, U)
64+
}
65+
66+
class SubG<T> : SuperG<T, T> { }
67+
68+
typealias SubGX<T> = SubG<T?>
69+
70+
func checkSugar(gs: SubGX<Int>.Composed) {
71+
let i4: Int = gs // expected-error{{cannot convert value of type 'SubGX<Int>.Composed' (aka '(Optional<Int>, Optional<Int>)') to specified type 'Int'}}
72+
}

0 commit comments

Comments
 (0)