diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 730accd71befa..9f66e4d0d097f 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2035,7 +2035,7 @@ ERROR(broken_decodable_requirement,none, NOTE(codable_extraneous_codingkey_case_here,none, "CodingKey case %0 does match any stored properties", (Identifier)) NOTE(codable_non_conforming_property_here,none, - "cannot automatically synthesize %0 because %1 does not conform to %0", (Type, Identifier)) + "cannot automatically synthesize %0 because %1 does not conform to %0", (Type, Type)) NOTE(codable_non_decoded_property_here,none, "cannot automatically synthesize %0 because %1 does not have a matching CodingKey and does not have a default value", (Type, Identifier)) NOTE(codable_codingkeys_type_is_not_an_enum_here,none, diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index f8d06f7fcac07..19376588f9ad3 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -40,12 +40,14 @@ IDENTIFIER(Darwin) IDENTIFIER(dealloc) IDENTIFIER(Decodable) IDENTIFIER(decode) +IDENTIFIER(decodeIfPresent) IDENTIFIER(Decoder) IDENTIFIER(decoder) IDENTIFIER(deinit) IDENTIFIER(Element) IDENTIFIER(Encodable) IDENTIFIER(encode) +IDENTIFIER(encodeIfPresent) IDENTIFIER(Encoder) IDENTIFIER(encoder) IDENTIFIER(error) diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index aca12184b3d39..2f4668d9c607e 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -64,7 +64,69 @@ static bool superclassIsDecodable(ClassDecl *target) { C.getProtocol(KnownProtocolKind::Decodable)); } -/// Returns whether the given variable conforms to the given protocol. +/// Represents the possible outcomes of checking whether a decl conforms to +/// Encodable or Decodable. +enum CodableConformanceType { + TypeNotValidated, + DoesNotConform, + Conforms +}; + +/// Returns whether the given type conforms to the given {En,De}codable +/// protocol. +/// +/// \param tc The typechecker to use in validating {En,De}codable conformance. +/// +/// \param context The \c DeclContext the var declarations belong to. +/// +/// \param target The \c Type to validate. +/// +/// \param proto The \c ProtocolDecl to check conformance to. +static CodableConformanceType typeConformsToCodable(TypeChecker &tc, + DeclContext *context, + Type target, + ProtocolDecl *proto) { + // Some generic types need to be introspected to get at their "true" Codable + // conformance. + auto canType = target->getCanonicalType(); + if (auto genericType = dyn_cast(canType)) { + auto *nominalTypeDecl = genericType->getAnyNominal(); + + // Implicitly unwrapped optionals need to be unwrapped; + // ImplicitlyUnwrappedOptional does not need to conform to Codable directly + // -- only its inner type does. + if (nominalTypeDecl == tc.Context.getImplicitlyUnwrappedOptionalDecl() || + // FIXME: Remove the following when conditional conformance lands. + // Some generic types in the stdlib currently conform to Codable even + // when the type they are generic on does not [Optional, Array, Set, + // Dictionary]. For synthesizing conformance, we don't want to + // consider these types as Codable if the nested type is not Codable. + // Look through the generic type parameters of these types recursively + // to avoid synthesizing code that will crash at runtime. + // + // We only want to look through generic params for these types; other + // types may validly conform to Codable even if their generic param + // types do not. + nominalTypeDecl == tc.Context.getOptionalDecl() || + nominalTypeDecl == tc.Context.getArrayDecl() || + nominalTypeDecl == tc.Context.getSetDecl() || + nominalTypeDecl == tc.Context.getDictionaryDecl()) { + for (auto paramType : genericType->getGenericArgs()) { + if (typeConformsToCodable(tc, context, paramType, proto) != Conforms) + return DoesNotConform; + } + + return Conforms; + } + } + + return tc.conformsToProtocol(target, proto, context, + ConformanceCheckFlags::Used) ? Conforms + : DoesNotConform; +} + +/// Returns whether the given variable conforms to the given {En,De}codable +/// protocol. /// /// \param tc The typechecker to use in validating {En,De}codable conformance. /// @@ -73,8 +135,10 @@ static bool superclassIsDecodable(ClassDecl *target) { /// \param varDecl The \c VarDecl to validate. /// /// \param proto The \c ProtocolDecl to check conformance to. -static bool varConformsToProtocol(TypeChecker &tc, DeclContext *context, - VarDecl *varDecl, ProtocolDecl *proto) { +static CodableConformanceType varConformsToCodable(TypeChecker &tc, + DeclContext *context, + VarDecl *varDecl, + ProtocolDecl *proto) { // If the decl doesn't yet have a type, we may be seeing it before the type // checker has gotten around to evaluating its type. For example: // @@ -94,10 +158,10 @@ static bool varConformsToProtocol(TypeChecker &tc, DeclContext *context, // If the var decl didn't validate, it may still not have a type; confirm it // has a type before ensuring the type conforms to Codable. - // TODO: Peer through Optional and collection types to get at inner type. - return varDecl->hasType() && - tc.conformsToProtocol(varDecl->getType(), proto, context, - ConformanceCheckFlags::Used); + if (!varDecl->hasType()) + return TypeNotValidated; + + return typeConformsToCodable(tc, context, varDecl->getType(), proto); } /// Validates the given CodingKeys enum decl by ensuring its cases are a 1-to-1 @@ -144,18 +208,26 @@ validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl, } // We have a property to map to. Ensure it's {En,De}codable. - bool conforms = varConformsToProtocol(tc, target->getDeclContext(), - it->second, proto); - if (!conforms) { - tc.diagnose(it->second->getLoc(), - diag::codable_non_conforming_property_here, - proto->getDeclaredType(), it->second->getName()); - propertiesAreValid = false; - continue; + auto conformance = varConformsToCodable(tc, target->getDeclContext(), + it->second, proto); + switch (conformance) { + case Conforms: + // The property was valid. Remove it from the list. + properties.erase(it); + break; + + case DoesNotConform: + tc.diagnose(it->second->getLoc(), + diag::codable_non_conforming_property_here, + proto->getDeclaredType(), it->second->getType()); + LLVM_FALLTHROUGH; + + case TypeNotValidated: + // We don't produce a diagnostic for a type which failed to validate. + // This will produce a diagnostic elsewhere anyway. + propertiesAreValid = false; + continue; } - - // The property was valid. Remove it from the list. - properties.erase(it); } if (!propertiesAreValid) @@ -181,6 +253,14 @@ validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl, return propertiesAreValid; } +/// A type which has information about the validity of an encountered +/// CodingKeys type. +struct CodingKeysValidity { + bool hasType; + bool isValid; + CodingKeysValidity(bool ht, bool iv) : hasType(ht), isValid(iv) {} +}; + /// Returns whether the given type has a valid nested \c CodingKeys enum. /// /// If the type has an invalid \c CodingKeys entity, produces diagnostics to @@ -195,13 +275,15 @@ validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl, /// /// \param proto The {En,De}codable protocol to ensure the properties matching /// the keys conform to. -static std::pair -hasValidCodingKeysEnum(TypeChecker &tc, NominalTypeDecl *target, - ProtocolDecl *proto) { +/// +/// \returns A \c CodingKeysValidity value representing the result of the check. +static CodingKeysValidity hasValidCodingKeysEnum(TypeChecker &tc, + NominalTypeDecl *target, + ProtocolDecl *proto) { auto &C = tc.Context; auto codingKeysDecls = target->lookupDirect(DeclName(C.Id_CodingKeys)); if (codingKeysDecls.empty()) - return {/* has type? */ false, /* error? */ false}; + return CodingKeysValidity(/*hasType=*/false, /*isValid=*/true); // Only ill-formed code would produce multiple results for this lookup. // This would get diagnosed later anyway, so we're free to only look at the @@ -213,16 +295,14 @@ hasValidCodingKeysEnum(TypeChecker &tc, NominalTypeDecl *target, tc.diagnose(result->getLoc(), diag::codable_codingkeys_type_is_not_an_enum_here, proto->getDeclaredType()); - return {/* has type? */ true, /* error? */ true}; + return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false); } // CodingKeys may be a typealias. If so, follow the alias to its canonical // type. auto codingKeysType = codingKeysTypeDecl->getDeclaredInterfaceType(); if (isa(codingKeysTypeDecl)) { - auto canType = codingKeysType->getCanonicalType(); - assert(canType); - codingKeysTypeDecl = canType->getAnyNominal(); + codingKeysTypeDecl = codingKeysType->getAnyNominal(); } // Ensure that the type we found conforms to the CodingKey protocol. @@ -233,7 +313,7 @@ hasValidCodingKeysEnum(TypeChecker &tc, NominalTypeDecl *target, tc.diagnose(codingKeysTypeDecl->getLoc(), diag::codable_codingkeys_type_does_not_conform_here, proto->getDeclaredType()); - return {/* has type? */ true, /* error? */ true}; + return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false); } // CodingKeys must be an enum for synthesized conformance. @@ -242,11 +322,11 @@ hasValidCodingKeysEnum(TypeChecker &tc, NominalTypeDecl *target, tc.diagnose(codingKeysTypeDecl->getLoc(), diag::codable_codingkeys_type_is_not_an_enum_here, proto->getDeclaredType()); - return {/* has type? */ true, /* error? */ true}; + return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false); } bool valid = validateCodingKeysEnum(tc, codingKeysEnum, target, proto); - return {/* has type? */ true, /* error? */ !valid}; + return CodingKeysValidity(/*hasType=*/true, /*isValid=*/valid); } /// Synthesizes a new \c CodingKeys enum based on the {En,De}codable members of @@ -265,7 +345,6 @@ static EnumDecl *synthesizeCodingKeysEnum(TypeChecker &tc, NominalTypeDecl *target, ProtocolDecl *proto) { auto &C = tc.Context; - auto *targetDC = cast(target); // We want to look through all the var declarations of this type to create // enum cases based on those var names. @@ -275,13 +354,10 @@ static EnumDecl *synthesizeCodingKeysEnum(TypeChecker &tc, MutableArrayRef inherited = C.AllocateCopy(protoTypeLoc); auto *enumDecl = new (C) EnumDecl(SourceLoc(), C.Id_CodingKeys, SourceLoc(), - inherited, nullptr, targetDC); + inherited, nullptr, target); enumDecl->setImplicit(); enumDecl->setAccessibility(Accessibility::Private); - auto *enumDC = cast(enumDecl); - auto *mutableEnumDC = cast(enumDecl); - // For classes which inherit from something Encodable or Decodable, we // provide case `super` as the first key (to be used in encoding super). auto *classDecl = dyn_cast(target); @@ -292,38 +368,51 @@ static EnumDecl *synthesizeCodingKeysEnum(TypeChecker &tc, // diagnose and bail. auto *super = new (C) EnumElementDecl(SourceLoc(), C.Id_super, TypeLoc(), /*HasArgumentType=*/false, - SourceLoc(), nullptr, enumDC); + SourceLoc(), nullptr, enumDecl); super->setImplicit(); - mutableEnumDC->addMember(super); + enumDecl->addMember(super); } // Each of these vars needs a case in the enum. For each var decl, if the type // conforms to {En,De}codable, add it to the enum. bool allConform = true; for (auto *varDecl : target->getStoredProperties(/*skipInaccessible=*/true)) { - if (!varConformsToProtocol(tc, target->getDeclContext(), varDecl, proto)) { - tc.diagnose(varDecl->getLoc(), - diag::codable_non_conforming_property_here, - proto->getDeclaredType(), varDecl->getName()); - allConform = false; - continue; - } + auto conformance = varConformsToCodable(tc, target->getDeclContext(), + varDecl, proto); + switch (conformance) { + case Conforms: + { + auto *elt = new (C) EnumElementDecl(SourceLoc(), varDecl->getName(), + TypeLoc(), + /*HasArgumentType=*/false, + SourceLoc(), nullptr, enumDecl); + elt->setImplicit(); + enumDecl->addMember(elt); + break; + } + + case DoesNotConform: + tc.diagnose(varDecl->getLoc(), + diag::codable_non_conforming_property_here, + proto->getDeclaredType(), varDecl->getType()); + LLVM_FALLTHROUGH; - auto *elt = new (C) EnumElementDecl(SourceLoc(), varDecl->getName(), - TypeLoc(), /*HasArgumentType=*/false, - SourceLoc(), nullptr, enumDC); - elt->setImplicit(); - mutableEnumDC->addMember(elt); + case TypeNotValidated: + // We don't produce a diagnostic for a type which failed to validate. + // This will produce a diagnostic elsewhere anyway. + allConform = false; + continue; + } } if (!allConform) return nullptr; // Forcibly derive conformance to CodingKey. - tc.checkConformancesInContext(enumDC, mutableEnumDC); + tc.checkConformancesInContext(enumDecl, enumDecl); // Add to the type. - cast(target)->addMember(enumDecl); + target->addMember(enumDecl); return enumDecl; } @@ -347,8 +436,7 @@ static EnumDecl *lookupEvaluatedCodingKeysEnum(ASTContext &C, auto *codingKeysDecl = codingKeyDecls.front(); if (auto *typealiasDecl = dyn_cast(codingKeysDecl)) { - codingKeysDecl = typealiasDecl->getDeclaredInterfaceType() - ->getCanonicalType()->getAnyNominal(); + codingKeysDecl = typealiasDecl->getDeclaredInterfaceType()->getAnyNominal(); } return dyn_cast(codingKeysDecl); @@ -513,7 +601,7 @@ static void deriveBodyEncodable_encode(AbstractFunctionDecl *encodeDecl) { statements.push_back(containerDecl); // Now need to generate `try container.encode(x, forKey: .x)` for all - // existing properties. + // existing properties. Optional properties get `encodeIfPresent`. for (auto *elt : codingKeysEnum->getAllElements()) { // Only ill-formed code would produce multiple results for this lookup. // This would get diagnosed later anyway, so we're free to only look at @@ -531,9 +619,16 @@ static void deriveBodyEncodable_encode(AbstractFunctionDecl *encodeDecl) { auto *metaTyRef = TypeExpr::createImplicit(codingKeysType, C); auto *keyExpr = new (C) DotSyntaxCallExpr(eltRef, SourceLoc(), metaTyRef); - // encode(_:forKey:) + // encode(_:forKey:)/encodeIfPresent(_:forKey:) + auto methodName = C.Id_encode; + auto varType = cast(matchingVars[0])->getType(); + if (varType->getAnyNominal() == C.getOptionalDecl() || + varType->getAnyNominal() == C.getImplicitlyUnwrappedOptionalDecl()) { + methodName = C.Id_encodeIfPresent; + } + SmallVector argNames{Identifier(), C.Id_forKey}; - DeclName name(C, C.Id_encode, argNames); + DeclName name(C, methodName, argNames); auto *encodeCall = new (C) UnresolvedDotExpr(containerExpr, SourceLoc(), name, DeclNameLoc(), /*Implicit=*/true); @@ -606,7 +701,6 @@ static void deriveBodyEncodable_encode(AbstractFunctionDecl *encodeDecl) { static FuncDecl *deriveEncodable_encode(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *target) { auto &C = tc.Context; - auto *targetDC = cast(target); // Expected type: (Self) -> (Encoder) throws -> () // Constructed as: func type @@ -632,10 +726,10 @@ static FuncDecl *deriveEncodable_encode(TypeChecker &tc, Decl *parentDecl, auto innerType = FunctionType::get(inputType, returnType, extInfo); // Params: (self [implicit], Encoder) - auto *selfDecl = ParamDecl::createSelf(SourceLoc(), targetDC); + auto *selfDecl = ParamDecl::createSelf(SourceLoc(), target); auto *encoderParam = new (C) ParamDecl(/*isLet=*/true, SourceLoc(), SourceLoc(), C.Id_to, SourceLoc(), - C.Id_encoder, encoderType, targetDC); + C.Id_encoder, encoderType, target); encoderParam->setInterfaceType(encoderType); ParameterList *params[] = {ParameterList::createWithoutLoc(selfDecl), @@ -648,7 +742,7 @@ static FuncDecl *deriveEncodable_encode(TypeChecker &tc, Decl *parentDecl, /*Throws=*/true, SourceLoc(), SourceLoc(), nullptr, params, TypeLoc::withoutLoc(returnType), - targetDC); + target); encodeDecl->setImplicit(); encodeDecl->setBodySynthesizer(deriveBodyEncodable_encode); @@ -661,12 +755,12 @@ static FuncDecl *deriveEncodable_encode(TypeChecker &tc, Decl *parentDecl, } // Evaluate the type of Self in (Self) -> (Encoder) throws -> (). - Type selfType = targetDC->getDeclaredInterfaceType(); + Type selfType = target->getDeclaredInterfaceType(); Type interfaceType; - if (auto sig = targetDC->getGenericSignatureOfContext()) { + if (auto sig = target->getGenericSignatureOfContext()) { // Evaluate the below, but in a generic environment (if Self is generic). encodeDecl->setGenericEnvironment( - targetDC->getGenericEnvironmentOfContext()); + target->getGenericEnvironmentOfContext()); interfaceType = GenericFunctionType::get(sig, selfType, innerType, FunctionType::ExtInfo()); } else { @@ -684,7 +778,7 @@ static FuncDecl *deriveEncodable_encode(TypeChecker &tc, Decl *parentDecl, if (target->hasClangNode()) tc.Context.addExternalDecl(encodeDecl); - cast(target)->addMember(encodeDecl); + target->addMember(encodeDecl); return encodeDecl; } @@ -770,8 +864,8 @@ static void deriveBodyDecodable_init(AbstractFunctionDecl *initDecl) { statements.push_back(bindingDecl); statements.push_back(containerDecl); - // Now need to generate `x = try container.encode(Type.self, forKey: .x)` - // for all existing properties. + // Now need to generate `x = try container.decode(Type.self, forKey: .x)` + // for all existing properties. Optional properties get `decodeIfPresent`. for (auto *elt : enumElements) { // Only ill-formed code would produce multiple results for this lookup. // This would get diagnosed later anyway, so we're free to only look at @@ -783,8 +877,28 @@ static void deriveBodyDecodable_init(AbstractFunctionDecl *initDecl) { if (varDecl->isLet() && varDecl->getParentInitializer() != nullptr) continue; - // Type.self (where Type === type(of: x) + // Potentially unwrap a layer of optionality from the var type. If the var + // is Optional, we want to decodeIfPresent(T.self, forKey: ...); + // otherwise, we can just decode(T.self, forKey: ...). + // This is also true if the type is an ImplicitlyUnwrappedOptional. auto varType = varDecl->getType(); + auto methodName = C.Id_decode; + if (varType->getAnyNominal() == C.getOptionalDecl() || + varType->getAnyNominal() == C.getImplicitlyUnwrappedOptionalDecl()) { + methodName = C.Id_decodeIfPresent; + + // The type we request out of decodeIfPresent needs to be unwrapped + // one level. + // e.g. String? => decodeIfPresent(String.self, forKey: ...), not + // decodeIfPresent(String?.self, forKey: ...) + auto boundOptionalType = + dyn_cast(varType->getCanonicalType()); + varType = boundOptionalType->getGenericArgs()[0]; + } + + // Type.self (where Type === type(of: x)) + // Calculating the metatype needs to happen after potential Optional + // unwrapping above. auto *metaTyRef = TypeExpr::createImplicit(varType, C); auto *targetExpr = new (C) DotSelfExpr(metaTyRef, SourceLoc(), SourceLoc(), varType); @@ -794,9 +908,9 @@ static void deriveBodyDecodable_init(AbstractFunctionDecl *initDecl) { metaTyRef = TypeExpr::createImplicit(codingKeysType, C); auto *keyExpr = new (C) DotSyntaxCallExpr(eltRef, SourceLoc(), metaTyRef); - // container.decode(_:forKey:) + // decode(_:forKey:)/decodeIfPresent(_:forKey:) SmallVector argNames{Identifier(), C.Id_forKey}; - DeclName name(C, C.Id_decode, argNames); + DeclName name(C, methodName, argNames); auto *decodeCall = new (C) UnresolvedDotExpr(containerExpr, SourceLoc(), name, DeclNameLoc(), /*Implicit=*/true); @@ -877,7 +991,6 @@ static void deriveBodyDecodable_init(AbstractFunctionDecl *initDecl) { static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *target) { auto &C = tc.Context; - auto *targetDC = cast(target); // Expected type: (Self) -> (Decoder) throws -> (Self) // Constructed as: func type @@ -898,7 +1011,7 @@ static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl, /*Throws=*/true); // (Self) - auto returnType = targetDC->getDeclaredInterfaceType(); + auto returnType = target->getDeclaredInterfaceType(); // (from: Decoder) throws -> (Self) Type innerType = FunctionType::get(inputType, returnType, extInfo); @@ -906,13 +1019,13 @@ static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl, // Params: (self [implicit], Decoder) // self should be inout if the type is a value type; not inout otherwise. auto inOut = !isa(target); - auto *selfDecl = ParamDecl::createSelf(SourceLoc(), targetDC, + auto *selfDecl = ParamDecl::createSelf(SourceLoc(), target, /*isStatic=*/false, /*isInOut=*/inOut); auto *decoderParamDecl = new (C) ParamDecl(/*isLet=*/true, SourceLoc(), SourceLoc(), C.Id_from, SourceLoc(), C.Id_decoder, - decoderType, targetDC); + decoderType, target); decoderParamDecl->setImplicit(); decoderParamDecl->setInterfaceType(decoderType); @@ -926,7 +1039,7 @@ static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl, /*Failability=*/OTK_None, /*FailabilityLoc=*/SourceLoc(), /*Throws=*/true, /*ThrowsLoc=*/SourceLoc(), selfDecl, paramList, - /*GenericParams=*/nullptr, targetDC); + /*GenericParams=*/nullptr, target); initDecl->setImplicit(); initDecl->setBodySynthesizer(deriveBodyDecodable_init); @@ -940,9 +1053,9 @@ static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl, Type selfInitType = initDecl->computeInterfaceSelfType(/*init=*/true); Type interfaceType; Type initializerType; - if (auto sig = targetDC->getGenericSignatureOfContext()) { + if (auto sig = target->getGenericSignatureOfContext()) { // Evaluate the below, but in a generic environment (if Self is generic). - initDecl->setGenericEnvironment(targetDC->getGenericEnvironmentOfContext()); + initDecl->setGenericEnvironment(target->getGenericEnvironmentOfContext()); interfaceType = GenericFunctionType::get(sig, selfType, innerType, FunctionType::ExtInfo()); initializerType = GenericFunctionType::get(sig, selfInitType, innerType, @@ -964,7 +1077,7 @@ static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl, if (target->hasClangNode()) tc.Context.addExternalDecl(initDecl); - cast(target)->addMember(initDecl); + target->addMember(initDecl); return initDecl; } @@ -981,15 +1094,14 @@ static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl, static bool canSynthesize(TypeChecker &tc, NominalTypeDecl *target, ProtocolDecl *proto) { // First, look up if the type has a valid CodingKeys enum we can use. - bool hasType, error; - std::tie(hasType, error) = hasValidCodingKeysEnum(tc, target, proto); + auto validity = hasValidCodingKeysEnum(tc, target, proto); // We found a type, but it wasn't valid. - if (error) + if (!validity.isValid) return false; // We can try to synthesize a type here. - if (!hasType) { + if (!validity.hasType) { auto *synthesizedEnum = synthesizeCodingKeysEnum(tc, target, proto); if (!synthesizedEnum) return false; diff --git a/stdlib/public/SDK/Foundation/JSONEncoder.swift b/stdlib/public/SDK/Foundation/JSONEncoder.swift index 97ed0972efc37..adf06e0647039 100644 --- a/stdlib/public/SDK/Foundation/JSONEncoder.swift +++ b/stdlib/public/SDK/Foundation/JSONEncoder.swift @@ -309,34 +309,34 @@ fileprivate struct _JSONKeyedEncodingContainer : KeyedEncodingCon // MARK: - KeyedEncodingContainerProtocol Methods - mutating func encode(_ value: Bool?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: Int?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: Int8?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: Int16?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: Int32?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: Int64?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: UInt?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: UInt8?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: UInt16?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: UInt32?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: UInt64?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: String?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - - mutating func encode(_ value: Float?, forKey key: Key) throws { + mutating func encode(_ value: Bool, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: Int, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: Int8, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: Int16, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: Int32, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: Int64, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: UInt, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: UInt8, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: UInt16, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: UInt32, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: UInt64, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: String, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + + mutating func encode(_ value: Float, forKey key: Key) throws { // Since the float may be invalid and throw, the coding path needs to contain this key. try self.encoder.with(pushedKey: key) { self.container[key.stringValue] = try self.encoder.box(value) } } - mutating func encode(_ value: Double?, forKey key: Key) throws { + mutating func encode(_ value: Double, forKey key: Key) throws { // Since the double may be invalid and throw, the coding path needs to contain this key. try self.encoder.with(pushedKey: key) { self.container[key.stringValue] = try self.encoder.box(value) } } - mutating func encode(_ value: T?, forKey key: Key) throws { + mutating func encode(_ value: T, forKey key: Key) throws { try self.encoder.with(pushedKey: key) { self.container[key.stringValue] = try self.encoder.box(value) } @@ -406,34 +406,34 @@ fileprivate struct _JSONUnkeyedEncodingContainer : UnkeyedEncodingContainer { // MARK: - UnkeyedEncodingContainer Methods - mutating func encode(_ value: Bool?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: Int?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: Int8?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: Int16?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: Int32?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: Int64?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: UInt?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: UInt8?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: UInt16?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: UInt32?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: UInt64?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: String?) throws { self.container.add(self.encoder.box(value)) } - - mutating func encode(_ value: Float?) throws { + mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) } + + mutating func encode(_ value: Float) throws { // Since the float may be invalid and throw, the coding path needs to contain this key. try self.encoder.with(pushedKey: nil) { self.container.add(try self.encoder.box(value)) } } - mutating func encode(_ value: Double?) throws { + mutating func encode(_ value: Double) throws { // Since the double may be invalid and throw, the coding path needs to contain this key. try self.encoder.with(pushedKey: nil) { self.container.add(try self.encoder.box(value)) } } - mutating func encode(_ value: T?) throws { + mutating func encode(_ value: T) throws { try self.encoder.with(pushedKey: nil) { self.container.add(try self.encoder.box(value)) } @@ -487,6 +487,11 @@ extension _JSONEncoder : SingleValueEncodingContainer { // MARK: - SingleValueEncodingContainer Methods + func encodeNil() throws { + assertCanEncodeSingleValue() + self.storage.push(container: NSNull()) + } + func encode(_ value: Bool) throws { assertCanEncodeSingleValue() self.storage.push(container: box(value)) @@ -556,30 +561,31 @@ extension _JSONEncoder : SingleValueEncodingContainer { assertCanEncodeSingleValue() try self.storage.push(container: box(value)) } + + func encode(_ value: T) throws { + assertCanEncodeSingleValue() + try self.storage.push(container: box(value)) + } } // MARK: - Concrete Value Representations extension _JSONEncoder { /// Returns the given value boxed in a container appropriate for pushing onto the container stack. - fileprivate func box(_ value: Bool?) -> NSObject { return value == nil ? NSNull() : NSNumber(value: value!) } - fileprivate func box(_ value: Int?) -> NSObject { return value == nil ? NSNull() : NSNumber(value: value!) } - fileprivate func box(_ value: Int8?) -> NSObject { return value == nil ? NSNull() : NSNumber(value: value!) } - fileprivate func box(_ value: Int16?) -> NSObject { return value == nil ? NSNull() : NSNumber(value: value!) } - fileprivate func box(_ value: Int32?) -> NSObject { return value == nil ? NSNull() : NSNumber(value: value!) } - fileprivate func box(_ value: Int64?) -> NSObject { return value == nil ? NSNull() : NSNumber(value: value!) } - fileprivate func box(_ value: UInt?) -> NSObject { return value == nil ? NSNull() : NSNumber(value: value!) } - fileprivate func box(_ value: UInt8?) -> NSObject { return value == nil ? NSNull() : NSNumber(value: value!) } - fileprivate func box(_ value: UInt16?) -> NSObject { return value == nil ? NSNull() : NSNumber(value: value!) } - fileprivate func box(_ value: UInt32?) -> NSObject { return value == nil ? NSNull() : NSNumber(value: value!) } - fileprivate func box(_ value: UInt64?) -> NSObject { return value == nil ? NSNull() : NSNumber(value: value!) } - fileprivate func box(_ value: String?) -> NSObject { return value == nil ? NSNull() : NSString(string: value!) } - - fileprivate func box(_ float: Float?) throws -> NSObject { - guard let float = float else { - return NSNull() - } - + fileprivate func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt16) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt32) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt64) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: String) -> NSObject { return NSString(string: value) } + + fileprivate func box(_ float: Float) throws -> NSObject { guard !float.isInfinite && !float.isNaN else { guard case let .convertToString(positiveInfinity: posInfString, negativeInfinity: negInfString, @@ -599,11 +605,7 @@ extension _JSONEncoder { return NSNumber(value: float) } - fileprivate func box(_ double: Double?) throws -> NSObject { - guard let double = double else { - return NSNull() - } - + fileprivate func box(_ double: Double) throws -> NSObject { guard !double.isInfinite && !double.isNaN else { guard case let .convertToString(positiveInfinity: posInfString, negativeInfinity: negInfString, @@ -623,11 +625,7 @@ extension _JSONEncoder { return NSNumber(value: double) } - fileprivate func box(_ date: Date?) throws -> NSObject { - guard let date = date else { - return NSNull() - } - + fileprivate func box(_ date: Date) throws -> NSObject { switch self.options.dateEncodingStrategy { case .deferredToDate: // Must be called with a surrounding with(pushedKey:) call. @@ -664,11 +662,7 @@ extension _JSONEncoder { } } - fileprivate func box(_ data: Data?) throws -> NSObject { - guard let data = data else { - return NSNull() - } - + fileprivate func box(_ data: Data) throws -> NSObject { switch self.options.dataEncodingStrategy { case .base64Encode: return NSString(string: data.base64EncodedString()) @@ -687,11 +681,7 @@ extension _JSONEncoder { } } - fileprivate func box(_ value: T?) throws -> NSObject { - guard let value = value else { - return NSNull() - } - + fileprivate func box(_ value: T) throws -> NSObject { if T.self == Date.self { // Respect Date encoding strategy return try self.box((value as! Date)) @@ -962,12 +952,6 @@ fileprivate class _JSONDecoder : Decoder { } func singleValueContainer() throws -> SingleValueDecodingContainer { - guard !(self.storage.topContainer is NSNull) else { - throw DecodingError.valueNotFound(SingleValueDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get single value decoding container -- found null value instead.")) - } - guard !(self.storage.topContainer is [String : Any]) else { throw DecodingError.typeMismatch(SingleValueDecodingContainer.self, DecodingError.Context(codingPath: self.codingPath, @@ -1472,22 +1456,160 @@ fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { extension _JSONDecoder : SingleValueDecodingContainer { // MARK: SingleValueDecodingContainer Methods + func decodeNil() -> Bool { + return self.storage.topContainer is NSNull + } + // These all unwrap the result, since we couldn't have gotten a single value container if the topContainer was null. - func decode(_ type: Bool.Type) throws -> Bool { return try self.unbox(self.storage.topContainer, as: Bool.self)! } - func decode(_ type: Int.Type) throws -> Int { return try self.unbox(self.storage.topContainer, as: Int.self)! } - func decode(_ type: Int8.Type) throws -> Int8 { return try self.unbox(self.storage.topContainer, as: Int8.self)! } - func decode(_ type: Int16.Type) throws -> Int16 { return try self.unbox(self.storage.topContainer, as: Int16.self)! } - func decode(_ type: Int32.Type) throws -> Int32 { return try self.unbox(self.storage.topContainer, as: Int32.self)! } - func decode(_ type: Int64.Type) throws -> Int64 { return try self.unbox(self.storage.topContainer, as: Int64.self)! } - func decode(_ type: UInt.Type) throws -> UInt { return try self.unbox(self.storage.topContainer, as: UInt.self)! } - func decode(_ type: UInt8.Type) throws -> UInt8 { return try self.unbox(self.storage.topContainer, as: UInt8.self)! } - func decode(_ type: UInt16.Type) throws -> UInt16 { return try self.unbox(self.storage.topContainer, as: UInt16.self)! } - func decode(_ type: UInt32.Type) throws -> UInt32 { return try self.unbox(self.storage.topContainer, as: UInt32.self)! } - func decode(_ type: UInt64.Type) throws -> UInt64 { return try self.unbox(self.storage.topContainer, as: UInt64.self)! } - func decode(_ type: Float.Type) throws -> Float { return try self.unbox(self.storage.topContainer, as: Float.self)! } - func decode(_ type: Double.Type) throws -> Double { return try self.unbox(self.storage.topContainer, as: Double.self)! } - func decode(_ type: String.Type) throws -> String { return try self.unbox(self.storage.topContainer, as: String.self)! } - func decode(_ type: Data.Type) throws -> Data { return try self.unbox(self.storage.topContainer, as: Data.self)! } + func decode(_ type: Bool.Type) throws -> Bool { + guard let value = try self.unbox(self.storage.topContainer, as: Bool.self) else { + throw DecodingError.valueNotFound(Bool.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Bool but found null value instead.")) + } + + return value + } + + func decode(_ type: Int.Type) throws -> Int { + guard let value = try self.unbox(self.storage.topContainer, as: Int.self) else { + throw DecodingError.valueNotFound(Int.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Int but found null value instead.")) + } + + return value + } + + func decode(_ type: Int8.Type) throws -> Int8 { + guard let value = try self.unbox(self.storage.topContainer, as: Int8.self) else { + throw DecodingError.valueNotFound(Int8.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Int8 but found null value instead.")) + } + + return value + } + + func decode(_ type: Int16.Type) throws -> Int16 { + guard let value = try self.unbox(self.storage.topContainer, as: Int16.self) else { + throw DecodingError.valueNotFound(Int16.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Int16 but found null value instead.")) + } + + return value + } + + func decode(_ type: Int32.Type) throws -> Int32 { + guard let value = try self.unbox(self.storage.topContainer, as: Int32.self) else { + throw DecodingError.valueNotFound(Int32.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Int32 but found null value instead.")) + } + + return value + } + + func decode(_ type: Int64.Type) throws -> Int64 { + guard let value = try self.unbox(self.storage.topContainer, as: Int64.self) else { + throw DecodingError.valueNotFound(Int64.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Int64 but found null value instead.")) + } + + return value + } + + func decode(_ type: UInt.Type) throws -> UInt { + guard let value = try self.unbox(self.storage.topContainer, as: UInt.self) else { + throw DecodingError.valueNotFound(UInt.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected UInt but found null value instead.")) + } + + return value + } + + func decode(_ type: UInt8.Type) throws -> UInt8 { + guard let value = try self.unbox(self.storage.topContainer, as: UInt8.self) else { + throw DecodingError.valueNotFound(UInt8.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected UInt8 but found null value instead.")) + } + + return value + } + + func decode(_ type: UInt16.Type) throws -> UInt16 { + guard let value = try self.unbox(self.storage.topContainer, as: UInt16.self) else { + throw DecodingError.valueNotFound(UInt16.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected UInt16 but found null value instead.")) + } + + return value + } + + func decode(_ type: UInt32.Type) throws -> UInt32 { + guard let value = try self.unbox(self.storage.topContainer, as: UInt32.self) else { + throw DecodingError.valueNotFound(UInt32.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected UInt32 but found null value instead.")) + } + + return value + } + + func decode(_ type: UInt64.Type) throws -> UInt64 { + guard let value = try self.unbox(self.storage.topContainer, as: UInt64.self) else { + throw DecodingError.valueNotFound(UInt64.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected UInt64 but found null value instead.")) + } + + return value + } + + func decode(_ type: Float.Type) throws -> Float { + guard let value = try self.unbox(self.storage.topContainer, as: Float.self) else { + throw DecodingError.valueNotFound(Float.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Float but found null value instead.")) + } + + return value + } + + func decode(_ type: Double.Type) throws -> Double { + guard let value = try self.unbox(self.storage.topContainer, as: Double.self) else { + throw DecodingError.valueNotFound(Double.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Double but found null value instead.")) + } + + return value + } + + func decode(_ type: String.Type) throws -> String { + guard let value = try self.unbox(self.storage.topContainer, as: String.self) else { + throw DecodingError.valueNotFound(String.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected String but found null value instead.")) + } + + return value + } + + func decode(_ type: T.Type) throws -> T { + guard let value = try self.unbox(self.storage.topContainer, as: T.self) else { + throw DecodingError.valueNotFound(T.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected \(T.self) but found null value instead.")) + } + + return value + } } // MARK: - Concrete Value Representations diff --git a/stdlib/public/SDK/Foundation/PlistEncoder.swift b/stdlib/public/SDK/Foundation/PlistEncoder.swift index 29426ac8dacb4..0b2d27d4716a1 100644 --- a/stdlib/public/SDK/Foundation/PlistEncoder.swift +++ b/stdlib/public/SDK/Foundation/PlistEncoder.swift @@ -251,22 +251,22 @@ fileprivate struct _PlistKeyedEncodingContainer : KeyedEncodingCo // MARK: - KeyedEncodingContainerProtocol Methods - mutating func encode(_ value: Bool?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: Int?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: Int8?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: Int16?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: Int32?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: Int64?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: UInt?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: UInt8?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: UInt16?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: UInt32?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: UInt64?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: String?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: Float?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - mutating func encode(_ value: Double?, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } - - mutating func encode(_ value: T?, forKey key: Key) throws { + mutating func encode(_ value: Bool, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: Int, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: Int8, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: Int16, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: Int32, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: Int64, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: UInt, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: UInt8, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: UInt16, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: UInt32, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: UInt64, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: String, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: Float, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + mutating func encode(_ value: Double, forKey key: Key) throws { self.container[key.stringValue] = self.encoder.box(value) } + + mutating func encode(_ value: T, forKey key: Key) throws { try self.encoder.with(pushedKey: key) { self.container[key.stringValue] = try self.encoder.box(value) } @@ -336,22 +336,22 @@ fileprivate struct _PlistUnkeyedEncodingContainer : UnkeyedEncodingContainer { // MARK: - UnkeyedEncodingContainer Methods - mutating func encode(_ value: Bool?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: Int?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: Int8?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: Int16?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: Int32?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: Int64?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: UInt?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: UInt8?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: UInt16?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: UInt32?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: UInt64?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: Float?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: Double?) throws { self.container.add(self.encoder.box(value)) } - mutating func encode(_ value: String?) throws { self.container.add(self.encoder.box(value)) } - - mutating func encode(_ value: T?) throws { + mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: Float) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: Double) throws { self.container.add(self.encoder.box(value)) } + mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) } + + mutating func encode(_ value: T) throws { try self.encoder.with(pushedKey: nil) { self.container.add(try self.encoder.box(value)) } @@ -405,6 +405,11 @@ extension _PlistEncoder : SingleValueEncodingContainer { // MARK: - SingleValueEncodingContainer Methods + func encodeNil() throws { + assertCanEncodeSingleValue() + self.storage.push(container: _plistNullNSString) + } + func encode(_ value: Bool) throws { assertCanEncodeSingleValue() self.storage.push(container: box(value)) @@ -474,6 +479,11 @@ extension _PlistEncoder : SingleValueEncodingContainer { assertCanEncodeSingleValue() self.storage.push(container: box(value)) } + + func encode(_ value: T) throws { + assertCanEncodeSingleValue() + try self.storage.push(container: box(value)) + } } // MARK: - Concrete Value Representations @@ -481,27 +491,23 @@ extension _PlistEncoder : SingleValueEncodingContainer { extension _PlistEncoder { /// Returns the given value boxed in a container appropriate for pushing onto the container stack. - fileprivate func box(_ value: Bool?) -> NSObject { return value == nil ? _plistNullNSString : NSNumber(value: value!) } - fileprivate func box(_ value: Int?) -> NSObject { return value == nil ? _plistNullNSString : NSNumber(value: value!) } - fileprivate func box(_ value: Int8?) -> NSObject { return value == nil ? _plistNullNSString : NSNumber(value: value!) } - fileprivate func box(_ value: Int16?) -> NSObject { return value == nil ? _plistNullNSString : NSNumber(value: value!) } - fileprivate func box(_ value: Int32?) -> NSObject { return value == nil ? _plistNullNSString : NSNumber(value: value!) } - fileprivate func box(_ value: Int64?) -> NSObject { return value == nil ? _plistNullNSString : NSNumber(value: value!) } - fileprivate func box(_ value: UInt?) -> NSObject { return value == nil ? _plistNullNSString : NSNumber(value: value!) } - fileprivate func box(_ value: UInt8?) -> NSObject { return value == nil ? _plistNullNSString : NSNumber(value: value!) } - fileprivate func box(_ value: UInt16?) -> NSObject { return value == nil ? _plistNullNSString : NSNumber(value: value!) } - fileprivate func box(_ value: UInt32?) -> NSObject { return value == nil ? _plistNullNSString : NSNumber(value: value!) } - fileprivate func box(_ value: UInt64?) -> NSObject { return value == nil ? _plistNullNSString : NSNumber(value: value!) } - fileprivate func box(_ value: Float?) -> NSObject { return value == nil ? _plistNullNSString : NSNumber(value: value!) } - fileprivate func box(_ value: Double?) -> NSObject { return value == nil ? _plistNullNSString : NSNumber(value: value!) } - fileprivate func box(_ value: String?) -> NSObject { return value == nil ? _plistNullNSString : NSString(string: value!) } - fileprivate func box(_ value: Data?) -> NSObject { return value == nil ? _plistNullNSString : NSData(data: value!) } - - fileprivate func box(_ value: T?) throws -> NSObject { - guard let value = value else { - return _plistNullNSString - } - + fileprivate func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt16) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt32) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt64) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Float) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Double) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: String) -> NSObject { return NSString(string: value) } + fileprivate func box(_ value: Data) -> NSObject { return NSData(data: value) } + + fileprivate func box(_ value: T) throws -> NSObject { if T.self == Date.self { // PropertyListSerialization handles Date directly. return NSDate(timeIntervalSinceReferenceDate: (value as! Date).timeIntervalSinceReferenceDate) @@ -727,12 +733,6 @@ fileprivate class _PlistDecoder : Decoder { } func singleValueContainer() throws -> SingleValueDecodingContainer { - guard !(self.storage.topContainer is NSNull) else { - throw DecodingError.valueNotFound(SingleValueDecodingContainer.self, - DecodingError.Context(codingPath: self.codingPath, - debugDescription: "Cannot get single value decoding container -- found null value instead.")) - } - guard !(self.storage.topContainer is [String : Any]) else { throw DecodingError.typeMismatch(SingleValueDecodingContainer.self, DecodingError.Context(codingPath: self.codingPath, @@ -1236,22 +1236,164 @@ fileprivate struct _PlistUnkeyedDecodingContainer : UnkeyedDecodingContainer { extension _PlistDecoder : SingleValueDecodingContainer { // MARK: SingleValueDecodingContainer Methods + func decodeNil() -> Bool { + guard let string = self.storage.topContainer as? String else { + return false + } + + return string == _plistNull + } + // These all unwrap the result, since we couldn't have gotten a single value container if the topContainer was null. - func decode(_ type: Bool.Type) throws -> Bool { return try self.unbox(self.storage.topContainer, as: Bool.self)! } - func decode(_ type: Int.Type) throws -> Int { return try self.unbox(self.storage.topContainer, as: Int.self)! } - func decode(_ type: Int8.Type) throws -> Int8 { return try self.unbox(self.storage.topContainer, as: Int8.self)! } - func decode(_ type: Int16.Type) throws -> Int16 { return try self.unbox(self.storage.topContainer, as: Int16.self)! } - func decode(_ type: Int32.Type) throws -> Int32 { return try self.unbox(self.storage.topContainer, as: Int32.self)! } - func decode(_ type: Int64.Type) throws -> Int64 { return try self.unbox(self.storage.topContainer, as: Int64.self)! } - func decode(_ type: UInt.Type) throws -> UInt { return try self.unbox(self.storage.topContainer, as: UInt.self)! } - func decode(_ type: UInt8.Type) throws -> UInt8 { return try self.unbox(self.storage.topContainer, as: UInt8.self)! } - func decode(_ type: UInt16.Type) throws -> UInt16 { return try self.unbox(self.storage.topContainer, as: UInt16.self)! } - func decode(_ type: UInt32.Type) throws -> UInt32 { return try self.unbox(self.storage.topContainer, as: UInt32.self)! } - func decode(_ type: UInt64.Type) throws -> UInt64 { return try self.unbox(self.storage.topContainer, as: UInt64.self)! } - func decode(_ type: Float.Type) throws -> Float { return try self.unbox(self.storage.topContainer, as: Float.self)! } - func decode(_ type: Double.Type) throws -> Double { return try self.unbox(self.storage.topContainer, as: Double.self)! } - func decode(_ type: String.Type) throws -> String { return try self.unbox(self.storage.topContainer, as: String.self)! } - func decode(_ type: Data.Type) throws -> Data { return try self.unbox(self.storage.topContainer, as: Data.self)! } + func decode(_ type: Bool.Type) throws -> Bool { + guard let value = try self.unbox(self.storage.topContainer, as: Bool.self) else { + throw DecodingError.valueNotFound(Bool.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Bool but found null value instead.")) + } + + return value + } + + func decode(_ type: Int.Type) throws -> Int { + guard let value = try self.unbox(self.storage.topContainer, as: Int.self) else { + throw DecodingError.valueNotFound(Int.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Int but found null value instead.")) + } + + return value + } + + func decode(_ type: Int8.Type) throws -> Int8 { + guard let value = try self.unbox(self.storage.topContainer, as: Int8.self) else { + throw DecodingError.valueNotFound(Int8.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Int8 but found null value instead.")) + } + + return value + } + + func decode(_ type: Int16.Type) throws -> Int16 { + guard let value = try self.unbox(self.storage.topContainer, as: Int16.self) else { + throw DecodingError.valueNotFound(Int16.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Int16 but found null value instead.")) + } + + return value + } + + func decode(_ type: Int32.Type) throws -> Int32 { + guard let value = try self.unbox(self.storage.topContainer, as: Int32.self) else { + throw DecodingError.valueNotFound(Int32.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Int32 but found null value instead.")) + } + + return value + } + + func decode(_ type: Int64.Type) throws -> Int64 { + guard let value = try self.unbox(self.storage.topContainer, as: Int64.self) else { + throw DecodingError.valueNotFound(Int64.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Int64 but found null value instead.")) + } + + return value + } + + func decode(_ type: UInt.Type) throws -> UInt { + guard let value = try self.unbox(self.storage.topContainer, as: UInt.self) else { + throw DecodingError.valueNotFound(UInt.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected UInt but found null value instead.")) + } + + return value + } + + func decode(_ type: UInt8.Type) throws -> UInt8 { + guard let value = try self.unbox(self.storage.topContainer, as: UInt8.self) else { + throw DecodingError.valueNotFound(UInt8.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected UInt8 but found null value instead.")) + } + + return value + } + + func decode(_ type: UInt16.Type) throws -> UInt16 { + guard let value = try self.unbox(self.storage.topContainer, as: UInt16.self) else { + throw DecodingError.valueNotFound(UInt16.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected UInt16 but found null value instead.")) + } + + return value + } + + func decode(_ type: UInt32.Type) throws -> UInt32 { + guard let value = try self.unbox(self.storage.topContainer, as: UInt32.self) else { + throw DecodingError.valueNotFound(UInt32.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected UInt32 but found null value instead.")) + } + + return value + } + + func decode(_ type: UInt64.Type) throws -> UInt64 { + guard let value = try self.unbox(self.storage.topContainer, as: UInt64.self) else { + throw DecodingError.valueNotFound(UInt64.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected UInt64 but found null value instead.")) + } + + return value + } + + func decode(_ type: Float.Type) throws -> Float { + guard let value = try self.unbox(self.storage.topContainer, as: Float.self) else { + throw DecodingError.valueNotFound(Float.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Float but found null value instead.")) + } + + return value + } + + func decode(_ type: Double.Type) throws -> Double { + guard let value = try self.unbox(self.storage.topContainer, as: Double.self) else { + throw DecodingError.valueNotFound(Double.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected Double but found null value instead.")) + } + + return value + } + + func decode(_ type: String.Type) throws -> String { + guard let value = try self.unbox(self.storage.topContainer, as: String.self) else { + throw DecodingError.valueNotFound(String.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected String but found null value instead.")) + } + + return value + } + + func decode(_ type: T.Type) throws -> T { + guard let value = try self.unbox(self.storage.topContainer, as: T.self) else { + throw DecodingError.valueNotFound(T.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Expected \(T.self) but found null value instead.")) + } + + return value + } } // MARK: - Concrete Value Representations diff --git a/stdlib/public/core/Codable.swift b/stdlib/public/core/Codable.swift index e4f0c1a4b305d..6db60613b6412 100644 --- a/stdlib/public/core/Codable.swift +++ b/stdlib/public/core/Codable.swift @@ -154,105 +154,105 @@ public protocol KeyedEncodingContainerProtocol { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: T?, forKey key: Key) throws + mutating func encode(_ value: Bool, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Bool?, forKey key: Key) throws + mutating func encode(_ value: Int, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Int?, forKey key: Key) throws + mutating func encode(_ value: Int8, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Int8?, forKey key: Key) throws + mutating func encode(_ value: Int16, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Int16?, forKey key: Key) throws + mutating func encode(_ value: Int32, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Int32?, forKey key: Key) throws + mutating func encode(_ value: Int64, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Int64?, forKey key: Key) throws + mutating func encode(_ value: UInt, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: UInt?, forKey key: Key) throws + mutating func encode(_ value: UInt8, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: UInt8?, forKey key: Key) throws + mutating func encode(_ value: UInt16, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: UInt16?, forKey key: Key) throws + mutating func encode(_ value: UInt32, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: UInt32?, forKey key: Key) throws + mutating func encode(_ value: UInt64, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: UInt64?, forKey key: Key) throws + mutating func encode(_ value: Float, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Float?, forKey key: Key) throws + mutating func encode(_ value: Double, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Double?, forKey key: Key) throws + mutating func encode(_ value: String, forKey key: Key) throws /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: String?, forKey key: Key) throws + mutating func encode(_ value: T, forKey key: Key) throws /// Encodes the given object weakly for the given key. /// @@ -263,7 +263,112 @@ public protocol KeyedEncodingContainerProtocol { /// - parameter object: The object to encode. /// - parameter key: The key to associate the object with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encodeWeak(_ object: T?, forKey key: Key) throws + mutating func encodeWeak(_ object: T, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: Bool?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: Int?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: Int8?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: Int16?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: Int32?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: Int64?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: UInt?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: UInt8?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: UInt16?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: UInt32?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: UInt64?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: Float?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: Double?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: String?, forKey key: Key) throws + + /// Encodes the given value for the given key if it is not `nil`. + /// + /// - parameter value: The value to encode. + /// - parameter key: The key to associate the value with. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + mutating func encodeIfPresent(_ value: T?, forKey key: Key) throws /// Stores a keyed encoding container for the given key and returns it. /// @@ -296,7 +401,7 @@ public protocol KeyedEncodingContainerProtocol { /// A concrete container that provides a view into an encoder's storage, making /// the encoded properties of an encodable type accessible by keys. -public struct KeyedEncodingContainer { +public struct KeyedEncodingContainer : KeyedEncodingContainerProtocol { public typealias Key = K /// The container for the concrete encoder. The type is _*Base so that it's generic on the key type. @@ -321,7 +426,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: Bool?, forKey key: Key) throws { + public mutating func encode(_ value: Bool, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -330,7 +435,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: Int?, forKey key: Key) throws { + public mutating func encode(_ value: Int, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -339,7 +444,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: Int8?, forKey key: Key) throws { + public mutating func encode(_ value: Int8, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -348,7 +453,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: Int16?, forKey key: Key) throws { + public mutating func encode(_ value: Int16, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -357,7 +462,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: Int32?, forKey key: Key) throws { + public mutating func encode(_ value: Int32, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -366,7 +471,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: Int64?, forKey key: Key) throws { + public mutating func encode(_ value: Int64, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -375,7 +480,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: UInt?, forKey key: Key) throws { + public mutating func encode(_ value: UInt, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -384,7 +489,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: UInt8?, forKey key: Key) throws { + public mutating func encode(_ value: UInt8, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -393,7 +498,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: UInt16?, forKey key: Key) throws { + public mutating func encode(_ value: UInt16, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -402,7 +507,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: UInt32?, forKey key: Key) throws { + public mutating func encode(_ value: UInt32, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -411,7 +516,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: UInt64?, forKey key: Key) throws { + public mutating func encode(_ value: UInt64, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -420,7 +525,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: Float?, forKey key: Key) throws { + public mutating func encode(_ value: Float, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -429,7 +534,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: Double?, forKey key: Key) throws { + public mutating func encode(_ value: Double, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -438,7 +543,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: String?, forKey key: Key) throws { + public mutating func encode(_ value: String, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -447,7 +552,7 @@ public struct KeyedEncodingContainer { /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encode(_ value: T?, forKey key: Key) throws { + public mutating func encode(_ value: T, forKey key: Key) throws { try _box.encode(value, forKey: key) } @@ -458,7 +563,7 @@ public struct KeyedEncodingContainer { /// - parameter object: The object to encode. /// - parameter key: The key to associate the object with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - public mutating func encodeWeak(_ object: T?, forKey key: Key) throws { + public mutating func encodeWeak(_ object: T, forKey key: Key) throws { try _box.encodeWeak(object, forKey: key) } @@ -1134,91 +1239,91 @@ public protocol UnkeyedEncodingContainer { /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: T?) throws + mutating func encode(_ value: Bool) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Bool?) throws + mutating func encode(_ value: Int) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Int?) throws + mutating func encode(_ value: Int8) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Int8?) throws + mutating func encode(_ value: Int16) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Int16?) throws + mutating func encode(_ value: Int32) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Int32?) throws + mutating func encode(_ value: Int64) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Int64?) throws + mutating func encode(_ value: UInt) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: UInt?) throws + mutating func encode(_ value: UInt8) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: UInt8?) throws + mutating func encode(_ value: UInt16) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: UInt16?) throws + mutating func encode(_ value: UInt32) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: UInt32?) throws + mutating func encode(_ value: UInt64) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: UInt64?) throws + mutating func encode(_ value: Float) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Float?) throws + mutating func encode(_ value: Double) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: Double?) throws + mutating func encode(_ value: String) throws /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encode(_ value: String?) throws + mutating func encode(_ value: T) throws /// Encodes the given object weakly. /// @@ -1228,7 +1333,7 @@ public protocol UnkeyedEncodingContainer { /// /// - parameter object: The object to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. - mutating func encodeWeak(_ object: T?) throws + mutating func encodeWeak(_ object: T) throws /// Encodes the elements of the given sequence. /// @@ -1635,6 +1740,12 @@ public protocol UnkeyedDecodingContainer { /// A container that can support the storage and direct encoding of a single /// non-keyed value. public protocol SingleValueEncodingContainer { + /// Encodes a null value. + /// + /// - throws: `EncodingError.invalidValue` if a null value is invalid in the current context for this format. + /// - precondition: May not be called after a previous `self.encode(_:)` call. + mutating func encodeNil() throws + /// Encodes a single value of the given type. /// /// - parameter value: The value to encode. @@ -1732,15 +1843,28 @@ public protocol SingleValueEncodingContainer { /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. /// - precondition: May not be called after a previous `self.encode(_:)` call. mutating func encode(_ value: String) throws + + /// Encodes a single value of the given type. + /// + /// - parameter value: The value to encode. + /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. + /// - precondition: May not be called after a previous `self.encode(_:)` call. + mutating func encode(_ value: T) throws } /// A `SingleValueDecodingContainer` is a container which can support the storage and direct decoding of a single non-keyed value. public protocol SingleValueDecodingContainer { + /// Decodes a null value. + /// + /// - returns: Whether the encountered value was null. + func decodeNil() -> Bool + /// Decodes a single value of the given type. /// /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: Bool.Type) throws -> Bool /// Decodes a single value of the given type. @@ -1748,6 +1872,7 @@ public protocol SingleValueDecodingContainer { /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: Int.Type) throws -> Int /// Decodes a single value of the given type. @@ -1755,6 +1880,7 @@ public protocol SingleValueDecodingContainer { /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: Int8.Type) throws -> Int8 /// Decodes a single value of the given type. @@ -1762,6 +1888,7 @@ public protocol SingleValueDecodingContainer { /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: Int16.Type) throws -> Int16 /// Decodes a single value of the given type. @@ -1769,6 +1896,7 @@ public protocol SingleValueDecodingContainer { /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: Int32.Type) throws -> Int32 /// Decodes a single value of the given type. @@ -1776,6 +1904,7 @@ public protocol SingleValueDecodingContainer { /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: Int64.Type) throws -> Int64 /// Decodes a single value of the given type. @@ -1783,6 +1912,7 @@ public protocol SingleValueDecodingContainer { /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: UInt.Type) throws -> UInt /// Decodes a single value of the given type. @@ -1790,6 +1920,7 @@ public protocol SingleValueDecodingContainer { /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: UInt8.Type) throws -> UInt8 /// Decodes a single value of the given type. @@ -1797,6 +1928,7 @@ public protocol SingleValueDecodingContainer { /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: UInt16.Type) throws -> UInt16 /// Decodes a single value of the given type. @@ -1804,6 +1936,7 @@ public protocol SingleValueDecodingContainer { /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: UInt32.Type) throws -> UInt32 /// Decodes a single value of the given type. @@ -1811,6 +1944,7 @@ public protocol SingleValueDecodingContainer { /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: UInt64.Type) throws -> UInt64 /// Decodes a single value of the given type. @@ -1818,6 +1952,7 @@ public protocol SingleValueDecodingContainer { /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: Float.Type) throws -> Float /// Decodes a single value of the given type. @@ -1825,6 +1960,7 @@ public protocol SingleValueDecodingContainer { /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: Double.Type) throws -> Double /// Decodes a single value of the given type. @@ -1832,7 +1968,16 @@ public protocol SingleValueDecodingContainer { /// - parameter type: The type to decode as. /// - returns: A value of the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. func decode(_ type: String.Type) throws -> String + + /// Decodes a single value of the given type. + /// + /// - parameter type: The type to decode as. + /// - returns: A value of the requested type. + /// - throws: `DecodingError.typeMismatch` if the encountered encoded value cannot be converted to the requested type. + /// - throws: `DecodingError.valueNotFound` if the encountered encoded value is null. + func decode(_ type: T.Type) throws -> T } //===----------------------------------------------------------------------===// @@ -1954,97 +2099,187 @@ internal class _KeyedEncodingContainerBase { @_inlineable @_versioned - internal func encode(_ value: Bool?, forKey key: Key) throws { + internal func encode(_ value: Bool, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encode(_ value: Int, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encode(_ value: Int8, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encode(_ value: Int16, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encode(_ value: Int32, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encode(_ value: Int64, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encode(_ value: UInt, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encode(_ value: UInt8, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encode(_ value: UInt16, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encode(_ value: UInt32, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encode(_ value: UInt64, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encode(_ value: Float, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encode(_ value: Double, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: Int?, forKey key: Key) throws { + internal func encode(_ value: String, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: Int8?, forKey key: Key) throws { + internal func encode(_ value: T, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: Int16?, forKey key: Key) throws { + internal func encodeWeak(_ object: T, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: Int32?, forKey key: Key) throws { + internal func encodeIfPresent(_ value: Bool?, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: Int64?, forKey key: Key) throws { + internal func encodeIfPresent(_ value: Int?, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: UInt?, forKey key: Key) throws { + internal func encodeIfPresent(_ value: Int8?, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: UInt8?, forKey key: Key) throws { + internal func encodeIfPresent(_ value: Int16?, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: UInt16?, forKey key: Key) throws { + internal func encodeIfPresent(_ value: Int32?, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: UInt32?, forKey key: Key) throws { + internal func encodeIfPresent(_ value: Int64?, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: UInt64?, forKey key: Key) throws { + internal func encodeIfPresent(_ value: UInt?, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: Float?, forKey key: Key) throws { + internal func encodeIfPresent(_ value: UInt8?, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: Double?, forKey key: Key) throws { + internal func encodeIfPresent(_ value: UInt16?, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: String?, forKey key: Key) throws { + internal func encodeIfPresent(_ value: UInt32?, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encode(_ value: T?, forKey key: Key) throws { + internal func encodeIfPresent(_ value: UInt64?, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @_inlineable @_versioned - internal func encodeWeak(_ object: T?, forKey key: Key) throws { + internal func encodeIfPresent(_ value: Float?, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encodeIfPresent(_ value: Double?, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encodeIfPresent(_ value: String?, forKey key: Key) throws { + fatalError("_KeyedEncodingContainerBase cannot be used directly.") + } + + @_inlineable + @_versioned + internal func encodeIfPresent(_ value: T?, forKey key: Key) throws { fatalError("_KeyedEncodingContainerBase cannot be used directly.") } @@ -2095,100 +2330,190 @@ internal final class _KeyedEncodingContainerBox(_ value: T?, forKey key: Key) throws { + override internal func encode(_ value: Bool, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: Bool?, forKey key: Key) throws { + override internal func encode(_ value: Int, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: Int?, forKey key: Key) throws { + override internal func encode(_ value: Int8, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: Int8?, forKey key: Key) throws { + override internal func encode(_ value: Int16, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: Int16?, forKey key: Key) throws { + override internal func encode(_ value: Int32, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: Int32?, forKey key: Key) throws { + override internal func encode(_ value: Int64, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: Int64?, forKey key: Key) throws { + override internal func encode(_ value: UInt, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: UInt?, forKey key: Key) throws { + override internal func encode(_ value: UInt8, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: UInt8?, forKey key: Key) throws { + override internal func encode(_ value: UInt16, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: UInt16?, forKey key: Key) throws { + override internal func encode(_ value: UInt32, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: UInt32?, forKey key: Key) throws { + override internal func encode(_ value: UInt64, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: UInt64?, forKey key: Key) throws { + override internal func encode(_ value: Float, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: Float?, forKey key: Key) throws { + override internal func encode(_ value: Double, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: Double?, forKey key: Key) throws { + override internal func encode(_ value: String, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encode(_ value: String?, forKey key: Key) throws { + override internal func encode(_ value: T, forKey key: Key) throws { try concrete.encode(value, forKey: key) } @_inlineable @_versioned - override internal func encodeWeak(_ object: T?, forKey key: Key) throws { + override internal func encodeWeak(_ object: T, forKey key: Key) throws { try concrete.encodeWeak(object, forKey: key) } + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: Bool?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: Int?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: Int8?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: Int16?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: Int32?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: Int64?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: UInt?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: UInt8?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: UInt16?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: UInt32?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: UInt64?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: Float?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: Double?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: String?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + + @_inlineable + @_versioned + override internal func encodeIfPresent(_ value: T?, forKey key: Key) throws { + try concrete.encodeIfPresent(value, forKey: key) + } + @_inlineable @_versioned override internal func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer { @@ -2908,7 +3233,44 @@ public extension RawRepresentable where RawValue == String, Self : Decodable { } //===----------------------------------------------------------------------===// -// Collection Extensions +// Optional Conformance +//===----------------------------------------------------------------------===// + +// FIXME: Uncomment when conditional conformance is available. +extension Optional : Encodable /* where Wrapped : Encodable */ { + public func encode(to encoder: Encoder) throws { + guard Wrapped.self is Encodable.Type else { + preconditionFailure("\(type(of: self)) does not conform to Encodable because \(Wrapped.self) does not conform to Encodable.") + } + + var container = encoder.singleValueContainer() + switch self { + case .none: try container.encodeNil() + case .some(let wrapped): try (wrapped as! Encodable).encode(to: encoder) + } + } +} + +extension Optional : Decodable /* where Wrapped : Decodable */ { + public init(from decoder: Decoder) throws { + // Initialize self here so we can print type(of: self). + self = .none + + guard Wrapped.self is Decodable.Type else { + preconditionFailure("\(type(of: self)) does not conform to Decodable because \(Wrapped.self) does not conform to Decodable.") + } + + let container = try decoder.singleValueContainer() + if !container.decodeNil() { + let metaType = (Wrapped.self as! Decodable.Type) + let element = try metaType.init(from: decoder) + self = .some(element as! Wrapped) + } + } +} + +//===----------------------------------------------------------------------===// +// Collection Conformances //===----------------------------------------------------------------------===// // FIXME: Uncomment when conditional conformance is available. @@ -2930,7 +3292,9 @@ extension Array : Encodable /* where Element : Encodable */ { extension Array : Decodable /* where Element : Decodable */ { public init(from decoder: Decoder) throws { + // Initialize self here so we can print type(of: self). self.init() + guard Element.self is Decodable.Type else { preconditionFailure("\(type(of: self)) does not conform to Decodable because \(Element.self) does not conform to Decodable.") } @@ -2965,6 +3329,7 @@ extension Set : Encodable /* where Element : Encodable */ { extension Set : Decodable /* where Element : Decodable */ { public init(from decoder: Decoder) throws { + // Initialize self here so we can print type(of: self). self.init() guard Element.self is Decodable.Type else { @@ -3044,6 +3409,7 @@ extension Dictionary : Encodable /* where Key : Encodable, Value : Encodable */ extension Dictionary : Decodable /* where Key : Decodable, Value : Decodable */ { public init(from decoder: Decoder) throws { + // Initialize self here so we can print type(of: self). self.init() guard Key.self is Encodable.Type else { @@ -3123,11 +3489,89 @@ extension Dictionary : Decodable /* where Key : Decodable, Value : Decodable */ // Default implementation for encodeWeak(_:forKey:) in terms of encode(_:forKey:) public extension KeyedEncodingContainerProtocol { - public mutating func encodeWeak(_ object: T?, forKey key: Key) throws { + public mutating func encodeWeak(_ object: T, forKey key: Key) throws { try encode(object, forKey: key) } } +// Default implementation for encodeIfPresent(_:forKey:) in terms of encode(_:forKey:) +public extension KeyedEncodingContainerProtocol { + public mutating func encodeIfPresent(_ value: Bool?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: Int?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: Int8?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: Int16?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: Int32?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: Int64?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: UInt?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: UInt8?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: UInt16?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: UInt32?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: UInt64?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: Float?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: Double?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: String?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } + + public mutating func encodeIfPresent(_ value: T?, forKey key: Key) throws { + guard let value = value else { return } + try encode(value, forKey: key) + } +} + // Default implementations for decode(_:forKey:) in terms of decodeIfPresent(_:forKey:) public extension KeyedDecodingContainerProtocol { public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { @@ -3343,7 +3787,7 @@ public extension KeyedDecodingContainerProtocol { // Default implementation of encodeWeak(_:) in terms of encode(_:), and encode(contentsOf:) in terms of encode(_:) loop. public extension UnkeyedEncodingContainer { - public mutating func encodeWeak(_ object: T?) throws { + public mutating func encodeWeak(_ object: T) throws { try encode(object) } diff --git a/test/IDE/complete_generic_optional.swift b/test/IDE/complete_generic_optional.swift index 588760c9b7e8b..06f4cc0af7c80 100644 --- a/test/IDE/complete_generic_optional.swift +++ b/test/IDE/complete_generic_optional.swift @@ -11,6 +11,6 @@ struct Foo { // SR-642 Code completion does not instantiate generic arguments of a type wrapped in an optional let x: Foo? = Foo() x.#^FOO_OPTIONAL_1^# -// FOO_OPTIONAL_1: Begin completions, 6 items +// FOO_OPTIONAL_1: Begin completions, 7 items // FOO_OPTIONAL_1-DAG: Decl[InstanceMethod]/CurrNominal/Erase[1]: ?.myFunction({#(foobar): Bar#})[#Void#]; name=myFunction(foobar: Bar) // FOO_OPTIONAL_1: End completions diff --git a/test/decl/protocol/special/coding/class_codable_nonconforming_property.swift b/test/decl/protocol/special/coding/class_codable_nonconforming_property.swift index 1ff88c7122ce7..99b4e95e8d8b6 100644 --- a/test/decl/protocol/special/coding/class_codable_nonconforming_property.swift +++ b/test/decl/protocol/special/coding/class_codable_nonconforming_property.swift @@ -1,6 +1,18 @@ // RUN: %target-typecheck-verify-swift -verify-ignore-unknown -struct NonCodable {} +struct NonCodable : Hashable { + var hashValue: Int { + return 1 + } + + static func ==(_ lhs: NonCodable, _ rhs: NonCodable) -> Bool { + return true + } +} + +struct CodableGeneric : Codable { + let value: Int = 5 +} // Classes whose properties are not all Codable should fail to synthesize // conformance. @@ -9,14 +21,146 @@ class NonConformingClass : Codable { // expected-error {{type 'NonConformingClas // expected-error@-2 {{type 'NonConformingClass' does not conform to protocol 'Encodable'}} // expected-error@-3 {{type 'NonConformingClass' does not conform to protocol 'Encodable'}} // expected-note@-4 {{did you mean 'init'?}} - var w: NonCodable = NonCodable() // expected-note {{cannot automatically synthesize 'Decodable' because 'w' does not conform to 'Decodable'}} - // expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'w' does not conform to 'Decodable'}} - // expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'w' does not conform to 'Encodable'}} - // expected-note@-3 {{cannot automatically synthesize 'Encodable' because 'w' does not conform to 'Encodable'}} + var w: NonCodable = NonCodable() // expected-note {{cannot automatically synthesize 'Decodable' because 'NonCodable' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'NonCodable' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'NonCodable' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because 'NonCodable' does not conform to 'Encodable'}} var x: Int = 1 var y: Double = .pi static var z: String = "foo" + // FIXME: Remove when conditional conformance lands. + // Because conditional conformance is not yet available, Optional, Array, + // Set, and Dictionary all conform to Codable even when their generic + // parameters do not. + // We want to make sure that these cases prevent derived conformance. + var nonCodableOptional: NonCodable? = nil // expected-note {{cannot automatically synthesize 'Decodable' because 'NonCodable?' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'NonCodable?' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'NonCodable?' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because 'NonCodable?' does not conform to 'Encodable'}} + var nonCodableArray: [NonCodable] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable]' does not conform to 'Encodable'}} + var nonCodableSet: Set = [] // expected-note {{cannot automatically synthesize 'Decodable' because 'Set' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'Set' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'Set' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because 'Set' does not conform to 'Encodable'}} + var nonCodableDictionary1: [String : NonCodable] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[String : NonCodable]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : NonCodable]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : NonCodable]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : NonCodable]' does not conform to 'Encodable'}} + var nonCodableDictionary2: [NonCodable : String] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : String]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : String]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : String]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : String]' does not conform to 'Encodable'}} + var nonCodableDictionary3: [NonCodable : NonCodable] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : NonCodable]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : NonCodable]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : NonCodable]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : NonCodable]' does not conform to 'Encodable'}} + + // These conditions should apply recursively, too. + var nonCodableOptionalOptional: NonCodable?? = nil // expected-note {{cannot automatically synthesize 'Decodable' because 'NonCodable??' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'NonCodable??' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'NonCodable??' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because 'NonCodable??' does not conform to 'Encodable'}} + var nonCodableOptionalArray: [NonCodable]? = nil // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable]?' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable]?' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable]?' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable]?' does not conform to 'Encodable'}} + var nonCodableOptionalSet: Set? = nil // expected-note {{cannot automatically synthesize 'Decodable' because 'Set?' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'Set?' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'Set?' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because 'Set?' does not conform to 'Encodable'}} + var nonCodableOptionalDictionary1: [String : NonCodable]? = nil // expected-note {{cannot automatically synthesize 'Decodable' because '[String : NonCodable]?' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : NonCodable]?' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : NonCodable]?' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : NonCodable]?' does not conform to 'Encodable'}} + var nonCodableOptionalDictionary2: [NonCodable : String]? = nil // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : String]?' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : String]?' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : String]?' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : String]?' does not conform to 'Encodable'}} + var nonCodableOptionalDictionary3: [NonCodable : NonCodable]? = nil // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : NonCodable]?' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : NonCodable]?' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : NonCodable]?' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : NonCodable]?' does not conform to 'Encodable'}} + + var nonCodableArrayOptional: [NonCodable?] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable?]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable?]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable?]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable?]' does not conform to 'Encodable'}} + var nonCodableArrayArray: [[NonCodable]] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[[NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[[NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[[NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[[NonCodable]]' does not conform to 'Encodable'}} + var nonCodableArraySet: [Set] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[Set]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[Set]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[Set]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[Set]' does not conform to 'Encodable'}} + var nonCodableArrayDictionary1: [[String : NonCodable]] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[[String : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[[String : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[[String : NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[[String : NonCodable]]' does not conform to 'Encodable'}} + var nonCodableArrayDictionary2: [[NonCodable : String]] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[[NonCodable : String]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[[NonCodable : String]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[[NonCodable : String]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[[NonCodable : String]]' does not conform to 'Encodable'}} + var nonCodableArrayDictionary3: [[NonCodable : NonCodable]] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[[NonCodable : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[[NonCodable : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[[NonCodable : NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[[NonCodable : NonCodable]]' does not conform to 'Encodable'}} + + var nonCodableDictionaryOptional1: [String : NonCodable?] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[String : NonCodable?]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : NonCodable?]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : NonCodable?]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : NonCodable?]' does not conform to 'Encodable'}} + var nonCodableDictionaryOptional2: [NonCodable : NonCodable?] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : NonCodable?]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : NonCodable?]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : NonCodable?]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : NonCodable?]' does not conform to 'Encodable'}} + var nonCodableDictionaryArray1: [String : [NonCodable]] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[String : [NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : [NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : [NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : [NonCodable]]' does not conform to 'Encodable'}} + var nonCodableDictionaryArray2: [NonCodable : [NonCodable]] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : [NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : [NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : [NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : [NonCodable]]' does not conform to 'Encodable'}} + var nonCodableDictionarySet1: [String : Set] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[String : Set]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : Set]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : Set]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : Set]' does not conform to 'Encodable'}} + var nonCodableDictionarySet2: [NonCodable : Set] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : Set]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : Set]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : Set]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : Set]' does not conform to 'Encodable'}} + var nonCodableDictionaryDictionary1: [String : [String : NonCodable]] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[String : [String : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : [String : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : [String : NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : [String : NonCodable]]' does not conform to 'Encodable'}} + var nonCodableDictionaryDictionary2: [NonCodable : [String : NonCodable]] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : [String : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : [String : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : [String : NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : [String : NonCodable]]' does not conform to 'Encodable'}} + var nonCodableDictionaryDictionary3: [String : [NonCodable : NonCodable]] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[String : [NonCodable : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : [NonCodable : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : [NonCodable : NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : [NonCodable : NonCodable]]' does not conform to 'Encodable'}} + var nonCodableDictionaryDictionary4: [NonCodable : [NonCodable : NonCodable]] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : [NonCodable : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : [NonCodable : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : [NonCodable : NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : [NonCodable : NonCodable]]' does not conform to 'Encodable'}} + + // However, arbitrary generic types which _do_ conform to Codable should be + // valid. + var codableGenericThing1: CodableGeneric? = nil + var codableGenericThing2: CodableGeneric? = nil + var codableGenericThing3: CodableGeneric<[NonCodable]>? = nil + var codableGenericThing4: CodableGeneric>? = nil + var codableGenericThing5: CodableGeneric<[String : NonCodable]>? = nil + var codableGenericThing6: CodableGeneric<[NonCodable : String]>? = nil + var codableGenericThing7: CodableGeneric<[NonCodable : NonCodable]>? = nil + // These lines have to be within the NonConformingClass type because // CodingKeys should be private. func foo() { diff --git a/test/decl/protocol/special/coding/struct_codable_nonconforming_property.swift b/test/decl/protocol/special/coding/struct_codable_nonconforming_property.swift index 9351eb638048d..f6874a5a5d302 100644 --- a/test/decl/protocol/special/coding/struct_codable_nonconforming_property.swift +++ b/test/decl/protocol/special/coding/struct_codable_nonconforming_property.swift @@ -1,6 +1,18 @@ // RUN: %target-typecheck-verify-swift -verify-ignore-unknown -struct NonCodable {} +struct NonCodable : Hashable { + var hashValue: Int { + return 1 + } + + static func ==(_ lhs: NonCodable, _ rhs: NonCodable) -> Bool { + return true + } +} + +struct CodableGeneric : Codable { + let value: Int = 5 +} // Structs whose properties are not all Codable should fail to synthesize // conformance. @@ -9,14 +21,146 @@ struct NonConformingStruct : Codable { // expected-error {{type 'NonConformingSt // expected-error@-2 {{type 'NonConformingStruct' does not conform to protocol 'Encodable'}} // expected-error@-3 {{type 'NonConformingStruct' does not conform to protocol 'Encodable'}} // expected-note@-4 {{did you mean 'init'?}} - var w: NonCodable // expected-note {{cannot automatically synthesize 'Decodable' because 'w' does not conform to 'Decodable'}} - // expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'w' does not conform to 'Decodable'}} - // expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'w' does not conform to 'Encodable'}} - // expected-note@-3 {{cannot automatically synthesize 'Encodable' because 'w' does not conform to 'Encodable'}} + var w: NonCodable // expected-note {{cannot automatically synthesize 'Decodable' because 'NonCodable' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'NonCodable' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'NonCodable' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because 'NonCodable' does not conform to 'Encodable'}} var x: Int var y: Double static var z: String = "foo" + // FIXME: Remove when conditional conformance lands. + // Because conditional conformance is not yet available, Optional, Array, + // Set, and Dictionary all conform to Codable even when their generic + // parameters do not. + // We want to make sure that these cases prevent derived conformance. + var nonCodableOptional: NonCodable? = nil // expected-note {{cannot automatically synthesize 'Decodable' because 'NonCodable?' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'NonCodable?' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'NonCodable?' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because 'NonCodable?' does not conform to 'Encodable'}} + var nonCodableArray: [NonCodable] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable]' does not conform to 'Encodable'}} + var nonCodableSet: Set = [] // expected-note {{cannot automatically synthesize 'Decodable' because 'Set' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'Set' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'Set' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because 'Set' does not conform to 'Encodable'}} + var nonCodableDictionary1: [String : NonCodable] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[String : NonCodable]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : NonCodable]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : NonCodable]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : NonCodable]' does not conform to 'Encodable'}} + var nonCodableDictionary2: [NonCodable : String] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : String]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : String]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : String]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : String]' does not conform to 'Encodable'}} + var nonCodableDictionary3: [NonCodable : NonCodable] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : NonCodable]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : NonCodable]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : NonCodable]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : NonCodable]' does not conform to 'Encodable'}} + + // These conditions should apply recursively, too. + var nonCodableOptionalOptional: NonCodable?? = nil // expected-note {{cannot automatically synthesize 'Decodable' because 'NonCodable??' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'NonCodable??' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'NonCodable??' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because 'NonCodable??' does not conform to 'Encodable'}} + var nonCodableOptionalArray: [NonCodable]? = nil // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable]?' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable]?' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable]?' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable]?' does not conform to 'Encodable'}} + var nonCodableOptionalSet: Set? = nil // expected-note {{cannot automatically synthesize 'Decodable' because 'Set?' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'Set?' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'Set?' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because 'Set?' does not conform to 'Encodable'}} + var nonCodableOptionalDictionary1: [String : NonCodable]? = nil // expected-note {{cannot automatically synthesize 'Decodable' because '[String : NonCodable]?' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : NonCodable]?' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : NonCodable]?' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : NonCodable]?' does not conform to 'Encodable'}} + var nonCodableOptionalDictionary2: [NonCodable : String]? = nil // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : String]?' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : String]?' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : String]?' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : String]?' does not conform to 'Encodable'}} + var nonCodableOptionalDictionary3: [NonCodable : NonCodable]? = nil // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : NonCodable]?' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : NonCodable]?' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : NonCodable]?' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : NonCodable]?' does not conform to 'Encodable'}} + + var nonCodableArrayOptional: [NonCodable?] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable?]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable?]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable?]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable?]' does not conform to 'Encodable'}} + var nonCodableArrayArray: [[NonCodable]] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[[NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[[NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[[NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[[NonCodable]]' does not conform to 'Encodable'}} + var nonCodableArraySet: [Set] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[Set]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[Set]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[Set]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[Set]' does not conform to 'Encodable'}} + var nonCodableArrayDictionary1: [[String : NonCodable]] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[[String : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[[String : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[[String : NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[[String : NonCodable]]' does not conform to 'Encodable'}} + var nonCodableArrayDictionary2: [[NonCodable : String]] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[[NonCodable : String]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[[NonCodable : String]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[[NonCodable : String]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[[NonCodable : String]]' does not conform to 'Encodable'}} + var nonCodableArrayDictionary3: [[NonCodable : NonCodable]] = [] // expected-note {{cannot automatically synthesize 'Decodable' because '[[NonCodable : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[[NonCodable : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[[NonCodable : NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[[NonCodable : NonCodable]]' does not conform to 'Encodable'}} + + var nonCodableDictionaryOptional1: [String : NonCodable?] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[String : NonCodable?]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : NonCodable?]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : NonCodable?]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : NonCodable?]' does not conform to 'Encodable'}} + var nonCodableDictionaryOptional2: [NonCodable : NonCodable?] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : NonCodable?]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : NonCodable?]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : NonCodable?]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : NonCodable?]' does not conform to 'Encodable'}} + var nonCodableDictionaryArray1: [String : [NonCodable]] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[String : [NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : [NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : [NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : [NonCodable]]' does not conform to 'Encodable'}} + var nonCodableDictionaryArray2: [NonCodable : [NonCodable]] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : [NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : [NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : [NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : [NonCodable]]' does not conform to 'Encodable'}} + var nonCodableDictionarySet1: [String : Set] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[String : Set]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : Set]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : Set]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : Set]' does not conform to 'Encodable'}} + var nonCodableDictionarySet2: [NonCodable : Set] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : Set]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : Set]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : Set]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : Set]' does not conform to 'Encodable'}} + var nonCodableDictionaryDictionary1: [String : [String : NonCodable]] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[String : [String : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : [String : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : [String : NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : [String : NonCodable]]' does not conform to 'Encodable'}} + var nonCodableDictionaryDictionary2: [NonCodable : [String : NonCodable]] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : [String : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : [String : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : [String : NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : [String : NonCodable]]' does not conform to 'Encodable'}} + var nonCodableDictionaryDictionary3: [String : [NonCodable : NonCodable]] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[String : [NonCodable : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[String : [NonCodable : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[String : [NonCodable : NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[String : [NonCodable : NonCodable]]' does not conform to 'Encodable'}} + var nonCodableDictionaryDictionary4: [NonCodable : [NonCodable : NonCodable]] = [:] // expected-note {{cannot automatically synthesize 'Decodable' because '[NonCodable : [NonCodable : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-1 {{cannot automatically synthesize 'Decodable' because '[NonCodable : [NonCodable : NonCodable]]' does not conform to 'Decodable'}} + // expected-note@-2 {{cannot automatically synthesize 'Encodable' because '[NonCodable : [NonCodable : NonCodable]]' does not conform to 'Encodable'}} + // expected-note@-3 {{cannot automatically synthesize 'Encodable' because '[NonCodable : [NonCodable : NonCodable]]' does not conform to 'Encodable'}} + + // However, arbitrary generic types which _do_ conform to Codable should be + // valid. + var codableGenericThing1: CodableGeneric? = nil + var codableGenericThing2: CodableGeneric? = nil + var codableGenericThing3: CodableGeneric<[NonCodable]>? = nil + var codableGenericThing4: CodableGeneric>? = nil + var codableGenericThing5: CodableGeneric<[String : NonCodable]>? = nil + var codableGenericThing6: CodableGeneric<[NonCodable : String]>? = nil + var codableGenericThing7: CodableGeneric<[NonCodable : NonCodable]>? = nil + // These lines have to be within the NonConformingStruct type because // CodingKeys should be private. func foo() { diff --git a/test/stdlib/TestJSONEncoder.swift b/test/stdlib/TestJSONEncoder.swift index 6187362ca988d..40c8b0c6d6527 100644 --- a/test/stdlib/TestJSONEncoder.swift +++ b/test/stdlib/TestJSONEncoder.swift @@ -58,8 +58,9 @@ class TestJSONEncoder : TestJSONEncoderSuper { func testEncodingTopLevelStructuredClass() { // Person is a class with multiple fields. + let expectedJSON = "{\"name\":\"Johnny Appleseed\",\"email\":\"appleseed@apple.com\"}".data(using: .utf8)! let person = Person.testValue - _testRoundTrip(of: person) + _testRoundTrip(of: person, expectedJSON: expectedJSON) } func testEncodingTopLevelDeepStructuredType() { @@ -471,13 +472,21 @@ fileprivate class Person : Codable, Equatable { let name: String let email: String - init(name: String, email: String) { + // FIXME: This property is present only in order to test the expected result of Codable synthesis in the compiler. + // We want to test against expected encoded output (to ensure this generates an encodeIfPresent call), but we need an output format for that. + // Once we have a VerifyingEncoder for compiler unit tests, we should move this test there. + let website: URL? + + init(name: String, email: String, website: URL? = nil) { self.name = name self.email = email + self.website = website } static func ==(_ lhs: Person, _ rhs: Person) -> Bool { - return lhs.name == rhs.name && lhs.email == rhs.email + return lhs.name == rhs.name && + lhs.email == rhs.email && + lhs.website == rhs.website } static var testValue: Person {