[Sema] Migrate almost everything to use DerivedConformance.

This commit is contained in:
Huon Wilson
2018-05-04 14:49:54 +10:00
parent 41942c9276
commit cfd068de6a
8 changed files with 169 additions and 207 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
} }
} }
} }

View File

@@ -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);
} }
} }

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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.
/// ///