mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Sema] Migrate almost everything to use DerivedConformance.
This commit is contained in:
@@ -68,14 +68,13 @@ static ArraySliceType *computeAllCasesType(NominalTypeDecl *enumType) {
|
|||||||
return ArraySliceType::get(metaTy->getRValueInstanceType());
|
return ArraySliceType::get(metaTy->getRValueInstanceType());
|
||||||
}
|
}
|
||||||
|
|
||||||
static Type deriveCaseIterable_AllCases(TypeChecker &tc, Decl *parentDecl,
|
static Type deriveCaseIterable_AllCases(DerivedConformance &derived) {
|
||||||
EnumDecl *enumDecl) {
|
|
||||||
// enum SomeEnum : CaseIterable {
|
// enum SomeEnum : CaseIterable {
|
||||||
// @derived
|
// @derived
|
||||||
// typealias AllCases = [SomeEnum]
|
// typealias AllCases = [SomeEnum]
|
||||||
// }
|
// }
|
||||||
auto *rawInterfaceType = computeAllCasesType(enumDecl);
|
auto *rawInterfaceType = computeAllCasesType(cast<EnumDecl>(derived.Nominal));
|
||||||
return cast<DeclContext>(parentDecl)->mapTypeIntoContext(rawInterfaceType);
|
return derived.getConformanceContext()->mapTypeIntoContext(rawInterfaceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) {
|
ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) {
|
||||||
@@ -115,10 +114,7 @@ ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) {
|
|||||||
|
|
||||||
getterDecl->setBodySynthesizer(&deriveCaseIterable_enum_getter);
|
getterDecl->setBodySynthesizer(&deriveCaseIterable_enum_getter);
|
||||||
|
|
||||||
auto dc = cast<IterableDeclContext>(ConformanceDecl);
|
addMembersToConformanceContext({getterDecl, propDecl, pbDecl});
|
||||||
dc->addMember(getterDecl);
|
|
||||||
dc->addMember(propDecl);
|
|
||||||
dc->addMember(pbDecl);
|
|
||||||
|
|
||||||
return propDecl;
|
return propDecl;
|
||||||
}
|
}
|
||||||
@@ -139,8 +135,7 @@ Type DerivedConformance::deriveCaseIterable(AssociatedTypeDecl *assocType) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (assocType->getName() == TC.Context.Id_AllCases) {
|
if (assocType->getName() == TC.Context.Id_AllCases) {
|
||||||
auto enumDecl = cast<EnumDecl>(Nominal);
|
return deriveCaseIterable_AllCases(*this);
|
||||||
return deriveCaseIterable_AllCases(TC, ConformanceDecl, enumDecl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TC.diagnose(assocType->getLoc(), diag::broken_case_iterable_requirement);
|
TC.diagnose(assocType->getLoc(), diag::broken_case_iterable_requirement);
|
||||||
|
|||||||
@@ -144,17 +144,11 @@ static CodableConformanceType varConformsToCodable(TypeChecker &tc,
|
|||||||
/// Validates the given CodingKeys enum decl by ensuring its cases are a 1-to-1
|
/// Validates the given CodingKeys enum decl by ensuring its cases are a 1-to-1
|
||||||
/// match with the stored vars of the given type.
|
/// match with the stored vars of the given type.
|
||||||
///
|
///
|
||||||
/// \param tc The typechecker to use in validating {En,De}codable conformance.
|
|
||||||
///
|
|
||||||
/// \param codingKeysDecl The \c CodingKeys enum decl to validate.
|
/// \param codingKeysDecl The \c CodingKeys enum decl to validate.
|
||||||
///
|
static bool validateCodingKeysEnum(DerivedConformance &derived,
|
||||||
/// \param target The nominal type decl to validate the \c CodingKeys against.
|
EnumDecl *codingKeysDecl) {
|
||||||
///
|
auto &tc = derived.TC;
|
||||||
/// \param proto The {En,De}codable protocol to validate all the keys conform
|
|
||||||
/// to.
|
|
||||||
static bool
|
|
||||||
validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl,
|
|
||||||
NominalTypeDecl *target, ProtocolDecl *proto) {
|
|
||||||
// Look through all var decls in the given type.
|
// Look through all var decls in the given type.
|
||||||
// * Filter out lazy/computed vars.
|
// * Filter out lazy/computed vars.
|
||||||
// * Filter out ones which are present in the given decl (by name).
|
// * Filter out ones which are present in the given decl (by name).
|
||||||
@@ -167,7 +161,8 @@ validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl,
|
|||||||
// Here we'll hold on to properties by name -- when we've validated a property
|
// Here we'll hold on to properties by name -- when we've validated a property
|
||||||
// against its CodingKey entry, it will get removed.
|
// against its CodingKey entry, it will get removed.
|
||||||
llvm::SmallDenseMap<Identifier, VarDecl *, 8> properties;
|
llvm::SmallDenseMap<Identifier, VarDecl *, 8> properties;
|
||||||
for (auto *varDecl : target->getStoredProperties(/*skipInaccessible=*/true)) {
|
for (auto *varDecl :
|
||||||
|
derived.Nominal->getStoredProperties(/*skipInaccessible=*/true)) {
|
||||||
if (varDecl->getAttrs().hasAttribute<LazyAttr>())
|
if (varDecl->getAttrs().hasAttribute<LazyAttr>())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -187,8 +182,8 @@ validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We have a property to map to. Ensure it's {En,De}codable.
|
// We have a property to map to. Ensure it's {En,De}codable.
|
||||||
auto conformance = varConformsToCodable(tc, target->getDeclContext(),
|
auto conformance = varConformsToCodable(
|
||||||
it->second, proto);
|
tc, derived.Nominal->getDeclContext(), it->second, derived.Protocol);
|
||||||
switch (conformance) {
|
switch (conformance) {
|
||||||
case Conforms:
|
case Conforms:
|
||||||
// The property was valid. Remove it from the list.
|
// The property was valid. Remove it from the list.
|
||||||
@@ -198,7 +193,7 @@ validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl,
|
|||||||
case DoesNotConform:
|
case DoesNotConform:
|
||||||
tc.diagnose(it->second->getLoc(),
|
tc.diagnose(it->second->getLoc(),
|
||||||
diag::codable_non_conforming_property_here,
|
diag::codable_non_conforming_property_here,
|
||||||
proto->getDeclaredType(), it->second->getType());
|
derived.getProtocolType(), it->second->getType());
|
||||||
LLVM_FALLTHROUGH;
|
LLVM_FALLTHROUGH;
|
||||||
|
|
||||||
case TypeNotValidated:
|
case TypeNotValidated:
|
||||||
@@ -216,7 +211,7 @@ validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl,
|
|||||||
// we can skip them on encode. On decode, though, we can only skip them if
|
// we can skip them on encode. On decode, though, we can only skip them if
|
||||||
// they have a default value.
|
// they have a default value.
|
||||||
if (!properties.empty() &&
|
if (!properties.empty() &&
|
||||||
proto->isSpecificProtocol(KnownProtocolKind::Decodable)) {
|
derived.Protocol->isSpecificProtocol(KnownProtocolKind::Decodable)) {
|
||||||
for (auto it = properties.begin(); it != properties.end(); ++it) {
|
for (auto it = properties.begin(); it != properties.end(); ++it) {
|
||||||
// If the var is default initializable, then it need not have an explicit
|
// If the var is default initializable, then it need not have an explicit
|
||||||
// initial value.
|
// initial value.
|
||||||
@@ -233,7 +228,7 @@ validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl,
|
|||||||
// initial value.
|
// initial value.
|
||||||
propertiesAreValid = false;
|
propertiesAreValid = false;
|
||||||
tc.diagnose(it->second->getLoc(), diag::codable_non_decoded_property_here,
|
tc.diagnose(it->second->getLoc(), diag::codable_non_decoded_property_here,
|
||||||
proto->getDeclaredType(), it->first);
|
derived.getProtocolType(), it->first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,19 +251,12 @@ struct CodingKeysValidity {
|
|||||||
/// diagnostics here, we don't want to then attempt to synthesize a CodingKeys
|
/// diagnostics here, we don't want to then attempt to synthesize a CodingKeys
|
||||||
/// enum.
|
/// enum.
|
||||||
///
|
///
|
||||||
/// \param tc The typechecker to use in validating {En,Decodable} conformance.
|
|
||||||
///
|
|
||||||
/// \param target The type decl whose nested \c CodingKeys type to validate.
|
|
||||||
///
|
|
||||||
/// \param proto The {En,De}codable protocol to ensure the properties matching
|
|
||||||
/// the keys conform to.
|
|
||||||
///
|
|
||||||
/// \returns A \c CodingKeysValidity value representing the result of the check.
|
/// \returns A \c CodingKeysValidity value representing the result of the check.
|
||||||
static CodingKeysValidity hasValidCodingKeysEnum(TypeChecker &tc,
|
static CodingKeysValidity hasValidCodingKeysEnum(DerivedConformance &derived) {
|
||||||
NominalTypeDecl *target,
|
auto &tc = derived.TC;
|
||||||
ProtocolDecl *proto) {
|
|
||||||
auto &C = tc.Context;
|
auto &C = tc.Context;
|
||||||
auto codingKeysDecls = target->lookupDirect(DeclName(C.Id_CodingKeys));
|
auto codingKeysDecls =
|
||||||
|
derived.Nominal->lookupDirect(DeclName(C.Id_CodingKeys));
|
||||||
if (codingKeysDecls.empty())
|
if (codingKeysDecls.empty())
|
||||||
return CodingKeysValidity(/*hasType=*/false, /*isValid=*/true);
|
return CodingKeysValidity(/*hasType=*/false, /*isValid=*/true);
|
||||||
|
|
||||||
@@ -281,7 +269,7 @@ static CodingKeysValidity hasValidCodingKeysEnum(TypeChecker &tc,
|
|||||||
if (!codingKeysTypeDecl) {
|
if (!codingKeysTypeDecl) {
|
||||||
tc.diagnose(result->getLoc(),
|
tc.diagnose(result->getLoc(),
|
||||||
diag::codable_codingkeys_type_is_not_an_enum_here,
|
diag::codable_codingkeys_type_is_not_an_enum_here,
|
||||||
proto->getDeclaredType());
|
derived.getProtocolType());
|
||||||
return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false);
|
return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,7 +285,7 @@ static CodingKeysValidity hasValidCodingKeysEnum(TypeChecker &tc,
|
|||||||
// Ensure that the type we found conforms to the CodingKey protocol.
|
// Ensure that the type we found conforms to the CodingKey protocol.
|
||||||
auto *codingKeyProto = C.getProtocol(KnownProtocolKind::CodingKey);
|
auto *codingKeyProto = C.getProtocol(KnownProtocolKind::CodingKey);
|
||||||
if (!tc.conformsToProtocol(codingKeysType, codingKeyProto,
|
if (!tc.conformsToProtocol(codingKeysType, codingKeyProto,
|
||||||
target->getDeclContext(),
|
derived.Nominal->getDeclContext(),
|
||||||
ConformanceCheckFlags::Used)) {
|
ConformanceCheckFlags::Used)) {
|
||||||
// If CodingKeys is a typealias which doesn't point to a valid nominal type,
|
// If CodingKeys is a typealias which doesn't point to a valid nominal type,
|
||||||
// codingKeysTypeDecl will be nullptr here. In that case, we need to warn on
|
// codingKeysTypeDecl will be nullptr here. In that case, we need to warn on
|
||||||
@@ -308,7 +296,7 @@ static CodingKeysValidity hasValidCodingKeysEnum(TypeChecker &tc,
|
|||||||
cast<TypeDecl>(result)->getLoc();
|
cast<TypeDecl>(result)->getLoc();
|
||||||
|
|
||||||
tc.diagnose(loc, diag::codable_codingkeys_type_does_not_conform_here,
|
tc.diagnose(loc, diag::codable_codingkeys_type_does_not_conform_here,
|
||||||
proto->getDeclaredType());
|
derived.getProtocolType());
|
||||||
|
|
||||||
return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false);
|
return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false);
|
||||||
}
|
}
|
||||||
@@ -318,29 +306,20 @@ static CodingKeysValidity hasValidCodingKeysEnum(TypeChecker &tc,
|
|||||||
if (!codingKeysEnum) {
|
if (!codingKeysEnum) {
|
||||||
tc.diagnose(codingKeysTypeDecl->getLoc(),
|
tc.diagnose(codingKeysTypeDecl->getLoc(),
|
||||||
diag::codable_codingkeys_type_is_not_an_enum_here,
|
diag::codable_codingkeys_type_is_not_an_enum_here,
|
||||||
proto->getDeclaredType());
|
derived.getProtocolType());
|
||||||
return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false);
|
return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool valid = validateCodingKeysEnum(tc, codingKeysEnum, target, proto);
|
bool valid = validateCodingKeysEnum(derived, codingKeysEnum);
|
||||||
return CodingKeysValidity(/*hasType=*/true, /*isValid=*/valid);
|
return CodingKeysValidity(/*hasType=*/true, /*isValid=*/valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Synthesizes a new \c CodingKeys enum based on the {En,De}codable members of
|
/// Synthesizes a new \c CodingKeys enum based on the {En,De}codable members of
|
||||||
/// the given type (\c nullptr if unable to synthesize).
|
/// the given type (\c nullptr if unable to synthesize).
|
||||||
///
|
///
|
||||||
/// If able to synthesize the enum, adds it directly to \c type.
|
/// If able to synthesize the enum, adds it directly to \c derived.Nominal.
|
||||||
///
|
static EnumDecl *synthesizeCodingKeysEnum(DerivedConformance &derived) {
|
||||||
/// \param tc The typechecker to use in validating {En,De}codable conformance.
|
auto &tc = derived.TC;
|
||||||
///
|
|
||||||
/// \param target The nominal type decl whose nested \c CodingKeys type to
|
|
||||||
/// synthesize.
|
|
||||||
///
|
|
||||||
/// \param proto The {En,De}codable protocol to validate all the keys conform
|
|
||||||
/// to.
|
|
||||||
static EnumDecl *synthesizeCodingKeysEnum(TypeChecker &tc,
|
|
||||||
NominalTypeDecl *target,
|
|
||||||
ProtocolDecl *proto) {
|
|
||||||
auto &C = tc.Context;
|
auto &C = tc.Context;
|
||||||
|
|
||||||
// We want to look through all the var declarations of this type to create
|
// We want to look through all the var declarations of this type to create
|
||||||
@@ -350,6 +329,7 @@ static EnumDecl *synthesizeCodingKeysEnum(TypeChecker &tc,
|
|||||||
TypeLoc protoTypeLoc[1] = {TypeLoc::withoutLoc(codingKeyType)};
|
TypeLoc protoTypeLoc[1] = {TypeLoc::withoutLoc(codingKeyType)};
|
||||||
MutableArrayRef<TypeLoc> inherited = C.AllocateCopy(protoTypeLoc);
|
MutableArrayRef<TypeLoc> inherited = C.AllocateCopy(protoTypeLoc);
|
||||||
|
|
||||||
|
auto target = derived.Nominal;
|
||||||
auto *enumDecl = new (C) EnumDecl(SourceLoc(), C.Id_CodingKeys, SourceLoc(),
|
auto *enumDecl = new (C) EnumDecl(SourceLoc(), C.Id_CodingKeys, SourceLoc(),
|
||||||
inherited, nullptr, target);
|
inherited, nullptr, target);
|
||||||
enumDecl->setImplicit();
|
enumDecl->setImplicit();
|
||||||
@@ -377,7 +357,7 @@ static EnumDecl *synthesizeCodingKeysEnum(TypeChecker &tc,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto conformance = varConformsToCodable(tc, target->getDeclContext(),
|
auto conformance = varConformsToCodable(tc, target->getDeclContext(),
|
||||||
varDecl, proto);
|
varDecl, derived.Protocol);
|
||||||
switch (conformance) {
|
switch (conformance) {
|
||||||
case Conforms:
|
case Conforms:
|
||||||
{
|
{
|
||||||
@@ -392,7 +372,7 @@ static EnumDecl *synthesizeCodingKeysEnum(TypeChecker &tc,
|
|||||||
case DoesNotConform:
|
case DoesNotConform:
|
||||||
tc.diagnose(varDecl->getLoc(),
|
tc.diagnose(varDecl->getLoc(),
|
||||||
diag::codable_non_conforming_property_here,
|
diag::codable_non_conforming_property_here,
|
||||||
proto->getDeclaredType(), varDecl->getType());
|
derived.getProtocolType(), varDecl->getType());
|
||||||
LLVM_FALLTHROUGH;
|
LLVM_FALLTHROUGH;
|
||||||
|
|
||||||
case TypeNotValidated:
|
case TypeNotValidated:
|
||||||
@@ -703,15 +683,10 @@ static void deriveBodyEncodable_encode(AbstractFunctionDecl *encodeDecl) {
|
|||||||
/// lazily synthesized body for the given type.
|
/// lazily synthesized body for the given type.
|
||||||
///
|
///
|
||||||
/// Adds the function declaration to the given type before returning it.
|
/// Adds the function declaration to the given type before returning it.
|
||||||
///
|
static FuncDecl *deriveEncodable_encode(DerivedConformance &derived) {
|
||||||
/// \param tc The type checker whose AST context to synthesize the decl in.
|
auto &C = derived.TC.Context;
|
||||||
///
|
|
||||||
/// \param parentDecl The parent declaration of the type.
|
auto target = derived.Nominal;
|
||||||
///
|
|
||||||
/// \param target The nominal type to synthesize the function for.
|
|
||||||
static FuncDecl *deriveEncodable_encode(TypeChecker &tc, Decl *parentDecl,
|
|
||||||
NominalTypeDecl *target) {
|
|
||||||
auto &C = tc.Context;
|
|
||||||
|
|
||||||
// Expected type: (Self) -> (Encoder) throws -> ()
|
// Expected type: (Self) -> (Encoder) throws -> ()
|
||||||
// Constructed as: func type
|
// Constructed as: func type
|
||||||
@@ -783,7 +758,7 @@ static FuncDecl *deriveEncodable_encode(TypeChecker &tc, Decl *parentDecl,
|
|||||||
encodeDecl->setValidationStarted();
|
encodeDecl->setValidationStarted();
|
||||||
encodeDecl->copyFormalAccessFrom(target, /*sourceIsParentContext*/true);
|
encodeDecl->copyFormalAccessFrom(target, /*sourceIsParentContext*/true);
|
||||||
|
|
||||||
tc.Context.addSynthesizedDecl(encodeDecl);
|
C.addSynthesizedDecl(encodeDecl);
|
||||||
|
|
||||||
target->addMember(encodeDecl);
|
target->addMember(encodeDecl);
|
||||||
return encodeDecl;
|
return encodeDecl;
|
||||||
@@ -1034,15 +1009,10 @@ static void deriveBodyDecodable_init(AbstractFunctionDecl *initDecl) {
|
|||||||
/// lazily synthesized body for the given type.
|
/// lazily synthesized body for the given type.
|
||||||
///
|
///
|
||||||
/// Adds the function declaration to the given type before returning it.
|
/// Adds the function declaration to the given type before returning it.
|
||||||
///
|
static ValueDecl *deriveDecodable_init(DerivedConformance &derived) {
|
||||||
/// \param tc The type checker whose AST context to synthesize the decl in.
|
auto &C = derived.TC.Context;
|
||||||
///
|
|
||||||
/// \param parentDecl The parent declaration of the type.
|
auto target = derived.Nominal;
|
||||||
///
|
|
||||||
/// \param target The nominal type to synthesize the function for.
|
|
||||||
static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl,
|
|
||||||
NominalTypeDecl *target) {
|
|
||||||
auto &C = tc.Context;
|
|
||||||
|
|
||||||
// Expected type: (Self) -> (Decoder) throws -> (Self)
|
// Expected type: (Self) -> (Decoder) throws -> (Self)
|
||||||
// Constructed as: func type
|
// Constructed as: func type
|
||||||
@@ -1123,9 +1093,9 @@ static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl,
|
|||||||
initDecl->setInitializerInterfaceType(initializerType);
|
initDecl->setInitializerInterfaceType(initializerType);
|
||||||
initDecl->copyFormalAccessFrom(target, /*sourceIsParentContext*/true);
|
initDecl->copyFormalAccessFrom(target, /*sourceIsParentContext*/true);
|
||||||
|
|
||||||
tc.Context.addSynthesizedDecl(initDecl);
|
C.addSynthesizedDecl(initDecl);
|
||||||
|
|
||||||
target->addMember(initDecl);
|
derived.addMembersToConformanceContext({initDecl});
|
||||||
return initDecl;
|
return initDecl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1134,15 +1104,8 @@ static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl,
|
|||||||
/// Checks to see whether the given type has a valid \c CodingKeys enum, and if
|
/// Checks to see whether the given type has a valid \c CodingKeys enum, and if
|
||||||
/// not, attempts to synthesize one for it.
|
/// not, attempts to synthesize one for it.
|
||||||
///
|
///
|
||||||
/// \param tc The typechecker to use in validating {En,Decodable} conformance.
|
|
||||||
///
|
|
||||||
/// \param target The type to validate.
|
|
||||||
///
|
|
||||||
/// \param requirement The requirement we want to synthesize.
|
/// \param requirement The requirement we want to synthesize.
|
||||||
///
|
static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) {
|
||||||
/// \param proto The *codable protocol to check for validity.
|
|
||||||
static bool canSynthesize(TypeChecker &tc, NominalTypeDecl *target,
|
|
||||||
ValueDecl *requirement, ProtocolDecl *proto) {
|
|
||||||
// Before we attempt to look up (or more importantly, synthesize) a CodingKeys
|
// Before we attempt to look up (or more importantly, synthesize) a CodingKeys
|
||||||
// entity on target, we need to make sure the type is otherwise valid.
|
// entity on target, we need to make sure the type is otherwise valid.
|
||||||
//
|
//
|
||||||
@@ -1153,8 +1116,10 @@ static bool canSynthesize(TypeChecker &tc, NominalTypeDecl *target,
|
|||||||
//
|
//
|
||||||
// If the required initializer is not available, we shouldn't attempt to
|
// If the required initializer is not available, we shouldn't attempt to
|
||||||
// synthesize CodingKeys.
|
// synthesize CodingKeys.
|
||||||
|
auto &tc = derived.TC;
|
||||||
ASTContext &C = tc.Context;
|
ASTContext &C = tc.Context;
|
||||||
auto *classDecl = dyn_cast<ClassDecl>(target);
|
auto proto = derived.Protocol;
|
||||||
|
auto *classDecl = dyn_cast<ClassDecl>(derived.Nominal);
|
||||||
if (proto->isSpecificProtocol(KnownProtocolKind::Decodable) && classDecl) {
|
if (proto->isSpecificProtocol(KnownProtocolKind::Decodable) && classDecl) {
|
||||||
if (auto *superclassDecl = classDecl->getSuperclassDecl()) {
|
if (auto *superclassDecl = classDecl->getSuperclassDecl()) {
|
||||||
DeclName memberName;
|
DeclName memberName;
|
||||||
@@ -1192,9 +1157,9 @@ static bool canSynthesize(TypeChecker &tc, NominalTypeDecl *target,
|
|||||||
diag::decodable_super_init_not_designated_here,
|
diag::decodable_super_init_not_designated_here,
|
||||||
requirement->getFullName(), memberName);
|
requirement->getFullName(), memberName);
|
||||||
return false;
|
return false;
|
||||||
} else if (!initializer->isAccessibleFrom(target)) {
|
} else if (!initializer->isAccessibleFrom(classDecl)) {
|
||||||
// Cannot call an inaccessible method.
|
// Cannot call an inaccessible method.
|
||||||
auto accessScope = initializer->getFormalAccessScope(target);
|
auto accessScope = initializer->getFormalAccessScope(classDecl);
|
||||||
tc.diagnose(initializer, diag::decodable_inaccessible_super_init_here,
|
tc.diagnose(initializer, diag::decodable_inaccessible_super_init_here,
|
||||||
requirement->getFullName(), memberName,
|
requirement->getFullName(), memberName,
|
||||||
accessScope.accessLevelForDiagnostics());
|
accessScope.accessLevelForDiagnostics());
|
||||||
@@ -1212,7 +1177,7 @@ static bool canSynthesize(TypeChecker &tc, NominalTypeDecl *target,
|
|||||||
|
|
||||||
// If the target already has a valid CodingKeys enum, we won't need to
|
// If the target already has a valid CodingKeys enum, we won't need to
|
||||||
// synthesize one.
|
// synthesize one.
|
||||||
auto validity = hasValidCodingKeysEnum(tc, target, proto);
|
auto validity = hasValidCodingKeysEnum(derived);
|
||||||
|
|
||||||
// We found a type, but it wasn't valid.
|
// We found a type, but it wasn't valid.
|
||||||
if (!validity.isValid)
|
if (!validity.isValid)
|
||||||
@@ -1220,7 +1185,7 @@ static bool canSynthesize(TypeChecker &tc, NominalTypeDecl *target,
|
|||||||
|
|
||||||
// We can try to synthesize a type here.
|
// We can try to synthesize a type here.
|
||||||
if (!validity.hasType) {
|
if (!validity.hasType) {
|
||||||
auto *synthesizedEnum = synthesizeCodingKeysEnum(tc, target, proto);
|
auto *synthesizedEnum = synthesizeCodingKeysEnum(derived);
|
||||||
if (!synthesizedEnum)
|
if (!synthesizedEnum)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1271,9 +1236,9 @@ ValueDecl *DerivedConformance::deriveEncodable(ValueDecl *requirement) {
|
|||||||
|
|
||||||
// Check other preconditions for synthesized conformance.
|
// Check other preconditions for synthesized conformance.
|
||||||
// This synthesizes a CodingKeys enum if possible.
|
// This synthesizes a CodingKeys enum if possible.
|
||||||
if (canSynthesize(TC, Nominal, requirement, encodableProto)) {
|
if (canSynthesize(*this, requirement)) {
|
||||||
diagnosticTransaction.abort();
|
diagnosticTransaction.abort();
|
||||||
return deriveEncodable_encode(TC, ConformanceDecl, Nominal);
|
return deriveEncodable_encode(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -1313,9 +1278,9 @@ ValueDecl *DerivedConformance::deriveDecodable(ValueDecl *requirement) {
|
|||||||
|
|
||||||
// Check other preconditions for synthesized conformance.
|
// Check other preconditions for synthesized conformance.
|
||||||
// This synthesizes a CodingKeys enum if possible.
|
// This synthesizes a CodingKeys enum if possible.
|
||||||
if (canSynthesize(TC, Nominal, requirement, decodableProto)) {
|
if (canSynthesize(*this, requirement)) {
|
||||||
diagnosticTransaction.abort();
|
diagnosticTransaction.abort();
|
||||||
return deriveDecodable_init(TC, ConformanceDecl, Nominal);
|
return deriveDecodable_init(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
@@ -102,24 +102,17 @@ static void deriveRawValueInit(AbstractFunctionDecl *initDecl) {
|
|||||||
/// Synthesizes a constructor declaration with the given parameter name and
|
/// Synthesizes a constructor declaration with the given parameter name and
|
||||||
/// type.
|
/// type.
|
||||||
///
|
///
|
||||||
/// \param tc The type checker to use in synthesizing the constructor.
|
|
||||||
///
|
|
||||||
/// \param parentDecl The parent declaration of the enum.
|
|
||||||
///
|
|
||||||
/// \param enumDecl The enum on which to synthesize the constructor.
|
|
||||||
///
|
|
||||||
/// \param paramType The type of the parameter.
|
/// \param paramType The type of the parameter.
|
||||||
///
|
///
|
||||||
/// \param paramName The name of the parameter.
|
/// \param paramName The name of the parameter.
|
||||||
///
|
///
|
||||||
/// \param synthesizer A lambda to call to set the constructor's body.
|
/// \param synthesizer A lambda to call to set the constructor's body.
|
||||||
template <typename Synthesizer>
|
template <typename Synthesizer>
|
||||||
static ValueDecl *deriveInitDecl(TypeChecker &tc, Decl *parentDecl,
|
static ValueDecl *deriveInitDecl(DerivedConformance &derived, Type paramType,
|
||||||
EnumDecl *enumDecl, Type paramType,
|
|
||||||
Identifier paramName,
|
Identifier paramName,
|
||||||
const Synthesizer &synthesizer) {
|
const Synthesizer &synthesizer) {
|
||||||
auto &C = tc.Context;
|
auto &C = derived.TC.Context;
|
||||||
auto *parentDC = cast<DeclContext>(parentDecl);
|
auto *parentDC = derived.getConformanceContext();
|
||||||
|
|
||||||
// rawValue
|
// rawValue
|
||||||
auto *rawDecl =
|
auto *rawDecl =
|
||||||
@@ -179,12 +172,12 @@ static ValueDecl *deriveInitDecl(TypeChecker &tc, Decl *parentDecl,
|
|||||||
}
|
}
|
||||||
initDecl->setInterfaceType(allocIfaceType);
|
initDecl->setInterfaceType(allocIfaceType);
|
||||||
initDecl->setInitializerInterfaceType(initIfaceType);
|
initDecl->setInitializerInterfaceType(initIfaceType);
|
||||||
initDecl->setAccess(enumDecl->getFormalAccess());
|
initDecl->setAccess(derived.Nominal->getFormalAccess());
|
||||||
initDecl->setValidationStarted();
|
initDecl->setValidationStarted();
|
||||||
|
|
||||||
tc.Context.addSynthesizedDecl(initDecl);
|
C.addSynthesizedDecl(initDecl);
|
||||||
|
|
||||||
cast<IterableDeclContext>(parentDecl)->addMember(initDecl);
|
derived.addMembersToConformanceContext({initDecl});
|
||||||
return initDecl;
|
return initDecl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,24 +359,18 @@ deriveBodyCodingKey_init_stringValue(AbstractFunctionDecl *initDecl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the given enum is eligible for CodingKey synthesis.
|
/// Returns whether the given enum is eligible for CodingKey synthesis.
|
||||||
///
|
static bool canSynthesizeCodingKey(DerivedConformance &derived) {
|
||||||
/// \param tc The type checker to use in checking eligibility.
|
auto enumDecl = cast<EnumDecl>(derived.Nominal);
|
||||||
///
|
|
||||||
/// \param parentDecl The parent declaration of the enum.
|
|
||||||
///
|
|
||||||
/// \param enumDecl The enum to check.
|
|
||||||
static bool canSynthesizeCodingKey(TypeChecker &tc, Decl *parentDecl,
|
|
||||||
EnumDecl *enumDecl) {
|
|
||||||
// Validate the enum and its raw type.
|
// Validate the enum and its raw type.
|
||||||
tc.validateDecl(enumDecl);
|
derived.TC.validateDecl(enumDecl);
|
||||||
|
|
||||||
// If the enum has a raw type (optional), it must be String or Int.
|
// If the enum has a raw type (optional), it must be String or Int.
|
||||||
Type rawType = enumDecl->getRawType();
|
Type rawType = enumDecl->getRawType();
|
||||||
if (rawType) {
|
if (rawType) {
|
||||||
auto *parentDC = cast<DeclContext>(parentDecl);
|
auto *parentDC = derived.getConformanceContext();
|
||||||
rawType = parentDC->mapTypeIntoContext(rawType);
|
rawType = parentDC->mapTypeIntoContext(rawType);
|
||||||
|
|
||||||
auto &C = tc.Context;
|
auto &C = derived.TC.Context;
|
||||||
auto *nominal = rawType->getCanonicalType()->getAnyNominal();
|
auto *nominal = rawType->getCanonicalType()->getAnyNominal();
|
||||||
if (nominal != C.getStringDecl() && nominal != C.getIntDecl())
|
if (nominal != C.getStringDecl() && nominal != C.getIntDecl())
|
||||||
return false;
|
return false;
|
||||||
@@ -407,7 +394,7 @@ ValueDecl *DerivedConformance::deriveCodingKey(ValueDecl *requirement) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Check other preconditions for synthesized conformance.
|
// Check other preconditions for synthesized conformance.
|
||||||
if (!canSynthesizeCodingKey(TC, Nominal, enumDecl))
|
if (!canSynthesizeCodingKey(*this))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto &C = TC.Context;
|
auto &C = TC.Context;
|
||||||
@@ -505,8 +492,7 @@ ValueDecl *DerivedConformance::deriveCodingKey(ValueDecl *requirement) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return deriveInitDecl(TC, ConformanceDecl, enumDecl, stringType,
|
return deriveInitDecl(*this, stringType, C.Id_stringValue, synth);
|
||||||
C.Id_stringValue, synth);
|
|
||||||
} else if (argumentNames[0] == C.Id_intValue) {
|
} else if (argumentNames[0] == C.Id_intValue) {
|
||||||
// Synthesize `init?(intValue:)`
|
// Synthesize `init?(intValue:)`
|
||||||
auto intType = C.getIntDecl()->getDeclaredType();
|
auto intType = C.getIntDecl()->getDeclaredType();
|
||||||
@@ -530,8 +516,7 @@ ValueDecl *DerivedConformance::deriveCodingKey(ValueDecl *requirement) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return deriveInitDecl(TC, ConformanceDecl, enumDecl, intType,
|
return deriveInitDecl(*this, intType, C.Id_intValue, synthesizer);
|
||||||
C.Id_intValue, synthesizer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -541,8 +541,7 @@ static void deriveBodyEquatable_struct_eq(AbstractFunctionDecl *eqDecl) {
|
|||||||
|
|
||||||
/// Derive an '==' operator implementation for an enum or a struct.
|
/// Derive an '==' operator implementation for an enum or a struct.
|
||||||
static ValueDecl *
|
static ValueDecl *
|
||||||
deriveEquatable_eq(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *typeDecl,
|
deriveEquatable_eq(DerivedConformance &derived, Identifier generatedIdentifier,
|
||||||
Identifier generatedIdentifier,
|
|
||||||
void (*bodySynthesizer)(AbstractFunctionDecl *)) {
|
void (*bodySynthesizer)(AbstractFunctionDecl *)) {
|
||||||
// enum SomeEnum<T...> {
|
// enum SomeEnum<T...> {
|
||||||
// case A, B(Int), C(String, Int)
|
// case A, B(Int), C(String, Int)
|
||||||
@@ -579,9 +578,9 @@ deriveEquatable_eq(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *typeDecl,
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
ASTContext &C = tc.Context;
|
ASTContext &C = derived.TC.Context;
|
||||||
|
|
||||||
auto parentDC = cast<DeclContext>(parentDecl);
|
auto parentDC = derived.getConformanceContext();
|
||||||
auto enumTy = parentDC->getDeclaredTypeInContext();
|
auto enumTy = parentDC->getDeclaredTypeInContext();
|
||||||
auto enumIfaceTy = parentDC->getDeclaredInterfaceType();
|
auto enumIfaceTy = parentDC->getDeclaredInterfaceType();
|
||||||
|
|
||||||
@@ -634,14 +633,15 @@ deriveEquatable_eq(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *typeDecl,
|
|||||||
DeclNameLoc()));
|
DeclNameLoc()));
|
||||||
|
|
||||||
if (!C.getEqualIntDecl()) {
|
if (!C.getEqualIntDecl()) {
|
||||||
tc.diagnose(parentDecl->getLoc(), diag::no_equal_overload_for_int);
|
derived.TC.diagnose(derived.ConformanceDecl->getLoc(),
|
||||||
|
diag::no_equal_overload_for_int);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
eqDecl->setBodySynthesizer(bodySynthesizer);
|
eqDecl->setBodySynthesizer(bodySynthesizer);
|
||||||
|
|
||||||
// Compute the type.
|
// Compute the type.
|
||||||
Type paramsTy = params[1]->getType(tc.Context);
|
Type paramsTy = params[1]->getType(C);
|
||||||
|
|
||||||
// Compute the interface type.
|
// Compute the interface type.
|
||||||
Type interfaceTy;
|
Type interfaceTy;
|
||||||
@@ -664,13 +664,13 @@ deriveEquatable_eq(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *typeDecl,
|
|||||||
FunctionType::ExtInfo());
|
FunctionType::ExtInfo());
|
||||||
}
|
}
|
||||||
eqDecl->setInterfaceType(interfaceTy);
|
eqDecl->setInterfaceType(interfaceTy);
|
||||||
eqDecl->copyFormalAccessFrom(typeDecl, /*sourceIsParentContext*/true);
|
eqDecl->copyFormalAccessFrom(derived.Nominal, /*sourceIsParentContext*/ true);
|
||||||
eqDecl->setValidationStarted();
|
eqDecl->setValidationStarted();
|
||||||
|
|
||||||
tc.Context.addSynthesizedDecl(eqDecl);
|
C.addSynthesizedDecl(eqDecl);
|
||||||
|
|
||||||
// Add the operator to the parent scope.
|
// Add the operator to the parent scope.
|
||||||
cast<IterableDeclContext>(parentDecl)->addMember(eqDecl);
|
derived.addMembersToConformanceContext({eqDecl});
|
||||||
|
|
||||||
return eqDecl;
|
return eqDecl;
|
||||||
}
|
}
|
||||||
@@ -701,12 +701,10 @@ ValueDecl *DerivedConformance::deriveEquatable(ValueDecl *requirement) {
|
|||||||
theEnum->hasOnlyCasesWithoutAssociatedValues()
|
theEnum->hasOnlyCasesWithoutAssociatedValues()
|
||||||
? &deriveBodyEquatable_enum_noAssociatedValues_eq
|
? &deriveBodyEquatable_enum_noAssociatedValues_eq
|
||||||
: &deriveBodyEquatable_enum_hasAssociatedValues_eq;
|
: &deriveBodyEquatable_enum_hasAssociatedValues_eq;
|
||||||
return deriveEquatable_eq(TC, ConformanceDecl, theEnum,
|
return deriveEquatable_eq(*this, TC.Context.Id_derived_enum_equals,
|
||||||
TC.Context.Id_derived_enum_equals,
|
|
||||||
bodySynthesizer);
|
bodySynthesizer);
|
||||||
} else if (auto theStruct = dyn_cast<StructDecl>(Nominal))
|
} else if (isa<StructDecl>(Nominal))
|
||||||
return deriveEquatable_eq(TC, ConformanceDecl, theStruct,
|
return deriveEquatable_eq(*this, TC.Context.Id_derived_struct_equals,
|
||||||
TC.Context.Id_derived_struct_equals,
|
|
||||||
&deriveBodyEquatable_struct_eq);
|
&deriveBodyEquatable_struct_eq);
|
||||||
else
|
else
|
||||||
llvm_unreachable("todo");
|
llvm_unreachable("todo");
|
||||||
@@ -740,13 +738,12 @@ static CallExpr *createHasherCombineCall(ASTContext &C,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static FuncDecl *
|
static FuncDecl *
|
||||||
deriveHashable_hashInto(TypeChecker &tc, Decl *parentDecl,
|
deriveHashable_hashInto(DerivedConformance &derived,
|
||||||
NominalTypeDecl *typeDecl,
|
|
||||||
void (*bodySynthesizer)(AbstractFunctionDecl *)) {
|
void (*bodySynthesizer)(AbstractFunctionDecl *)) {
|
||||||
// @derived func hash(into hasher: inout Hasher)
|
// @derived func hash(into hasher: inout Hasher)
|
||||||
|
|
||||||
ASTContext &C = tc.Context;
|
ASTContext &C = derived.TC.Context;
|
||||||
auto parentDC = cast<DeclContext>(parentDecl);
|
auto parentDC = derived.getConformanceContext();
|
||||||
|
|
||||||
// Expected type: (Self) -> (into: inout Hasher) -> ()
|
// Expected type: (Self) -> (into: inout Hasher) -> ()
|
||||||
// Constructed as:
|
// Constructed as:
|
||||||
@@ -757,8 +754,9 @@ deriveHashable_hashInto(TypeChecker &tc, Decl *parentDecl,
|
|||||||
|
|
||||||
auto hasherDecl = C.getHasherDecl();
|
auto hasherDecl = C.getHasherDecl();
|
||||||
if (!hasherDecl) {
|
if (!hasherDecl) {
|
||||||
auto hashableProto = tc.Context.getProtocol(KnownProtocolKind::Hashable);
|
auto hashableProto = C.getProtocol(KnownProtocolKind::Hashable);
|
||||||
tc.diagnose(hashableProto->getLoc(), diag::broken_hashable_no_hasher);
|
derived.TC.diagnose(hashableProto->getLoc(),
|
||||||
|
diag::broken_hashable_no_hasher);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
Type hasherType = hasherDecl->getDeclaredType();
|
Type hasherType = hasherDecl->getDeclaredType();
|
||||||
@@ -807,12 +805,12 @@ deriveHashable_hashInto(TypeChecker &tc, Decl *parentDecl,
|
|||||||
FunctionType::ExtInfo());
|
FunctionType::ExtInfo());
|
||||||
}
|
}
|
||||||
hashDecl->setInterfaceType(interfaceType);
|
hashDecl->setInterfaceType(interfaceType);
|
||||||
hashDecl->copyFormalAccessFrom(typeDecl);
|
hashDecl->copyFormalAccessFrom(derived.Nominal);
|
||||||
hashDecl->setValidationStarted();
|
hashDecl->setValidationStarted();
|
||||||
|
|
||||||
C.addSynthesizedDecl(hashDecl);
|
C.addSynthesizedDecl(hashDecl);
|
||||||
|
|
||||||
cast<IterableDeclContext>(parentDecl)->addMember(hashDecl);
|
derived.addMembersToConformanceContext({hashDecl});
|
||||||
return hashDecl;
|
return hashDecl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1038,29 +1036,30 @@ deriveBodyHashable_hashValue(AbstractFunctionDecl *hashValueDecl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Derive a 'hashValue' implementation.
|
/// Derive a 'hashValue' implementation.
|
||||||
static ValueDecl *
|
static ValueDecl *deriveHashable_hashValue(DerivedConformance &derived) {
|
||||||
deriveHashable_hashValue(TypeChecker &tc, Decl *parentDecl,
|
|
||||||
NominalTypeDecl *typeDecl) {
|
|
||||||
// @derived var hashValue: Int {
|
// @derived var hashValue: Int {
|
||||||
// return _hashValue(for: self)
|
// return _hashValue(for: self)
|
||||||
// }
|
// }
|
||||||
|
auto &tc = derived.TC;
|
||||||
ASTContext &C = tc.Context;
|
ASTContext &C = tc.Context;
|
||||||
|
|
||||||
auto parentDC = cast<DeclContext>(parentDecl);
|
auto parentDC = derived.getConformanceContext();
|
||||||
Type intType = C.getIntDecl()->getDeclaredType();
|
Type intType = C.getIntDecl()->getDeclaredType();
|
||||||
|
|
||||||
// We can't form a Hashable conformance if Int isn't Hashable or
|
// We can't form a Hashable conformance if Int isn't Hashable or
|
||||||
// ExpressibleByIntegerLiteral.
|
// ExpressibleByIntegerLiteral.
|
||||||
if (!tc.conformsToProtocol(intType,C.getProtocol(KnownProtocolKind::Hashable),
|
if (!tc.conformsToProtocol(intType,
|
||||||
typeDecl, None)) {
|
C.getProtocol(KnownProtocolKind::Hashable),
|
||||||
tc.diagnose(typeDecl->getLoc(), diag::broken_int_hashable_conformance);
|
derived.Nominal, None)) {
|
||||||
|
tc.diagnose(derived.Nominal->getLoc(),
|
||||||
|
diag::broken_int_hashable_conformance);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtocolDecl *intLiteralProto =
|
ProtocolDecl *intLiteralProto =
|
||||||
C.getProtocol(KnownProtocolKind::ExpressibleByIntegerLiteral);
|
C.getProtocol(KnownProtocolKind::ExpressibleByIntegerLiteral);
|
||||||
if (!tc.conformsToProtocol(intType, intLiteralProto, typeDecl, None)) {
|
if (!tc.conformsToProtocol(intType, intLiteralProto, derived.Nominal, None)) {
|
||||||
tc.diagnose(typeDecl->getLoc(),
|
tc.diagnose(derived.Nominal->getLoc(),
|
||||||
diag::broken_int_integer_literal_convertible_conformance);
|
diag::broken_int_integer_literal_convertible_conformance);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -1088,7 +1087,7 @@ deriveHashable_hashValue(TypeChecker &tc, Decl *parentDecl,
|
|||||||
getterDecl->setBodySynthesizer(&deriveBodyHashable_hashValue);
|
getterDecl->setBodySynthesizer(&deriveBodyHashable_hashValue);
|
||||||
|
|
||||||
// Compute the type of hashValue().
|
// Compute the type of hashValue().
|
||||||
Type methodType = FunctionType::get(TupleType::getEmpty(tc.Context), intType);
|
Type methodType = FunctionType::get(TupleType::getEmpty(C), intType);
|
||||||
|
|
||||||
// Compute the interface type of hashValue().
|
// Compute the interface type of hashValue().
|
||||||
Type interfaceType;
|
Type interfaceType;
|
||||||
@@ -1103,7 +1102,8 @@ deriveHashable_hashValue(TypeChecker &tc, Decl *parentDecl,
|
|||||||
|
|
||||||
getterDecl->setInterfaceType(interfaceType);
|
getterDecl->setInterfaceType(interfaceType);
|
||||||
getterDecl->setValidationStarted();
|
getterDecl->setValidationStarted();
|
||||||
getterDecl->copyFormalAccessFrom(typeDecl, /*sourceIsParentContext*/true);
|
getterDecl->copyFormalAccessFrom(derived.Nominal,
|
||||||
|
/*sourceIsParentContext*/ true);
|
||||||
|
|
||||||
// Finish creating the property.
|
// Finish creating the property.
|
||||||
hashValueDecl->setImplicit();
|
hashValueDecl->setImplicit();
|
||||||
@@ -1111,7 +1111,8 @@ deriveHashable_hashValue(TypeChecker &tc, Decl *parentDecl,
|
|||||||
hashValueDecl->setValidationStarted();
|
hashValueDecl->setValidationStarted();
|
||||||
hashValueDecl->makeComputed(SourceLoc(), getterDecl,
|
hashValueDecl->makeComputed(SourceLoc(), getterDecl,
|
||||||
nullptr, nullptr, SourceLoc());
|
nullptr, nullptr, SourceLoc());
|
||||||
hashValueDecl->copyFormalAccessFrom(typeDecl, /*sourceIsParentContext*/true);
|
hashValueDecl->copyFormalAccessFrom(derived.Nominal,
|
||||||
|
/*sourceIsParentContext*/ true);
|
||||||
|
|
||||||
Pattern *hashValuePat = new (C) NamedPattern(hashValueDecl, /*implicit*/true);
|
Pattern *hashValuePat = new (C) NamedPattern(hashValueDecl, /*implicit*/true);
|
||||||
hashValuePat->setType(intType);
|
hashValuePat->setType(intType);
|
||||||
@@ -1126,13 +1127,10 @@ deriveHashable_hashValue(TypeChecker &tc, Decl *parentDecl,
|
|||||||
parentDC);
|
parentDC);
|
||||||
patDecl->setImplicit();
|
patDecl->setImplicit();
|
||||||
|
|
||||||
tc.Context.addSynthesizedDecl(hashValueDecl);
|
C.addSynthesizedDecl(hashValueDecl);
|
||||||
tc.Context.addSynthesizedDecl(getterDecl);
|
C.addSynthesizedDecl(getterDecl);
|
||||||
|
|
||||||
auto dc = cast<IterableDeclContext>(parentDecl);
|
derived.addMembersToConformanceContext({getterDecl, hashValueDecl, patDecl});
|
||||||
dc->addMember(getterDecl);
|
|
||||||
dc->addMember(hashValueDecl);
|
|
||||||
dc->addMember(patDecl);
|
|
||||||
return hashValueDecl;
|
return hashValueDecl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1180,7 +1178,7 @@ ValueDecl *DerivedConformance::deriveHashable(ValueDecl *requirement) {
|
|||||||
if (requirement->getBaseName() == C.Id_hashValue) {
|
if (requirement->getBaseName() == C.Id_hashValue) {
|
||||||
// We always allow hashValue to be synthesized; invalid cases are diagnosed
|
// We always allow hashValue to be synthesized; invalid cases are diagnosed
|
||||||
// during hash(into:) synthesis.
|
// during hash(into:) synthesis.
|
||||||
return deriveHashable_hashValue(TC, ConformanceDecl, Nominal);
|
return deriveHashable_hashValue(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hashable.hash(into:)
|
// Hashable.hash(into:)
|
||||||
@@ -1223,10 +1221,9 @@ ValueDecl *DerivedConformance::deriveHashable(ValueDecl *requirement) {
|
|||||||
auto bodySynthesizer = hasAssociatedValues
|
auto bodySynthesizer = hasAssociatedValues
|
||||||
? &deriveBodyHashable_enum_hasAssociatedValues_hashInto
|
? &deriveBodyHashable_enum_hasAssociatedValues_hashInto
|
||||||
: &deriveBodyHashable_enum_noAssociatedValues_hashInto;
|
: &deriveBodyHashable_enum_noAssociatedValues_hashInto;
|
||||||
return deriveHashable_hashInto(TC, ConformanceDecl, theEnum,
|
return deriveHashable_hashInto(*this, bodySynthesizer);
|
||||||
bodySynthesizer);
|
} else if (isa<StructDecl>(Nominal))
|
||||||
} else if (auto theStruct = dyn_cast<StructDecl>(Nominal))
|
return deriveHashable_hashInto(*this,
|
||||||
return deriveHashable_hashInto(TC, ConformanceDecl, theStruct,
|
|
||||||
&deriveBodyHashable_struct_hashInto);
|
&deriveBodyHashable_struct_hashInto);
|
||||||
else // This should've been caught by canDeriveHashable above.
|
else // This should've been caught by canDeriveHashable above.
|
||||||
llvm_unreachable("Attempt to derive Hashable for a type other "
|
llvm_unreachable("Attempt to derive Hashable for a type other "
|
||||||
@@ -1234,7 +1231,7 @@ ValueDecl *DerivedConformance::deriveHashable(ValueDecl *requirement) {
|
|||||||
} else {
|
} else {
|
||||||
// We can always derive hash(into:) if hashValue has an explicit
|
// We can always derive hash(into:) if hashValue has an explicit
|
||||||
// implementation.
|
// implementation.
|
||||||
return deriveHashable_hashInto(TC, ConformanceDecl, Nominal,
|
return deriveHashable_hashInto(*this,
|
||||||
&deriveBodyHashable_compat_hashInto);
|
&deriveBodyHashable_compat_hashInto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,10 +80,7 @@ deriveBridgedNSError_enum_nsErrorDomain(DerivedConformance &derived) {
|
|||||||
derived.TC, propDecl, stringTy);
|
derived.TC, propDecl, stringTy);
|
||||||
getterDecl->setBodySynthesizer(&deriveBodyBridgedNSError_enum_nsErrorDomain);
|
getterDecl->setBodySynthesizer(&deriveBodyBridgedNSError_enum_nsErrorDomain);
|
||||||
|
|
||||||
auto dc = cast<IterableDeclContext>(derived.ConformanceDecl);
|
derived.addMembersToConformanceContext({getterDecl, propDecl, pbDecl});
|
||||||
dc->addMember(getterDecl);
|
|
||||||
dc->addMember(propDecl);
|
|
||||||
dc->addMember(pbDecl);
|
|
||||||
|
|
||||||
return propDecl;
|
return propDecl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,14 +50,13 @@ static LiteralExpr *cloneRawLiteralExpr(ASTContext &C, LiteralExpr *expr) {
|
|||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Type deriveRawRepresentable_Raw(TypeChecker &tc, Decl *parentDecl,
|
static Type deriveRawRepresentable_Raw(DerivedConformance &derived) {
|
||||||
EnumDecl *enumDecl) {
|
|
||||||
// enum SomeEnum : SomeType {
|
// enum SomeEnum : SomeType {
|
||||||
// @derived
|
// @derived
|
||||||
// typealias Raw = SomeType
|
// typealias Raw = SomeType
|
||||||
// }
|
// }
|
||||||
auto rawInterfaceType = enumDecl->getRawType();
|
auto rawInterfaceType = cast<EnumDecl>(derived.Nominal)->getRawType();
|
||||||
return cast<DeclContext>(parentDecl)->mapTypeIntoContext(rawInterfaceType);
|
return derived.getConformanceContext()->mapTypeIntoContext(rawInterfaceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deriveBodyRawRepresentable_raw(AbstractFunctionDecl *toRawDecl) {
|
static void deriveBodyRawRepresentable_raw(AbstractFunctionDecl *toRawDecl) {
|
||||||
@@ -122,11 +121,11 @@ static void deriveBodyRawRepresentable_raw(AbstractFunctionDecl *toRawDecl) {
|
|||||||
toRawDecl->setBody(body);
|
toRawDecl->setBody(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VarDecl *deriveRawRepresentable_raw(DerivedConformance &derived,
|
static VarDecl *deriveRawRepresentable_raw(DerivedConformance &derived) {
|
||||||
EnumDecl *enumDecl) {
|
|
||||||
ASTContext &C = derived.TC.Context;
|
ASTContext &C = derived.TC.Context;
|
||||||
|
|
||||||
auto parentDC = cast<DeclContext>(derived.ConformanceDecl);
|
auto enumDecl = cast<EnumDecl>(derived.Nominal);
|
||||||
|
auto parentDC = derived.getConformanceContext();
|
||||||
auto rawInterfaceType = enumDecl->getRawType();
|
auto rawInterfaceType = enumDecl->getRawType();
|
||||||
auto rawType = parentDC->mapTypeIntoContext(rawInterfaceType);
|
auto rawType = parentDC->mapTypeIntoContext(rawInterfaceType);
|
||||||
|
|
||||||
@@ -153,10 +152,7 @@ static VarDecl *deriveRawRepresentable_raw(DerivedConformance &derived,
|
|||||||
getterDecl->getAttrs().add(new (C) InlinableAttr(/*implicit*/false));
|
getterDecl->getAttrs().add(new (C) InlinableAttr(/*implicit*/false));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dc = cast<IterableDeclContext>(derived.ConformanceDecl);
|
derived.addMembersToConformanceContext({getterDecl, propDecl, pbDecl});
|
||||||
dc->addMember(getterDecl);
|
|
||||||
dc->addMember(propDecl);
|
|
||||||
dc->addMember(pbDecl);
|
|
||||||
|
|
||||||
return propDecl;
|
return propDecl;
|
||||||
}
|
}
|
||||||
@@ -279,12 +275,13 @@ deriveBodyRawRepresentable_init(AbstractFunctionDecl *initDecl) {
|
|||||||
initDecl->setBody(body);
|
initDecl->setBody(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstructorDecl *deriveRawRepresentable_init(TypeChecker &tc,
|
static ConstructorDecl *
|
||||||
Decl *parentDecl,
|
deriveRawRepresentable_init(DerivedConformance &derived) {
|
||||||
EnumDecl *enumDecl) {
|
auto &tc = derived.TC;
|
||||||
ASTContext &C = tc.Context;
|
ASTContext &C = tc.Context;
|
||||||
|
|
||||||
auto parentDC = cast<DeclContext>(parentDecl);
|
auto enumDecl = cast<EnumDecl>(derived.Nominal);
|
||||||
|
auto parentDC = derived.getConformanceContext();
|
||||||
auto rawInterfaceType = enumDecl->getRawType();
|
auto rawInterfaceType = enumDecl->getRawType();
|
||||||
auto rawType = parentDC->mapTypeIntoContext(rawInterfaceType);
|
auto rawType = parentDC->mapTypeIntoContext(rawInterfaceType);
|
||||||
|
|
||||||
@@ -362,14 +359,16 @@ static ConstructorDecl *deriveRawRepresentable_init(TypeChecker &tc,
|
|||||||
initDecl->getAttrs().add(new (C) InlinableAttr(/*implicit*/false));
|
initDecl->getAttrs().add(new (C) InlinableAttr(/*implicit*/false));
|
||||||
}
|
}
|
||||||
|
|
||||||
tc.Context.addSynthesizedDecl(initDecl);
|
C.addSynthesizedDecl(initDecl);
|
||||||
|
|
||||||
cast<IterableDeclContext>(parentDecl)->addMember(initDecl);
|
derived.addMembersToConformanceContext({initDecl});
|
||||||
return initDecl;
|
return initDecl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool canSynthesizeRawRepresentable(TypeChecker &tc, Decl *parentDecl,
|
static bool canSynthesizeRawRepresentable(DerivedConformance &derived) {
|
||||||
EnumDecl *enumDecl) {
|
auto enumDecl = cast<EnumDecl>(derived.Nominal);
|
||||||
|
auto &tc = derived.TC;
|
||||||
|
|
||||||
// Validate the enum and its raw type.
|
// Validate the enum and its raw type.
|
||||||
tc.validateDecl(enumDecl);
|
tc.validateDecl(enumDecl);
|
||||||
|
|
||||||
@@ -377,7 +376,7 @@ static bool canSynthesizeRawRepresentable(TypeChecker &tc, Decl *parentDecl,
|
|||||||
Type rawType = enumDecl->getRawType();
|
Type rawType = enumDecl->getRawType();
|
||||||
if (!rawType)
|
if (!rawType)
|
||||||
return false;
|
return false;
|
||||||
auto parentDC = cast<DeclContext>(parentDecl);
|
auto parentDC = cast<DeclContext>(derived.ConformanceDecl);
|
||||||
rawType = parentDC->mapTypeIntoContext(rawType);
|
rawType = parentDC->mapTypeIntoContext(rawType);
|
||||||
|
|
||||||
auto inherited = enumDecl->getInherited();
|
auto inherited = enumDecl->getInherited();
|
||||||
@@ -387,8 +386,8 @@ static bool canSynthesizeRawRepresentable(TypeChecker &tc, Decl *parentDecl,
|
|||||||
|
|
||||||
// The raw type must be Equatable, so that we have a suitable ~= for
|
// The raw type must be Equatable, so that we have a suitable ~= for
|
||||||
// synthesized switch statements.
|
// synthesized switch statements.
|
||||||
auto equatableProto = tc.getProtocol(enumDecl->getLoc(),
|
auto equatableProto =
|
||||||
KnownProtocolKind::Equatable);
|
tc.getProtocol(enumDecl->getLoc(), KnownProtocolKind::Equatable);
|
||||||
if (!equatableProto)
|
if (!equatableProto)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -416,19 +415,18 @@ static bool canSynthesizeRawRepresentable(TypeChecker &tc, Decl *parentDecl,
|
|||||||
ValueDecl *DerivedConformance::deriveRawRepresentable(ValueDecl *requirement) {
|
ValueDecl *DerivedConformance::deriveRawRepresentable(ValueDecl *requirement) {
|
||||||
|
|
||||||
// We can only synthesize RawRepresentable for enums.
|
// We can only synthesize RawRepresentable for enums.
|
||||||
auto enumDecl = dyn_cast<EnumDecl>(Nominal);
|
if (!isa<EnumDecl>(Nominal))
|
||||||
if (!enumDecl)
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Check other preconditions for synthesized conformance.
|
// Check other preconditions for synthesized conformance.
|
||||||
if (!canSynthesizeRawRepresentable(TC, ConformanceDecl, enumDecl))
|
if (!canSynthesizeRawRepresentable(*this))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (requirement->getBaseName() == TC.Context.Id_rawValue)
|
if (requirement->getBaseName() == TC.Context.Id_rawValue)
|
||||||
return deriveRawRepresentable_raw(*this, enumDecl);
|
return deriveRawRepresentable_raw(*this);
|
||||||
|
|
||||||
if (requirement->getBaseName() == DeclBaseName::createConstructor())
|
if (requirement->getBaseName() == DeclBaseName::createConstructor())
|
||||||
return deriveRawRepresentable_init(TC, ConformanceDecl, enumDecl);
|
return deriveRawRepresentable_init(*this);
|
||||||
|
|
||||||
TC.diagnose(requirement->getLoc(),
|
TC.diagnose(requirement->getLoc(),
|
||||||
diag::broken_raw_representable_requirement);
|
diag::broken_raw_representable_requirement);
|
||||||
@@ -438,16 +436,15 @@ ValueDecl *DerivedConformance::deriveRawRepresentable(ValueDecl *requirement) {
|
|||||||
Type DerivedConformance::deriveRawRepresentable(AssociatedTypeDecl *assocType) {
|
Type DerivedConformance::deriveRawRepresentable(AssociatedTypeDecl *assocType) {
|
||||||
|
|
||||||
// We can only synthesize RawRepresentable for enums.
|
// We can only synthesize RawRepresentable for enums.
|
||||||
auto enumDecl = dyn_cast<EnumDecl>(Nominal);
|
if (!isa<EnumDecl>(Nominal))
|
||||||
if (!enumDecl)
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Check other preconditions for synthesized conformance.
|
// Check other preconditions for synthesized conformance.
|
||||||
if (!canSynthesizeRawRepresentable(TC, ConformanceDecl, enumDecl))
|
if (!canSynthesizeRawRepresentable(*this))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (assocType->getName() == TC.Context.Id_RawValue) {
|
if (assocType->getName() == TC.Context.Id_RawValue) {
|
||||||
return deriveRawRepresentable_Raw(TC, ConformanceDecl, enumDecl);
|
return deriveRawRepresentable_Raw(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
TC.diagnose(assocType->getLoc(), diag::broken_raw_representable_requirement);
|
TC.diagnose(assocType->getLoc(), diag::broken_raw_representable_requirement);
|
||||||
|
|||||||
@@ -27,10 +27,26 @@ DerivedConformance::DerivedConformance(TypeChecker &tc, Decl *conformanceDecl,
|
|||||||
ProtocolDecl *protocol)
|
ProtocolDecl *protocol)
|
||||||
: TC(tc), ConformanceDecl(conformanceDecl), Nominal(nominal),
|
: TC(tc), ConformanceDecl(conformanceDecl), Nominal(nominal),
|
||||||
Protocol(protocol) {
|
Protocol(protocol) {
|
||||||
assert(cast<DeclContext>(conformanceDecl)
|
assert(getConformanceContext()
|
||||||
->getAsNominalTypeOrNominalTypeExtensionContext() == nominal);
|
->getAsNominalTypeOrNominalTypeExtensionContext() == nominal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeclContext *DerivedConformance::getConformanceContext() const {
|
||||||
|
return cast<DeclContext>(ConformanceDecl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DerivedConformance::addMembersToConformanceContext(
|
||||||
|
ArrayRef<Decl *> children) {
|
||||||
|
auto IDC = cast<IterableDeclContext>(ConformanceDecl);
|
||||||
|
for (auto child : children) {
|
||||||
|
IDC->addMember(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Type DerivedConformance::getProtocolType() const {
|
||||||
|
return Protocol->getDeclaredType();
|
||||||
|
}
|
||||||
|
|
||||||
bool DerivedConformance::derivesProtocolConformance(TypeChecker &TC,
|
bool DerivedConformance::derivesProtocolConformance(TypeChecker &TC,
|
||||||
NominalTypeDecl *Nominal,
|
NominalTypeDecl *Nominal,
|
||||||
ProtocolDecl *Protocol) {
|
ProtocolDecl *Protocol) {
|
||||||
|
|||||||
@@ -41,6 +41,16 @@ public:
|
|||||||
DerivedConformance(TypeChecker &tc, Decl *conformanceDecl,
|
DerivedConformance(TypeChecker &tc, Decl *conformanceDecl,
|
||||||
NominalTypeDecl *nominal, ProtocolDecl *protocol);
|
NominalTypeDecl *nominal, ProtocolDecl *protocol);
|
||||||
|
|
||||||
|
/// Retrieve the context in which the conformance is declared (either the
|
||||||
|
/// nominal type, or an extension of it) as a \c DeclContext.
|
||||||
|
DeclContext *getConformanceContext() const;
|
||||||
|
|
||||||
|
/// Add \c children as members of the context that declares the conformance.
|
||||||
|
void addMembersToConformanceContext(ArrayRef<Decl *> children);
|
||||||
|
|
||||||
|
/// Get the declared type of the protocol that this is conformance is for.
|
||||||
|
Type getProtocolType() const;
|
||||||
|
|
||||||
/// True if the type can implicitly derive a conformance for the given
|
/// True if the type can implicitly derive a conformance for the given
|
||||||
/// protocol.
|
/// protocol.
|
||||||
///
|
///
|
||||||
|
|||||||
Reference in New Issue
Block a user