Merge remote-tracking branch 'origin/master' into master-next

This commit is contained in:
swift-ci
2017-04-28 20:08:31 -07:00
49 changed files with 5806 additions and 15 deletions

View File

@@ -2912,6 +2912,9 @@ public:
private:
/// Predicate used to filter StoredPropertyRange.
struct ToStoredProperty {
ToStoredProperty(bool skipInaccessible = false) :
skipUserInaccessible(skipInaccessible) {}
bool skipUserInaccessible;
Optional<VarDecl *> operator()(Decl *decl) const;
};
@@ -2921,8 +2924,9 @@ public:
ToStoredProperty>;
/// Return a collection of the stored member variables of this type.
StoredPropertyRange getStoredProperties() const {
return StoredPropertyRange(getMembers(), ToStoredProperty());
StoredPropertyRange getStoredProperties(bool skipInaccessible = false) const {
return StoredPropertyRange(getMembers(),
ToStoredProperty(skipInaccessible));
}
// Implement isa/cast/dyncast/etc.
@@ -6119,7 +6123,8 @@ inline bool ValueDecl::isSettable(const DeclContext *UseDC,
inline Optional<VarDecl *>
NominalTypeDecl::ToStoredProperty::operator()(Decl *decl) const {
if (auto var = dyn_cast<VarDecl>(decl)) {
if (!var->isStatic() && var->hasStorage())
if (!var->isStatic() && var->hasStorage() &&
(!skipUserInaccessible || var->isUserAccessible()))
return var;
}

View File

@@ -1966,6 +1966,12 @@ ERROR(broken_int_integer_literal_convertible_conformance,none,
"Int type is broken: does not conform to ExpressibleByIntegerLiteral", ())
ERROR(no_equal_overload_for_int,none,
"no overload of '==' for Int", ())
ERROR(broken_coding_key_requirement,none,
"CodingKey protocol is broken: unexpected requirement", ())
ERROR(broken_encodable_requirement,none,
"Encodable protocol is broken: unexpected requirement", ())
ERROR(broken_decodable_requirement,none,
"Decodable protocol is broken: unexpected requirement", ())
// Dynamic Self
ERROR(dynamic_self_non_method,none,

View File

@@ -29,24 +29,40 @@ IDENTIFIER(Any)
IDENTIFIER(atIndexedSubscript)
IDENTIFIER_(bridgeToObjectiveC)
IDENTIFIER_WITH_NAME(code_, "_code")
IDENTIFIER(CodingKeys)
IDENTIFIER(container)
IDENTIFIER(CoreGraphics)
IDENTIFIER(CoreMedia)
IDENTIFIER(CGFloat)
IDENTIFIER(CVarArg)
IDENTIFIER(Darwin)
IDENTIFIER(dealloc)
IDENTIFIER(Decodable)
IDENTIFIER(decode)
IDENTIFIER(Decoder)
IDENTIFIER(decoder)
IDENTIFIER(deinit)
IDENTIFIER(Element)
IDENTIFIER(Encodable)
IDENTIFIER(encode)
IDENTIFIER(Encoder)
IDENTIFIER(encoder)
IDENTIFIER(error)
IDENTIFIER(forKeyedSubscript)
IDENTIFIER(Foundation)
IDENTIFIER(forKey)
IDENTIFIER(from)
IDENTIFIER(fromRaw)
IDENTIFIER(hashValue)
IDENTIFIER(init)
IDENTIFIER(initialize)
IDENTIFIER(initStorage)
IDENTIFIER(initialValue)
IDENTIFIER(intValue)
IDENTIFIER(Key)
IDENTIFIER(KeyedDecodingContainer)
IDENTIFIER(KeyedEncodingContainer)
IDENTIFIER(keyedBy)
IDENTIFIER(keyPath)
IDENTIFIER(makeIterator)
IDENTIFIER(Iterator)
@@ -70,10 +86,16 @@ IDENTIFIER(setObject)
IDENTIFIER(simd)
IDENTIFIER(some)
IDENTIFIER(storage)
IDENTIFIER(stringValue)
IDENTIFIER(subscript)
IDENTIFIER(super)
IDENTIFIER(superDecoder)
IDENTIFIER(superEncoder)
IDENTIFIER(SwiftObject)
IDENTIFIER(to)
IDENTIFIER(toRaw)
IDENTIFIER(Type)
IDENTIFIER(type)
IDENTIFIER(Value)
IDENTIFIER(value)
IDENTIFIER_WITH_NAME(value_, "_value")

View File

@@ -60,6 +60,9 @@ PROTOCOL_(ErrorCodeProtocol)
PROTOCOL(OptionSet)
PROTOCOL_(BridgedNSError)
PROTOCOL_(BridgedStoredNSError)
PROTOCOL(CodingKey)
PROTOCOL(Encodable)
PROTOCOL(Decodable)
PROTOCOL_(ObjectiveCBridgeable)
PROTOCOL_(DestructorSafeContainer)

View File

@@ -71,4 +71,9 @@ KNOWN_STDLIB_TYPE_DECL(Unmanaged, NominalTypeDecl, 1)
KNOWN_STDLIB_TYPE_DECL(Never, NominalTypeDecl, 0)
KNOWN_STDLIB_TYPE_DECL(Encoder, ProtocolDecl, 1)
KNOWN_STDLIB_TYPE_DECL(Decoder, ProtocolDecl, 1)
KNOWN_STDLIB_TYPE_DECL(KeyedEncodingContainer, NominalTypeDecl, 1)
KNOWN_STDLIB_TYPE_DECL(KeyedDecodingContainer, NominalTypeDecl, 1)
#undef KNOWN_STDLIB_TYPE_DECL

View File

@@ -203,7 +203,8 @@ struct SynthesizedExtensionAnalyzer::Implementation {
unsigned countInherits(ExtensionDecl *ED) {
unsigned Count = 0;
for (auto TL : ED->getInherited()) {
if (shouldPrint(TL.getType()->getAnyNominal(), Options))
auto *nominal = TL.getType()->getAnyNominal();
if (nominal && shouldPrint(nominal, Options))
Count ++;
}
return Count;

View File

@@ -2106,9 +2106,42 @@ bool NominalTypeDecl::derivesProtocolConformance(ProtocolDecl *protocol) const {
return isObjC() && enumDecl->hasCases()
&& enumDecl->hasOnlyCasesWithoutAssociatedValues();
// Enums without associated values and enums with a raw type of String
// or Int can explicitly derive CodingKey conformance.
case KnownProtocolKind::CodingKey: {
Type rawType = enumDecl->getRawType();
if (rawType) {
auto parentDC = enumDecl->getDeclContext();
ASTContext &C = parentDC->getASTContext();
auto nominal = rawType->getAnyNominal();
return nominal == C.getStringDecl() || nominal == C.getIntDecl();
}
// hasOnlyCasesWithoutAssociatedValues will return true for empty enums;
// empty enumas are allowed to conform as well.
return enumDecl->hasOnlyCasesWithoutAssociatedValues();
}
default:
return false;
}
} else if (isa<StructDecl>(this) || isa<ClassDecl>(this)) {
// Structs and classes can explicitly derive Encodable and Decodable
// conformance (explicitly meaning we can synthesize an implementation if
// a type conforms manually).
if (*knownProtocol == KnownProtocolKind::Encodable ||
*knownProtocol == KnownProtocolKind::Decodable) {
// FIXME: This is not actually correct. We cannot promise to always
// provide a witness here for all structs and classes. Unfortunately,
// figuring out whether this is actually possible requires much more
// context -- a TypeChecker and the parent decl context at least -- and is
// tightly coupled to the logic within DerivedConformance.
// This unfortunately means that we expect a witness even if one will not
// be produced, which requires DerivedConformance::deriveCodable to output
// its own diagnostics.
return true;
}
}
return false;
}

View File

@@ -5538,6 +5538,9 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
case KnownProtocolKind::ErrorCodeProtocol:
case KnownProtocolKind::ExpressibleByBuiltinConstStringLiteral:
case KnownProtocolKind::ExpressibleByBuiltinConstUTF16StringLiteral:
case KnownProtocolKind::CodingKey:
case KnownProtocolKind::Encodable:
case KnownProtocolKind::Decodable:
return SpecialProtocol::None;
}

View File

@@ -16,6 +16,8 @@ add_swift_library(swiftSema STATIC
ConstraintGraph.cpp
ConstraintLocator.cpp
ConstraintSystem.cpp
DerivedConformanceCodable.cpp
DerivedConformanceCodingKey.cpp
DerivedConformanceEquatableHashable.cpp
DerivedConformanceError.cpp
DerivedConformanceRawRepresentable.cpp

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,561 @@
//===--- DerivedConformanceCodingKey.cpp - Derived CodingKey --------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements explicit derivation of the CodingKey protocol for an
// enum.
//
//===----------------------------------------------------------------------===//
#include "TypeChecker.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/Stmt.h"
#include "swift/AST/Types.h"
#include "DerivedConformances.h"
using namespace swift;
using namespace DerivedConformance;
/// Sets the body of the given function to `return nil`.
///
/// \param funcDecl The function whose body to set.
static void deriveNilReturn(AbstractFunctionDecl *funcDecl) {
auto *parentDC = funcDecl->getDeclContext();
auto &C = parentDC->getASTContext();
auto *nilExpr = new (C) NilLiteralExpr(SourceLoc(), /*Implicit=*/true);
auto *returnStmt = new (C) ReturnStmt(SourceLoc(), nilExpr);
auto *body = BraceStmt::create(C, SourceLoc(), ASTNode(returnStmt),
SourceLoc());
funcDecl->setBody(body);
}
/// Sets the body of the given function to `return self.rawValue`.
///
/// \param funcDecl The function whose body to set.
static void deriveRawValueReturn(AbstractFunctionDecl *funcDecl) {
auto *parentDC = funcDecl->getDeclContext();
auto &C = parentDC->getASTContext();
auto *selfRef = createSelfDeclRef(funcDecl);
auto *memberRef = new (C) UnresolvedDotExpr(selfRef, SourceLoc(),
C.Id_rawValue, DeclNameLoc(),
/*Implicit=*/true);
auto *returnStmt = new (C) ReturnStmt(SourceLoc(), memberRef);
auto *body = BraceStmt::create(C, SourceLoc(), ASTNode(returnStmt),
SourceLoc());
funcDecl->setBody(body);
}
/// Sets the body of the given function to `self.init(rawValue:)`, passing along
/// the parameter of the given constructor.
///
/// \param initDecl The constructor whose body to set.
static void deriveRawValueInit(AbstractFunctionDecl *initDecl) {
auto *parentDC = initDecl->getDeclContext();
auto &C = parentDC->getASTContext();
// Get the param from init({string,int}Value:). self is the first param in the
// list; stringValue is the second.
auto *valueParam = initDecl->getParameterList(1)->get(0);
auto *valueParamExpr = new (C) DeclRefExpr(ConcreteDeclRef(valueParam),
DeclNameLoc(), /*Implicit=*/true);
// rawValue param to init(rawValue:)
auto *rawValueDecl = new (C) ParamDecl(/*IsLet=*/true, SourceLoc(),
SourceLoc(), C.Id_rawValue,
SourceLoc(), C.Id_rawValue,
valueParam->getType(), parentDC);
rawValueDecl->setInterfaceType(C.getIntDecl()->getDeclaredType());
rawValueDecl->setImplicit();
auto *paramList = ParameterList::createWithoutLoc(rawValueDecl);
// init(rawValue:) constructor name
DeclName ctorName(C, C.Id_init, paramList);
// self.init(rawValue:) expr
auto *selfRef = createSelfDeclRef(initDecl);
auto *initExpr = new (C) UnresolvedDotExpr(selfRef, SourceLoc(), ctorName,
DeclNameLoc(), /*Implicit=*/true);
// Bind the value param in self.init(rawValue: {string,int}Value).
Expr *args[1] = {valueParamExpr};
Identifier argLabels[1] = {C.Id_rawValue};
auto *callExpr = CallExpr::createImplicit(C, initExpr, C.AllocateCopy(args),
C.AllocateCopy(argLabels));
auto *body = BraceStmt::create(C, SourceLoc(), ASTNode(callExpr),
SourceLoc());
initDecl->setBody(body);
}
/// Synthesizes a constructor declaration with the given parameter name and
/// type.
///
/// \param tc The type checker to use in synthesizing the constructor.
///
/// \param parentDecl The parent declaration of the enum.
///
/// \param enumDecl The enum on which to synthesize the constructor.
///
/// \param paramType The type of the parameter.
///
/// \param paramName The name of the parameter.
///
/// \param synthesizer A lambda to call to set the constructor's body.
template <typename Synthesizer>
static ValueDecl *deriveInitDecl(TypeChecker &tc, Decl *parentDecl,
EnumDecl *enumDecl, Type paramType,
Identifier paramName,
const Synthesizer &synthesizer) {
auto &C = tc.Context;
auto *parentDC = cast<DeclContext>(parentDecl);
// rawValue
auto *rawDecl = new (C) ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(),
paramName, SourceLoc(), paramName,
paramType, parentDC);
rawDecl->setInterfaceType(paramType);
rawDecl->setImplicit();
// init(rawValue:) name
auto *paramList = ParameterList::createWithoutLoc(rawDecl);
DeclName name(C, C.Id_init, paramList);
// init(rawValue:) decl
auto *selfDecl = ParamDecl::createSelf(SourceLoc(), parentDC,
/*static*/false, /*inout*/true);
auto *initDecl =
new (C) ConstructorDecl(name, SourceLoc(),
/*Failability=*/OTK_Optional,
/*FailabilityLoc=*/SourceLoc(),
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
selfDecl, paramList,
/*GenericParams=*/nullptr, parentDC);
initDecl->setImplicit();
// Synthesize the body.
synthesizer(initDecl);
// Compute the type of the initializer.
TupleTypeElt element(paramType, paramName);
TupleTypeElt interfaceElement(paramType, paramName);
auto interfaceArgType = TupleType::get(interfaceElement, C);
// Compute the interface type of the initializer.
Type retInterfaceType =
OptionalType::get(parentDC->getDeclaredInterfaceType());
Type interfaceType = FunctionType::get(interfaceArgType, retInterfaceType);
Type selfInterfaceType = initDecl->computeInterfaceSelfType();
Type selfInitializerInterfaceType =
initDecl->computeInterfaceSelfType(/*init*/ true);
Type allocIfaceType;
Type initIfaceType;
if (auto sig = parentDC->getGenericSignatureOfContext()) {
initDecl->setGenericEnvironment(parentDC->getGenericEnvironmentOfContext());
allocIfaceType = GenericFunctionType::get(sig, selfInterfaceType,
interfaceType,
FunctionType::ExtInfo());
initIfaceType = GenericFunctionType::get(sig, selfInitializerInterfaceType,
interfaceType,
FunctionType::ExtInfo());
} else {
allocIfaceType = FunctionType::get(selfInterfaceType,
interfaceType);
initIfaceType = FunctionType::get(selfInitializerInterfaceType,
interfaceType);
}
initDecl->setInterfaceType(allocIfaceType);
initDecl->setInitializerInterfaceType(initIfaceType);
initDecl->setAccessibility(std::max(Accessibility::Internal,
enumDecl->getFormalAccess()));
// If the enum was not imported, the derived conformance is either from the
// enum itself or an extension, in which case we will emit the declaration
// normally.
if (enumDecl->hasClangNode())
tc.Context.addExternalDecl(initDecl);
cast<IterableDeclContext>(parentDecl)->addMember(initDecl);
return initDecl;
}
/// Synthesizes a read-only computed property with a given type and name.
///
/// \param tc The type checker to use in synthesizing the property.
///
/// \param parentDecl The parent declaration of the enum.
///
/// \param enumDecl The enum on which to synthesize the property.
///
/// \param type The type of the property.
///
/// \param name The name of the property.
///
/// \param synthesizer A lambda to call to set the property's getter.
template <typename Synthesizer>
static ValueDecl *deriveProperty(TypeChecker &tc, Decl *parentDecl,
EnumDecl *enumDecl, Type type, Identifier name,
const Synthesizer &synthesizer) {
// Define the getter.
auto *getterDecl = declareDerivedPropertyGetter(tc, parentDecl, enumDecl,
type, type,
/*isStatic=*/false,
/*isFinal=*/false);
// Synthesize the body.
synthesizer(getterDecl);
// Define the property.
VarDecl *propDecl;
PatternBindingDecl *pbDecl;
std::tie(propDecl, pbDecl)
= declareDerivedReadOnlyProperty(tc, parentDecl, enumDecl, name, type, type,
getterDecl, /*isStatic=*/false,
/*isFinal=*/false);
auto *dc = cast<IterableDeclContext>(parentDecl);
dc->addMember(getterDecl);
dc->addMember(propDecl);
dc->addMember(pbDecl);
return propDecl;
}
/// Sets the body of the given function to return a string value based on
/// switching on `self`.
///
/// \param strValDecl The function whose body to set.
static void
deriveBodyCodingKey_enum_stringValue(AbstractFunctionDecl *strValDecl) {
// enum SomeEnum {
// case A, B, C
// @derived var stringValue: String {
// switch self {
// case A:
// return "A"
// case B:
// return "B"
// case C:
// return "C"
// }
// }
// }
auto *parentDC = strValDecl->getDeclContext();
auto &C = parentDC->getASTContext();
auto *enumDecl = parentDC->getAsEnumOrEnumExtensionContext();
Type enumType = parentDC->getDeclaredTypeInContext();
BraceStmt *body = nullptr;
auto elements = enumDecl->getAllElements();
if (elements.empty() /* empty enum */) {
// return ""
auto *emptyStringExpr = new (C) StringLiteralExpr("", SourceRange(),
/*Implicit=*/true);
auto *returnStmt = new (C) ReturnStmt(SourceLoc(), emptyStringExpr);
body = BraceStmt::create(C, SourceLoc(), ASTNode(returnStmt),
SourceLoc());
} else {
SmallVector<CaseStmt *, 4> cases;
for (auto *elt : elements) {
auto *pat = new (C) EnumElementPattern(TypeLoc::withoutLoc(enumType),
SourceLoc(), SourceLoc(),
Identifier(), elt, nullptr);
pat->setImplicit();
auto labelItem = CaseLabelItem(/*IsDefault=*/false, pat, SourceLoc(),
nullptr);
auto *caseValue = new (C) StringLiteralExpr(elt->getNameStr(),
SourceRange(),
/*Implicit=*/true);
auto *returnStmt = new (C) ReturnStmt(SourceLoc(), caseValue);
auto *caseBody = BraceStmt::create(C, SourceLoc(), ASTNode(returnStmt),
SourceLoc());
cases.push_back(CaseStmt::create(C, SourceLoc(), labelItem,
/*HasBoundDecls=*/false, SourceLoc(),
caseBody));
}
auto *selfRef = createSelfDeclRef(strValDecl);
auto *switchStmt = SwitchStmt::create(LabeledStmtInfo(), SourceLoc(),
selfRef, SourceLoc(), cases,
SourceLoc(), C);
body = BraceStmt::create(C, SourceLoc(), ASTNode(switchStmt), SourceLoc());
}
strValDecl->setBody(body);
}
/// Sets the body of the given constructor to initialize `self` based on the
/// value of the given string param.
///
/// \param initDecl The function whose body to set.
static void
deriveBodyCodingKey_init_stringValue(AbstractFunctionDecl *initDecl) {
// enum SomeEnum {
// case A, B, C
// @derived init?(stringValue: String) {
// switch stringValue {
// case "A":
// self = .A
// case "B":
// self = .B
// case "C":
// self = .C
// default:
// return nil
// }
// }
// }
auto *parentDC = initDecl->getDeclContext();
auto &C = parentDC->getASTContext();
auto *enumDecl = parentDC->getAsEnumOrEnumExtensionContext();
Type enumType = parentDC->getDeclaredTypeInContext();
auto elements = enumDecl->getAllElements();
if (elements.empty() /* empty enum */) {
deriveNilReturn(initDecl);
return;
}
auto *selfRef = createSelfDeclRef(initDecl);
SmallVector<CaseStmt *, 4> cases;
for (auto *elt : elements) {
auto *litExpr = new (C) StringLiteralExpr(elt->getNameStr(), SourceRange(),
/*Implicit=*/true);
auto *litPat = new (C) ExprPattern(litExpr, /*IsResolved=*/true, nullptr,
nullptr);
litPat->setImplicit();
auto labelItem = CaseLabelItem(/*IsDefault=*/false, litPat, SourceLoc(),
nullptr);
auto *eltRef = new (C) DeclRefExpr(elt, DeclNameLoc(), /*Implicit=*/true);
auto *metaTyRef = TypeExpr::createImplicit(enumType, C);
auto *valueExpr = new (C) DotSyntaxCallExpr(eltRef, SourceLoc(), metaTyRef);
auto *assignment = new (C) AssignExpr(selfRef, SourceLoc(), valueExpr,
/*Implicit=*/true);
auto *body = BraceStmt::create(C, SourceLoc(), ASTNode(assignment),
SourceLoc());
cases.push_back(CaseStmt::create(C, SourceLoc(), labelItem,
/*HasBoundDecls=*/false, SourceLoc(),
body));
}
auto *anyPat = new (C) AnyPattern(SourceLoc());
anyPat->setImplicit();
auto dfltLabelItem = CaseLabelItem(/*IsDefault=*/true, anyPat, SourceLoc(),
nullptr);
auto *dfltReturnStmt = new (C) FailStmt(SourceLoc(), SourceLoc());
auto *dfltBody = BraceStmt::create(C, SourceLoc(), ASTNode(dfltReturnStmt),
SourceLoc());
cases.push_back(CaseStmt::create(C, SourceLoc(), dfltLabelItem,
/*HasBoundDecls=*/false, SourceLoc(),
dfltBody));
auto *stringValueDecl = initDecl->getParameterList(1)->get(0);
auto *stringValueRef = new (C) DeclRefExpr(stringValueDecl, DeclNameLoc(),
/*Implicit=*/true);
auto *switchStmt = SwitchStmt::create(LabeledStmtInfo(), SourceLoc(),
stringValueRef, SourceLoc(), cases,
SourceLoc(), C);
auto *body = BraceStmt::create(C, SourceLoc(), ASTNode(switchStmt),
SourceLoc());
initDecl->setBody(body);
}
/// Returns whether the given enum is eligible for CodingKey synthesis.
///
/// \param tc The type checker to use in checking eligibility.
///
/// \param parentDecl The parent declaration of the enum.
///
/// \param enumDecl The enum to check.
static bool canSynthesizeCodingKey(TypeChecker &tc, Decl *parentDecl,
EnumDecl *enumDecl) {
// If the enum has a raw type (optional), it must be String or Int.
Type rawType = enumDecl->getRawType();
if (rawType) {
auto *parentDC = cast<DeclContext>(parentDecl);
rawType = parentDC->mapTypeIntoContext(rawType);
auto &C = tc.Context;
auto *nominal = rawType->getCanonicalType()->getAnyNominal();
if (nominal != C.getStringDecl() && nominal != C.getIntDecl())
return false;
}
if (!enumDecl->getInherited().empty() &&
enumDecl->getInherited().front().isError())
return false;
// If it meets all of those requirements, we can synthesize CodingKey
// conformance.
return true;
}
ValueDecl *DerivedConformance::deriveCodingKey(TypeChecker &tc,
Decl *parentDecl,
NominalTypeDecl *type,
ValueDecl *requirement) {
// We can only synthesize CodingKey for enums.
auto *enumDecl = dyn_cast<EnumDecl>(type);
if (!enumDecl)
return nullptr;
// Check other preconditions for synthesized conformance.
if (!canSynthesizeCodingKey(tc, parentDecl, enumDecl))
return nullptr;
auto &C = tc.Context;
auto rawType = enumDecl->getRawType();
auto name = requirement->getName();
if (name == C.Id_stringValue) {
// Synthesize `var stringValue: String { get }`
auto stringType = C.getStringDecl()->getDeclaredType();
auto synth = [rawType, stringType](AbstractFunctionDecl *getterDecl) {
if (rawType && rawType->isEqual(stringType)) {
// enum SomeStringEnum : String {
// case A, B, C
// @derived var stringValue: String {
// return self.rawValue
// }
getterDecl->setBodySynthesizer(&deriveRawValueReturn);
} else {
// enum SomeEnum {
// case A, B, C
// @derived var stringValue: String {
// switch self {
// case A:
// return "A"
// case B:
// return "B"
// case C:
// return "C"
// }
// }
// }
getterDecl->setBodySynthesizer(&deriveBodyCodingKey_enum_stringValue);
}
};
return deriveProperty(tc, parentDecl, enumDecl, stringType,
C.Id_stringValue, synth);
} else if (name == C.Id_intValue) {
// Synthesize `var intValue: Int? { get }`
auto intType = C.getIntDecl()->getDeclaredType();
auto optionalIntType = OptionalType::get(OTK_Optional, intType);
auto synth = [rawType, intType](AbstractFunctionDecl *getterDecl) {
if (rawType && rawType->isEqual(intType)) {
// enum SomeIntEnum : Int {
// case A = 1, B = 2, C = 3
// @derived var intValue: Int? {
// return self.rawValue
// }
// }
getterDecl->setBodySynthesizer(&deriveRawValueReturn);
} else {
// enum SomeEnum {
// case A, B, C
// @derived var intValue: Int? {
// return nil
// }
// }
getterDecl->setBodySynthesizer(&deriveNilReturn);
}
};
return deriveProperty(tc, parentDecl, enumDecl, optionalIntType,
C.Id_intValue, synth);
} else if (name == C.Id_init) {
auto argumentNames = requirement->getFullName().getArgumentNames();
if (argumentNames.size() == 1) {
if (argumentNames[0] == C.Id_stringValue) {
// Derive `init?(stringValue:)`
auto stringType = C.getStringDecl()->getDeclaredType();
auto synth = [rawType, stringType](AbstractFunctionDecl *initDecl) {
if (rawType && rawType->isEqual(stringType)) {
// enum SomeStringEnum : String {
// case A = "a", B = "b", C = "c"
// @derived init?(stringValue: String) {
// self.init(rawValue: stringValue)
// }
// }
initDecl->setBodySynthesizer(&deriveRawValueInit);
} else {
// enum SomeEnum {
// case A, B, C
// @derived init?(stringValue: String) {
// switch stringValue {
// case "A":
// self = .A
// case "B":
// self = .B
// case "C":
// self = .C
// default:
// return nil
// }
// }
// }
initDecl->setBodySynthesizer(&deriveBodyCodingKey_init_stringValue);
}
};
return deriveInitDecl(tc, parentDecl, enumDecl, stringType,
C.Id_stringValue, synth);
} else if (argumentNames[0] == C.Id_intValue) {
// Synthesize `init?(intValue:)`
auto intType = C.getIntDecl()->getDeclaredType();
auto synthesizer = [rawType, intType](AbstractFunctionDecl *initDecl) {
if (rawType && rawType->isEqual(intType)) {
// enum SomeIntEnum : Int {
// case A = 1, B = 2, C = 3
// @derived init?(intValue: Int) {
// self.init(rawValue: intValue)
// }
// }
initDecl->setBodySynthesizer(&deriveRawValueInit);
} else {
// enum SomeEnum {
// case A, B, C
// @derived init?(intValue: Int) {
// return nil
// }
// }
initDecl->setBodySynthesizer(&deriveNilReturn);
}
};
return deriveInitDecl(tc, parentDecl, enumDecl, intType, C.Id_intValue,
synthesizer);
}
}
}
tc.diagnose(requirement->getLoc(), diag::broken_coding_key_requirement);
return nullptr;
}

View File

@@ -59,6 +59,14 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal,
if (name.isSimpleName(ctx.Id_nsErrorDomain))
return getRequirement(KnownProtocolKind::BridgedNSError);
// CodingKey.stringValue
if (name.isSimpleName(ctx.Id_stringValue))
return getRequirement(KnownProtocolKind::CodingKey);
// CodingKey.intValue
if (name.isSimpleName(ctx.Id_intValue))
return getRequirement(KnownProtocolKind::CodingKey);
return nullptr;
}
@@ -67,14 +75,33 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal,
if (func->isOperator() && name.getBaseName().str() == "==")
return getRequirement(KnownProtocolKind::Equatable);
// Encodable.encode(to: Encoder)
if (name.isCompoundName() && name.getBaseName() == ctx.Id_encode) {
auto argumentNames = name.getArgumentNames();
if (argumentNames.size() == 1 && argumentNames[0] == ctx.Id_to)
return getRequirement(KnownProtocolKind::Encodable);
}
return nullptr;
}
// Initializers.
if (isa<ConstructorDecl>(requirement)) {
if (auto ctor = dyn_cast<ConstructorDecl>(requirement)) {
auto argumentNames = name.getArgumentNames();
if (argumentNames.size() == 1 && argumentNames[0] == ctx.Id_rawValue)
return getRequirement(KnownProtocolKind::RawRepresentable);
if (argumentNames.size() == 1) {
if (argumentNames[0] == ctx.Id_rawValue)
return getRequirement(KnownProtocolKind::RawRepresentable);
// CodingKey.init?(stringValue:), CodingKey.init?(intValue:)
if (ctor->getFailability() == OTK_Optional &&
(argumentNames[0] == ctx.Id_stringValue ||
argumentNames[0] == ctx.Id_intValue))
return getRequirement(KnownProtocolKind::CodingKey);
// Decodable.init(from: Decoder)
if (argumentNames[0] == ctx.Id_from)
return getRequirement(KnownProtocolKind::Decodable);
}
return nullptr;
}

View File

@@ -96,6 +96,30 @@ ValueDecl *deriveBridgedNSError(TypeChecker &tc,
NominalTypeDecl *type,
ValueDecl *requirement);
/// Derive a CodingKey requirement for an enum type.
///
/// \returns the derived member, which will also be added to the type.
ValueDecl *deriveCodingKey(TypeChecker &tc,
Decl *parentDecl,
NominalTypeDecl *type,
ValueDecl *requirement);
/// Derive an Encodable requirement for a struct type.
///
/// \returns the derived member, which will also be added to the type.
ValueDecl *deriveEncodable(TypeChecker &tc,
Decl *parentDecl,
NominalTypeDecl *type,
ValueDecl *requirement);
/// Derive a Decodable requirement for a struct type.
///
/// \returns the derived member, which will also be added to the type.
ValueDecl *deriveDecodable(TypeChecker &tc,
Decl *parentDecl,
NominalTypeDecl *type,
ValueDecl *requirement);
/// Declare a getter for a derived property.
FuncDecl *declareDerivedPropertyGetter(TypeChecker &tc,
Decl *parentDecl,

View File

@@ -6217,6 +6217,15 @@ ValueDecl *TypeChecker::deriveProtocolRequirement(DeclContext *DC,
return DerivedConformance::deriveBridgedNSError(*this, Decl, TypeDecl,
Requirement);
case KnownProtocolKind::CodingKey:
return DerivedConformance::deriveCodingKey(*this, Decl, TypeDecl, Requirement);
case KnownProtocolKind::Encodable:
return DerivedConformance::deriveEncodable(*this, Decl, TypeDecl, Requirement);
case KnownProtocolKind::Decodable:
return DerivedConformance::deriveDecodable(*this, Decl, TypeDecl, Requirement);
default:
return nullptr;
}

View File

@@ -100,6 +100,9 @@ static Type getStdlibType(TypeChecker &TC, Type &cached, DeclContext *dc,
Type TypeChecker::getStringType(DeclContext *dc) {
return ::getStdlibType(*this, StringType, dc, "String");
}
Type TypeChecker::getIntType(DeclContext *dc) {
return ::getStdlibType(*this, IntType, dc, "Int");
}
Type TypeChecker::getInt8Type(DeclContext *dc) {
return ::getStdlibType(*this, Int8Type, dc, "Int8");
}

View File

@@ -790,6 +790,7 @@ private:
Type ImageLiteralType;
Type FileReferenceLiteralType;
Type StringType;
Type IntType;
Type Int8Type;
Type UInt8Type;
Type NSObjectType;
@@ -880,6 +881,7 @@ public:
Type getOptionalType(SourceLoc loc, Type elementType);
Type getImplicitlyUnwrappedOptionalType(SourceLoc loc, Type elementType);
Type getStringType(DeclContext *dc);
Type getIntType(DeclContext *dc);
Type getInt8Type(DeclContext *dc);
Type getUInt8Type(DeclContext *dc);
Type getNSObjectType(DeclContext *dc);

View File

@@ -629,7 +629,7 @@ func _childProcess() {
#if _runtime(_ObjC)
objc_setUncaughtExceptionHandler {
let exception = $0! as AnyObject
let exception = ($0 as Optional)! as AnyObject
var stderr = _Stderr()
let maybeNSException =
unsafeBitCast(exception, to: _StdlibUnittestNSException.self)

View File

@@ -27,13 +27,17 @@ public func withOverriddenLocaleCurrentLocale<Result>(
_ temporaryLocale: NSLocale,
_ body: () -> Result
) -> Result {
let oldMethod = class_getClassMethod(
NSLocale.self, #selector(getter: NSLocale.current))
precondition(oldMethod != nil, "could not find +[Locale currentLocale]")
guard let oldMethod = class_getClassMethod(
NSLocale.self, #selector(getter: NSLocale.current)) as Optional
else {
_preconditionFailure("could not find +[Locale currentLocale]")
}
let newMethod = class_getClassMethod(
NSLocale.self, #selector(NSLocale._swiftUnittest_currentLocale))
precondition(newMethod != nil, "could not find +[Locale _swiftUnittest_currentLocale]")
guard let newMethod = class_getClassMethod(
NSLocale.self, #selector(NSLocale._swiftUnittest_currentLocale)) as Optional
else {
_preconditionFailure("could not find +[Locale _swiftUnittest_currentLocale]")
}
precondition(_temporaryLocaleCurrentLocale == nil,
"nested calls to withOverriddenLocaleCurrentLocale are not supported")

View File

@@ -35,6 +35,7 @@ set(SWIFTLIB_ESSENTIAL
BuiltinMath.swift.gyb
Character.swift
CocoaArray.swift
Codable.swift
Collection.swift
CollectionAlgorithms.swift.gyb
Comparable.swift

File diff suppressed because it is too large Load Diff

View File

@@ -162,6 +162,7 @@
"DebuggerSupport.swift",
"Equatable.swift",
"Comparable.swift",
"Hashable.swift"
"Hashable.swift",
"Codable.swift"
]
}

View File

@@ -5259,6 +5259,11 @@ var FooSubUnnamedEnumeratorA1: Int { get }
key.length: 31,
key.fully_annotated_decl: "<decl.function.constructor><syntaxtype.keyword>init</syntaxtype.keyword>(<decl.var.parameter><decl.var.parameter.argument_label>rawValue</decl.var.parameter.argument_label>: <decl.var.parameter.type><ref.struct usr=\"s:s6UInt32V\">UInt32</ref.struct></decl.var.parameter.type></decl.var.parameter>)</decl.function.constructor>",
key.conforms: [
{
key.kind: source.lang.swift.ref.function.constructor,
key.name: "init(rawValue:)",
key.usr: "s:s16RawRepresentablePxSg0A5ValueQz03rawC0_tcfc"
},
{
key.kind: source.lang.swift.ref.function.constructor,
key.name: "init(rawValue:)",
@@ -5283,6 +5288,11 @@ var FooSubUnnamedEnumeratorA1: Int { get }
key.length: 20,
key.fully_annotated_decl: "<decl.var.instance><syntaxtype.keyword>var</syntaxtype.keyword> <decl.name>rawValue</decl.name>: <decl.var.type><ref.struct usr=\"s:s6UInt32V\">UInt32</ref.struct></decl.var.type></decl.var.instance>",
key.conforms: [
{
key.kind: source.lang.swift.ref.var.instance,
key.name: "rawValue",
key.usr: "s:s16RawRepresentableP8rawValue0aD0Qzv"
},
{
key.kind: source.lang.swift.ref.var.instance,
key.name: "rawValue",
@@ -5372,6 +5382,11 @@ var FooSubUnnamedEnumeratorA1: Int { get }
key.length: 31,
key.fully_annotated_decl: "<decl.function.constructor><syntaxtype.keyword>init</syntaxtype.keyword>(<decl.var.parameter><decl.var.parameter.argument_label>rawValue</decl.var.parameter.argument_label>: <decl.var.parameter.type><ref.struct usr=\"s:s6UInt32V\">UInt32</ref.struct></decl.var.parameter.type></decl.var.parameter>)</decl.function.constructor>",
key.conforms: [
{
key.kind: source.lang.swift.ref.function.constructor,
key.name: "init(rawValue:)",
key.usr: "s:s16RawRepresentablePxSg0A5ValueQz03rawC0_tcfc"
},
{
key.kind: source.lang.swift.ref.function.constructor,
key.name: "init(rawValue:)",
@@ -5396,6 +5411,11 @@ var FooSubUnnamedEnumeratorA1: Int { get }
key.length: 20,
key.fully_annotated_decl: "<decl.var.instance><syntaxtype.keyword>var</syntaxtype.keyword> <decl.name>rawValue</decl.name>: <decl.var.type><ref.struct usr=\"s:s6UInt32V\">UInt32</ref.struct></decl.var.type></decl.var.instance>",
key.conforms: [
{
key.kind: source.lang.swift.ref.var.instance,
key.name: "rawValue",
key.usr: "s:s16RawRepresentableP8rawValue0aD0Qzv"
},
{
key.kind: source.lang.swift.ref.var.instance,
key.name: "rawValue",
@@ -5492,6 +5512,11 @@ var FooSubUnnamedEnumeratorA1: Int { get }
key.length: 31,
key.fully_annotated_decl: "<decl.function.constructor><syntaxtype.keyword>init</syntaxtype.keyword>(<decl.var.parameter><decl.var.parameter.argument_label>rawValue</decl.var.parameter.argument_label>: <decl.var.parameter.type><ref.struct usr=\"s:s6UInt32V\">UInt32</ref.struct></decl.var.parameter.type></decl.var.parameter>)</decl.function.constructor>",
key.conforms: [
{
key.kind: source.lang.swift.ref.function.constructor,
key.name: "init(rawValue:)",
key.usr: "s:s16RawRepresentablePxSg0A5ValueQz03rawC0_tcfc"
},
{
key.kind: source.lang.swift.ref.function.constructor,
key.name: "init(rawValue:)",
@@ -5516,6 +5541,11 @@ var FooSubUnnamedEnumeratorA1: Int { get }
key.length: 20,
key.fully_annotated_decl: "<decl.var.instance><syntaxtype.keyword>var</syntaxtype.keyword> <decl.name>rawValue</decl.name>: <decl.var.type><ref.struct usr=\"s:s6UInt32V\">UInt32</ref.struct></decl.var.type></decl.var.instance>",
key.conforms: [
{
key.kind: source.lang.swift.ref.var.instance,
key.name: "rawValue",
key.usr: "s:s16RawRepresentableP8rawValue0aD0Qzv"
},
{
key.kind: source.lang.swift.ref.var.instance,
key.name: "rawValue",
@@ -8017,6 +8047,11 @@ var FooSubUnnamedEnumeratorA1: Int { get }
key.length: 31,
key.fully_annotated_decl: "<decl.function.constructor><syntaxtype.keyword>init</syntaxtype.keyword>(<decl.var.parameter><decl.var.parameter.argument_label>rawValue</decl.var.parameter.argument_label>: <decl.var.parameter.type><ref.struct usr=\"s:s6UInt32V\">UInt32</ref.struct></decl.var.parameter.type></decl.var.parameter>)</decl.function.constructor>",
key.conforms: [
{
key.kind: source.lang.swift.ref.function.constructor,
key.name: "init(rawValue:)",
key.usr: "s:s16RawRepresentablePxSg0A5ValueQz03rawC0_tcfc"
},
{
key.kind: source.lang.swift.ref.function.constructor,
key.name: "init(rawValue:)",
@@ -8041,6 +8076,11 @@ var FooSubUnnamedEnumeratorA1: Int { get }
key.length: 20,
key.fully_annotated_decl: "<decl.var.instance><syntaxtype.keyword>var</syntaxtype.keyword> <decl.name>rawValue</decl.name>: <decl.var.type><ref.struct usr=\"s:s6UInt32V\">UInt32</ref.struct></decl.var.type></decl.var.instance>",
key.conforms: [
{
key.kind: source.lang.swift.ref.var.instance,
key.name: "rawValue",
key.usr: "s:s16RawRepresentableP8rawValue0aD0Qzv"
},
{
key.kind: source.lang.swift.ref.var.instance,
key.name: "rawValue",

View File

@@ -0,0 +1,21 @@
// Simple classes with all Codable properties should get derived conformance to
// Codable.
class SimpleClass : Codable {
var x: Int = 1
var y: Double = .pi
static var z: String = "foo"
// These lines have to be within the SimpleClass type because CodingKeys
// should be private.
func foo() {
// They should receive a synthesized CodingKeys enum.
let _ = SimpleClass.CodingKeys.self
// The enum should have a case for each of the vars.
let _ = SimpleClass.CodingKeys.x
let _ = SimpleClass.CodingKeys.y
// Static vars should not be part of the CodingKeys enum.
let _ = SimpleClass.CodingKeys.z // expected-error {{type 'SimpleClass.CodingKeys' has no member 'z'}}
}
}

View File

@@ -0,0 +1,10 @@
// These are wrapped in a dummy function to avoid binding a global variable.
func foo() {
// They should receive synthesized init(from:) and an encode(to:).
let _ = SimpleClass.init(from:)
let _ = SimpleClass.encode(to:)
// The synthesized CodingKeys type should not be accessible from outside the
// class.
let _ = SimpleClass.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
}

View File

@@ -0,0 +1,11 @@
enum NoRawTypeKey {
case a, b, c
}
enum StringKey : String {
case a = "A", b, c = "Foo"
}
enum IntKey : Int {
case a = 3, b, c = 1
}

View File

@@ -0,0 +1,3 @@
extension NoRawTypeKey : CodingKey {}
extension StringKey : CodingKey {}
extension IntKey : CodingKey {}

View File

@@ -0,0 +1,16 @@
func foo() {
let _ = NoRawTypeKey.a.stringValue
let _ = NoRawTypeKey(stringValue: "a")
let _ = NoRawTypeKey.a.intValue
let _ = NoRawTypeKey(intValue: 0)
let _ = StringKey.a.stringValue
let _ = StringKey(stringValue: "A")
let _ = StringKey.a.intValue
let _ = StringKey(intValue: 0)
let _ = IntKey.a.stringValue
let _ = IntKey(stringValue: "a")
let _ = IntKey.a.intValue
let _ = IntKey(intValue: 3)
}

View File

@@ -0,0 +1,11 @@
enum NoRawTypeKey : CodingKey {
case a, b, c
}
enum StringKey : String, CodingKey {
case a = "A", b, c = "Foo"
}
enum IntKey : Int, CodingKey {
case a = 3, b, c = 1
}

View File

@@ -0,0 +1,16 @@
func foo() {
let _ = NoRawTypeKey.a.stringValue
let _ = NoRawTypeKey(stringValue: "a")
let _ = NoRawTypeKey.a.intValue
let _ = NoRawTypeKey(intValue: 0)
let _ = StringKey.a.stringValue
let _ = StringKey(stringValue: "A")
let _ = StringKey.a.intValue
let _ = StringKey(intValue: 0)
let _ = IntKey.a.stringValue
let _ = IntKey(stringValue: "a")
let _ = IntKey.a.intValue
let _ = IntKey(intValue: 3)
}

View File

@@ -0,0 +1,23 @@
// RUN: %target-typecheck-verify-swift
// Simple structs with all Codable properties should get derived conformance to
// Codable.
struct SimpleStruct : Codable {
var x: Int
var y: Double
static var z: String = "foo"
// These lines have to be within the SimpleStruct type because CodingKeys
// should be private.
func foo() {
// They should receive a synthesized CodingKeys enum.
let _ = SimpleStruct.CodingKeys.self
// The enum should have a case for each of the vars.
let _ = SimpleStruct.CodingKeys.x
let _ = SimpleStruct.CodingKeys.y
// Static vars should not be part of the CodingKeys enum.
let _ = SimpleStruct.CodingKeys.z // expected-error {{type 'SimpleStruct.CodingKeys' has no member 'z'}}
}
}

View File

@@ -0,0 +1,10 @@
// These are wrapped in a dummy function to avoid binding a global variable.
func foo() {
// They should receive synthesized init(from:) and an encode(to:).
let _ = SimpleStruct.init(from:)
let _ = SimpleStruct.encode(to:)
// The synthesized CodingKeys type should not be accessible from outside the
// struct.
let _ = SimpleStruct.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
}

View File

@@ -0,0 +1,39 @@
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown
// Classes with computed members should get synthesized conformance to Codable,
// but their lazy and computed members should be skipped as part of the
// synthesis.
class ClassWithComputedMembers : Codable {
var x: Int = 1
lazy var y: Double = .pi
var z: String {
return "foo"
}
// These lines have to be within the ClassWithComputedMembers type because
// CodingKeys should be private.
func foo() {
// They should receive a synthesized CodingKeys enum.
let _ = ClassWithComputedMembers.CodingKeys.self
// The enum should have a case for each of the vars.
let _ = ClassWithComputedMembers.CodingKeys.x
// Lazy vars should not be part of the CodingKeys enum.
let _ = ClassWithComputedMembers.CodingKeys.y // expected-error {{type 'ClassWithComputedMembers.CodingKeys' has no member 'y'}}
// Computed vars should not be part of the CodingKeys enum.
let _ = ClassWithComputedMembers.CodingKeys.z // expected-error {{type 'ClassWithComputedMembers.CodingKeys' has no member 'z'}}
}
}
// These are wrapped in a dummy function to avoid binding a global variable.
func foo() {
// They should receive synthesized init(from:) and an encode(to:).
let _ = ClassWithComputedMembers.init(from:)
let _ = ClassWithComputedMembers.encode(to:)
// The synthesized CodingKeys type should not be accessible from outside the
// class.
let _ = ClassWithComputedMembers.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
}

View File

@@ -0,0 +1,55 @@
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown
class SimpleClass : Codable {
var x: Int = 1
var y: Double = .pi
static var z: String = "foo"
}
// The synthesized CodingKeys type should not be accessible from outside the
// class.
let _ = SimpleClass.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
// Classes which inherit from classes that are codable should synthesize Codable
// conformance as well.
class SimpleChildClass : SimpleClass {
var w: Bool = true
// NOTE: These tests will fail in the future as Codable classes are updated
// to derive Codable conformance instead of inheriting their
// superclass's. Classes currently inherit their parent's Codable
// conformance and we never get the chance to derive a CodingKeys
// type, nor overridden methods.
// These lines have to be within the SimpleChildClass type because
// CodingKeys should be private.
func foo() {
// They should receive a synthesized CodingKeys enum.
// NOTE: This expected error will need to be removed in the future.
let _ = SimpleChildClass.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
// The enum should have a case for each of the vars.
// NOTE: This expectedxerror will need to be removed in the future.
let _ = SimpleChildClass.CodingKeys.w // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
// Inherited vars should not be part of the CodingKeys enum.
// NOTE: This expected error will need to be updated in the future.
// Should be `type 'SimpleClass.CodingKeys' has no member 'x'`
let _ = SimpleChildClass.CodingKeys.x // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
// NOTE: This expected error will need to be updated in the future.
// Should be `type 'SimpleClass.CodingKeys' has no member 'y'`
let _ = SimpleChildClass.CodingKeys.y // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
}
}
// These are wrapped in a dummy function to avoid binding a global variable.
func foo() {
// They should receive synthesized init(from:) and an encode(to:).
let _ = SimpleChildClass.init(from:)
let _ = SimpleChildClass.encode(to:)
// The synthesized CodingKeys type should not be accessible from outside the
// class.
let _ = SimpleChildClass.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
}

View File

@@ -0,0 +1,34 @@
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown
// Simple classes with all Codable properties should get derived conformance to
// Codable.
class SimpleClass : Codable {
var x: Int = 1
var y: Double = .pi
static var z: String = "foo"
// These lines have to be within the SimpleClass type because CodingKeys
// should be private.
func foo() {
// They should receive a synthesized CodingKeys enum.
let _ = SimpleClass.CodingKeys.self
// The enum should have a case for each of the vars.
let _ = SimpleClass.CodingKeys.x
let _ = SimpleClass.CodingKeys.y
// Static vars should not be part of the CodingKeys enum.
let _ = SimpleClass.CodingKeys.z // expected-error {{type 'SimpleClass.CodingKeys' has no member 'z'}}
}
}
// These are wrapped in a dummy function to avoid binding a global variable.
func foo() {
// They should receive synthesized init(from:) and an encode(to:).
let _ = SimpleClass.init(from:)
let _ = SimpleClass.encode(to:)
// The synthesized CodingKeys type should not be accessible from outside the
// class.
let _ = SimpleClass.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
}

View File

@@ -0,0 +1,36 @@
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown
// Simple classes where Codable conformance is added in extensions should still
// derive conformance.
class SimpleClass {
var x: Int = 1
var y: Double = .pi
static var z: String = "foo"
// These lines have to be within the SimpleClass type because CodingKeys
// should be private.
func foo() {
// They should receive a synthesized CodingKeys enum.
let _ = SimpleClass.CodingKeys.self
// The enum should have a case for each of the vars.
let _ = SimpleClass.CodingKeys.x
let _ = SimpleClass.CodingKeys.y
// Static vars should not be part of the CodingKeys enum.
let _ = SimpleClass.CodingKeys.z // expected-error {{type 'SimpleClass.CodingKeys' has no member 'z'}}
}
}
extension SimpleClass : Codable {}
// These are wrapped in a dummy function to avoid binding a global variable.
func foo() {
// They should receive synthesized init(from:) and an encode(to:).
let _ = SimpleClass.init(from:)
let _ = SimpleClass.encode(to:)
// The synthesized CodingKeys type should not be accessible from outside the
// class.
let _ = SimpleClass.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
}

View File

@@ -0,0 +1,2 @@
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown %S/Inputs/class_codable_simple_multi1.swift %S/Inputs/class_codable_simple_multi2.swift
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown %S/Inputs/class_codable_simple_multi2.swift %S/Inputs/class_codable_simple_multi1.swift

View File

@@ -0,0 +1,99 @@
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown
// Enums with no raw type conforming to CodingKey should get implicit derived
// conformance of methods.
enum NoRawTypeKey : CodingKey {
case a, b, c
}
let _ = NoRawTypeKey.a.stringValue
let _ = NoRawTypeKey(stringValue: "a")
let _ = NoRawTypeKey.a.intValue
let _ = NoRawTypeKey(intValue: 0)
// Enums with raw type of String conforming to CodingKey should get implicit
// derived conformance of methods.
enum StringKey : String, CodingKey {
case a = "A", b, c = "Foo"
}
let _ = StringKey.a.stringValue
let _ = StringKey(stringValue: "A")
let _ = StringKey.a.intValue
let _ = StringKey(intValue: 0)
// Enums with raw type of Int conforming to CodingKey should get implicit
// derived conformance of methods.
enum IntKey : Int, CodingKey {
case a = 3, b, c = 1
}
let _ = IntKey.a.stringValue
let _ = IntKey(stringValue: "a")
let _ = IntKey.a.intValue
let _ = IntKey(intValue: 3)
// Enums with a different raw value conforming to CodingKey should not get
// implicit derived conformance.
enum Int8Key : Int8, CodingKey { // expected-error {{type 'Int8Key' does not conform to protocol 'CodingKey'}}
case a = -1, b = 0, c = 1
}
// Structs conforming to CodingKey should not get implicit derived conformance.
struct StructKey : CodingKey { // expected-error {{type 'StructKey' does not conform to protocol 'CodingKey'}}
// expected-note@-1 {{candidate has non-matching type '()'}}
// expected-note@-2 {{candidate has non-matching type '()'}}
}
// Classes conforming to CodingKey should not get implict derived conformance.
class ClassKey : CodingKey { //expected-error {{type 'ClassKey' does not conform to protocol 'CodingKey'}}
// expected-note@-1 {{candidate has non-matching type '()'}}
// expected-note@-2 {{candidate has non-matching type '()'}}
}
// Types which are valid for CodingKey derived conformance should not get that
// derivation unless they explicitly conform to CodingKey.
enum X { case a }
enum Y : String { case a } // expected-note {{did you mean the implicitly-synthesized property 'rawValue'?}}
enum Z : Int { case a } // expected-note {{did you mean the implicitly-synthesized property 'rawValue'?}}
let _ = X.a.stringValue // expected-error {{value of type 'X' has no member 'stringValue'}}
let _ = Y.a.stringValue // expected-error {{value of type 'Y' has no member 'stringValue'}}
let _ = Z.a.stringValue // expected-error {{value of type 'Z' has no member 'stringValue'}}
let _ = X(stringValue: "a") // expected-error {{'X' cannot be constructed because it has no accessible initializers}}
let _ = Y(stringValue: "a") // expected-error {{incorrect argument label in call (have 'stringValue:', expected 'rawValue:')}}
let _ = Z(stringValue: "a") // expected-error {{incorrect argument label in call (have 'stringValue:', expected 'rawValue:')}}
let _ = X.a.intValue // expected-error {{value of type 'X' has no member 'intValue'}}
let _ = Y.a.intValue // expected-error {{value of type 'Y' has no member 'intValue'}}
let _ = Z.a.intValue // expected-error {{value of type 'Z' has no member 'intValue'}}
let _ = X(intValue: 0) // expected-error {{'X' cannot be constructed because it has no accessible initializers}}
let _ = Y(intValue: 0) // expected-error {{incorrect argument label in call (have 'intValue:', expected 'rawValue:')}}
let _ = Z(intValue: 0) // expected-error {{incorrect argument label in call (have 'intValue:', expected 'rawValue:')}}
// Types which are valid for CodingKey derived conformance should get derivation
// through extensions.
enum X2 { case a }
enum Y2 : String { case a }
enum Z2 : Int { case a }
extension X2 : CodingKey {}
extension Y2 : CodingKey {}
extension Z2 : CodingKey {}
let _ = X2.a.stringValue
let _ = Y2.a.stringValue
let _ = Z2.a.stringValue
let _ = X2(stringValue: "a")
let _ = Y2(stringValue: "a")
let _ = Z2(stringValue: "a")
let _ = X2.a.intValue
let _ = Y2.a.intValue
let _ = Z2.a.intValue
let _ = X2(intValue: 0)
let _ = Y2(intValue: 0)
let _ = Z2(intValue: 0)

View File

@@ -0,0 +1,10 @@
// RUN: %target-run-simple-swift
// REQUIRES: executable_test
// Cannot create an enum with a raw value but no cases.
enum EmptyEnum : CodingKey {}
// Cannot check accessors since there are no instances of EmptyEnum to test on.
guard EmptyEnum(stringValue: "") == nil else { fatalError() }
guard EmptyEnum(intValue: 0) == nil else { fatalError() }

View File

@@ -0,0 +1,36 @@
// RUN: %target-typecheck-verify-swift
// Enums where CodingKey conformance is added in extensions should still derive
// conformance.
enum NoRawTypeKey {
case a, b, c
}
extension NoRawTypeKey : CodingKey {}
let _ = NoRawTypeKey.a.stringValue
let _ = NoRawTypeKey(stringValue: "a")
let _ = NoRawTypeKey.a.intValue
let _ = NoRawTypeKey(intValue: 0)
enum StringKey : String {
case a = "A", b, c = "Foo"
}
extension StringKey : CodingKey {}
let _ = StringKey.a.stringValue
let _ = StringKey(stringValue: "A")
let _ = StringKey.a.intValue
let _ = StringKey(intValue: 0)
enum IntKey : Int {
case a = 3, b, c = 1
}
extension IntKey : CodingKey {}
let _ = IntKey.a.stringValue
let _ = IntKey(stringValue: "a")
let _ = IntKey.a.intValue
let _ = IntKey(intValue: 3)

View File

@@ -0,0 +1,6 @@
// RUN: %target-swift-frontend -typecheck -verify %S/Inputs/enum_coding_key_extension_multi1.swift %S/Inputs/enum_coding_key_extension_multi2.swift %S/Inputs/enum_coding_key_extension_multi3.swift
// RUN: %target-swift-frontend -typecheck -verify %S/Inputs/enum_coding_key_extension_multi1.swift %S/Inputs/enum_coding_key_extension_multi3.swift %S/Inputs/enum_coding_key_extension_multi2.swift
// RUN: %target-swift-frontend -typecheck -verify %S/Inputs/enum_coding_key_extension_multi2.swift %S/Inputs/enum_coding_key_extension_multi1.swift %S/Inputs/enum_coding_key_extension_multi3.swift
// RUN: %target-swift-frontend -typecheck -verify %S/Inputs/enum_coding_key_extension_multi2.swift %S/Inputs/enum_coding_key_extension_multi3.swift %S/Inputs/enum_coding_key_extension_multi1.swift
// RUN: %target-swift-frontend -typecheck -verify %S/Inputs/enum_coding_key_extension_multi3.swift %S/Inputs/enum_coding_key_extension_multi1.swift %S/Inputs/enum_coding_key_extension_multi2.swift
// RUN: %target-swift-frontend -typecheck -verify %S/Inputs/enum_coding_key_extension_multi3.swift %S/Inputs/enum_coding_key_extension_multi2.swift %S/Inputs/enum_coding_key_extension_multi1.swift

View File

@@ -0,0 +1,49 @@
// RUN: %target-run-simple-swift
// REQUIRES: executable_test
enum IntKey : Int, CodingKey {
case a = 3
case b // Implicitly 4
case c = 1
}
for (val, str, idx) in [(IntKey.a, "a", 3), (.b, "b", 4), (.c, "c", 1)] {
// Keys with a raw type of Int should get a stringValue which matches the
// case name.
guard val.stringValue == str else { fatalError() }
guard IntKey(stringValue: str) == val else { fatalError() }
// Keys with a raw type of Int should get an intValue based on their
// rawValue.
guard val.intValue == idx else { fatalError() }
guard IntKey(intValue: idx) == val else { fatalError() }
}
enum PartialIntKey : Int, CodingKey {
case a = 3
case b // Implicitly 4
case c = 1
var intValue: Int? {
return self.rawValue + 1
}
var stringValue: String {
switch self {
case .a: return "A"
case .b: return "B"
case .c: return "C"
}
}
}
for (val, str, idx) in [(PartialIntKey.a, "a", 3), (.b, "b", 4), (.c, "c", 1)] {
guard val.stringValue == str.uppercased() else { fatalError() }
guard val.intValue == idx + 1 else { fatalError() }
// Keys which define some methods should still get derived conformance
// to the others.
guard PartialIntKey(stringValue: str) == val else { fatalError() }
guard PartialIntKey(intValue: idx) == val else { fatalError() }
}

View File

@@ -0,0 +1,2 @@
// RUN: %target-swift-frontend -typecheck -verify %S/Inputs/enum_coding_key_multi1.swift %S/Inputs/enum_coding_key_multi2.swift
// RUN: %target-swift-frontend -typecheck -verify %S/Inputs/enum_coding_key_multi2.swift %S/Inputs/enum_coding_key_multi1.swift

View File

@@ -0,0 +1,48 @@
// RUN: %target-run-simple-swift
// REQUIRES: executable_test
enum ImplicitKey : CodingKey {
case a, b, c
}
for (index, (val, str)) in [(ImplicitKey.a, "a"), (.b, "b"), (.c, "c")].enumerated() {
// Keys with no raw type should get a stringValue which matches the case
// name.
guard val.stringValue == str else { fatalError() }
guard ImplicitKey(stringValue: str) == val else { fatalError() }
// They should not have an intValue.
guard val.intValue == nil else { fatalError() }
guard ImplicitKey(intValue: index) == nil else { fatalError() }
}
enum PartialImplicitKey : CodingKey {
case a, b, c
var intValue: Int? {
switch self {
case .a: return 1
case .b: return 2
case .c: return 3
}
}
var stringValue: String {
switch self {
case .a: return "A"
case .b: return "B"
case .c: return "C"
}
}
}
for (val, str, idx) in [(PartialImplicitKey.a, "a", 1), (.b, "b", 2), (.c, "c", 3)] {
guard val.stringValue == str.uppercased() else { fatalError() }
guard val.intValue == idx else { fatalError() }
// Keys which define some methods should still get derived conformance
// to the others.
guard PartialImplicitKey(stringValue: str) == val else { fatalError() }
guard PartialImplicitKey(intValue: idx) == nil else { fatalError() }
}

View File

@@ -0,0 +1,147 @@
// RUN: %target-typecheck-verify-swift
// Enums which conform to CodingKey and which should derive conformance should
// get all synthesized methods that they do not implement themselves.
enum NoRawTypeKey1 : CodingKey {
case a, b, c
}
let _ = NoRawTypeKey1.a.stringValue
let _ = NoRawTypeKey1(stringValue: "a")
let _ = NoRawTypeKey1.a.intValue
let _ = NoRawTypeKey1(intValue: 0)
enum NoRawTypeKey2 : CodingKey {
case a, b, c
var stringValue: String { return "" }
}
let _ = NoRawTypeKey2.a.stringValue
let _ = NoRawTypeKey2(stringValue: "a")
let _ = NoRawTypeKey2.a.intValue
let _ = NoRawTypeKey2(intValue: 0)
enum NoRawTypeKey3 : CodingKey {
case a, b, c
var intValue: Int? { return nil }
}
let _ = NoRawTypeKey3.a.stringValue
let _ = NoRawTypeKey3(stringValue: "a")
let _ = NoRawTypeKey3.a.intValue
let _ = NoRawTypeKey3(intValue: 0)
enum NoRawTypeKey4 : CodingKey {
case a, b, c
init?(stringValue: String) { return nil }
}
let _ = NoRawTypeKey4.a.stringValue
let _ = NoRawTypeKey4(stringValue: "a")
let _ = NoRawTypeKey4.a.intValue
let _ = NoRawTypeKey4(intValue: 0)
enum NoRawTypeKey5 : CodingKey {
case a, b, c
init?(intValue: Int) { return nil }
}
let _ = NoRawTypeKey5.a.stringValue
let _ = NoRawTypeKey5(stringValue: "a")
let _ = NoRawTypeKey5.a.intValue
let _ = NoRawTypeKey5(intValue: 0)
enum NoRawTypeKey6 : CodingKey {
case a, b, c
var stringValue: String { return "" }
var intValue: Int? { return nil }
}
let _ = NoRawTypeKey6.a.stringValue
let _ = NoRawTypeKey6(stringValue: "a")
let _ = NoRawTypeKey6.a.intValue
let _ = NoRawTypeKey6(intValue: 0)
enum NoRawTypeKey7 : CodingKey {
case a, b, c
var stringValue: String { return "" }
init?(stringValue: String) { return nil }
}
let _ = NoRawTypeKey7.a.stringValue
let _ = NoRawTypeKey7(stringValue: "a")
let _ = NoRawTypeKey7.a.intValue
let _ = NoRawTypeKey7(intValue: 0)
enum NoRawTypeKey8 : CodingKey {
case a, b, c
var stringValue: String { return "" }
init?(intValue: Int) { return nil }
}
let _ = NoRawTypeKey8.a.stringValue
let _ = NoRawTypeKey8(stringValue: "a")
let _ = NoRawTypeKey8.a.intValue
let _ = NoRawTypeKey8(intValue: 0)
enum NoRawTypeKey9 : CodingKey {
case a, b, c
var intValue: Int? { return nil }
init?(stringValue: String) { return nil }
}
let _ = NoRawTypeKey9.a.stringValue
let _ = NoRawTypeKey9(stringValue: "a")
let _ = NoRawTypeKey9.a.intValue
let _ = NoRawTypeKey9(intValue: 0)
enum NoRawTypeKey10 : CodingKey {
case a, b, c
var intValue: Int? { return nil }
init?(intValue: Int) { return nil }
}
let _ = NoRawTypeKey10.a.stringValue
let _ = NoRawTypeKey10(stringValue: "a")
let _ = NoRawTypeKey10.a.intValue
let _ = NoRawTypeKey10(intValue: 0)
enum NoRawTypeKey11 : CodingKey {
case a, b, c
var stringValue: String { return "" }
var intValue: Int? { return nil }
init?(stringValue: String) { return nil }
}
let _ = NoRawTypeKey11.a.stringValue
let _ = NoRawTypeKey11(stringValue: "a")
let _ = NoRawTypeKey11.a.intValue
let _ = NoRawTypeKey11(intValue: 0)
enum NoRawTypeKey12 : CodingKey {
case a, b, c
var stringValue: String { return "" }
var intValue: Int? { return nil }
init?(intValue: Int) { return nil }
}
let _ = NoRawTypeKey12.a.stringValue
let _ = NoRawTypeKey12(stringValue: "a")
let _ = NoRawTypeKey12.a.intValue
let _ = NoRawTypeKey12(intValue: 0)
// Enums which provide implementations for all CodingKey methods should not
// derive conformance (but derived conformance should not interfere with the
// existing methods).
enum NoRawTypeKey13 : CodingKey {
case a, b, c
var stringValue: String { return "" }
var intValue: Int? { return nil }
init?(stringValue: String) { return nil }
init?(intValue: Int) { return nil }
}
let _ = NoRawTypeKey13.a.stringValue
let _ = NoRawTypeKey13(stringValue: "a")
let _ = NoRawTypeKey13.a.intValue
let _ = NoRawTypeKey13(intValue: 0)

View File

@@ -0,0 +1,52 @@
// RUN: %target-run-simple-swift
// REQUIRES: executable_test
enum StringKey : String, CodingKey {
case a = "A"
case b // Implicitly "b"
case c = "Foo"
}
for (index, (val, str)) in [(StringKey.a, "A"), (.b, "b"), (.c, "Foo")].enumerated() {
// Keys with a raw type of String should get a stringValue based on their
// rawValue.
guard val.stringValue == str else { fatalError() }
guard StringKey(stringValue: str) == val else { fatalError() }
// They should not have an intValue.
guard val.intValue == nil else { fatalError() }
guard StringKey(intValue: index) == nil else { fatalError() }
}
enum PartialStringKey : String, CodingKey {
case a = "A"
case b // Implicitly "b"
case c = "Foo"
var intValue: Int? {
switch self {
case .a: return 1
case .b: return 2
case .c: return 3
}
}
var stringValue: String {
switch self {
case .a: return "x"
case .b: return "y"
case .c: return "z"
}
}
}
for (val, realStr, str, idx) in [(PartialStringKey.a, "A", "x", 1), (.b, "b", "y", 2), (.c, "Foo", "z", 3)] {
guard val.stringValue == str else { fatalError() }
guard val.intValue == idx else { fatalError() }
// Keys which define some methods should still get derived conformance
// to the others.
guard PartialStringKey(stringValue: realStr) == val else { fatalError() }
guard PartialStringKey(intValue: idx) == nil else { fatalError() }
}

View File

@@ -0,0 +1,36 @@
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown
// Structs with computed members should get synthesized conformance to Codable,
// but their lazy and computed members should be skipped as part of the
// synthesis.
struct StructWithComputedMembers : Codable {
var x: Int
lazy var y: Double = Double.pi
var z: String {
return "foo"
}
// These lines have to be within the StructWithComputedMembers type because
// CodingKeys should be private.
func foo() {
// They should receive a synthesized CodingKeys enum.
let _ = StructWithComputedMembers.CodingKeys.self
// The enum should have a case for each of the vars.
let _ = StructWithComputedMembers.CodingKeys.x
// Lazy vars should not be part of the CodingKeys enum.
let _ = StructWithComputedMembers.CodingKeys.y // expected-error {{type 'StructWithComputedMembers.CodingKeys' has no member 'y'}}
// Computed vars should not be part of the CodingKeys enum.
let _ = StructWithComputedMembers.CodingKeys.z // expected-error {{type 'StructWithComputedMembers.CodingKeys' has no member 'z'}}
}
}
// They should receive synthesized init(from:) and an encode(to:).
let _ = StructWithComputedMembers.init(from:)
let _ = StructWithComputedMembers.encode(to:)
// The synthesized CodingKeys type should not be accessible from outside the
// struct.
let _ = StructWithComputedMembers.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}

View File

@@ -0,0 +1,31 @@
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown
// Simple structs with all Codable properties should get derived conformance to
// Codable.
struct SimpleStruct : Codable {
var x: Int
var y: Double
static var z: String = "foo"
// These lines have to be within the SimpleStruct type because CodingKeys
// should be private.
func foo() {
// They should receive a synthesized CodingKeys enum.
let _ = SimpleStruct.CodingKeys.self
// The enum should have a case for each of the vars.
let _ = SimpleStruct.CodingKeys.x
let _ = SimpleStruct.CodingKeys.y
// Static vars should not be part of the CodingKeys enum.
let _ = SimpleStruct.CodingKeys.z // expected-error {{type 'SimpleStruct.CodingKeys' has no member 'z'}}
}
}
// They should receive synthesized init(from:) and an encode(to:).
let _ = SimpleStruct.init(from:)
let _ = SimpleStruct.encode(to:)
// The synthesized CodingKeys type should not be accessible from outside the
// struct.
let _ = SimpleStruct.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}

View File

@@ -0,0 +1,36 @@
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown
// Simple structs where Codable conformance is added in extensions should still
// derive conformance.
struct SimpleStruct {
var x: Int
var y: Double
static var z: String = "foo"
// These lines have to be within the SimpleStruct type because CodingKeys
// should be private.
func foo() {
// They should receive synthesized init(from:) and an encode(to:).
let _ = SimpleStruct.init(from:)
let _ = SimpleStruct.encode(to:)
// They should receive a synthesized CodingKeys enum.
let _ = SimpleStruct.CodingKeys.self
// The enum should have a case for each of the vars.
let _ = SimpleStruct.CodingKeys.x
let _ = SimpleStruct.CodingKeys.y
// Static vars should not be part of the CodingKeys enum.
let _ = SimpleStruct.CodingKeys.z // expected-error {{type 'SimpleStruct.CodingKeys' has no member 'z'}}
}
}
extension SimpleStruct : Codable {}
// These are wrapped in a dummy function to avoid binding a global variable.
func foo() {
// The synthesized CodingKeys type should not be accessible from outside the
// struct.
let _ = SimpleStruct.CodingKeys.self // expected-error {{'CodingKeys' is inaccessible due to 'private' protection level}}
}

View File

@@ -0,0 +1,2 @@
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown %S/Inputs/struct_codable_simple_multi1.swift %S/Inputs/struct_codable_simple_multi2.swift
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown %S/Inputs/struct_codable_simple_multi2.swift %S/Inputs/struct_codable_simple_multi1.swift