Skip to content

Commit 5833f8b

Browse files
authored
Merge pull request #4637 from DougGregor/se-0112-customnserror-defaults-3-0
[SE-0112] [3.0] Provide default implements for the requirements of CustomNSError
2 parents da4d996 + cfe809e commit 5833f8b

16 files changed

+189
-196
lines changed

lib/AST/Decl.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2012,10 +2012,6 @@ bool NominalTypeDecl::derivesProtocolConformance(ProtocolDecl *protocol) const {
20122012
if (!knownProtocol)
20132013
return false;
20142014

2015-
// All nominal types can derive their Error conformance.
2016-
if (*knownProtocol == KnownProtocolKind::Error)
2017-
return true;
2018-
20192015
if (auto *enumDecl = dyn_cast<EnumDecl>(this)) {
20202016
switch (*knownProtocol) {
20212017
// Enums with raw types can implicitly derive their RawRepresentable

lib/Sema/DerivedConformanceError.cpp

Lines changed: 0 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -26,167 +26,6 @@
2626
using namespace swift;
2727
using namespace DerivedConformance;
2828

29-
static void deriveBodyError_enum_code(AbstractFunctionDecl *codeDecl) {
30-
// enum SomeEnum {
31-
// case A,B,C,D
32-
//
33-
// @derived
34-
// var code: Int {
35-
// switch self {
36-
// case A: return 0
37-
// case B: return 1
38-
// case C: return 2
39-
// ...
40-
// }
41-
// }
42-
// }
43-
//
44-
// TODO: Some convenient way to override the code if that's desired.
45-
46-
auto parentDC = codeDecl->getDeclContext();
47-
ASTContext &C = parentDC->getASTContext();
48-
49-
auto enumDecl = parentDC->getAsEnumOrEnumExtensionContext();
50-
Type enumType = parentDC->getDeclaredTypeInContext();
51-
52-
SmallVector<CaseStmt*, 4> cases;
53-
SmallString<11> strBuf;
54-
55-
unsigned code = 0;
56-
for (auto elt : enumDecl->getAllElements()) {
57-
auto pat = new (C) EnumElementPattern(TypeLoc::withoutLoc(enumType),
58-
SourceLoc(), SourceLoc(),
59-
Identifier(), elt, nullptr);
60-
pat->setImplicit();
61-
62-
auto labelItem =
63-
CaseLabelItem(/*IsDefault=*/false, pat, SourceLoc(), nullptr);
64-
65-
{
66-
strBuf.clear();
67-
llvm::raw_svector_ostream os(strBuf);
68-
os << code;
69-
}
70-
71-
auto codeStr = C.AllocateCopy(StringRef(strBuf));
72-
73-
auto returnExpr = new (C) IntegerLiteralExpr(codeStr, SourceLoc(),
74-
/*implicit*/ true);
75-
auto returnStmt = new (C) ReturnStmt(SourceLoc(), returnExpr,
76-
/*implicit*/ true);
77-
78-
auto body = BraceStmt::create(C, SourceLoc(),
79-
ASTNode(returnStmt), SourceLoc());
80-
81-
cases.push_back(CaseStmt::create(C, SourceLoc(), labelItem,
82-
/*HasBoundDecls=*/false, SourceLoc(),
83-
body));
84-
85-
++code;
86-
}
87-
88-
Stmt *bodyStmt;
89-
// If the enum is empty, simply return zero. (It doesn't really matter, since
90-
// the enum can't be instantiated regardless.)
91-
if (cases.empty()) {
92-
static const char zero[] = "0";
93-
auto returnExpr = new (C) IntegerLiteralExpr(zero, SourceLoc(),
94-
/*implicit*/ true);
95-
bodyStmt = new (C) ReturnStmt(SourceLoc(), returnExpr,
96-
/*implicit*/ true);
97-
} else {
98-
auto selfRef = createSelfDeclRef(codeDecl);
99-
bodyStmt = SwitchStmt::create(LabeledStmtInfo(), SourceLoc(), selfRef,
100-
SourceLoc(), cases, SourceLoc(), C);
101-
}
102-
auto body = BraceStmt::create(C, SourceLoc(),
103-
ASTNode(bodyStmt),
104-
SourceLoc());
105-
106-
codeDecl->setBody(body);
107-
}
108-
109-
static void deriveBodyError_zero_code(AbstractFunctionDecl *codeDecl) {
110-
// struct SomeStruct {
111-
// @derived
112-
// var code: Int { return 0 }
113-
// }
114-
//
115-
// TODO: Some convenient way to override the code if that's desired.
116-
117-
auto parentDC = codeDecl->getDeclContext();
118-
ASTContext &C = parentDC->getASTContext();
119-
120-
auto returnExpr = new (C) IntegerLiteralExpr("1", SourceLoc(),
121-
/*implicit*/ true);
122-
auto returnStmt = new (C) ReturnStmt(SourceLoc(), returnExpr,
123-
/*implicit*/ true);
124-
125-
auto body = BraceStmt::create(C, SourceLoc(),
126-
ASTNode(returnStmt), SourceLoc());
127-
128-
codeDecl->setBody(body);
129-
}
130-
131-
static ValueDecl *deriveError_code(TypeChecker &tc, Decl *parentDecl,
132-
NominalTypeDecl *nominal) {
133-
// enum SomeEnum {
134-
// case A,B,C,D
135-
//
136-
// @derived
137-
// var code: Int {
138-
// switch self {
139-
// case A: return 0
140-
// case B: return 1
141-
// case C: return 2
142-
// ...
143-
// }
144-
// }
145-
// }
146-
147-
ASTContext &C = tc.Context;
148-
149-
auto intTy = C.getIntDecl()->getDeclaredType();
150-
151-
// Define the getter.
152-
auto getterDecl = declareDerivedPropertyGetter(tc, parentDecl, nominal,
153-
intTy, intTy,
154-
/*isStatic=*/false,
155-
/*isFinal=*/true);
156-
if (isa<EnumDecl>(nominal))
157-
getterDecl->setBodySynthesizer(&deriveBodyError_enum_code);
158-
else
159-
getterDecl->setBodySynthesizer(&deriveBodyError_zero_code);
160-
161-
// Define the property.
162-
VarDecl *propDecl;
163-
PatternBindingDecl *pbDecl;
164-
std::tie(propDecl, pbDecl)
165-
= declareDerivedReadOnlyProperty(tc, parentDecl, nominal, C.Id_code_,
166-
intTy, intTy, getterDecl,
167-
/*isStatic=*/false, /*isFinal=*/true);
168-
169-
auto dc = cast<IterableDeclContext>(parentDecl);
170-
dc->addMember(getterDecl);
171-
dc->addMember(propDecl);
172-
dc->addMember(pbDecl);
173-
174-
return propDecl;
175-
176-
}
177-
178-
ValueDecl *DerivedConformance::deriveError(TypeChecker &tc,
179-
Decl *parentDecl,
180-
NominalTypeDecl *type,
181-
ValueDecl *requirement) {
182-
if (requirement->getName() == tc.Context.Id_code_)
183-
return deriveError_code(tc, parentDecl, type);
184-
185-
tc.diagnose(requirement->getLoc(),
186-
diag::broken_errortype_requirement);
187-
return nullptr;
188-
}
189-
19029
static void deriveBodyBridgedNSError_enum_nsErrorDomain(
19130
AbstractFunctionDecl *domainDecl) {
19231
// enum SomeEnum {

lib/Sema/DerivedConformances.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal,
5353
if (name.isSimpleName(ctx.Id_hashValue))
5454
return getRequirement(KnownProtocolKind::Hashable);
5555

56-
// Error._code
57-
if (name.isSimpleName(ctx.Id_code_))
58-
return getRequirement(KnownProtocolKind::Error);
59-
6056
// _BridgedNSError._nsErrorDomain
6157
if (name.isSimpleName(ctx.Id_nsErrorDomain))
6258
return getRequirement(KnownProtocolKind::BridgedNSError);

lib/Sema/DerivedConformances.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,6 @@ ValueDecl *deriveHashable(TypeChecker &tc,
8787
Decl *parentDecl,
8888
NominalTypeDecl *type,
8989
ValueDecl *requirement);
90-
91-
/// Derive an Error requirement for an enum type.
92-
///
93-
/// A unique string representation of the enum type will be used as the domain
94-
/// for members of the enum, and each case will have its own integer code.
95-
///
96-
/// \returns the derived member, which will also be added to the type.
97-
ValueDecl *deriveError(TypeChecker &tc,
98-
Decl *parentDecl,
99-
NominalTypeDecl *type,
100-
ValueDecl *requirement);
10190

10291
/// Derive a _BridgedNSError requirement for an @objc enum type.
10392
///

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4913,9 +4913,6 @@ ValueDecl *TypeChecker::deriveProtocolRequirement(DeclContext *DC,
49134913
case KnownProtocolKind::Hashable:
49144914
return DerivedConformance::deriveHashable(*this, Decl, TypeDecl, Requirement);
49154915

4916-
case KnownProtocolKind::Error:
4917-
return DerivedConformance::deriveError(*this, Decl, TypeDecl, Requirement);
4918-
49194916
case KnownProtocolKind::BridgedNSError:
49204917
return DerivedConformance::deriveBridgedNSError(*this, Decl, TypeDecl,
49214918
Requirement);

lib/Serialization/Deserialization.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,13 @@ static void filterValues(Type expectedTy, Module *expectedModule,
10231023
->getCanonicalSignature() != expectedGenericSig)
10241024
return true;
10251025

1026+
// If we don't expect a specific generic signature, ignore anything from a
1027+
// constrained extension.
1028+
if (!expectedGenericSig &&
1029+
isa<ExtensionDecl>(value->getDeclContext()) &&
1030+
cast<ExtensionDecl>(value->getDeclContext())->isConstrainedExtension())
1031+
return true;
1032+
10261033
// If we're looking at members of a protocol or protocol extension,
10271034
// filter by whether we expect to find something in a protocol extension or
10281035
// not. This lets us distinguish between a protocol member and a protocol

stdlib/public/SDK/Foundation/NSError.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,37 @@ public protocol CustomNSError : Error {
121121
var errorUserInfo: [String : Any] { get }
122122
}
123123

124+
public extension CustomNSError {
125+
/// Default domain of the error.
126+
static var errorDomain: String {
127+
return String(reflecting: type(of: self))
128+
}
129+
130+
/// The error code within the given domain.
131+
var errorCode: Int {
132+
return _swift_getDefaultErrorCode(self)
133+
}
134+
135+
/// The default user-info dictionary.
136+
var errorUserInfo: [String : Any] {
137+
return [:]
138+
}
139+
}
140+
141+
extension CustomNSError where Self: RawRepresentable, Self.RawValue: SignedInteger {
142+
// The error code of Error with integral raw values is the raw value.
143+
public var errorCode: Int {
144+
return numericCast(self.rawValue)
145+
}
146+
}
147+
148+
extension CustomNSError where Self: RawRepresentable, Self.RawValue: UnsignedInteger {
149+
// The error code of Error with integral raw values is the raw value.
150+
public var errorCode: Int {
151+
return numericCast(self.rawValue)
152+
}
153+
}
154+
124155
public extension Error where Self : CustomNSError {
125156
/// Default implementation for customized NSErrors.
126157
var _domain: String { return Self.errorDomain }
@@ -129,6 +160,18 @@ public extension Error where Self : CustomNSError {
129160
var _code: Int { return self.errorCode }
130161
}
131162

163+
public extension Error where Self: CustomNSError, Self: RawRepresentable,
164+
Self.RawValue: SignedInteger {
165+
/// Default implementation for customized NSErrors.
166+
var _code: Int { return self.errorCode }
167+
}
168+
169+
public extension Error where Self: CustomNSError, Self: RawRepresentable,
170+
Self.RawValue: UnsignedInteger {
171+
/// Default implementation for customized NSErrors.
172+
var _code: Int { return self.errorCode }
173+
}
174+
132175
public extension Error {
133176
/// Retrieve the localized description for this error.
134177
var localizedDescription: String {

stdlib/public/core/ErrorType.swift

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,21 @@ public func _errorInMain(_ error: Error) {
184184
fatalError("Error raised at top level: \(String(reflecting: error))")
185185
}
186186

187+
/// Runtime function to determine the default code for an Error-conforming type.
188+
@_silgen_name("swift_getDefaultErrorCode")
189+
public func _swift_getDefaultErrorCode<T : Error>(_ x: T) -> Int
190+
187191
@available(*, unavailable, renamed: "Error")
188192
public typealias ErrorType = Error
189193

190194
@available(*, unavailable, renamed: "Error")
191195
public typealias ErrorProtocol = Error
192196

193-
194197
extension Error {
198+
public var _code: Int {
199+
return _swift_getDefaultErrorCode(self)
200+
}
201+
195202
public var _domain: String {
196203
return String(reflecting: type(of: self))
197204
}
@@ -204,3 +211,17 @@ extension Error {
204211
#endif
205212
}
206213
}
214+
215+
extension Error where Self: RawRepresentable, Self.RawValue: SignedInteger {
216+
// The error code of Error with integral raw values is the raw value.
217+
public var _code: Int {
218+
return numericCast(self.rawValue)
219+
}
220+
}
221+
222+
extension Error where Self: RawRepresentable, Self.RawValue: UnsignedInteger {
223+
// The error code of Error with integral raw values is the raw value.
224+
public var _code: Int {
225+
return numericCast(self.rawValue)
226+
}
227+
}

stdlib/public/runtime/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ set(swift_runtime_sources
4040
Enum.cpp
4141
ErrorObjectNative.cpp
4242
Errors.cpp
43+
ErrorDefaultImpls.cpp
4344
Heap.cpp
4445
HeapObject.cpp
4546
KnownMetadata.cpp
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//===--- ErrorDefaultImpls.cpp - Error default implementations ------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This implements helpers for the default implementations of Error protocol
14+
// members.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#include "swift/Runtime/Config.h"
19+
#include "swift/Runtime/Metadata.h"
20+
using namespace swift;
21+
22+
// @_silgen_name("swift_getDefaultErrorCode")
23+
// func _swift_getDefaultErrorCode<T : Error>(_ x: T) -> Int
24+
SWIFT_CC(swift) SWIFT_RT_ENTRY_VISIBILITY
25+
extern "C" intptr_t swift_getDefaultErrorCode(OpaqueValue *error,
26+
const Metadata *T,
27+
const WitnessTable *Error) {
28+
intptr_t result;
29+
30+
switch (T->getKind()) {
31+
case MetadataKind::Enum:
32+
// Enum tags use negative values for payload cases, so adjust code to be
33+
// in the range [0, num-cases).
34+
result = T->vw_getEnumTag(error) +
35+
T->getNominalTypeDescriptor()->Enum.getNumPayloadCases();
36+
break;
37+
38+
case MetadataKind::Class:
39+
case MetadataKind::ObjCClassWrapper:
40+
case MetadataKind::ForeignClass:
41+
case MetadataKind::Function:
42+
case MetadataKind::Struct:
43+
case MetadataKind::Optional:
44+
case MetadataKind::Opaque:
45+
case MetadataKind::Tuple:
46+
case MetadataKind::Existential:
47+
case MetadataKind::Metatype:
48+
case MetadataKind::ExistentialMetatype:
49+
case MetadataKind::HeapLocalVariable:
50+
case MetadataKind::HeapGenericLocalVariable:
51+
case MetadataKind::ErrorObject:
52+
result = 1;
53+
break;
54+
}
55+
56+
// Destroy the value.
57+
T->vw_destroy(error);
58+
return result;
59+
}

0 commit comments

Comments
 (0)