Skip to content

Commit c6ab136

Browse files
authored
Merge pull request #14628 from huonw/no-conditional-objc-generics
[Sema] Disallow conditional conformances on objective-c generics.
2 parents a14b0d0 + dd845c4 commit c6ab136

File tree

9 files changed

+142
-43
lines changed

9 files changed

+142
-43
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,10 @@ ERROR(objc_runtime_visible_cannot_conform_to_objc_protocol,none,
14201420
"class %0 cannot conform to @objc protocol %1 because "
14211421
"the class is only visible via the Objective-C runtime",
14221422
(Type, Type))
1423+
ERROR(objc_generics_cannot_conditionally_conform,none,
1424+
"type %0 cannot conditionally conform to protocol %1 because "
1425+
"the type uses the Objective-C generics model",
1426+
(Type, Type))
14231427
ERROR(protocol_has_missing_requirements,none,
14241428
"type %0 cannot conform to protocol %1 because it has requirements that "
14251429
"cannot be satisfied", (Type, Type))

include/swift/AST/PrintOptions.h

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/Basic/STLExtras.h"
1717
#include "swift/AST/AttrKind.h"
1818
#include "swift/AST/Identifier.h"
19+
#include "swift/AST/TypeOrExtensionDecl.h"
1920
#include "llvm/ADT/Optional.h"
2021
#include <limits.h>
2122
#include <vector>
@@ -36,32 +37,6 @@ enum DeclAttrKind : unsigned;
3637
class SynthesizedExtensionAnalyzer;
3738
struct PrintOptions;
3839

39-
/// \brief Describes either a nominal type declaration or an extension
40-
/// declaration.
41-
struct TypeOrExtensionDecl {
42-
llvm::PointerUnion<NominalTypeDecl *, ExtensionDecl *> Decl;
43-
44-
TypeOrExtensionDecl() = default;
45-
46-
TypeOrExtensionDecl(NominalTypeDecl *D);
47-
TypeOrExtensionDecl(ExtensionDecl *D);
48-
49-
/// \brief Return the contained *Decl as the Decl superclass.
50-
class Decl *getAsDecl() const;
51-
/// \brief Return the contained *Decl as the DeclContext superclass.
52-
DeclContext *getAsDeclContext() const;
53-
/// \brief Return the contained NominalTypeDecl or that of the extended type
54-
/// in the ExtensionDecl.
55-
NominalTypeDecl *getBaseNominal() const;
56-
57-
/// \brief Is the contained pointer null?
58-
bool isNull() const;
59-
explicit operator bool() const { return !isNull(); }
60-
61-
bool operator==(TypeOrExtensionDecl rhs) { return Decl == rhs.Decl; }
62-
bool operator!=(TypeOrExtensionDecl rhs) { return Decl != rhs.Decl; }
63-
bool operator<(TypeOrExtensionDecl rhs) { return Decl < rhs.Decl; }
64-
};
6540

6641
/// Necessary information for archetype transformation during printing.
6742
struct TypeTransformContext {

include/swift/AST/TypeAlignments.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ namespace swift {
3737
class ExtensionDecl;
3838
class GenericEnvironment;
3939
class GenericTypeParamDecl;
40+
class NominalTypeDecl;
4041
class NormalProtocolConformance;
4142
class OperatorDecl;
4243
class Pattern;
@@ -90,6 +91,7 @@ LLVM_DECLARE_TYPE_ALIGNMENT(swift::OperatorDecl, swift::DeclAlignInBits)
9091
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ProtocolDecl, swift::DeclAlignInBits)
9192
LLVM_DECLARE_TYPE_ALIGNMENT(swift::TypeDecl, swift::DeclAlignInBits)
9293
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ValueDecl, swift::DeclAlignInBits)
94+
LLVM_DECLARE_TYPE_ALIGNMENT(swift::NominalTypeDecl, swift::DeclAlignInBits)
9395
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ExtensionDecl, swift::DeclAlignInBits)
9496

9597
LLVM_DECLARE_TYPE_ALIGNMENT(swift::TypeBase, swift::TypeAlignInBits)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//===- TypeOrExtensionDecl.h - Swift Language Declaration ASTs -*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines the TypeOrExtensionDecl struct, separately to Decl.h so
14+
// that this can be included in files that Decl.h includes.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_TYPE_OR_EXTENSION_DECL_H
19+
#define SWIFT_TYPE_OR_EXTENSION_DECL_H
20+
21+
#include "swift/AST/TypeAlignments.h"
22+
#include "llvm/ADT/PointerUnion.h"
23+
24+
namespace swift {
25+
26+
/// \brief Describes either a nominal type declaration or an extension
27+
/// declaration.
28+
struct TypeOrExtensionDecl {
29+
// (The definitions are in Decl.cpp.)
30+
llvm::PointerUnion<NominalTypeDecl *, ExtensionDecl *> Decl;
31+
32+
TypeOrExtensionDecl() = default;
33+
34+
TypeOrExtensionDecl(NominalTypeDecl *D);
35+
TypeOrExtensionDecl(ExtensionDecl *D);
36+
37+
/// \brief Return the contained *Decl as the Decl superclass.
38+
class Decl *getAsDecl() const;
39+
/// \brief Return the contained *Decl as the DeclContext superclass.
40+
DeclContext *getAsDeclContext() const;
41+
/// \brief Return the contained NominalTypeDecl or that of the extended type
42+
/// in the ExtensionDecl.
43+
NominalTypeDecl *getBaseNominal() const;
44+
45+
/// \brief Is the contained pointer null?
46+
bool isNull() const;
47+
explicit operator bool() const { return !isNull(); }
48+
49+
bool operator==(TypeOrExtensionDecl rhs) { return Decl == rhs.Decl; }
50+
bool operator!=(TypeOrExtensionDecl rhs) { return Decl != rhs.Decl; }
51+
bool operator<(TypeOrExtensionDecl rhs) { return Decl < rhs.Decl; }
52+
};
53+
54+
} // end namespace swift
55+
56+
#endif

lib/AST/ASTPrinter.cpp

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -63,23 +63,6 @@ void PrintOptions::clearSynthesizedExtension() {
6363
TransformContext.reset();
6464
}
6565

66-
TypeOrExtensionDecl::TypeOrExtensionDecl(NominalTypeDecl *D) : Decl(D) {}
67-
TypeOrExtensionDecl::TypeOrExtensionDecl(ExtensionDecl *D) : Decl(D) {}
68-
69-
Decl *TypeOrExtensionDecl::getAsDecl() const {
70-
if (auto NTD = Decl.dyn_cast<NominalTypeDecl *>())
71-
return NTD;
72-
73-
return Decl.get<ExtensionDecl *>();
74-
}
75-
DeclContext *TypeOrExtensionDecl::getAsDeclContext() const {
76-
return getAsDecl()->getInnermostDeclContext();
77-
}
78-
NominalTypeDecl *TypeOrExtensionDecl::getBaseNominal() const {
79-
return getAsDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext();
80-
}
81-
bool TypeOrExtensionDecl::isNull() const { return Decl.isNull(); }
82-
8366
TypeTransformContext::TypeTransformContext(Type T)
8467
: BaseType(T.getPointer()) {
8568
assert(T->mayHaveMembers());

lib/AST/Decl.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5688,3 +5688,20 @@ UnifiedStatsReporter::getStatsTracer(StringRef EventName, const Decl *D) {
56885688
// Return inert tracer object.
56895689
return FrontendStatsTracer();
56905690
}
5691+
5692+
TypeOrExtensionDecl::TypeOrExtensionDecl(NominalTypeDecl *D) : Decl(D) {}
5693+
TypeOrExtensionDecl::TypeOrExtensionDecl(ExtensionDecl *D) : Decl(D) {}
5694+
5695+
Decl *TypeOrExtensionDecl::getAsDecl() const {
5696+
if (auto NTD = Decl.dyn_cast<NominalTypeDecl *>())
5697+
return NTD;
5698+
5699+
return Decl.get<ExtensionDecl *>();
5700+
}
5701+
DeclContext *TypeOrExtensionDecl::getAsDeclContext() const {
5702+
return getAsDecl()->getInnermostDeclContext();
5703+
}
5704+
NominalTypeDecl *TypeOrExtensionDecl::getBaseNominal() const {
5705+
return getAsDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext();
5706+
}
5707+
bool TypeOrExtensionDecl::isNull() const { return Decl.isNull(); }

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,6 +1331,27 @@ checkIndividualConformance(NormalProtocolConformance *conformance,
13311331
}
13321332
}
13331333

1334+
// Not every protocol/type is compatible with conditional conformances.
1335+
if (!conformance->getConditionalRequirements().empty()) {
1336+
auto nestedType = canT;
1337+
// Obj-C generics cannot be looked up at runtime, so we don't support
1338+
// conditional conformances involving them. Check the full stack of nested
1339+
// types for any obj-c ones.
1340+
while (nestedType) {
1341+
if (auto clas = nestedType->getClassOrBoundGenericClass()) {
1342+
if (clas->usesObjCGenericsModel()) {
1343+
TC.diagnose(ComplainLoc,
1344+
diag::objc_generics_cannot_conditionally_conform, T,
1345+
Proto->getDeclaredType());
1346+
conformance->setInvalid();
1347+
return conformance;
1348+
}
1349+
}
1350+
1351+
nestedType = nestedType.getNominalParent();
1352+
}
1353+
}
1354+
13341355
// If the protocol contains missing requirements, it can't be conformed to
13351356
// at all.
13361357
if (Proto->hasMissingRequirements()) {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@import Foundation;
2+
3+
@interface ObjC <ObjectType>: NSObject
4+
@end
5+
6+
@interface ObjC2: NSObject
7+
@end
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %target-typecheck-verify-swift -import-objc-header %S/Inputs/conditional_conformances_objc.h
2+
3+
// REQUIRES: objc_interop
4+
5+
protocol Foo {}
6+
extension ObjC: Foo where ObjectType == ObjC2 {}
7+
// expected-error@-1{{type 'ObjC<ObjectType>' cannot conditionally conform to protocol 'Foo' because the type uses the Objective-C generics model}}
8+
9+
protocol Bar {}
10+
extension ObjC: Bar where ObjectType: Bar {}
11+
// expected-error@-1{{type 'ObjC<ObjectType>' cannot conditionally conform to protocol 'Bar' because the type uses the Objective-C generics model}}
12+
13+
extension ObjC {
14+
struct Struct {
15+
enum Enum {}
16+
}
17+
class Class<T> {}
18+
}
19+
20+
extension ObjC.Struct: Foo where ObjectType == ObjC2 {}
21+
// expected-error@-1{{type 'ObjC<ObjectType>.Struct' cannot conditionally conform to protocol 'Foo' because the type uses the Objective-C generics model}}
22+
extension ObjC.Struct: Bar where ObjectType: Bar {}
23+
// expected-error@-1{{type 'ObjC<ObjectType>.Struct' cannot conditionally conform to protocol 'Bar' because the type uses the Objective-C generics model}}
24+
25+
extension ObjC.Struct.Enum: Foo where ObjectType == ObjC2 {}
26+
// expected-error@-1{{type 'ObjC<ObjectType>.Struct.Enum' cannot conditionally conform to protocol 'Foo' because the type uses the Objective-C generics model}}
27+
extension ObjC.Struct.Enum: Bar where ObjectType: Bar {}
28+
// expected-error@-1{{type 'ObjC<ObjectType>.Struct.Enum' cannot conditionally conform to protocol 'Bar' because the type uses the Objective-C generics model}}
29+
30+
extension ObjC.Class: Foo where T == ObjC2 {}
31+
// expected-error@-1{{type 'ObjC<ObjectType>.Class<T>' cannot conditionally conform to protocol 'Foo' because the type uses the Objective-C generics model}}
32+
extension ObjC.Class: Bar where T: Bar {}
33+
// expected-error@-1{{type 'ObjC<ObjectType>.Class<T>' cannot conditionally conform to protocol 'Bar' because the type uses the Objective-C generics model}}
34+

0 commit comments

Comments
 (0)