Skip to content

Commit ad7073d

Browse files
committed
---
yaml --- r: 348497 b: refs/heads/master c: a72ef5d h: refs/heads/master i: 348495: 0284823
1 parent f1696f8 commit ad7073d

File tree

13 files changed

+133
-61
lines changed

13 files changed

+133
-61
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: b9d1078bf682ca39cc949833e51d38be2589a75e
2+
refs/heads/master: a72ef5d912a155f16bbfb7b2f0144a166f80aeed
33
refs/heads/master-next: 203b3026584ecad859eb328b2e12490099409cd5
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea

trunk/include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,6 +1616,11 @@ ERROR(inferred_opaque_type,none,
16161616
// Extensions
16171617
ERROR(non_nominal_extension,none,
16181618
"non-nominal type %0 cannot be extended", (Type))
1619+
WARNING(composition_in_extended_type,none,
1620+
"extending a protocol composition is not supported; extending %0 "
1621+
"instead", (Type))
1622+
NOTE(composition_in_extended_type_alternative,none,
1623+
"did you mean to extend the most specific type %0 instead?", (Type))
16191624
ERROR(extension_access_with_conformances,none,
16201625
"%0 modifier cannot be used with extensions that declare "
16211626
"protocol conformances", (DeclAttribute))

trunk/lib/AST/NameLookup.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2123,26 +2123,25 @@ SuperclassDeclRequest::evaluate(Evaluator &evaluator,
21232123
llvm::Expected<NominalTypeDecl *>
21242124
ExtendedNominalRequest::evaluate(Evaluator &evaluator,
21252125
ExtensionDecl *ext) const {
2126-
DirectlyReferencedTypeDecls referenced;
2127-
ASTContext &ctx = ext->getASTContext();
2126+
auto typeRepr = ext->getExtendedTypeRepr();
2127+
if (!typeRepr)
2128+
// We must've seen 'extension { ... }' during parsing.
2129+
return nullptr;
21282130

2129-
// Prefer syntactic information when we have it.
2130-
if (auto typeRepr = ext->getExtendedTypeRepr()) {
2131-
referenced = directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext);
2132-
} else if (auto type = ext->getExtendedType()) {
2133-
// Fall back to semantic types.
2134-
// FIXME: In the long run, we shouldn't need this. Non-syntactic results
2135-
// should be cached.
2136-
referenced = directReferencesForType(type);
2137-
}
2131+
ASTContext &ctx = ext->getASTContext();
2132+
DirectlyReferencedTypeDecls referenced =
2133+
directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext);
21382134

21392135
// Resolve those type declarations to nominal type declarations.
21402136
SmallVector<ModuleDecl *, 2> modulesFound;
21412137
bool anyObject = false;
21422138
auto nominalTypes
21432139
= resolveTypeDeclsToNominal(evaluator, ctx, referenced, modulesFound,
21442140
anyObject);
2145-
return nominalTypes.empty() ? nullptr : nominalTypes.front();
2141+
2142+
// If there is more than 1 element, we will emit a warning or an error
2143+
// elsewhere, so don't handle that case here.
2144+
return nominalTypes.empty() ? nullptr : nominalTypes[0];
21462145
}
21472146

21482147
llvm::Expected<NominalTypeDecl *>

trunk/lib/ClangImporter/ImportDecl.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/AST/GenericSignature.h"
3131
#include "swift/AST/Module.h"
3232
#include "swift/AST/NameLookup.h"
33+
#include "swift/AST/NameLookupRequests.h"
3334
#include "swift/AST/ParameterList.h"
3435
#include "swift/AST/Pattern.h"
3536
#include "swift/AST/PrettyStackTrace.h"
@@ -4545,10 +4546,10 @@ namespace {
45454546
Impl.SwiftContext, loc,
45464547
nullptr,
45474548
{ }, dc, nullptr, decl);
4548-
Impl.SwiftContext
4549-
.evaluator
4550-
.cacheOutput(ExtendedTypeRequest{result},
4551-
objcClass->getDeclaredType());
4549+
Impl.SwiftContext.evaluator.cacheOutput(ExtendedTypeRequest{result},
4550+
objcClass->getDeclaredType());
4551+
Impl.SwiftContext.evaluator.cacheOutput(ExtendedNominalRequest{result},
4552+
objcClass);
45524553

45534554
// Determine the type and generic args of the extension.
45544555
if (objcClass->getGenericParams()) {
@@ -8126,6 +8127,8 @@ ClangImporter::Implementation::importDeclContextOf(
81268127
getClangModuleForDecl(decl), nullptr);
81278128
SwiftContext.evaluator.cacheOutput(ExtendedTypeRequest{ext},
81288129
nominal->getDeclaredType());
8130+
SwiftContext.evaluator.cacheOutput(ExtendedNominalRequest{ext},
8131+
std::move(nominal));
81298132
ext->setValidationToChecked();
81308133
ext->setMemberLoader(this, reinterpret_cast<uintptr_t>(declSubmodule));
81318134

trunk/lib/Sema/TypeCheckDecl.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3057,7 +3057,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
30573057

30583058
auto nominal = ED->getExtendedNominal();
30593059
if (nominal == nullptr) {
3060-
const bool wasAlreadyInvalid = ED->isInvalid();
3060+
const bool wasAlreadyInvalid = ED->isInvalid();
30613061
ED->setInvalid();
30623062
if (extType && !extType->hasError() && extType->getAnyNominal()) {
30633063
// If we've got here, then we have some kind of extension of a prima
@@ -3075,14 +3075,49 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
30753075
.fixItReplace(ED->getExtendedTypeRepr()->getSourceRange(),
30763076
canExtType->getString());
30773077
} else if (!wasAlreadyInvalid) {
3078-
// If nothing else applies, fall back to a generic diagnostic.
3078+
// If nothing else applies, fall back to a generic diagnostic.
30793079
ED->diagnose(diag::non_nominal_extension, extType);
30803080
}
30813081
return;
30823082
}
30833083

30843084
TC.validateExtension(ED);
30853085

3086+
extType = ED->getExtendedType();
3087+
if (extType && !extType->hasError()) {
3088+
// The first condition catches syntactic forms like
3089+
// protocol A & B { ... } // may be protocols or typealiases
3090+
// The second condition also looks through typealiases and catches
3091+
// typealias T = P1 & P2 // P2 is a refined protocol of P1
3092+
// extension T { ... }
3093+
// However, it is trickier to catch cases like
3094+
// typealias T = P2 & P1 // P2 is a refined protocol of P1
3095+
// extension T { ... }
3096+
// so we don't do that here.
3097+
auto extTypeRepr = ED->getExtendedTypeRepr();
3098+
auto *extTypeNominal = extType->getAnyNominal();
3099+
bool firstNominalIsNotMostSpecific =
3100+
extTypeNominal && extTypeNominal != nominal;
3101+
if (isa<CompositionTypeRepr>(extTypeRepr)
3102+
|| firstNominalIsNotMostSpecific) {
3103+
auto firstNominalType = nominal->getDeclaredType();
3104+
auto diag = ED->diagnose(diag::composition_in_extended_type,
3105+
firstNominalType);
3106+
diag.highlight(extTypeRepr->getSourceRange());
3107+
if (firstNominalIsNotMostSpecific) {
3108+
diag.flush();
3109+
Type mostSpecificProtocol = extTypeNominal->getDeclaredType();
3110+
ED->diagnose(diag::composition_in_extended_type_alternative,
3111+
mostSpecificProtocol)
3112+
.fixItReplace(extTypeRepr->getSourceRange(),
3113+
mostSpecificProtocol->getString());
3114+
} else {
3115+
diag.fixItReplace(extTypeRepr->getSourceRange(),
3116+
firstNominalType->getString());
3117+
}
3118+
}
3119+
}
3120+
30863121
checkInheritanceClause(ED);
30873122

30883123
// Check the raw values of an enum, since we might synthesize

trunk/lib/Sema/TypeCheckGeneric.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//===----------------------------------------------------------------------===//
1616
#include "TypeChecker.h"
1717
#include "TypeCheckType.h"
18+
#include "swift/AST/DiagnosticsSema.h"
1819
#include "swift/AST/ExistentialLayout.h"
1920
#include "swift/AST/GenericEnvironment.h"
2021
#include "swift/AST/GenericSignatureBuilder.h"

trunk/lib/Serialization/Deserialization.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/ForeignErrorConvention.h"
2121
#include "swift/AST/GenericEnvironment.h"
2222
#include "swift/AST/Initializer.h"
23+
#include "swift/AST/NameLookupRequests.h"
2324
#include "swift/AST/Pattern.h"
2425
#include "swift/AST/ParameterList.h"
2526
#include "swift/AST/PrettyStackTrace.h"
@@ -3688,14 +3689,16 @@ class swift::DeclDeserializer {
36883689

36893690
Expected<Decl *> deserializeExtension(ArrayRef<uint64_t> scratch,
36903691
StringRef blobData) {
3691-
TypeID baseID;
3692+
TypeID extendedTypeID;
3693+
DeclID extendedNominalID;
36923694
DeclContextID contextID;
36933695
bool isImplicit;
36943696
GenericSignatureID genericEnvID;
36953697
unsigned numConformances, numInherited;
36963698
ArrayRef<uint64_t> inheritedAndDependencyIDs;
36973699

3698-
decls_block::ExtensionLayout::readRecord(scratch, baseID, contextID,
3700+
decls_block::ExtensionLayout::readRecord(scratch, extendedTypeID,
3701+
extendedNominalID, contextID,
36993702
isImplicit, genericEnvID,
37003703
numConformances, numInherited,
37013704
inheritedAndDependencyIDs);
@@ -3732,10 +3735,12 @@ class swift::DeclDeserializer {
37323735

37333736
MF.configureGenericEnvironment(extension, genericEnvID);
37343737

3735-
auto baseTy = MF.getType(baseID);
3738+
auto extendedType = MF.getType(extendedTypeID);
37363739
ctx.evaluator.cacheOutput(ExtendedTypeRequest{extension},
3737-
std::move(baseTy));
3738-
auto nominal = extension->getExtendedNominal();
3740+
std::move(extendedType));
3741+
auto nominal = dyn_cast<NominalTypeDecl>(MF.getDecl(extendedNominalID));
3742+
ctx.evaluator.cacheOutput(ExtendedNominalRequest{extension},
3743+
std::move(nominal));
37393744

37403745
if (isImplicit)
37413746
extension->setImplicit();

trunk/lib/Serialization/ModuleFormat.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5252
/// describe what change you made. The content of this comment isn't important;
5353
/// it just ensures a conflict if two people change the module format.
5454
/// Don't worry about adhering to the 80-column limit for this line.
55-
const uint16_t SWIFTMODULE_VERSION_MINOR = 517; // better string hash seed
55+
const uint16_t SWIFTMODULE_VERSION_MINOR = 518; // save extended nominal separately when serializing extensions
5656

5757
/// A standard hash seed used for all string hashes in a serialized module.
5858
///
@@ -1284,7 +1284,8 @@ namespace decls_block {
12841284

12851285
using ExtensionLayout = BCRecordLayout<
12861286
EXTENSION_DECL,
1287-
TypeIDField, // base type
1287+
TypeIDField, // extended type
1288+
DeclIDField, // extended nominal
12881289
DeclContextIDField, // context decl
12891290
BCFixed<1>, // implicit flag
12901291
GenericSignatureIDField, // generic environment

trunk/lib/Serialization/Serialization.cpp

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2641,8 +2641,8 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
26412641
verifyAttrSerializable(extension);
26422642

26432643
auto contextID = S.addDeclContextRef(extension->getDeclContext());
2644-
Type baseTy = extension->getExtendedType();
2645-
assert(!baseTy->hasArchetype());
2644+
Type extendedType = extension->getExtendedType();
2645+
assert(!extendedType->hasArchetype());
26462646

26472647
// FIXME: Use the canonical type here in order to minimize circularity
26482648
// issues at deserialization time. A known problematic case here is
@@ -2652,12 +2652,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
26522652
//
26532653
// We could limit this to only the problematic cases, but it seems like a
26542654
// simpler user model to just always desugar extension types.
2655-
baseTy = baseTy->getCanonicalType();
2656-
2657-
// Make sure the base type has registered itself as a provider of generic
2658-
// parameters.
2659-
auto baseNominal = baseTy->getAnyNominal();
2660-
(void)S.addDeclRef(baseNominal);
2655+
extendedType = extendedType->getCanonicalType();
26612656

26622657
auto conformances = extension->getLocalConformances(
26632658
ConformanceLookupKind::All, nullptr);
@@ -2670,7 +2665,8 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
26702665
size_t numInherited = inheritedAndDependencyTypes.size();
26712666

26722667
llvm::SmallSetVector<Type, 4> dependencies;
2673-
collectDependenciesFromType(dependencies, baseTy, /*excluding*/nullptr);
2668+
collectDependenciesFromType(
2669+
dependencies, extendedType, /*excluding*/nullptr);
26742670
for (Requirement req : extension->getGenericRequirements()) {
26752671
collectDependenciesFromRequirement(dependencies, req,
26762672
/*excluding*/nullptr);
@@ -2679,8 +2675,10 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
26792675
inheritedAndDependencyTypes.push_back(S.addTypeRef(dependencyTy));
26802676

26812677
unsigned abbrCode = S.DeclTypeAbbrCodes[ExtensionLayout::Code];
2678+
auto extendedNominal = extension->getExtendedNominal();
26822679
ExtensionLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode,
2683-
S.addTypeRef(baseTy),
2680+
S.addTypeRef(extendedType),
2681+
S.addDeclRef(extendedNominal),
26842682
contextID.getOpaqueValue(),
26852683
extension->isImplicit(),
26862684
S.addGenericEnvironmentRef(
@@ -2690,9 +2688,9 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
26902688
inheritedAndDependencyTypes);
26912689

26922690
bool isClassExtension = false;
2693-
if (baseNominal) {
2694-
isClassExtension = isa<ClassDecl>(baseNominal) ||
2695-
isa<ProtocolDecl>(baseNominal);
2691+
if (extendedNominal) {
2692+
isClassExtension = isa<ClassDecl>(extendedNominal) ||
2693+
isa<ProtocolDecl>(extendedNominal);
26962694
}
26972695

26982696
// Extensions of nested generic types have multiple generic parameter
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %target-typecheck-verify-swift
2+
// RUN: %empty-directory(%t)
3+
// RUN: %target-swift-frontend -primary-file %s %S/Inputs/composition_extension_usage.swift -emit-module-path %t/P-partial.swiftmodule -module-name SR11227 -enable-testing
4+
// RUN: %target-swift-frontend -primary-file %S/Inputs/composition_extension_usage.swift %s -emit-module-path %t/S-partial.swiftmodule -module-name SR11227 -enable-testing
5+
// RUN: %target-swift-frontend -sil-merge-partial-modules %t/P-partial.swiftmodule %t/S-partial.swiftmodule -emit-module -o %t/SR11227.swiftmodule
6+
7+
protocol P1 {}
8+
9+
protocol P1_1 : P1 {
10+
func p1_1()
11+
}
12+
13+
protocol P2 {}
14+
15+
extension P1 & P1_1 where Self : P2 {
16+
// expected-warning@-1 {{extending a protocol composition is not supported; extending 'P1' instead}}
17+
// expected-note@-2 {{did you mean to extend the most specific type 'P1_1' instead?}} {{11-20=P1_1}}
18+
func p1_1() {}
19+
}
20+
21+
extension P1_1 & P1 where Self : P2 {
22+
// expected-warning@-1 {{extending a protocol composition is not supported; extending 'P1_1' instead}} {{11-20=P1_1}}
23+
func p1_1_alt() {}
24+
}
25+
26+
typealias T1 = P1 & P1_1
27+
28+
extension T1 {
29+
// expected-warning@-1 {{extending a protocol composition is not supported; extending 'P1' instead}}
30+
// expected-note@-2 {{did you mean to extend the most specific type 'P1_1' instead?}} {{11-13=P1_1}}
31+
func t1() {}
32+
}
33+
34+
typealias T2 = T1
35+
36+
extension T2 {
37+
// expected-warning@-1 {{extending a protocol composition is not supported; extending 'P1' instead}}
38+
// expected-note@-2 {{did you mean to extend the most specific type 'P1_1' instead?}} {{11-13=P1_1}}
39+
func t2() {}
40+
}
41+
42+
typealias T3 = P1_1 & P1
43+
44+
extension T3 { // Ideally, we should emit a warning here but the current implementation doesn't do that.
45+
func t3() {}
46+
}

trunk/test/Sema/composition_extensions.swift

Lines changed: 0 additions & 19 deletions
This file was deleted.

trunk/test/decl/ext/protocol.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -991,9 +991,7 @@ class BadClass5 : BadProto5 {} // expected-error{{type 'BadClass5' does not conf
991991
typealias A = BadProto1
992992
typealias B = BadProto1
993993

994-
extension A & B { // okay
995-
996-
}
994+
extension A & B {} // expected-warning {{extending a protocol composition is not supported; extending 'BadProto1' instead}}
997995

998996
// Suppress near-miss warning for unlabeled initializers.
999997
protocol P9 {

0 commit comments

Comments
 (0)