Skip to content

Commit b2d71ec

Browse files
authored
Merge pull request #9064 from DougGregor/typealias-infer-same-type-requirements
2 parents ed0bae7 + e858c55 commit b2d71ec

File tree

4 files changed

+147
-18
lines changed

4 files changed

+147
-18
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 96 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,31 @@ static unsigned sourcePathLength(const RequirementSource *source) {
674674
return count;
675675
}
676676

677+
/// Check whether we have a NestedTypeNameMatch/ProtocolRequirement requirement
678+
/// pair, in which case we prefer the RequirementSignature.
679+
///
680+
/// This is part of staging out NestedTypeNameMatch requirement sources in
681+
/// favor of something more principled.
682+
static int isNestedTypeNameMatchAndRequirementSignaturePair(
683+
const RequirementSource *lhs,
684+
const RequirementSource *rhs) {
685+
if (lhs->getRoot()->kind == RequirementSource::NestedTypeNameMatch &&
686+
rhs->isProtocolRequirement())
687+
return +1;
688+
689+
if (rhs->getRoot()->kind == RequirementSource::NestedTypeNameMatch &&
690+
lhs->isProtocolRequirement())
691+
return -1;
692+
693+
return 0;
694+
}
695+
677696
int RequirementSource::compare(const RequirementSource *other) const {
697+
// FIXME: Egregious hack while we phase out NestedTypeNameMatch
698+
if (int compare =
699+
isNestedTypeNameMatchAndRequirementSignaturePair(this, other))
700+
return compare;
701+
678702
// Prefer the derived option, if there is one.
679703
bool thisIsDerived = this->isDerivedRequirement();
680704
bool otherIsDerived = other->isDerivedRequirement();
@@ -2459,7 +2483,7 @@ ConstraintResult GenericSignatureBuilder::addConformanceRequirement(
24592483

24602484
// Collect all of the inherited associated types and typealiases in the
24612485
// inherited protocols (recursively).
2462-
DenseMap<DeclName, TinyPtrVector<TypeDecl *>> inheritedTypeDecls;
2486+
llvm::MapVector<DeclName, TinyPtrVector<TypeDecl *>> inheritedTypeDecls;
24632487
{
24642488
Proto->walkInheritedProtocols(
24652489
[&](ProtocolDecl *inheritedProto) -> TypeWalker::Action {
@@ -2523,17 +2547,58 @@ ConstraintResult GenericSignatureBuilder::addConformanceRequirement(
25232547
return result;
25242548
};
25252549

2550+
// Form an unsubstituted type referring to the given type declaration,
2551+
// for use in an inferred same-type requirement.
2552+
auto formUnsubstitutedType = [&](TypeDecl *typeDecl) -> Type {
2553+
if (auto assocType = dyn_cast<AssociatedTypeDecl>(typeDecl)) {
2554+
return DependentMemberType::get(
2555+
assocType->getProtocol()->getSelfInterfaceType(),
2556+
assocType);
2557+
}
2558+
2559+
if (auto typealias = dyn_cast<TypeAliasDecl>(typeDecl)) {
2560+
// Resolve the underlying type, if we haven't done so yet.
2561+
if (!typealias->hasInterfaceType()) {
2562+
getLazyResolver()->resolveDeclSignature(typealias);
2563+
}
2564+
2565+
return typealias->getUnderlyingTypeLoc().getType();
2566+
}
2567+
2568+
return Type();
2569+
};
2570+
2571+
// An an inferred same-type requirement between the two type declarations
2572+
// within this protocol or a protocol it inherits.
2573+
auto addInferredSameTypeReq = [&](TypeDecl *first, TypeDecl *second) {
2574+
Type firstType = formUnsubstitutedType(first);
2575+
if (!firstType) return;
2576+
2577+
Type secondType = formUnsubstitutedType(second);
2578+
if (!secondType) return;
2579+
2580+
auto inferredSameTypeSource =
2581+
FloatingRequirementSource::viaProtocolRequirement(
2582+
Source, Proto, WrittenRequirementLoc(), /*inferred=*/true);
2583+
2584+
addRequirement(
2585+
Requirement(RequirementKind::SameType, firstType, secondType),
2586+
inferredSameTypeSource, Proto->getParentModule(),
2587+
&protocolSubMap);
2588+
};
2589+
25262590
// Add requirements for each of the associated types.
25272591
for (auto Member : getProtocolMembers(Proto)) {
2528-
if (auto AssocType = dyn_cast<AssociatedTypeDecl>(Member)) {
2592+
if (auto assocTypeDecl = dyn_cast<AssociatedTypeDecl>(Member)) {
25292593
// Add requirements placed directly on this associated type.
2530-
Type assocType = DependentMemberType::get(concreteSelf, AssocType);
2594+
Type assocType = DependentMemberType::get(concreteSelf, assocTypeDecl);
25312595
auto assocResult =
2532-
addInheritedRequirements(AssocType, assocType, Source, protoModule);
2596+
addInheritedRequirements(assocTypeDecl, assocType, Source, protoModule);
25332597
if (isErrorResult(assocResult))
25342598
return assocResult;
25352599

2536-
if (auto WhereClause = AssocType->getTrailingWhereClause()) {
2600+
// Add requirements from this associated type's where clause.
2601+
if (auto WhereClause = assocTypeDecl->getTrailingWhereClause()) {
25372602
for (auto &req : WhereClause->getRequirements()) {
25382603
auto innerSource =
25392604
FloatingRequirementSource::viaProtocolRequirement(
@@ -2543,30 +2608,33 @@ ConstraintResult GenericSignatureBuilder::addConformanceRequirement(
25432608
}
25442609

25452610
// Check whether we inherited any types with the same name.
2546-
auto knownInherited = inheritedTypeDecls.find(AssocType->getFullName());
2611+
auto knownInherited =
2612+
inheritedTypeDecls.find(assocTypeDecl->getFullName());
25472613
if (knownInherited == inheritedTypeDecls.end()) continue;
25482614

25492615
bool shouldWarnAboutRedeclaration =
25502616
Source->kind == RequirementSource::RequirementSignatureSelf &&
2551-
AssocType->getDefaultDefinitionLoc().isNull();
2552-
for (auto inheritedType : knownInherited->getSecond()) {
2617+
assocTypeDecl->getDefaultDefinitionLoc().isNull();
2618+
for (auto inheritedType : knownInherited->second) {
25532619
// If we have inherited associated type...
25542620
if (auto inheritedAssocTypeDecl =
25552621
dyn_cast<AssociatedTypeDecl>(inheritedType)) {
2556-
// FIXME: Wire up same-type constraint.
2622+
// Infer a same-type requirement among the same-named associated
2623+
// types.
2624+
addInferredSameTypeReq(assocTypeDecl, inheritedAssocTypeDecl);
25572625

25582626
// Complain about the first redeclaration.
25592627
if (shouldWarnAboutRedeclaration) {
25602628
auto inheritedFromProto = inheritedAssocTypeDecl->getProtocol();
25612629
auto fixItWhere = getProtocolWhereLoc();
2562-
Diags.diagnose(AssocType,
2630+
Diags.diagnose(assocTypeDecl,
25632631
diag::inherited_associated_type_redecl,
2564-
AssocType->getFullName(),
2632+
assocTypeDecl->getFullName(),
25652633
inheritedFromProto->getDeclaredInterfaceType())
25662634
.fixItInsertAfter(
2567-
fixItWhere.first,
2568-
getAssociatedTypeReqs(AssocType, fixItWhere.second))
2569-
.fixItRemove(AssocType->getSourceRange());
2635+
fixItWhere.first,
2636+
getAssociatedTypeReqs(assocTypeDecl, fixItWhere.second))
2637+
.fixItRemove(assocTypeDecl->getSourceRange());
25702638

25712639
Diags.diagnose(inheritedAssocTypeDecl, diag::decl_declared_here,
25722640
inheritedAssocTypeDecl->getFullName());
@@ -2592,11 +2660,13 @@ ConstraintResult GenericSignatureBuilder::addConformanceRequirement(
25922660
bool shouldWarnAboutRedeclaration =
25932661
Source->kind == RequirementSource::RequirementSignatureSelf;
25942662

2595-
for (auto inheritedType : knownInherited->getSecond()) {
2663+
for (auto inheritedType : knownInherited->second) {
25962664
// If we have inherited associated type...
25972665
if (auto inheritedAssocTypeDecl =
25982666
dyn_cast<AssociatedTypeDecl>(inheritedType)) {
2599-
// FIXME: Wire up same-type constraint.
2667+
// Infer a same-type requirement between the typealias' underlying
2668+
// type and the inherited associated type.
2669+
addInferredSameTypeReq(inheritedAssocTypeDecl, typealias);
26002670

26012671
// Warn that one should use where clauses for this.
26022672
if (shouldWarnAboutRedeclaration) {
@@ -2626,6 +2696,16 @@ ConstraintResult GenericSignatureBuilder::addConformanceRequirement(
26262696
}
26272697
}
26282698

2699+
// Infer same-type requirements among inherited type declarations.
2700+
for (auto &entry : inheritedTypeDecls) {
2701+
if (entry.second.size() < 2) continue;
2702+
2703+
auto firstDecl = entry.second.front();
2704+
for (auto otherDecl : ArrayRef<TypeDecl *>(entry.second).slice(1)) {
2705+
addInferredSameTypeReq(firstDecl, otherDecl);
2706+
}
2707+
}
2708+
26292709
return ConstraintResult::Resolved;
26302710
}
26312711

lib/Sema/TypeCheckDecl.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7393,6 +7393,40 @@ void TypeChecker::validateDeclForNameLookup(ValueDecl *D) {
73937393
validateAccessibility(assocType);
73947394
break;
73957395
}
7396+
case DeclKind::TypeAlias: {
7397+
auto typealias = cast<TypeAliasDecl>(D);
7398+
if (typealias->getUnderlyingTypeLoc().getType())
7399+
return;
7400+
7401+
// Perform earlier validation of typealiases in protocols.
7402+
if (auto proto = dyn_cast<ProtocolDecl>(dc)) {
7403+
if (!typealias->getGenericParams()) {
7404+
ProtocolRequirementTypeResolver resolver(proto);
7405+
TypeResolutionOptions options;
7406+
7407+
if (typealias->isBeingValidated()) return;
7408+
7409+
typealias->setIsBeingValidated();
7410+
SWIFT_DEFER { typealias->setIsBeingValidated(false); };
7411+
7412+
validateAccessibility(typealias);
7413+
if (typealias->getFormalAccess() <= Accessibility::FilePrivate)
7414+
options |= TR_KnownNonCascadingDependency;
7415+
7416+
if (validateType(typealias->getUnderlyingTypeLoc(),
7417+
typealias, options, &resolver)) {
7418+
typealias->setInvalid();
7419+
typealias->getUnderlyingTypeLoc().setInvalidType(Context);
7420+
}
7421+
7422+
typealias->setUnderlyingType(
7423+
typealias->getUnderlyingTypeLoc().getType());
7424+
7425+
return;
7426+
}
7427+
}
7428+
LLVM_FALLTHROUGH;
7429+
}
73967430

73977431
default:
73987432
validateDecl(D);

test/Generics/protocol_type_aliases.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ protocol Q3: P3 {
6262
protocol P3_1 {
6363
typealias T = Float // expected-error{{type alias 'T' requires types 'P3.T' (aka 'Int') and 'Float' to be the same}}
6464
}
65-
protocol Q3_1: P3, P3_1 {}
65+
protocol Q3_1: P3, P3_1 {} // expected-error{{generic signature requires types 'Float'}}
6666

6767
// FIXME: these shouldn't be necessary to trigger the errors above, but are, due to
6868
// the 'recursive decl validation' FIXME in GenericSignatureBuilder.cpp.

test/Generics/requirement_inference.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func inferSuperclassRequirement2<T : Canidae>(_ v: U<T>) {}
9191
// ----------------------------------------------------------------------------
9292

9393
protocol P3 {
94-
associatedtype P3Assoc : P2
94+
associatedtype P3Assoc : P2 // expected-note{{declared here}}
9595
}
9696

9797
protocol P4 {
@@ -389,3 +389,18 @@ protocol P27b {
389389
associatedtype A
390390
associatedtype B where A == X26<B>
391391
}
392+
393+
// ----------------------------------------------------------------------------
394+
// Inference of associated type relationships within a protocol hierarchy
395+
// ----------------------------------------------------------------------------
396+
397+
struct X28 : P2 {
398+
func p1() { }
399+
}
400+
401+
// CHECK-LABEL: .P28@
402+
// CHECK-NEXT: Requirement signature: <Self where Self : P3, Self.P3Assoc == X28>
403+
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0 : P3, τ_0_0.P3Assoc == X28>
404+
protocol P28: P3 {
405+
typealias P3Assoc = X28 // expected-warning{{typealias overriding associated type}}
406+
}

0 commit comments

Comments
 (0)