[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());
}
static Type deriveCaseIterable_AllCases(TypeChecker &tc, Decl *parentDecl,
EnumDecl *enumDecl) {
static Type deriveCaseIterable_AllCases(DerivedConformance &derived) {
// enum SomeEnum : CaseIterable {
// @derived
// typealias AllCases = [SomeEnum]
// }
auto *rawInterfaceType = computeAllCasesType(enumDecl);
return cast<DeclContext>(parentDecl)->mapTypeIntoContext(rawInterfaceType);
auto *rawInterfaceType = computeAllCasesType(cast<EnumDecl>(derived.Nominal));
return derived.getConformanceContext()->mapTypeIntoContext(rawInterfaceType);
}
ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) {
@@ -115,10 +114,7 @@ ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) {
getterDecl->setBodySynthesizer(&deriveCaseIterable_enum_getter);
auto dc = cast<IterableDeclContext>(ConformanceDecl);
dc->addMember(getterDecl);
dc->addMember(propDecl);
dc->addMember(pbDecl);
addMembersToConformanceContext({getterDecl, propDecl, pbDecl});
return propDecl;
}
@@ -139,8 +135,7 @@ Type DerivedConformance::deriveCaseIterable(AssociatedTypeDecl *assocType) {
return nullptr;
if (assocType->getName() == TC.Context.Id_AllCases) {
auto enumDecl = cast<EnumDecl>(Nominal);
return deriveCaseIterable_AllCases(TC, ConformanceDecl, enumDecl);
return deriveCaseIterable_AllCases(*this);
}
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
/// 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 target The nominal type decl to validate the \c CodingKeys against.
///
/// \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) {
static bool validateCodingKeysEnum(DerivedConformance &derived,
EnumDecl *codingKeysDecl) {
auto &tc = derived.TC;
// Look through all var decls in the given type.
// * Filter out lazy/computed vars.
// * 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
// against its CodingKey entry, it will get removed.
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>())
continue;
@@ -187,8 +182,8 @@ validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl,
}
// We have a property to map to. Ensure it's {En,De}codable.
auto conformance = varConformsToCodable(tc, target->getDeclContext(),
it->second, proto);
auto conformance = varConformsToCodable(
tc, derived.Nominal->getDeclContext(), it->second, derived.Protocol);
switch (conformance) {
case Conforms:
// The property was valid. Remove it from the list.
@@ -198,7 +193,7 @@ validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl,
case DoesNotConform:
tc.diagnose(it->second->getLoc(),
diag::codable_non_conforming_property_here,
proto->getDeclaredType(), it->second->getType());
derived.getProtocolType(), it->second->getType());
LLVM_FALLTHROUGH;
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
// they have a default value.
if (!properties.empty() &&
proto->isSpecificProtocol(KnownProtocolKind::Decodable)) {
derived.Protocol->isSpecificProtocol(KnownProtocolKind::Decodable)) {
for (auto it = properties.begin(); it != properties.end(); ++it) {
// If the var is default initializable, then it need not have an explicit
// initial value.
@@ -233,7 +228,7 @@ validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl,
// initial value.
propertiesAreValid = false;
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
/// 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.
static CodingKeysValidity hasValidCodingKeysEnum(TypeChecker &tc,
NominalTypeDecl *target,
ProtocolDecl *proto) {
static CodingKeysValidity hasValidCodingKeysEnum(DerivedConformance &derived) {
auto &tc = derived.TC;
auto &C = tc.Context;
auto codingKeysDecls = target->lookupDirect(DeclName(C.Id_CodingKeys));
auto codingKeysDecls =
derived.Nominal->lookupDirect(DeclName(C.Id_CodingKeys));
if (codingKeysDecls.empty())
return CodingKeysValidity(/*hasType=*/false, /*isValid=*/true);
@@ -281,7 +269,7 @@ static CodingKeysValidity hasValidCodingKeysEnum(TypeChecker &tc,
if (!codingKeysTypeDecl) {
tc.diagnose(result->getLoc(),
diag::codable_codingkeys_type_is_not_an_enum_here,
proto->getDeclaredType());
derived.getProtocolType());
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.
auto *codingKeyProto = C.getProtocol(KnownProtocolKind::CodingKey);
if (!tc.conformsToProtocol(codingKeysType, codingKeyProto,
target->getDeclContext(),
derived.Nominal->getDeclContext(),
ConformanceCheckFlags::Used)) {
// 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
@@ -308,7 +296,7 @@ static CodingKeysValidity hasValidCodingKeysEnum(TypeChecker &tc,
cast<TypeDecl>(result)->getLoc();
tc.diagnose(loc, diag::codable_codingkeys_type_does_not_conform_here,
proto->getDeclaredType());
derived.getProtocolType());
return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false);
}
@@ -318,29 +306,20 @@ static CodingKeysValidity hasValidCodingKeysEnum(TypeChecker &tc,
if (!codingKeysEnum) {
tc.diagnose(codingKeysTypeDecl->getLoc(),
diag::codable_codingkeys_type_is_not_an_enum_here,
proto->getDeclaredType());
derived.getProtocolType());
return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false);
}
bool valid = validateCodingKeysEnum(tc, codingKeysEnum, target, proto);
bool valid = validateCodingKeysEnum(derived, codingKeysEnum);
return CodingKeysValidity(/*hasType=*/true, /*isValid=*/valid);
}
/// Synthesizes a new \c CodingKeys enum based on the {En,De}codable members of
/// the given type (\c nullptr if unable to synthesize).
///
/// If able to synthesize the enum, adds it directly to \c type.
///
/// \param tc The typechecker to use in validating {En,De}codable conformance.
///
/// \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) {
/// If able to synthesize the enum, adds it directly to \c derived.Nominal.
static EnumDecl *synthesizeCodingKeysEnum(DerivedConformance &derived) {
auto &tc = derived.TC;
auto &C = tc.Context;
// 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)};
MutableArrayRef<TypeLoc> inherited = C.AllocateCopy(protoTypeLoc);
auto target = derived.Nominal;
auto *enumDecl = new (C) EnumDecl(SourceLoc(), C.Id_CodingKeys, SourceLoc(),
inherited, nullptr, target);
enumDecl->setImplicit();
@@ -377,7 +357,7 @@ static EnumDecl *synthesizeCodingKeysEnum(TypeChecker &tc,
continue;
auto conformance = varConformsToCodable(tc, target->getDeclContext(),
varDecl, proto);
varDecl, derived.Protocol);
switch (conformance) {
case Conforms:
{
@@ -392,7 +372,7 @@ static EnumDecl *synthesizeCodingKeysEnum(TypeChecker &tc,
case DoesNotConform:
tc.diagnose(varDecl->getLoc(),
diag::codable_non_conforming_property_here,
proto->getDeclaredType(), varDecl->getType());
derived.getProtocolType(), varDecl->getType());
LLVM_FALLTHROUGH;
case TypeNotValidated:
@@ -703,15 +683,10 @@ static void deriveBodyEncodable_encode(AbstractFunctionDecl *encodeDecl) {
/// lazily synthesized body for the given type.
///
/// Adds the function declaration to the given type before returning it.
///
/// \param tc The type checker whose AST context to synthesize the decl in.
///
/// \param parentDecl The parent declaration of the type.
///
/// \param target The nominal type to synthesize the function for.
static FuncDecl *deriveEncodable_encode(TypeChecker &tc, Decl *parentDecl,
NominalTypeDecl *target) {
auto &C = tc.Context;
static FuncDecl *deriveEncodable_encode(DerivedConformance &derived) {
auto &C = derived.TC.Context;
auto target = derived.Nominal;
// Expected type: (Self) -> (Encoder) throws -> ()
// Constructed as: func type
@@ -783,7 +758,7 @@ static FuncDecl *deriveEncodable_encode(TypeChecker &tc, Decl *parentDecl,
encodeDecl->setValidationStarted();
encodeDecl->copyFormalAccessFrom(target, /*sourceIsParentContext*/true);
tc.Context.addSynthesizedDecl(encodeDecl);
C.addSynthesizedDecl(encodeDecl);
target->addMember(encodeDecl);
return encodeDecl;
@@ -1034,15 +1009,10 @@ static void deriveBodyDecodable_init(AbstractFunctionDecl *initDecl) {
/// lazily synthesized body for the given type.
///
/// Adds the function declaration to the given type before returning it.
///
/// \param tc The type checker whose AST context to synthesize the decl in.
///
/// \param parentDecl The parent declaration of the type.
///
/// \param target The nominal type to synthesize the function for.
static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl,
NominalTypeDecl *target) {
auto &C = tc.Context;
static ValueDecl *deriveDecodable_init(DerivedConformance &derived) {
auto &C = derived.TC.Context;
auto target = derived.Nominal;
// Expected type: (Self) -> (Decoder) throws -> (Self)
// Constructed as: func type
@@ -1123,9 +1093,9 @@ static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl,
initDecl->setInitializerInterfaceType(initializerType);
initDecl->copyFormalAccessFrom(target, /*sourceIsParentContext*/true);
tc.Context.addSynthesizedDecl(initDecl);
C.addSynthesizedDecl(initDecl);
target->addMember(initDecl);
derived.addMembersToConformanceContext({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
/// 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 proto The *codable protocol to check for validity.
static bool canSynthesize(TypeChecker &tc, NominalTypeDecl *target,
ValueDecl *requirement, ProtocolDecl *proto) {
static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) {
// 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.
//
@@ -1153,8 +1116,10 @@ static bool canSynthesize(TypeChecker &tc, NominalTypeDecl *target,
//
// If the required initializer is not available, we shouldn't attempt to
// synthesize CodingKeys.
auto &tc = derived.TC;
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 (auto *superclassDecl = classDecl->getSuperclassDecl()) {
DeclName memberName;
@@ -1192,9 +1157,9 @@ static bool canSynthesize(TypeChecker &tc, NominalTypeDecl *target,
diag::decodable_super_init_not_designated_here,
requirement->getFullName(), memberName);
return false;
} else if (!initializer->isAccessibleFrom(target)) {
} else if (!initializer->isAccessibleFrom(classDecl)) {
// Cannot call an inaccessible method.
auto accessScope = initializer->getFormalAccessScope(target);
auto accessScope = initializer->getFormalAccessScope(classDecl);
tc.diagnose(initializer, diag::decodable_inaccessible_super_init_here,
requirement->getFullName(), memberName,
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
// synthesize one.
auto validity = hasValidCodingKeysEnum(tc, target, proto);
auto validity = hasValidCodingKeysEnum(derived);
// We found a type, but it wasn't valid.
if (!validity.isValid)
@@ -1220,7 +1185,7 @@ static bool canSynthesize(TypeChecker &tc, NominalTypeDecl *target,
// We can try to synthesize a type here.
if (!validity.hasType) {
auto *synthesizedEnum = synthesizeCodingKeysEnum(tc, target, proto);
auto *synthesizedEnum = synthesizeCodingKeysEnum(derived);
if (!synthesizedEnum)
return false;
}
@@ -1271,9 +1236,9 @@ ValueDecl *DerivedConformance::deriveEncodable(ValueDecl *requirement) {
// Check other preconditions for synthesized conformance.
// This synthesizes a CodingKeys enum if possible.
if (canSynthesize(TC, Nominal, requirement, encodableProto)) {
if (canSynthesize(*this, requirement)) {
diagnosticTransaction.abort();
return deriveEncodable_encode(TC, ConformanceDecl, Nominal);
return deriveEncodable_encode(*this);
}
return nullptr;
@@ -1313,9 +1278,9 @@ ValueDecl *DerivedConformance::deriveDecodable(ValueDecl *requirement) {
// Check other preconditions for synthesized conformance.
// This synthesizes a CodingKeys enum if possible.
if (canSynthesize(TC, Nominal, requirement, decodableProto)) {
if (canSynthesize(*this, requirement)) {
diagnosticTransaction.abort();
return deriveDecodable_init(TC, ConformanceDecl, Nominal);
return deriveDecodable_init(*this);
}
return nullptr;

View File

@@ -102,24 +102,17 @@ static void deriveRawValueInit(AbstractFunctionDecl *initDecl) {
/// Synthesizes a constructor declaration with the given parameter name and
/// type.
///
/// \param tc The type checker to use in synthesizing the constructor.
///
/// \param parentDecl The parent declaration of the enum.
///
/// \param enumDecl The enum on which to synthesize the constructor.
///
/// \param paramType The type of the parameter.
///
/// \param paramName The name of the parameter.
///
/// \param synthesizer A lambda to call to set the constructor's body.
template <typename Synthesizer>
static ValueDecl *deriveInitDecl(TypeChecker &tc, Decl *parentDecl,
EnumDecl *enumDecl, Type paramType,
static ValueDecl *deriveInitDecl(DerivedConformance &derived, Type paramType,
Identifier paramName,
const Synthesizer &synthesizer) {
auto &C = tc.Context;
auto *parentDC = cast<DeclContext>(parentDecl);
auto &C = derived.TC.Context;
auto *parentDC = derived.getConformanceContext();
// rawValue
auto *rawDecl =
@@ -179,12 +172,12 @@ static ValueDecl *deriveInitDecl(TypeChecker &tc, Decl *parentDecl,
}
initDecl->setInterfaceType(allocIfaceType);
initDecl->setInitializerInterfaceType(initIfaceType);
initDecl->setAccess(enumDecl->getFormalAccess());
initDecl->setAccess(derived.Nominal->getFormalAccess());
initDecl->setValidationStarted();
tc.Context.addSynthesizedDecl(initDecl);
C.addSynthesizedDecl(initDecl);
cast<IterableDeclContext>(parentDecl)->addMember(initDecl);
derived.addMembersToConformanceContext({initDecl});
return initDecl;
}
@@ -366,24 +359,18 @@ deriveBodyCodingKey_init_stringValue(AbstractFunctionDecl *initDecl) {
}
/// Returns whether the given enum is eligible for CodingKey synthesis.
///
/// \param tc The type checker to use in checking eligibility.
///
/// \param parentDecl The parent declaration of the enum.
///
/// \param enumDecl The enum to check.
static bool canSynthesizeCodingKey(TypeChecker &tc, Decl *parentDecl,
EnumDecl *enumDecl) {
static bool canSynthesizeCodingKey(DerivedConformance &derived) {
auto enumDecl = cast<EnumDecl>(derived.Nominal);
// 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.
Type rawType = enumDecl->getRawType();
if (rawType) {
auto *parentDC = cast<DeclContext>(parentDecl);
auto *parentDC = derived.getConformanceContext();
rawType = parentDC->mapTypeIntoContext(rawType);
auto &C = tc.Context;
auto &C = derived.TC.Context;
auto *nominal = rawType->getCanonicalType()->getAnyNominal();
if (nominal != C.getStringDecl() && nominal != C.getIntDecl())
return false;
@@ -407,7 +394,7 @@ ValueDecl *DerivedConformance::deriveCodingKey(ValueDecl *requirement) {
return nullptr;
// Check other preconditions for synthesized conformance.
if (!canSynthesizeCodingKey(TC, Nominal, enumDecl))
if (!canSynthesizeCodingKey(*this))
return nullptr;
auto &C = TC.Context;
@@ -505,8 +492,7 @@ ValueDecl *DerivedConformance::deriveCodingKey(ValueDecl *requirement) {
}
};
return deriveInitDecl(TC, ConformanceDecl, enumDecl, stringType,
C.Id_stringValue, synth);
return deriveInitDecl(*this, stringType, C.Id_stringValue, synth);
} else if (argumentNames[0] == C.Id_intValue) {
// Synthesize `init?(intValue:)`
auto intType = C.getIntDecl()->getDeclaredType();
@@ -530,8 +516,7 @@ ValueDecl *DerivedConformance::deriveCodingKey(ValueDecl *requirement) {
}
};
return deriveInitDecl(TC, ConformanceDecl, enumDecl, intType,
C.Id_intValue, synthesizer);
return deriveInitDecl(*this, intType, 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.
static ValueDecl *
deriveEquatable_eq(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *typeDecl,
Identifier generatedIdentifier,
deriveEquatable_eq(DerivedConformance &derived, Identifier generatedIdentifier,
void (*bodySynthesizer)(AbstractFunctionDecl *)) {
// enum SomeEnum<T...> {
// 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 enumIfaceTy = parentDC->getDeclaredInterfaceType();
@@ -634,14 +633,15 @@ deriveEquatable_eq(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *typeDecl,
DeclNameLoc()));
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;
}
eqDecl->setBodySynthesizer(bodySynthesizer);
// Compute the type.
Type paramsTy = params[1]->getType(tc.Context);
Type paramsTy = params[1]->getType(C);
// Compute the interface type.
Type interfaceTy;
@@ -664,13 +664,13 @@ deriveEquatable_eq(TypeChecker &tc, Decl *parentDecl, NominalTypeDecl *typeDecl,
FunctionType::ExtInfo());
}
eqDecl->setInterfaceType(interfaceTy);
eqDecl->copyFormalAccessFrom(typeDecl, /*sourceIsParentContext*/true);
eqDecl->copyFormalAccessFrom(derived.Nominal, /*sourceIsParentContext*/ true);
eqDecl->setValidationStarted();
tc.Context.addSynthesizedDecl(eqDecl);
C.addSynthesizedDecl(eqDecl);
// Add the operator to the parent scope.
cast<IterableDeclContext>(parentDecl)->addMember(eqDecl);
derived.addMembersToConformanceContext({eqDecl});
return eqDecl;
}
@@ -701,12 +701,10 @@ ValueDecl *DerivedConformance::deriveEquatable(ValueDecl *requirement) {
theEnum->hasOnlyCasesWithoutAssociatedValues()
? &deriveBodyEquatable_enum_noAssociatedValues_eq
: &deriveBodyEquatable_enum_hasAssociatedValues_eq;
return deriveEquatable_eq(TC, ConformanceDecl, theEnum,
TC.Context.Id_derived_enum_equals,
return deriveEquatable_eq(*this, TC.Context.Id_derived_enum_equals,
bodySynthesizer);
} else if (auto theStruct = dyn_cast<StructDecl>(Nominal))
return deriveEquatable_eq(TC, ConformanceDecl, theStruct,
TC.Context.Id_derived_struct_equals,
} else if (isa<StructDecl>(Nominal))
return deriveEquatable_eq(*this, TC.Context.Id_derived_struct_equals,
&deriveBodyEquatable_struct_eq);
else
llvm_unreachable("todo");
@@ -740,13 +738,12 @@ static CallExpr *createHasherCombineCall(ASTContext &C,
}
static FuncDecl *
deriveHashable_hashInto(TypeChecker &tc, Decl *parentDecl,
NominalTypeDecl *typeDecl,
deriveHashable_hashInto(DerivedConformance &derived,
void (*bodySynthesizer)(AbstractFunctionDecl *)) {
// @derived func hash(into hasher: inout Hasher)
ASTContext &C = tc.Context;
auto parentDC = cast<DeclContext>(parentDecl);
ASTContext &C = derived.TC.Context;
auto parentDC = derived.getConformanceContext();
// Expected type: (Self) -> (into: inout Hasher) -> ()
// Constructed as:
@@ -757,8 +754,9 @@ deriveHashable_hashInto(TypeChecker &tc, Decl *parentDecl,
auto hasherDecl = C.getHasherDecl();
if (!hasherDecl) {
auto hashableProto = tc.Context.getProtocol(KnownProtocolKind::Hashable);
tc.diagnose(hashableProto->getLoc(), diag::broken_hashable_no_hasher);
auto hashableProto = C.getProtocol(KnownProtocolKind::Hashable);
derived.TC.diagnose(hashableProto->getLoc(),
diag::broken_hashable_no_hasher);
return nullptr;
}
Type hasherType = hasherDecl->getDeclaredType();
@@ -807,12 +805,12 @@ deriveHashable_hashInto(TypeChecker &tc, Decl *parentDecl,
FunctionType::ExtInfo());
}
hashDecl->setInterfaceType(interfaceType);
hashDecl->copyFormalAccessFrom(typeDecl);
hashDecl->copyFormalAccessFrom(derived.Nominal);
hashDecl->setValidationStarted();
C.addSynthesizedDecl(hashDecl);
cast<IterableDeclContext>(parentDecl)->addMember(hashDecl);
derived.addMembersToConformanceContext({hashDecl});
return hashDecl;
}
@@ -1038,29 +1036,30 @@ deriveBodyHashable_hashValue(AbstractFunctionDecl *hashValueDecl) {
}
/// Derive a 'hashValue' implementation.
static ValueDecl *
deriveHashable_hashValue(TypeChecker &tc, Decl *parentDecl,
NominalTypeDecl *typeDecl) {
static ValueDecl *deriveHashable_hashValue(DerivedConformance &derived) {
// @derived var hashValue: Int {
// return _hashValue(for: self)
// }
auto &tc = derived.TC;
ASTContext &C = tc.Context;
auto parentDC = cast<DeclContext>(parentDecl);
auto parentDC = derived.getConformanceContext();
Type intType = C.getIntDecl()->getDeclaredType();
// We can't form a Hashable conformance if Int isn't Hashable or
// ExpressibleByIntegerLiteral.
if (!tc.conformsToProtocol(intType,C.getProtocol(KnownProtocolKind::Hashable),
typeDecl, None)) {
tc.diagnose(typeDecl->getLoc(), diag::broken_int_hashable_conformance);
if (!tc.conformsToProtocol(intType,
C.getProtocol(KnownProtocolKind::Hashable),
derived.Nominal, None)) {
tc.diagnose(derived.Nominal->getLoc(),
diag::broken_int_hashable_conformance);
return nullptr;
}
ProtocolDecl *intLiteralProto =
C.getProtocol(KnownProtocolKind::ExpressibleByIntegerLiteral);
if (!tc.conformsToProtocol(intType, intLiteralProto, typeDecl, None)) {
tc.diagnose(typeDecl->getLoc(),
if (!tc.conformsToProtocol(intType, intLiteralProto, derived.Nominal, None)) {
tc.diagnose(derived.Nominal->getLoc(),
diag::broken_int_integer_literal_convertible_conformance);
return nullptr;
}
@@ -1088,7 +1087,7 @@ deriveHashable_hashValue(TypeChecker &tc, Decl *parentDecl,
getterDecl->setBodySynthesizer(&deriveBodyHashable_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().
Type interfaceType;
@@ -1103,7 +1102,8 @@ deriveHashable_hashValue(TypeChecker &tc, Decl *parentDecl,
getterDecl->setInterfaceType(interfaceType);
getterDecl->setValidationStarted();
getterDecl->copyFormalAccessFrom(typeDecl, /*sourceIsParentContext*/true);
getterDecl->copyFormalAccessFrom(derived.Nominal,
/*sourceIsParentContext*/ true);
// Finish creating the property.
hashValueDecl->setImplicit();
@@ -1111,7 +1111,8 @@ deriveHashable_hashValue(TypeChecker &tc, Decl *parentDecl,
hashValueDecl->setValidationStarted();
hashValueDecl->makeComputed(SourceLoc(), getterDecl,
nullptr, nullptr, SourceLoc());
hashValueDecl->copyFormalAccessFrom(typeDecl, /*sourceIsParentContext*/true);
hashValueDecl->copyFormalAccessFrom(derived.Nominal,
/*sourceIsParentContext*/ true);
Pattern *hashValuePat = new (C) NamedPattern(hashValueDecl, /*implicit*/true);
hashValuePat->setType(intType);
@@ -1126,13 +1127,10 @@ deriveHashable_hashValue(TypeChecker &tc, Decl *parentDecl,
parentDC);
patDecl->setImplicit();
tc.Context.addSynthesizedDecl(hashValueDecl);
tc.Context.addSynthesizedDecl(getterDecl);
C.addSynthesizedDecl(hashValueDecl);
C.addSynthesizedDecl(getterDecl);
auto dc = cast<IterableDeclContext>(parentDecl);
dc->addMember(getterDecl);
dc->addMember(hashValueDecl);
dc->addMember(patDecl);
derived.addMembersToConformanceContext({getterDecl, hashValueDecl, patDecl});
return hashValueDecl;
}
@@ -1180,7 +1178,7 @@ ValueDecl *DerivedConformance::deriveHashable(ValueDecl *requirement) {
if (requirement->getBaseName() == C.Id_hashValue) {
// We always allow hashValue to be synthesized; invalid cases are diagnosed
// during hash(into:) synthesis.
return deriveHashable_hashValue(TC, ConformanceDecl, Nominal);
return deriveHashable_hashValue(*this);
}
// Hashable.hash(into:)
@@ -1223,10 +1221,9 @@ ValueDecl *DerivedConformance::deriveHashable(ValueDecl *requirement) {
auto bodySynthesizer = hasAssociatedValues
? &deriveBodyHashable_enum_hasAssociatedValues_hashInto
: &deriveBodyHashable_enum_noAssociatedValues_hashInto;
return deriveHashable_hashInto(TC, ConformanceDecl, theEnum,
bodySynthesizer);
} else if (auto theStruct = dyn_cast<StructDecl>(Nominal))
return deriveHashable_hashInto(TC, ConformanceDecl, theStruct,
return deriveHashable_hashInto(*this, bodySynthesizer);
} else if (isa<StructDecl>(Nominal))
return deriveHashable_hashInto(*this,
&deriveBodyHashable_struct_hashInto);
else // This should've been caught by canDeriveHashable above.
llvm_unreachable("Attempt to derive Hashable for a type other "
@@ -1234,7 +1231,7 @@ ValueDecl *DerivedConformance::deriveHashable(ValueDecl *requirement) {
} else {
// We can always derive hash(into:) if hashValue has an explicit
// implementation.
return deriveHashable_hashInto(TC, ConformanceDecl, Nominal,
return deriveHashable_hashInto(*this,
&deriveBodyHashable_compat_hashInto);
}
}

View File

@@ -80,10 +80,7 @@ deriveBridgedNSError_enum_nsErrorDomain(DerivedConformance &derived) {
derived.TC, propDecl, stringTy);
getterDecl->setBodySynthesizer(&deriveBodyBridgedNSError_enum_nsErrorDomain);
auto dc = cast<IterableDeclContext>(derived.ConformanceDecl);
dc->addMember(getterDecl);
dc->addMember(propDecl);
dc->addMember(pbDecl);
derived.addMembersToConformanceContext({getterDecl, propDecl, pbDecl});
return propDecl;
}

View File

@@ -50,14 +50,13 @@ static LiteralExpr *cloneRawLiteralExpr(ASTContext &C, LiteralExpr *expr) {
return clone;
}
static Type deriveRawRepresentable_Raw(TypeChecker &tc, Decl *parentDecl,
EnumDecl *enumDecl) {
static Type deriveRawRepresentable_Raw(DerivedConformance &derived) {
// enum SomeEnum : SomeType {
// @derived
// typealias Raw = SomeType
// }
auto rawInterfaceType = enumDecl->getRawType();
return cast<DeclContext>(parentDecl)->mapTypeIntoContext(rawInterfaceType);
auto rawInterfaceType = cast<EnumDecl>(derived.Nominal)->getRawType();
return derived.getConformanceContext()->mapTypeIntoContext(rawInterfaceType);
}
static void deriveBodyRawRepresentable_raw(AbstractFunctionDecl *toRawDecl) {
@@ -122,11 +121,11 @@ static void deriveBodyRawRepresentable_raw(AbstractFunctionDecl *toRawDecl) {
toRawDecl->setBody(body);
}
static VarDecl *deriveRawRepresentable_raw(DerivedConformance &derived,
EnumDecl *enumDecl) {
static VarDecl *deriveRawRepresentable_raw(DerivedConformance &derived) {
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 rawType = parentDC->mapTypeIntoContext(rawInterfaceType);
@@ -153,10 +152,7 @@ static VarDecl *deriveRawRepresentable_raw(DerivedConformance &derived,
getterDecl->getAttrs().add(new (C) InlinableAttr(/*implicit*/false));
}
auto dc = cast<IterableDeclContext>(derived.ConformanceDecl);
dc->addMember(getterDecl);
dc->addMember(propDecl);
dc->addMember(pbDecl);
derived.addMembersToConformanceContext({getterDecl, propDecl, pbDecl});
return propDecl;
}
@@ -279,12 +275,13 @@ deriveBodyRawRepresentable_init(AbstractFunctionDecl *initDecl) {
initDecl->setBody(body);
}
static ConstructorDecl *deriveRawRepresentable_init(TypeChecker &tc,
Decl *parentDecl,
EnumDecl *enumDecl) {
static ConstructorDecl *
deriveRawRepresentable_init(DerivedConformance &derived) {
auto &tc = derived.TC;
ASTContext &C = tc.Context;
auto parentDC = cast<DeclContext>(parentDecl);
auto enumDecl = cast<EnumDecl>(derived.Nominal);
auto parentDC = derived.getConformanceContext();
auto rawInterfaceType = enumDecl->getRawType();
auto rawType = parentDC->mapTypeIntoContext(rawInterfaceType);
@@ -362,14 +359,16 @@ static ConstructorDecl *deriveRawRepresentable_init(TypeChecker &tc,
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;
}
static bool canSynthesizeRawRepresentable(TypeChecker &tc, Decl *parentDecl,
EnumDecl *enumDecl) {
static bool canSynthesizeRawRepresentable(DerivedConformance &derived) {
auto enumDecl = cast<EnumDecl>(derived.Nominal);
auto &tc = derived.TC;
// Validate the enum and its raw type.
tc.validateDecl(enumDecl);
@@ -377,7 +376,7 @@ static bool canSynthesizeRawRepresentable(TypeChecker &tc, Decl *parentDecl,
Type rawType = enumDecl->getRawType();
if (!rawType)
return false;
auto parentDC = cast<DeclContext>(parentDecl);
auto parentDC = cast<DeclContext>(derived.ConformanceDecl);
rawType = parentDC->mapTypeIntoContext(rawType);
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
// synthesized switch statements.
auto equatableProto = tc.getProtocol(enumDecl->getLoc(),
KnownProtocolKind::Equatable);
auto equatableProto =
tc.getProtocol(enumDecl->getLoc(), KnownProtocolKind::Equatable);
if (!equatableProto)
return false;
@@ -416,19 +415,18 @@ static bool canSynthesizeRawRepresentable(TypeChecker &tc, Decl *parentDecl,
ValueDecl *DerivedConformance::deriveRawRepresentable(ValueDecl *requirement) {
// We can only synthesize RawRepresentable for enums.
auto enumDecl = dyn_cast<EnumDecl>(Nominal);
if (!enumDecl)
if (!isa<EnumDecl>(Nominal))
return nullptr;
// Check other preconditions for synthesized conformance.
if (!canSynthesizeRawRepresentable(TC, ConformanceDecl, enumDecl))
if (!canSynthesizeRawRepresentable(*this))
return nullptr;
if (requirement->getBaseName() == TC.Context.Id_rawValue)
return deriveRawRepresentable_raw(*this, enumDecl);
return deriveRawRepresentable_raw(*this);
if (requirement->getBaseName() == DeclBaseName::createConstructor())
return deriveRawRepresentable_init(TC, ConformanceDecl, enumDecl);
return deriveRawRepresentable_init(*this);
TC.diagnose(requirement->getLoc(),
diag::broken_raw_representable_requirement);
@@ -438,16 +436,15 @@ ValueDecl *DerivedConformance::deriveRawRepresentable(ValueDecl *requirement) {
Type DerivedConformance::deriveRawRepresentable(AssociatedTypeDecl *assocType) {
// We can only synthesize RawRepresentable for enums.
auto enumDecl = dyn_cast<EnumDecl>(Nominal);
if (!enumDecl)
if (!isa<EnumDecl>(Nominal))
return nullptr;
// Check other preconditions for synthesized conformance.
if (!canSynthesizeRawRepresentable(TC, ConformanceDecl, enumDecl))
if (!canSynthesizeRawRepresentable(*this))
return nullptr;
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);

View File

@@ -27,10 +27,26 @@ DerivedConformance::DerivedConformance(TypeChecker &tc, Decl *conformanceDecl,
ProtocolDecl *protocol)
: TC(tc), ConformanceDecl(conformanceDecl), Nominal(nominal),
Protocol(protocol) {
assert(cast<DeclContext>(conformanceDecl)
assert(getConformanceContext()
->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,
NominalTypeDecl *Nominal,
ProtocolDecl *Protocol) {

View File

@@ -41,6 +41,16 @@ public:
DerivedConformance(TypeChecker &tc, Decl *conformanceDecl,
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
/// protocol.
///