Skip to content

Commit e49dbf5

Browse files
authored
Merge pull request #15002 from DougGregor/gsb-ext-typealias-inherited-assoc-sr-7097
[GSB] Always ensure that we wire up typealiases in protocol extensions.
2 parents 90d2740 + 823d2a9 commit e49dbf5

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
@@ -4011,17 +4011,21 @@ ConstraintResult GenericSignatureBuilder::expandConformanceRequirement(
40114011
// Retrieve the requirement that a given typealias introduces when it
40124012
// overrides an inherited associated type with the same name, as a string
40134013
// suitable for use in a where clause.
4014-
auto getTypeAliasReq = [&](TypeAliasDecl *typealias, const char *start) {
4014+
auto getConcreteTypeReq = [&](TypeDecl *type, const char *start) {
40154015
std::string result;
40164016
{
40174017
llvm::raw_string_ostream out(result);
40184018
out << start;
4019-
out << typealias->getFullName() << " == ";
4020-
if (auto underlyingTypeRepr =
4021-
typealias->getUnderlyingTypeLoc().getTypeRepr())
4022-
underlyingTypeRepr->print(out);
4023-
else
4024-
typealias->getUnderlyingTypeLoc().getType().print(out);
4019+
out << type->getFullName() << " == ";
4020+
if (auto typealias = dyn_cast<TypeAliasDecl>(type)) {
4021+
if (auto underlyingTypeRepr =
4022+
typealias->getUnderlyingTypeLoc().getTypeRepr())
4023+
underlyingTypeRepr->print(out);
4024+
else
4025+
typealias->getUnderlyingTypeLoc().getType().print(out);
4026+
} else {
4027+
type->print(out);
4028+
}
40254029
}
40264030
return result;
40274031
};
@@ -4151,51 +4155,68 @@ ConstraintResult GenericSignatureBuilder::expandConformanceRequirement(
41514155
inheritedTypeDecls.erase(knownInherited);
41524156
continue;
41534157
}
4158+
}
41544159

4155-
if (auto typealias = dyn_cast<TypeAliasDecl>(Member)) {
4156-
// Check whether we inherited any types with the same name.
4157-
auto knownInherited = inheritedTypeDecls.find(typealias->getFullName());
4158-
if (knownInherited == inheritedTypeDecls.end()) continue;
4160+
// Check all remaining inherited type declarations to determine if
4161+
// this protocol has a non-associated-type type with the same name.
4162+
inheritedTypeDecls.remove_if(
4163+
[&](const std::pair<DeclName, TinyPtrVector<TypeDecl *>> &inherited) {
4164+
auto name = inherited.first;
4165+
for (auto found : proto->lookupDirect(name)) {
4166+
// We only want concrete type declarations.
4167+
auto type = dyn_cast<TypeDecl>(found);
4168+
if (!type || isa<AssociatedTypeDecl>(type)) continue;
41594169

4160-
bool shouldWarnAboutRedeclaration =
4161-
source->kind == RequirementSource::RequirementSignatureSelf;
4170+
// ... from the same module as the protocol.
4171+
if (type->getModuleContext() != proto->getModuleContext()) continue;
41624172

4163-
for (auto inheritedType : knownInherited->second) {
4164-
// If we have inherited associated type...
4165-
if (auto inheritedAssocTypeDecl =
4166-
dyn_cast<AssociatedTypeDecl>(inheritedType)) {
4167-
// Infer a same-type requirement between the typealias' underlying
4168-
// type and the inherited associated type.
4169-
addInferredSameTypeReq(inheritedAssocTypeDecl, typealias);
4173+
// Or is constrained.
4174+
if (auto ext = dyn_cast<ExtensionDecl>(type->getDeclContext())) {
4175+
if (ext->isConstrainedExtension()) continue;
4176+
}
41704177

4171-
// Warn that one should use where clauses for this.
4172-
if (shouldWarnAboutRedeclaration) {
4173-
auto inheritedFromProto = inheritedAssocTypeDecl->getProtocol();
4174-
auto fixItWhere = getProtocolWhereLoc();
4175-
Diags.diagnose(typealias,
4176-
diag::typealias_override_associated_type,
4177-
typealias->getFullName(),
4178-
inheritedFromProto->getDeclaredInterfaceType())
4179-
.fixItInsertAfter(fixItWhere.first,
4180-
getTypeAliasReq(typealias, fixItWhere.second))
4181-
.fixItRemove(typealias->getSourceRange());
4182-
Diags.diagnose(inheritedAssocTypeDecl, diag::decl_declared_here,
4183-
inheritedAssocTypeDecl->getFullName());
4178+
// We found something.
4179+
bool shouldWarnAboutRedeclaration =
4180+
source->kind == RequirementSource::RequirementSignatureSelf;
4181+
4182+
for (auto inheritedType : inherited.second) {
4183+
// If we have inherited associated type...
4184+
if (auto inheritedAssocTypeDecl =
4185+
dyn_cast<AssociatedTypeDecl>(inheritedType)) {
4186+
// Infer a same-type requirement between the typealias' underlying
4187+
// type and the inherited associated type.
4188+
addInferredSameTypeReq(inheritedAssocTypeDecl, type);
4189+
4190+
// Warn that one should use where clauses for this.
4191+
if (shouldWarnAboutRedeclaration) {
4192+
auto inheritedFromProto = inheritedAssocTypeDecl->getProtocol();
4193+
auto fixItWhere = getProtocolWhereLoc();
4194+
Diags.diagnose(type,
4195+
diag::typealias_override_associated_type,
4196+
name,
4197+
inheritedFromProto->getDeclaredInterfaceType())
4198+
.fixItInsertAfter(fixItWhere.first,
4199+
getConcreteTypeReq(type, fixItWhere.second))
4200+
.fixItRemove(type->getSourceRange());
4201+
Diags.diagnose(inheritedAssocTypeDecl, diag::decl_declared_here,
4202+
inheritedAssocTypeDecl->getFullName());
4203+
4204+
shouldWarnAboutRedeclaration = false;
4205+
}
41844206

4185-
shouldWarnAboutRedeclaration = false;
4207+
continue;
41864208
}
41874209

4188-
continue;
4210+
// Two typealiases that should be the same.
4211+
addInferredSameTypeReq(inheritedType, type);
41894212
}
41904213

4191-
// Two typealiases that should be the same.
4192-
addInferredSameTypeReq(inheritedType, typealias);
4214+
// We can remove this entry.
4215+
return true;
41934216
}
41944217

4195-
inheritedTypeDecls.erase(knownInherited);
4196-
continue;
4197-
}
4198-
}
4218+
return false;
4219+
});
41994220

42004221
// Infer same-type requirements among inherited type declarations.
42014222
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)