Skip to content

Commit f452171

Browse files
authored
Merge pull request #15014 from DougGregor/gsb-ext-typealias-inherited-assoc-sr-7097-4.1
[4.1] [GSB] Always ensure that we wire up typealiases in protocol extensions.
2 parents b2d7fb9 + db6a817 commit f452171

File tree

2 files changed

+96
-41
lines changed

2 files changed

+96
-41
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 62 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3326,17 +3326,21 @@ ConstraintResult GenericSignatureBuilder::expandConformanceRequirement(
33263326
// Retrieve the requirement that a given typealias introduces when it
33273327
// overrides an inherited associated type with the same name, as a string
33283328
// suitable for use in a where clause.
3329-
auto getTypeAliasReq = [&](TypeAliasDecl *typealias, const char *start) {
3329+
auto getConcreteTypeReq = [&](TypeDecl *type, const char *start) {
33303330
std::string result;
33313331
{
33323332
llvm::raw_string_ostream out(result);
33333333
out << start;
3334-
out << typealias->getFullName() << " == ";
3335-
if (auto underlyingTypeRepr =
3336-
typealias->getUnderlyingTypeLoc().getTypeRepr())
3337-
underlyingTypeRepr->print(out);
3338-
else
3339-
typealias->getUnderlyingTypeLoc().getType().print(out);
3334+
out << type->getFullName() << " == ";
3335+
if (auto typealias = dyn_cast<TypeAliasDecl>(type)) {
3336+
if (auto underlyingTypeRepr =
3337+
typealias->getUnderlyingTypeLoc().getTypeRepr())
3338+
underlyingTypeRepr->print(out);
3339+
else
3340+
typealias->getUnderlyingTypeLoc().getType().print(out);
3341+
} else {
3342+
type->print(out);
3343+
}
33403344
}
33413345
return result;
33423346
};
@@ -3466,51 +3470,68 @@ ConstraintResult GenericSignatureBuilder::expandConformanceRequirement(
34663470
inheritedTypeDecls.erase(knownInherited);
34673471
continue;
34683472
}
3473+
}
34693474

3470-
if (auto typealias = dyn_cast<TypeAliasDecl>(Member)) {
3471-
// Check whether we inherited any types with the same name.
3472-
auto knownInherited = inheritedTypeDecls.find(typealias->getFullName());
3473-
if (knownInherited == inheritedTypeDecls.end()) continue;
3475+
// Check all remaining inherited type declarations to determine if
3476+
// this protocol has a non-associated-type type with the same name.
3477+
inheritedTypeDecls.remove_if(
3478+
[&](const std::pair<DeclName, TinyPtrVector<TypeDecl *>> &inherited) {
3479+
auto name = inherited.first;
3480+
for (auto found : proto->lookupDirect(name)) {
3481+
// We only want concrete type declarations.
3482+
auto type = dyn_cast<TypeDecl>(found);
3483+
if (!type || isa<AssociatedTypeDecl>(type)) continue;
34743484

3475-
bool shouldWarnAboutRedeclaration =
3476-
source->kind == RequirementSource::RequirementSignatureSelf;
3485+
// ... from the same module as the protocol.
3486+
if (type->getModuleContext() != proto->getModuleContext()) continue;
34773487

3478-
for (auto inheritedType : knownInherited->second) {
3479-
// If we have inherited associated type...
3480-
if (auto inheritedAssocTypeDecl =
3481-
dyn_cast<AssociatedTypeDecl>(inheritedType)) {
3482-
// Infer a same-type requirement between the typealias' underlying
3483-
// type and the inherited associated type.
3484-
addInferredSameTypeReq(inheritedAssocTypeDecl, typealias);
3488+
// Or is constrained.
3489+
if (auto ext = dyn_cast<ExtensionDecl>(type->getDeclContext())) {
3490+
if (ext->isConstrainedExtension()) continue;
3491+
}
34853492

3486-
// Warn that one should use where clauses for this.
3487-
if (shouldWarnAboutRedeclaration) {
3488-
auto inheritedFromProto = inheritedAssocTypeDecl->getProtocol();
3489-
auto fixItWhere = getProtocolWhereLoc();
3490-
Diags.diagnose(typealias,
3491-
diag::typealias_override_associated_type,
3492-
typealias->getFullName(),
3493-
inheritedFromProto->getDeclaredInterfaceType())
3494-
.fixItInsertAfter(fixItWhere.first,
3495-
getTypeAliasReq(typealias, fixItWhere.second))
3496-
.fixItRemove(typealias->getSourceRange());
3497-
Diags.diagnose(inheritedAssocTypeDecl, diag::decl_declared_here,
3498-
inheritedAssocTypeDecl->getFullName());
3493+
// We found something.
3494+
bool shouldWarnAboutRedeclaration =
3495+
source->kind == RequirementSource::RequirementSignatureSelf;
3496+
3497+
for (auto inheritedType : inherited.second) {
3498+
// If we have inherited associated type...
3499+
if (auto inheritedAssocTypeDecl =
3500+
dyn_cast<AssociatedTypeDecl>(inheritedType)) {
3501+
// Infer a same-type requirement between the typealias' underlying
3502+
// type and the inherited associated type.
3503+
addInferredSameTypeReq(inheritedAssocTypeDecl, type);
3504+
3505+
// Warn that one should use where clauses for this.
3506+
if (shouldWarnAboutRedeclaration) {
3507+
auto inheritedFromProto = inheritedAssocTypeDecl->getProtocol();
3508+
auto fixItWhere = getProtocolWhereLoc();
3509+
Diags.diagnose(type,
3510+
diag::typealias_override_associated_type,
3511+
name,
3512+
inheritedFromProto->getDeclaredInterfaceType())
3513+
.fixItInsertAfter(fixItWhere.first,
3514+
getConcreteTypeReq(type, fixItWhere.second))
3515+
.fixItRemove(type->getSourceRange());
3516+
Diags.diagnose(inheritedAssocTypeDecl, diag::decl_declared_here,
3517+
inheritedAssocTypeDecl->getFullName());
3518+
3519+
shouldWarnAboutRedeclaration = false;
3520+
}
34993521

3500-
shouldWarnAboutRedeclaration = false;
3522+
continue;
35013523
}
35023524

3503-
continue;
3525+
// Two typealiases that should be the same.
3526+
addInferredSameTypeReq(inheritedType, type);
35043527
}
35053528

3506-
// Two typealiases that should be the same.
3507-
addInferredSameTypeReq(inheritedType, typealias);
3529+
// We can remove this entry.
3530+
return true;
35083531
}
35093532

3510-
inheritedTypeDecls.erase(knownInherited);
3511-
continue;
3512-
}
3513-
}
3533+
return false;
3534+
});
35143535

35153536
// Infer same-type requirements among inherited type declarations.
35163537
for (auto &entry : inheritedTypeDecls) {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %target-swift-frontend -typecheck -verify %s
2+
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures %s 2>&1 | %FileCheck %s
3+
// RUN: %target-swift-frontend -primary-file %s -emit-ir -o -
4+
5+
protocol P1 { }
6+
7+
protocol P2 {
8+
associatedtype Assoc // expected-note{{'Assoc' declared here}}
9+
}
10+
11+
// CHECK-LABEL: .P3@
12+
// CHECK-NEXT: Requirement signature: <Self where Self : P2, Self.Assoc == ConformsToP1>
13+
protocol P3 : P2 { }
14+
15+
struct S0<M: P3> where M.Assoc: P1 { } // expected-warning{{redundant conformance constraint 'M.Assoc': 'P1'}}
16+
// expected-note@-1{{conformance constraint 'M.Assoc': 'P1' implied here}}
17+
18+
struct ConformsToP1: P1 { }
19+
20+
extension P3 {
21+
typealias Assoc = ConformsToP1 // expected-warning{{typealias overriding associated type 'Assoc' from protocol 'P2' is better expressed as same-type constraint on the protocol}}
22+
}
23+
24+
protocol P5 {
25+
}
26+
27+
extension P5 {
28+
// CHECK-LABEL: P5.testSR7097
29+
// CHECK-NEXT: Generic signature: <Self, M where Self : P5, M : P3>
30+
// CHECK-NEXT: <τ_0_0, τ_1_0 where τ_0_0 : P5, τ_1_0 : P3>
31+
func testSR7097<M>(_: S0<M>.Type) {}
32+
}
33+
34+

0 commit comments

Comments
 (0)