本文整理汇总了C++中TypeChecker类的典型用法代码示例。如果您正苦于以下问题:C++ TypeChecker类的具体用法?C++ TypeChecker怎么用?C++ TypeChecker使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了TypeChecker类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: computeSelfTypeRelationship
/// Determine the relationship between the self types of the given declaration
/// contexts..
static SelfTypeRelationship computeSelfTypeRelationship(TypeChecker &tc,
DeclContext *dc,
DeclContext *dc1,
DeclContext *dc2){
// If at least one of the contexts is a non-type context, the two are
// unrelated.
if (!dc1->isTypeContext() || !dc2->isTypeContext())
return SelfTypeRelationship::Unrelated;
Type type1 = dc1->getDeclaredInterfaceType();
Type type2 = dc2->getDeclaredInterfaceType();
// If the types are equal, the answer is simple.
if (type1->isEqual(type2))
return SelfTypeRelationship::Equivalent;
// If both types can have superclasses, which whether one is a superclass
// of the other. The subclass is the common base type.
if (type1->mayHaveSuperclass() && type2->mayHaveSuperclass()) {
if (isNominallySuperclassOf(tc, type1, type2))
return SelfTypeRelationship::Superclass;
if (isNominallySuperclassOf(tc, type2, type1))
return SelfTypeRelationship::Subclass;
return SelfTypeRelationship::Unrelated;
}
// If neither or both are protocol types, consider the bases unrelated.
bool isProtocol1 = isa<ProtocolDecl>(dc1);
bool isProtocol2 = isa<ProtocolDecl>(dc2);
if (isProtocol1 == isProtocol2)
return SelfTypeRelationship::Unrelated;
// Just one of the two is a protocol. Check whether the other conforms to
// that protocol.
Type protoTy = isProtocol1? type1 : type2;
Type modelTy = isProtocol1? type2 : type1;
auto proto = protoTy->castTo<ProtocolType>()->getDecl();
// If the model type does not conform to the protocol, the bases are
// unrelated.
if (!tc.conformsToProtocol(modelTy, proto, dc,
ConformanceCheckFlags::InExpression))
return SelfTypeRelationship::Unrelated;
return isProtocol1? SelfTypeRelationship::ConformedToBy
: SelfTypeRelationship::ConformsTo;
}
示例2: typeCheck
void ArraySetElementAST::typeCheck(TypeChecker& checker) {
mArrayRefExpression->typeCheck(checker);
mAccessExpression->typeCheck(checker);
mRightHandSide->typeCheck(checker);
//Check if array
auto arrayRefType = std::dynamic_pointer_cast<ArrayType>(mArrayRefExpression->expressionType(checker));
if (arrayRefType == nullptr) {
checker.typeError("The expression '" + mArrayRefExpression->asString() + "' is not of array type.");
}
//Access access
checker.assertSameType(
*checker.makeType("Int"),
*mAccessExpression->expressionType(checker),
"Expected the array indexing to be of type 'Int'.");
//Check rhs
checker.assertSameType(
*arrayRefType->elementType(),
*mRightHandSide->expressionType(checker),
asString());
}
示例3: getTypeOfCompletionContextExpr
static Optional<Type> getTypeOfCompletionContextExpr(
TypeChecker &TC,
DeclContext *DC,
CompletionTypeCheckKind kind,
Expr *&parsedExpr,
ConcreteDeclRef &referencedDecl) {
switch (kind) {
case CompletionTypeCheckKind::Normal:
// Handle below.
break;
case CompletionTypeCheckKind::ObjCKeyPath:
referencedDecl = nullptr;
if (auto keyPath = dyn_cast<ObjCKeyPathExpr>(parsedExpr))
return TC.checkObjCKeyPathExpr(DC, keyPath, /*requireResultType=*/true);
return None;
}
Type originalType = parsedExpr->getType();
if (auto T = TC.getTypeOfExpressionWithoutApplying(parsedExpr, DC,
referencedDecl, FreeTypeVariableBinding::GenericParameters))
return T;
// Try to recover if we've made any progress.
if (parsedExpr &&
!isa<ErrorExpr>(parsedExpr) &&
parsedExpr->getType() &&
!parsedExpr->getType()->hasError() &&
(originalType.isNull() ||
!parsedExpr->getType()->isEqual(originalType))) {
return parsedExpr->getType();
}
return None;
}
示例4: Infer
ValuePtr BSequence::Infer(TypeChecker& checker, const vector<ExprPtr>& args)
{
for(auto& e : args)
{
TypeSubst lastSubst;
checker.subst.swap(lastSubst);
checker.Visit(e.get());
if(!e->value)
return {};
Compose(lastSubst, checker.subst);
}
return args.back()->value;
}
示例5: getInfixData
/// getInfixData - If the specified expression is an infix binary
/// operator, return its infix operator attributes.
static InfixData getInfixData(TypeChecker &TC, DeclContext *DC, Expr *E) {
if (auto *ifExpr = dyn_cast<IfExpr>(E)) {
// Ternary has fixed precedence.
assert(!ifExpr->isFolded() && "already folded if expr in sequence?!");
(void)ifExpr;
return InfixData(IntrinsicPrecedences::IfExpr,
Associativity::Right,
/*assignment*/ false);
} else if (auto *assign = dyn_cast<AssignExpr>(E)) {
// Assignment has fixed precedence.
assert(!assign->isFolded() && "already folded assign expr in sequence?!");
(void)assign;
return InfixData(IntrinsicPrecedences::AssignExpr,
Associativity::Right,
/*assignment*/ true);
} else if (auto *as = dyn_cast<ExplicitCastExpr>(E)) {
// 'as' and 'is' casts have fixed precedence.
assert(!as->isFolded() && "already folded 'as' expr in sequence?!");
(void)as;
return InfixData(IntrinsicPrecedences::ExplicitCastExpr,
Associativity::None,
/*assignment*/ false);
} else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
SourceFile *SF = DC->getParentSourceFile();
Identifier name = DRE->getDecl()->getName();
bool isCascading = DC->isCascadingContextForLookup(true);
if (InfixOperatorDecl *op = SF->lookupInfixOperator(name, isCascading,
E->getLoc()))
return op->getInfixData();
} else if (OverloadedDeclRefExpr *OO = dyn_cast<OverloadedDeclRefExpr>(E)) {
SourceFile *SF = DC->getParentSourceFile();
Identifier name = OO->getDecls()[0]->getName();
bool isCascading = DC->isCascadingContextForLookup(true);
if (InfixOperatorDecl *op = SF->lookupInfixOperator(name, isCascading,
E->getLoc()))
return op->getInfixData();
}
TC.diagnose(E->getLoc(), diag::unknown_binop);
// Recover with an infinite-precedence left-associative operator.
return InfixData((unsigned char)~0U, Associativity::Left,
/*assignment*/ false);
}
示例6: checkGenericParamList
/// Check the generic parameters in the given generic parameter list (and its
/// parent generic parameter lists) according to the given resolver.
void checkGenericParamList(TypeChecker &tc,
GenericSignatureBuilder *builder,
GenericParamList *genericParams,
GenericSignature *parentSig,
TypeResolution resolution) {
// If there is a parent context, add the generic parameters and requirements
// from that context.
if (builder)
builder->addGenericSignature(parentSig);
// If there aren't any generic parameters at this level, we're done.
if (!genericParams)
return;
assert(genericParams->size() > 0 &&
"Parsed an empty generic parameter list?");
// Determine where and how to perform name lookup.
TypeResolutionOptions options = None;
DeclContext *lookupDC = genericParams->begin()[0]->getDeclContext();
assert(lookupDC == resolution.getDeclContext());
// First, add the generic parameters to the generic signature builder.
// Do this before checking the inheritance clause, since it may
// itself be dependent on one of these parameters.
if (builder) {
for (auto param : *genericParams)
builder->addGenericParameter(param);
}
// Add the requirements for each of the generic parameters to the builder.
// Now, check the inheritance clauses of each parameter.
if (builder) {
for (auto param : *genericParams)
builder->addGenericParameterRequirements(param);
}
// Add the requirements clause to the builder, validating the types in
// the requirements clause along the way.
tc.validateRequirements(genericParams->getWhereLoc(),
genericParams->getRequirements(), resolution,
options, builder);
}
示例7: getResultType
static Type getResultType(TypeChecker &TC, FuncDecl *fn, Type resultType) {
// Look through optional types.
OptionalTypeKind optKind;
if (auto origValueType = resultType->getAnyOptionalObjectType(optKind)) {
// Get the interface type of the result.
Type ifaceValueType = getResultType(TC, fn, origValueType);
// Preserve the optional type's original spelling if the interface
// type is the same as the original.
if (origValueType.getPointer() == ifaceValueType.getPointer()) {
return resultType;
}
// Wrap the interface type in the right kind of optional.
switch (optKind) {
case OTK_None: llvm_unreachable("impossible");
case OTK_Optional:
return OptionalType::get(ifaceValueType);
case OTK_ImplicitlyUnwrappedOptional:
return ImplicitlyUnwrappedOptionalType::get(ifaceValueType);
}
llvm_unreachable("bad optional kind");
}
// Rewrite dynamic self to the appropriate interface type.
if (resultType->is<DynamicSelfType>()) {
return fn->getDynamicSelfInterface();
}
// Weird hacky special case.
if (!fn->getBodyResultTypeLoc().hasLocation() &&
fn->isGenericContext()) {
// FIXME: This should not be rewritten. This is only needed in cases where
// we synthesize a function which returns a generic value. In that case,
// the return type is specified in terms of archetypes, but has no TypeLoc
// in the TypeRepr. Because of this, Sema isn't able to rebuild it in
// terms of interface types. When interface types prevail, this should be
// removed. Until then, we hack the mapping here.
return TC.getInterfaceTypeFromInternalType(fn, resultType);
}
return resultType;
}
示例8: typeConformsToCodable
/// Returns whether the given type conforms to the given {En,De}codable
/// protocol.
///
/// \param tc The typechecker to use in validating {En,De}codable conformance.
///
/// \param context The \c DeclContext the var declarations belong to.
///
/// \param target The \c Type to validate.
///
/// \param proto The \c ProtocolDecl to check conformance to.
static CodableConformanceType typeConformsToCodable(TypeChecker &tc,
DeclContext *context,
Type target,
ProtocolDecl *proto) {
// Some generic types need to be introspected to get at their "true" Codable
// conformance.
auto canType = target->getCanonicalType();
if (auto genericType = dyn_cast<BoundGenericType>(canType)) {
auto *nominalTypeDecl = genericType->getAnyNominal();
// Implicitly unwrapped optionals need to be unwrapped;
// ImplicitlyUnwrappedOptional does not need to conform to Codable directly
// -- only its inner type does.
if (nominalTypeDecl == tc.Context.getImplicitlyUnwrappedOptionalDecl() ||
// FIXME: Remove the following when conditional conformance lands.
// Some generic types in the stdlib currently conform to Codable even
// when the type they are generic on does not [Optional, Array, Set,
// Dictionary]. For synthesizing conformance, we don't want to
// consider these types as Codable if the nested type is not Codable.
// Look through the generic type parameters of these types recursively
// to avoid synthesizing code that will crash at runtime.
//
// We only want to look through generic params for these types; other
// types may validly conform to Codable even if their generic param
// types do not.
nominalTypeDecl == tc.Context.getOptionalDecl() ||
nominalTypeDecl == tc.Context.getArrayDecl() ||
nominalTypeDecl == tc.Context.getSetDecl() ||
nominalTypeDecl == tc.Context.getDictionaryDecl()) {
for (auto paramType : genericType->getGenericArgs()) {
if (typeConformsToCodable(tc, context, paramType, proto) != Conforms)
return DoesNotConform;
}
return Conforms;
}
}
return tc.conformsToProtocol(target, proto, context,
ConformanceCheckFlags::Used) ? Conforms
: DoesNotConform;
}
示例9: typeCheck
void SetFieldValueAST::typeCheck(TypeChecker& checker) {
mObjectRefExpression->typeCheck(checker);
std::shared_ptr<Type> objRefType;
if (auto varRef = std::dynamic_pointer_cast<VariableReferenceExpressionAST>(mObjectRefExpression)) {
auto varSymbol = std::dynamic_pointer_cast<VariableSymbol>(mSymbolTable->find(varRef->name()));
objRefType = checker.findType(varSymbol->variableType());
} else if (auto arrayRef = std::dynamic_pointer_cast<ArrayAccessAST>(mObjectRefExpression)) {
objRefType = arrayRef->expressionType(checker);
} else {
checker.typeError("Not implemented");
}
auto memberName = getMemberName();
std::string objName = objRefType->name();
if (!checker.objectExists(objName)) {
checker.typeError(objRefType->name() + " is not an object type.");
}
auto& object = checker.getObject(objName);
if (!object.fieldExists(memberName)) {
checker.typeError("There exists no field '" + memberName + "' in the type '" + objRefType->name() + "'.");
}
mRightHandSide->typeCheck(checker);
//Check rhs
std::shared_ptr<Type> fieldType;
if (std::dynamic_pointer_cast<ArrayAccessAST>(mMemberExpression)) {
fieldType = std::dynamic_pointer_cast<ArrayType>(object.getField(memberName).type())->elementType();
} else {
fieldType = object.getField(memberName).type();
}
checker.assertSameType(
*fieldType,
*mRightHandSide->expressionType(checker),
asString());
}
示例10: typeConformsToCodable
/// Returns whether the given type conforms to the given {En,De}codable
/// protocol.
///
/// \param tc The typechecker to use in validating {En,De}codable conformance.
///
/// \param context The \c DeclContext the var declarations belong to.
///
/// \param target The \c Type to validate.
///
/// \param proto The \c ProtocolDecl to check conformance to.
static CodableConformanceType typeConformsToCodable(TypeChecker &tc,
DeclContext *context,
Type target, bool isIUO,
ProtocolDecl *proto) {
target = context->mapTypeIntoContext(target->mapTypeOutOfContext());
// Some generic types need to be introspected to get at their "true" Codable
// conformance.
if (auto referenceType = target->getAs<ReferenceStorageType>()) {
// This is a weak/unowned/unmanaged var. Get the inner type before checking
// conformance.
target = referenceType->getReferentType();
}
if (isIUO)
return typeConformsToCodable(tc, context, target->getOptionalObjectType(),
false, proto);
return tc.conformsToProtocol(target, proto, context,
ConformanceCheckFlags::Used) ? Conforms
: DoesNotConform;
}
示例11: deriveRawRepresentable
Type DerivedConformance::deriveRawRepresentable(TypeChecker &tc,
Decl *parentDecl,
NominalTypeDecl *type,
AssociatedTypeDecl *assocType) {
// We can only synthesize RawRepresentable for enums.
auto enumDecl = dyn_cast<EnumDecl>(type);
if (!enumDecl)
return nullptr;
// Check other preconditions for synthesized conformance.
if (!canSynthesizeRawRepresentable(tc, parentDecl, enumDecl))
return nullptr;
if (assocType->getName() == tc.Context.Id_RawValue) {
return deriveRawRepresentable_Raw(tc, parentDecl, enumDecl);
}
tc.diagnose(assocType->getLoc(),
diag::broken_raw_representable_requirement);
return nullptr;
}
示例12: checkProtocolSelfRequirements
// For a generic requirement in a protocol, make sure that the requirement
// set didn't add any requirements to Self or its associated types.
static bool checkProtocolSelfRequirements(GenericSignature *sig,
ValueDecl *decl,
TypeChecker &TC) {
// For a generic requirement in a protocol, make sure that the requirement
// set didn't add any requirements to Self or its associated types.
if (auto *proto = dyn_cast<ProtocolDecl>(decl->getDeclContext())) {
auto protoSelf = proto->getSelfInterfaceType();
for (auto req : sig->getRequirements()) {
// If one of the types in the requirement is dependent on a non-Self
// type parameter, this requirement is okay.
if (!isSelfDerivedOrConcrete(protoSelf, req.getFirstType()) ||
!isSelfDerivedOrConcrete(protoSelf, req.getSecondType()))
continue;
// The conformance of 'Self' to the protocol is okay.
if (req.getKind() == RequirementKind::Conformance &&
req.getSecondType()->getAs<ProtocolType>()->getDecl() == proto &&
req.getFirstType()->is<GenericTypeParamType>())
continue;
TC.diagnose(decl,
TC.Context.LangOpts.EffectiveLanguageVersion[0] >= 4
? diag::requirement_restricts_self
: diag::requirement_restricts_self_swift3,
decl->getDescriptiveKind(), decl->getFullName(),
req.getFirstType().getString(),
static_cast<unsigned>(req.getKind()),
req.getSecondType().getString());
if (TC.Context.LangOpts.EffectiveLanguageVersion[0] >= 4)
return true;
}
}
return false;
}
示例13: checkReferencedGenericParams
/// All generic parameters of a generic function must be referenced in the
/// declaration's type, otherwise we have no way to infer them.
static void checkReferencedGenericParams(GenericContext *dc,
GenericSignature *sig,
TypeChecker &TC) {
auto *genericParams = dc->getGenericParams();
if (!genericParams)
return;
auto *decl = cast<ValueDecl>(dc->getInnermostDeclarationDeclContext());
// A helper class to collect referenced generic type parameters
// and dependent member types.
class ReferencedGenericTypeWalker : public TypeWalker {
SmallPtrSet<CanType, 4> ReferencedGenericParams;
public:
ReferencedGenericTypeWalker() {}
Action walkToTypePre(Type ty) override {
// Find generic parameters or dependent member types.
// Once such a type is found, don't recurse into its children.
if (!ty->hasTypeParameter())
return Action::SkipChildren;
if (ty->isTypeParameter()) {
ReferencedGenericParams.insert(ty->getCanonicalType());
return Action::SkipChildren;
}
return Action::Continue;
}
SmallPtrSet<CanType, 4> &getReferencedGenericParams() {
return ReferencedGenericParams;
}
};
// Collect all generic params referenced in parameter types and
// return type.
ReferencedGenericTypeWalker paramsAndResultWalker;
auto *funcTy = decl->getInterfaceType()->castTo<GenericFunctionType>();
funcTy->getInput().walk(paramsAndResultWalker);
funcTy->getResult().walk(paramsAndResultWalker);
// Set of generic params referenced in parameter types,
// return type or requirements.
auto &referencedGenericParams =
paramsAndResultWalker.getReferencedGenericParams();
// Check if at least one of the generic params in the requirement refers
// to an already referenced generic parameter. If this is the case,
// then the other type is also considered as referenced, because
// it is used to put requirements on the first type.
auto reqTypesVisitor = [&referencedGenericParams](Requirement req) -> bool {
Type first;
Type second;
switch (req.getKind()) {
case RequirementKind::Superclass:
case RequirementKind::SameType:
second = req.getSecondType();
LLVM_FALLTHROUGH;
case RequirementKind::Conformance:
case RequirementKind::Layout:
first = req.getFirstType();
break;
}
// Collect generic parameter types referenced by types used in a requirement.
ReferencedGenericTypeWalker walker;
if (first && first->hasTypeParameter())
first.walk(walker);
if (second && second->hasTypeParameter())
second.walk(walker);
auto &genericParamsUsedByRequirementTypes =
walker.getReferencedGenericParams();
// If at least one of the collected generic types or a root generic
// parameter of dependent member types is known to be referenced by
// parameter types, return types or other types known to be "referenced",
// then all the types used in the requirement are considered to be
// referenced, because they are used to defined something that is known
// to be referenced.
bool foundNewReferencedGenericParam = false;
if (std::any_of(genericParamsUsedByRequirementTypes.begin(),
genericParamsUsedByRequirementTypes.end(),
[&referencedGenericParams](CanType t) {
assert(t->isTypeParameter());
return referencedGenericParams.find(
t->getRootGenericParam()
->getCanonicalType()) !=
referencedGenericParams.end();
})) {
std::for_each(genericParamsUsedByRequirementTypes.begin(),
genericParamsUsedByRequirementTypes.end(),
[&referencedGenericParams,
&foundNewReferencedGenericParam](CanType t) {
// Add only generic type parameters, but ignore any
// dependent member types, because requirement
// on a dependent member type does not provide enough
// information to infer the base generic type
//.........这里部分代码省略.........
示例14: bindExtensionDecl
static void bindExtensionDecl(ExtensionDecl *ED, TypeChecker &TC) {
if (ED->getExtendedType())
return;
// If we didn't parse a type, fill in an error type and bail out.
if (!ED->getExtendedTypeLoc().getTypeRepr()) {
ED->setInvalid();
ED->getExtendedTypeLoc().setInvalidType(TC.Context);
return;
}
auto dc = ED->getDeclContext();
// Validate the representation.
// FIXME: Perform some kind of "shallow" validation here?
TypeResolutionOptions options;
options |= TR_AllowUnboundGenerics;
options |= TR_ExtensionBinding;
if (TC.validateType(ED->getExtendedTypeLoc(), dc, options)) {
ED->setInvalid();
return;
}
// Dig out the extended type.
auto extendedType = ED->getExtendedType();
// Hack to allow extending a generic typealias.
if (auto *unboundGeneric = extendedType->getAs<UnboundGenericType>()) {
if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(unboundGeneric->getDecl())) {
auto extendedNominal = aliasDecl->getDeclaredInterfaceType()->getAnyNominal();
if (extendedNominal) {
extendedType = extendedNominal->getDeclaredType();
ED->getExtendedTypeLoc().setType(extendedType);
}
}
}
// Handle easy cases.
// Cannot extend a metatype.
if (extendedType->is<AnyMetatypeType>()) {
TC.diagnose(ED->getLoc(), diag::extension_metatype, extendedType)
.highlight(ED->getExtendedTypeLoc().getSourceRange());
ED->setInvalid();
ED->getExtendedTypeLoc().setInvalidType(TC.Context);
return;
}
// Cannot extend a bound generic type.
if (extendedType->isSpecialized()) {
TC.diagnose(ED->getLoc(), diag::extension_specialization,
extendedType->getAnyNominal()->getName())
.highlight(ED->getExtendedTypeLoc().getSourceRange());
ED->setInvalid();
ED->getExtendedTypeLoc().setInvalidType(TC.Context);
return;
}
// Dig out the nominal type being extended.
NominalTypeDecl *extendedNominal = extendedType->getAnyNominal();
if (!extendedNominal) {
TC.diagnose(ED->getLoc(), diag::non_nominal_extension, extendedType)
.highlight(ED->getExtendedTypeLoc().getSourceRange());
ED->setInvalid();
ED->getExtendedTypeLoc().setInvalidType(TC.Context);
return;
}
assert(extendedNominal && "Should have the nominal type being extended");
// If the extended type is generic or is a protocol. Clone or create
// the generic parameters.
if (extendedNominal->isGenericContext()) {
if (auto proto = dyn_cast<ProtocolDecl>(extendedNominal)) {
// For a protocol extension, build the generic parameter list.
ED->setGenericParams(proto->createGenericParams(ED));
} else {
// Clone the existing generic parameter list.
ED->setGenericParams(
cloneGenericParams(TC.Context, ED,
extendedNominal->getGenericParamsOfContext()));
}
}
// If we have a trailing where clause, deal with it now.
// For now, trailing where clauses are only permitted on protocol extensions.
if (auto trailingWhereClause = ED->getTrailingWhereClause()) {
if (!extendedNominal->isGenericContext()) {
// Only generic and protocol types are permitted to have
// trailing where clauses.
TC.diagnose(ED, diag::extension_nongeneric_trailing_where, extendedType)
.highlight(trailingWhereClause->getSourceRange());
ED->setTrailingWhereClause(nullptr);
} else {
// Merge the trailing where clause into the generic parameter list.
// FIXME: Long-term, we'd like clients to deal with the trailing where
// clause explicitly, but for now it's far more direct to represent
// the trailing where clause as part of the requirements.
ED->getGenericParams()->addTrailingWhereClause(
TC.Context,
trailingWhereClause->getWhereLoc(),
//.........这里部分代码省略.........
示例15: validateCodingKeysEnum
/// 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) {
// Look through all var decls in the given type.
// * Filter out lazy/computed vars (currently already done by
// getStoredProperties).
// * Filter out ones which are present in the given decl (by name).
//
// If any of the entries in the CodingKeys decl are not present in the type
// by name, then this decl doesn't match.
// If there are any vars left in the type which don't have a default value
// (for Decodable), then this decl doesn't match.
// 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)) {
properties[varDecl->getName()] = varDecl;
}
bool propertiesAreValid = true;
for (auto elt : codingKeysDecl->getAllElements()) {
auto it = properties.find(elt->getName());
if (it == properties.end()) {
tc.diagnose(elt->getLoc(), diag::codable_extraneous_codingkey_case_here,
elt->getName());
// TODO: Investigate typo-correction here; perhaps the case name was
// misspelled and we can provide a fix-it.
propertiesAreValid = false;
continue;
}
// We have a property to map to. Ensure it's {En,De}codable.
auto conformance = varConformsToCodable(tc, target->getDeclContext(),
it->second, proto);
switch (conformance) {
case Conforms:
// The property was valid. Remove it from the list.
properties.erase(it);
break;
case DoesNotConform:
tc.diagnose(it->second->getLoc(),
diag::codable_non_conforming_property_here,
proto->getDeclaredType(), it->second->getType());
LLVM_FALLTHROUGH;
case TypeNotValidated:
// We don't produce a diagnostic for a type which failed to validate.
// This will produce a diagnostic elsewhere anyway.
propertiesAreValid = false;
continue;
}
}
if (!propertiesAreValid)
return false;
// If there are any remaining properties which the CodingKeys did not cover,
// we can skip them on encode. On decode, though, we can only skip them if
// they have a default value.
if (!properties.empty() &&
proto == tc.Context.getProtocol(KnownProtocolKind::Decodable)) {
for (auto it = properties.begin(); it != properties.end(); ++it) {
if (it->second->getParentInitializer() != nullptr) {
// Var has a default value.
continue;
}
propertiesAreValid = false;
tc.diagnose(it->second->getLoc(), diag::codable_non_decoded_property_here,
proto->getDeclaredType(), it->first);
}
}
return propertiesAreValid;
}