Skip to content

Commit 0775808

Browse files
committed
Reject invalid derived Hashable members explicitly
Hashable doesn't quite have the know-how to reject invalid derivation contexts before hand. Give it a little help by adding a way to retrieve if a decl added to the conformance context was invalid after type checking completes. Otherwise we'll emit "Hashable is broken".
1 parent cab4e9f commit 0775808

File tree

4 files changed

+15
-5
lines changed

4 files changed

+15
-5
lines changed

lib/Sema/DerivedConformanceEquatableHashable.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1251,7 +1251,11 @@ static ValueDecl *deriveHashable_hashValue(DerivedConformance &derived) {
12511251
C, StaticSpellingKind::None, hashValuePat, /*InitExpr*/ nullptr,
12521252
parentDC);
12531253

1254-
derived.addMembersToConformanceContext({hashValueDecl, patDecl});
1254+
// If any of the members we synthesized didn't typecheck, bail out.
1255+
if (derived.addMembersToConformanceContext({hashValueDecl, patDecl})) {
1256+
return nullptr;
1257+
}
1258+
12551259
return hashValueDecl;
12561260
}
12571261

lib/Sema/DerivedConformances.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,16 @@ DeclContext *DerivedConformance::getConformanceContext() const {
3535
return cast<DeclContext>(ConformanceDecl);
3636
}
3737

38-
void DerivedConformance::addMembersToConformanceContext(
38+
bool DerivedConformance::addMembersToConformanceContext(
3939
ArrayRef<Decl *> children) {
4040
auto IDC = cast<IterableDeclContext>(ConformanceDecl);
41+
bool anyInvalid = false;
4142
for (auto child : children) {
4243
IDC->addMember(child);
4344
TypeChecker::typeCheckDecl(child);
45+
anyInvalid |= child->isInvalid();
4446
}
47+
return anyInvalid;
4548
}
4649

4750
Type DerivedConformance::getProtocolType() const {

lib/Sema/DerivedConformances.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ class DerivedConformance {
4646
DeclContext *getConformanceContext() const;
4747

4848
/// Add \c children as members of the context that declares the conformance.
49-
void addMembersToConformanceContext(ArrayRef<Decl *> children);
49+
///
50+
/// \returns True if any of the added members were found to be invalid after type
51+
/// checking.
52+
bool addMembersToConformanceContext(ArrayRef<Decl *> children);
5053

5154
/// Get the declared type of the protocol that this is conformance is for.
5255
Type getProtocolType() const;

test/Sema/enum_conformance_synthesis.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func customHashable() {
6161
enum InvalidCustomHashable {
6262
case A, B
6363

64-
var hashValue: String { return "" } // expected-note{{previously declared here}}
64+
var hashValue: String { return "" } // expected-note 2 {{previously declared here}}
6565
}
6666
func ==(x: InvalidCustomHashable, y: InvalidCustomHashable) -> String {
6767
return ""
@@ -72,7 +72,7 @@ func invalidCustomHashable() {
7272
s = InvalidCustomHashable.A.hashValue
7373
_ = s
7474
var _: Int = InvalidCustomHashable.A.hashValue
75-
InvalidCustomHashable.A.hash(into: &hasher)
75+
InvalidCustomHashable.A.hash(into: &hasher) // expected-error {{value of type 'InvalidCustomHashable' has no member 'hash'}}
7676
}
7777

7878
// Check use of an enum's synthesized members before the enum is actually declared.

0 commit comments

Comments
 (0)