mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge remote-tracking branch 'origin/master' into master-next
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -60,6 +60,9 @@ PROTOCOL_(ErrorCodeProtocol)
|
||||
PROTOCOL(OptionSet)
|
||||
PROTOCOL_(BridgedNSError)
|
||||
PROTOCOL_(BridgedStoredNSError)
|
||||
PROTOCOL(CodingKey)
|
||||
PROTOCOL(Encodable)
|
||||
PROTOCOL(Decodable)
|
||||
|
||||
PROTOCOL_(ObjectiveCBridgeable)
|
||||
PROTOCOL_(DestructorSafeContainer)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
1022
lib/Sema/DerivedConformanceCodable.cpp
Normal file
1022
lib/Sema/DerivedConformanceCodable.cpp
Normal file
File diff suppressed because it is too large
Load Diff
561
lib/Sema/DerivedConformanceCodingKey.cpp
Normal file
561
lib/Sema/DerivedConformanceCodingKey.cpp
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -35,6 +35,7 @@ set(SWIFTLIB_ESSENTIAL
|
||||
BuiltinMath.swift.gyb
|
||||
Character.swift
|
||||
CocoaArray.swift
|
||||
Codable.swift
|
||||
Collection.swift
|
||||
CollectionAlgorithms.swift.gyb
|
||||
Comparable.swift
|
||||
|
||||
3176
stdlib/public/core/Codable.swift
Normal file
3176
stdlib/public/core/Codable.swift
Normal file
File diff suppressed because it is too large
Load Diff
@@ -162,6 +162,7 @@
|
||||
"DebuggerSupport.swift",
|
||||
"Equatable.swift",
|
||||
"Comparable.swift",
|
||||
"Hashable.swift"
|
||||
"Hashable.swift",
|
||||
"Codable.swift"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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'}}
|
||||
}
|
||||
}
|
||||
@@ -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}}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
extension NoRawTypeKey : CodingKey {}
|
||||
extension StringKey : CodingKey {}
|
||||
extension IntKey : CodingKey {}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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'}}
|
||||
}
|
||||
}
|
||||
@@ -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}}
|
||||
}
|
||||
@@ -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}}
|
||||
}
|
||||
@@ -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}}
|
||||
}
|
||||
34
test/decl/protocol/special/coding/class_codable_simple.swift
Normal file
34
test/decl/protocol/special/coding/class_codable_simple.swift
Normal 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}}
|
||||
}
|
||||
@@ -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}}
|
||||
}
|
||||
@@ -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
|
||||
99
test/decl/protocol/special/coding/enum_coding_key.swift
Normal file
99
test/decl/protocol/special/coding/enum_coding_key.swift
Normal 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)
|
||||
@@ -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() }
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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}}
|
||||
@@ -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}}
|
||||
@@ -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}}
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user