| //===--- DerivedConformances.cpp - Derived conformance utilities ----------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "TypeChecker.h" |
| #include "swift/AST/Decl.h" |
| #include "swift/AST/Stmt.h" |
| #include "swift/AST/Expr.h" |
| #include "swift/AST/Pattern.h" |
| #include "swift/AST/ParameterList.h" |
| #include "swift/AST/ProtocolConformance.h" |
| #include "swift/AST/Types.h" |
| #include "swift/ClangImporter/ClangModule.h" |
| #include "DerivedConformances.h" |
| |
| using namespace swift; |
| |
| DerivedConformance::DerivedConformance(TypeChecker &tc, Decl *conformanceDecl, |
| NominalTypeDecl *nominal, |
| ProtocolDecl *protocol) |
| : TC(tc), ConformanceDecl(conformanceDecl), Nominal(nominal), |
| Protocol(protocol) { |
| assert(getConformanceContext()->getSelfNominalTypeDecl() == 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(DeclContext *DC, |
| NominalTypeDecl *Nominal, |
| ProtocolDecl *Protocol) { |
| // Only known protocols can be derived. |
| auto knownProtocol = Protocol->getKnownProtocolKind(); |
| if (!knownProtocol) |
| return false; |
| |
| if (*knownProtocol == KnownProtocolKind::Hashable) { |
| // We can always complete a partial Hashable implementation, and we can |
| // synthesize a full Hashable implementation for structs and enums with |
| // Hashable components. |
| return canDeriveHashable(Nominal); |
| } |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| if (*knownProtocol == KnownProtocolKind::AdditiveArithmetic) |
| return canDeriveAdditiveArithmetic(Nominal, DC); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| if (*knownProtocol == KnownProtocolKind::PointwiseMultiplicative) |
| return canDerivePointwiseMultiplicative(Nominal, DC); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| if (*knownProtocol == KnownProtocolKind::ElementaryFunctions) |
| return canDeriveElementaryFunctions(Nominal, DC); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| if (*knownProtocol == KnownProtocolKind::KeyPathIterable) |
| return canDeriveKeyPathIterable(Nominal); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| if (*knownProtocol == KnownProtocolKind::TensorArrayProtocol) |
| return canDeriveTensorArrayProtocol(Nominal, DC); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| if (*knownProtocol == KnownProtocolKind::TensorGroup) |
| return canDeriveTensorGroup(Nominal, DC); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| if (*knownProtocol == KnownProtocolKind::VectorProtocol) |
| return canDeriveVectorProtocol(Nominal, DC); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| if (*knownProtocol == KnownProtocolKind::Differentiable) |
| return canDeriveDifferentiable(Nominal, DC); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| if (*knownProtocol == KnownProtocolKind::EuclideanDifferentiable) |
| return canDeriveEuclideanDifferentiable(Nominal, DC); |
| |
| if (auto *enumDecl = dyn_cast<EnumDecl>(Nominal)) { |
| switch (*knownProtocol) { |
| // The presence of a raw type is an explicit declaration that |
| // the compiler should derive a RawRepresentable conformance. |
| case KnownProtocolKind::RawRepresentable: |
| return enumDecl->hasRawType(); |
| |
| // Enums without associated values can implicitly derive Equatable |
| // conformance. |
| case KnownProtocolKind::Equatable: |
| return canDeriveEquatable(DC, Nominal); |
| |
| // "Simple" enums without availability attributes can explicitly derive |
| // a CaseIterable conformance. |
| // |
| // FIXME: Lift the availability restriction. |
| case KnownProtocolKind::CaseIterable: |
| return !enumDecl->hasPotentiallyUnavailableCaseValue() |
| && enumDecl->hasOnlyCasesWithoutAssociatedValues(); |
| |
| // @objc enums can explicitly derive their _BridgedNSError conformance. |
| case KnownProtocolKind::BridgedNSError: |
| return enumDecl->isObjC() && enumDecl->hasCases() |
| && enumDecl->hasOnlyCasesWithoutAssociatedValues(); |
| |
| // Enums without associated values and enums with a raw type of String |
| // or Int can explicitly derive CodingKey conformance. |
| case KnownProtocolKind::CodingKey: { |
| Type rawType = enumDecl->getRawType(); |
| if (rawType) { |
| auto parentDC = enumDecl->getDeclContext(); |
| ASTContext &C = parentDC->getASTContext(); |
| |
| auto nominal = rawType->getAnyNominal(); |
| return nominal == C.getStringDecl() || nominal == C.getIntDecl(); |
| } |
| |
| // hasOnlyCasesWithoutAssociatedValues will return true for empty enums; |
| // empty enumas are allowed to conform as well. |
| return enumDecl->hasOnlyCasesWithoutAssociatedValues(); |
| } |
| |
| default: |
| return false; |
| } |
| } else if (isa<StructDecl>(Nominal) || isa<ClassDecl>(Nominal)) { |
| // Structs and classes can explicitly derive Encodable and Decodable |
| // conformance (explicitly meaning we can synthesize an implementation if |
| // a type conforms manually). |
| if (*knownProtocol == KnownProtocolKind::Encodable || |
| *knownProtocol == KnownProtocolKind::Decodable) { |
| // FIXME: This is not actually correct. We cannot promise to always |
| // provide a witness here for all structs and classes. Unfortunately, |
| // figuring out whether this is actually possible requires much more |
| // context -- a TypeChecker and the parent decl context at least -- and is |
| // tightly coupled to the logic within DerivedConformance. |
| // This unfortunately means that we expect a witness even if one will not |
| // be produced, which requires DerivedConformance::deriveCodable to output |
| // its own diagnostics. |
| return true; |
| } |
| |
| // Structs can explicitly derive Equatable conformance. |
| if (isa<StructDecl>(Nominal)) { |
| switch (*knownProtocol) { |
| case KnownProtocolKind::Equatable: |
| return canDeriveEquatable(DC, Nominal); |
| default: |
| return false; |
| } |
| } |
| } |
| return false; |
| } |
| |
| void DerivedConformance::tryDiagnoseFailedDerivation(DeclContext *DC, |
| NominalTypeDecl *nominal, |
| ProtocolDecl *protocol) { |
| auto knownProtocol = protocol->getKnownProtocolKind(); |
| if (!knownProtocol) |
| return; |
| |
| if (*knownProtocol == KnownProtocolKind::Equatable) { |
| tryDiagnoseFailedEquatableDerivation(DC, nominal); |
| } |
| |
| if (*knownProtocol == KnownProtocolKind::Hashable) { |
| tryDiagnoseFailedHashableDerivation(DC, nominal); |
| } |
| } |
| |
| ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal, |
| ValueDecl *requirement) { |
| // Note: whenever you update this function, also update |
| // TypeChecker::deriveProtocolRequirement. |
| ASTContext &ctx = nominal->getASTContext(); |
| auto name = requirement->getFullName(); |
| |
| // Local function that retrieves the requirement with the same name as |
| // the provided requirement, but within the given known protocol. |
| // SWIFT_ENABLE_TENSORFLOW |
| auto getRequirement = [&](KnownProtocolKind kind, |
| llvm::function_ref<bool(ValueDecl *)> filter = |
| nullptr) -> ValueDecl * { |
| // Dig out the protocol. |
| auto proto = ctx.getProtocol(kind); |
| if (!proto) return nullptr; |
| |
| if (auto conformance = TypeChecker::conformsToProtocol( |
| nominal->getDeclaredInterfaceType(), proto, nominal, |
| ConformanceCheckFlags::SkipConditionalRequirements)) { |
| auto DC = conformance->getConcrete()->getDeclContext(); |
| // Check whether this nominal type derives conformances to the protocol. |
| if (!DerivedConformance::derivesProtocolConformance(DC, nominal, proto)) |
| return nullptr; |
| } |
| |
| // Retrieve the requirement. |
| auto results = proto->lookupDirect(name); |
| // SWIFT_ENABLE_TENSORFLOW |
| // Filter requirements, if `filter` function is specified. |
| if (filter) { |
| llvm::erase_if(results, [&](ValueDecl *v) { |
| return !isa<ProtocolDecl>(v->getDeclContext()) || |
| !v->isProtocolRequirement() || !filter(v); |
| }); |
| } |
| return results.empty() ? nullptr : results.front(); |
| // SWIFT_ENABLE_TENSORFLOW END |
| }; |
| |
| // Properties. |
| if (isa<VarDecl>(requirement)) { |
| // RawRepresentable.rawValue |
| if (name.isSimpleName(ctx.Id_rawValue)) |
| return getRequirement(KnownProtocolKind::RawRepresentable); |
| |
| // Hashable.hashValue |
| if (name.isSimpleName(ctx.Id_hashValue)) |
| return getRequirement(KnownProtocolKind::Hashable); |
| |
| // CaseIterable.allValues |
| if (name.isSimpleName(ctx.Id_allCases)) |
| return getRequirement(KnownProtocolKind::CaseIterable); |
| |
| // _BridgedNSError._nsErrorDomain |
| if (name.isSimpleName(ctx.Id_nsErrorDomain)) |
| return getRequirement(KnownProtocolKind::BridgedNSError); |
| |
| // CodingKey.stringValue |
| if (name.isSimpleName(ctx.Id_stringValue)) |
| return getRequirement(KnownProtocolKind::CodingKey); |
| |
| // CodingKey.intValue |
| if (name.isSimpleName(ctx.Id_intValue)) |
| return getRequirement(KnownProtocolKind::CodingKey); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // AdditiveArithmetic.zero |
| if (name.isSimpleName(ctx.Id_zero)) |
| return getRequirement(KnownProtocolKind::AdditiveArithmetic); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // EuclideanDifferentiable.differentiableVectorView |
| if (name.isSimpleName(ctx.Id_differentiableVectorView)) |
| return getRequirement(KnownProtocolKind::EuclideanDifferentiable); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // PointwiseMultiplicative.one |
| if (name.isSimpleName(ctx.Id_one)) |
| return getRequirement(KnownProtocolKind::PointwiseMultiplicative); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // PointwiseMultiplicative.reciprocal |
| if (name.isSimpleName(ctx.Id_reciprocal)) |
| return getRequirement(KnownProtocolKind::PointwiseMultiplicative); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // KeyPathIterable.allKeyPaths |
| if (name.isSimpleName(ctx.Id_allKeyPaths)) |
| return getRequirement(KnownProtocolKind::KeyPathIterable); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // TensorArrayProtocol._tensorHandleCount |
| if (name.isSimpleName(ctx.Id_tensorHandleCount)) |
| return getRequirement(KnownProtocolKind::TensorArrayProtocol); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // TensorArrayProtocol._typeList |
| if (name.isSimpleName(ctx.Id_typeList) && !requirement->isStatic()) |
| return getRequirement(KnownProtocolKind::TensorArrayProtocol); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // TensorGroup._typeList |
| if (name.isSimpleName(ctx.Id_typeList)) |
| return getRequirement(KnownProtocolKind::TensorGroup); |
| |
| return nullptr; |
| } |
| |
| // Functions. |
| if (auto func = dyn_cast<FuncDecl>(requirement)) { |
| if (func->isOperator() && name.getBaseName() == "==") |
| return getRequirement(KnownProtocolKind::Equatable); |
| |
| // Encodable.encode(to: Encoder) |
| if (name.isCompoundName() && name.getBaseName() == ctx.Id_encode) { |
| auto argumentNames = name.getArgumentNames(); |
| if (argumentNames.size() == 1 && argumentNames[0] == ctx.Id_to) |
| return getRequirement(KnownProtocolKind::Encodable); |
| } |
| |
| // Hashable.hash(into: inout Hasher) |
| if (name.isCompoundName() && name.getBaseName() == ctx.Id_hash) { |
| auto argumentNames = name.getArgumentNames(); |
| if (argumentNames.size() == 1 && argumentNames[0] == ctx.Id_into) |
| return getRequirement(KnownProtocolKind::Hashable); |
| } |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // AdditiveArithmetic.+ |
| // AdditiveArithmetic.- |
| if (func->isOperator() && (name.getBaseName() == "+" || |
| name.getBaseName() == "-")) { |
| auto argumentNames = name.getArgumentNames(); |
| if (argumentNames.size() == 2) |
| return getRequirement(KnownProtocolKind::AdditiveArithmetic); |
| } |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // PointwiseMultiplicative.(.*) |
| if (func->isOperator() && name.getBaseName() == ".*") { |
| auto argumentNames = name.getArgumentNames(); |
| if (argumentNames.size() == 2) |
| return getRequirement(KnownProtocolKind::PointwiseMultiplicative); |
| } |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // ElementaryFunctions requirements |
| if (name.isCompoundName()) { |
| auto argumentNames = name.getArgumentNames(); |
| if (argumentNames.size() == 1 && (false |
| #define ELEMENTARY_FUNCTION_UNARY(ID, NAME) || name.getBaseName() == NAME |
| #include "DerivedConformanceElementaryFunctions.def" |
| #undef ELEMENTARY_FUNCTION_UNARY |
| )) { |
| return getRequirement(KnownProtocolKind::ElementaryFunctions); |
| } |
| if (argumentNames.size() == 2) { |
| if (name.getBaseName() == "root") |
| return getRequirement(KnownProtocolKind::ElementaryFunctions); |
| if (name.getBaseName() == "pow") { |
| return getRequirement( |
| KnownProtocolKind::ElementaryFunctions, |
| [&](ValueDecl *v) { |
| auto *funcDecl = dyn_cast<FuncDecl>(v); |
| if (!funcDecl) |
| return false; |
| return funcDecl->getParameters()->get(1)->getName() == |
| func->getParameters()->get(1)->getName(); |
| }); |
| } |
| } |
| } |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // VectorProtocol.scaled(by:) |
| if (name.isCompoundName() && name.getBaseName() == ctx.Id_scaled) { |
| auto argumentNames = name.getArgumentNames(); |
| if (argumentNames.size() == 1 && |
| argumentNames[0] == ctx.getIdentifier("by")) |
| return getRequirement(KnownProtocolKind::VectorProtocol); |
| } |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // VectorProtocol.adding(_:) |
| // VectorProtocol.subtracting(_:) |
| if (name.isCompoundName() && |
| (name.getBaseName() == ctx.Id_adding || |
| name.getBaseName() == ctx.Id_subtracting)) { |
| auto argumentNames = name.getArgumentNames(); |
| if (argumentNames.size() == 1 && argumentNames[0].empty()) |
| return getRequirement(KnownProtocolKind::VectorProtocol); |
| } |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // TensorArrayProtocol._unpackTensorHandles(into:) |
| if (name.isCompoundName() && |
| name.getBaseName() == ctx.Id_unpackTensorHandles) { |
| auto argumentNames = name.getArgumentNames(); |
| if (argumentNames.size() == 1 && |
| argumentNames[0] == ctx.getIdentifier("into")) { |
| return getRequirement(KnownProtocolKind::TensorArrayProtocol); |
| } |
| } |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // Differentiable.move(along:) |
| if (name.isCompoundName() && |
| name.getBaseName() == ctx.Id_move) { |
| auto argumentNames = name.getArgumentNames(); |
| if (argumentNames.size() == 1 && |
| argumentNames[0] == ctx.getIdentifier("along")) { |
| return getRequirement(KnownProtocolKind::Differentiable); |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| // Initializers. |
| if (auto ctor = dyn_cast<ConstructorDecl>(requirement)) { |
| auto argumentNames = name.getArgumentNames(); |
| if (argumentNames.size() == 1) { |
| if (argumentNames[0] == ctx.Id_rawValue) |
| return getRequirement(KnownProtocolKind::RawRepresentable); |
| |
| // CodingKey.init?(stringValue:), CodingKey.init?(intValue:) |
| if (ctor->isFailable() && |
| !ctor->isImplicitlyUnwrappedOptional() && |
| (argumentNames[0] == ctx.Id_stringValue || |
| argumentNames[0] == ctx.Id_intValue)) |
| return getRequirement(KnownProtocolKind::CodingKey); |
| |
| // Decodable.init(from: Decoder) |
| if (argumentNames[0] == ctx.Id_from) |
| return getRequirement(KnownProtocolKind::Decodable); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // TensorGroup.init(_owning:) |
| if (argumentNames[0] == ctx.getIdentifier("_owning")) { |
| return getRequirement(KnownProtocolKind::TensorGroup); |
| } |
| } else if (argumentNames.size() == 2) { |
| // SWIFT_ENABLE_TENSORFLOW |
| // TensorArrayProtocol.init(_owning:count) |
| if (argumentNames[0] == ctx.getIdentifier("_owning") && |
| argumentNames[1] == ctx.getIdentifier("count")) { |
| return getRequirement(KnownProtocolKind::TensorArrayProtocol); |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| // Associated types. |
| if (isa<AssociatedTypeDecl>(requirement)) { |
| // RawRepresentable.RawValue |
| if (name.isSimpleName(ctx.Id_RawValue)) |
| return getRequirement(KnownProtocolKind::RawRepresentable); |
| |
| // CaseIterable.AllCases |
| if (name.isSimpleName(ctx.Id_AllCases)) |
| return getRequirement(KnownProtocolKind::CaseIterable); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // KeyPathIterable.AllKeyPaths |
| if (name.isSimpleName(ctx.Id_AllKeyPaths)) |
| return getRequirement(KnownProtocolKind::KeyPathIterable); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // Differentiable.TangentVector |
| if (name.isSimpleName(ctx.Id_TangentVector)) |
| return getRequirement(KnownProtocolKind::Differentiable); |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| // VectorProtocol.VectorSpaceScalar |
| if (name.isSimpleName(ctx.Id_VectorSpaceScalar)) |
| return getRequirement(KnownProtocolKind::VectorProtocol); |
| |
| return nullptr; |
| } |
| |
| return nullptr; |
| } |
| |
| DeclRefExpr * |
| DerivedConformance::createSelfDeclRef(AbstractFunctionDecl *fn) { |
| ASTContext &C = fn->getASTContext(); |
| |
| auto selfDecl = fn->getImplicitSelfDecl(); |
| return new (C) DeclRefExpr(selfDecl, DeclNameLoc(), /*implicit*/true); |
| } |
| |
| AccessorDecl *DerivedConformance:: |
| addGetterToReadOnlyDerivedProperty(VarDecl *property, |
| Type propertyContextType) { |
| auto getter = |
| declareDerivedPropertyGetter(property, propertyContextType); |
| |
| property->setImplInfo(StorageImplInfo::getImmutableComputed()); |
| property->setAccessors(SourceLoc(), {getter}, SourceLoc()); |
| |
| return getter; |
| } |
| |
| std::pair<AccessorDecl *, AccessorDecl *> |
| DerivedConformance::addGetterAndSetterToMutableDerivedProperty( |
| VarDecl *property, Type propertyContextType) { |
| auto *getter = declareDerivedPropertyGetter(property, propertyContextType); |
| auto *setter = declareDerivedPropertySetter(property, propertyContextType); |
| property->setImplInfo(StorageImplInfo::getMutableComputed()); |
| property->setAccessors(SourceLoc(), {getter, setter}, SourceLoc()); |
| return std::make_pair(getter, setter); |
| } |
| |
| AccessorDecl * |
| DerivedConformance::declareDerivedPropertyGetter(VarDecl *property, |
| Type propertyContextType) { |
| bool isStatic = property->isStatic(); |
| |
| auto &C = property->getASTContext(); |
| auto parentDC = property->getDeclContext(); |
| ParameterList *params = ParameterList::createEmpty(C); |
| |
| Type propertyInterfaceType = property->getInterfaceType(); |
| |
| auto getterDecl = AccessorDecl::create(C, |
| /*FuncLoc=*/SourceLoc(), /*AccessorKeywordLoc=*/SourceLoc(), |
| AccessorKind::Get, property, |
| /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, |
| /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), |
| /*GenericParams=*/nullptr, params, |
| TypeLoc::withoutLoc(propertyInterfaceType), parentDC); |
| getterDecl->setImplicit(); |
| getterDecl->setStatic(isStatic); |
| getterDecl->setIsTransparent(false); |
| |
| // Compute the interface type of the getter. |
| getterDecl->setGenericSignature(parentDC->getGenericSignatureOfContext()); |
| getterDecl->computeType(); |
| |
| getterDecl->copyFormalAccessFrom(property); |
| |
| C.addSynthesizedDecl(getterDecl); |
| |
| return getterDecl; |
| } |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| AccessorDecl * |
| DerivedConformance::declareDerivedPropertySetter(VarDecl *property, |
| Type propertyContextType) { |
| bool isStatic = property->isStatic(); |
| bool isFinal = property->isFinal(); |
| |
| auto &C = property->getASTContext(); |
| auto parentDC = property->getDeclContext(); |
| |
| auto propertyInterfaceType = property->getInterfaceType(); |
| auto propertyParam = new (C) |
| ParamDecl(ParamDecl::Specifier::Default, SourceLoc(), SourceLoc(), |
| Identifier(), property->getLoc(), C.getIdentifier("newValue"), |
| parentDC); |
| propertyParam->setInterfaceType(propertyInterfaceType); |
| |
| ParameterList *params = ParameterList::create(C, propertyParam); |
| |
| auto setterDecl = AccessorDecl::create(C, |
| /*FuncLoc*/ SourceLoc(), /*AccessorKeywordLoc*/ SourceLoc(), |
| AccessorKind::Set, property, /*StaticLoc*/ SourceLoc(), |
| StaticSpellingKind::None, /*Throws*/ false, /*ThrowsLoc*/ SourceLoc(), |
| /*GenericParams*/ nullptr, params, TypeLoc(), parentDC); |
| setterDecl->setImplicit(); |
| setterDecl->setStatic(isStatic); |
| // Set mutating if parent is not a class. |
| if (!parentDC->getSelfClassDecl()) |
| setterDecl->setSelfAccessKind(SelfAccessKind::Mutating); |
| |
| // If this is supposed to be a final method, mark it as such. |
| assert(isFinal || !parentDC->getSelfClassDecl()); |
| if (isFinal && parentDC->getSelfClassDecl() && |
| !setterDecl->isFinal()) |
| setterDecl->getAttrs().add(new (C) FinalAttr(/*Implicit*/ true)); |
| |
| // Compute the interface type of the setter. |
| setterDecl->setGenericSignature(parentDC->getGenericSignatureOfContext()); |
| setterDecl->computeType(); |
| setterDecl->copyFormalAccessFrom(property); |
| |
| C.addSynthesizedDecl(setterDecl); |
| return setterDecl; |
| } |
| |
| std::pair<VarDecl *, PatternBindingDecl *> |
| DerivedConformance::declareDerivedProperty(Identifier name, |
| Type propertyInterfaceType, |
| Type propertyContextType, |
| bool isStatic, bool isFinal) { |
| auto &C = TC.Context; |
| auto parentDC = getConformanceContext(); |
| |
| VarDecl *propDecl = new (C) VarDecl(/*IsStatic*/isStatic, VarDecl::Introducer::Var, |
| /*IsCaptureList*/false, SourceLoc(), name, |
| parentDC); |
| // SWIFT_ENABLE_TENSORFLOW |
| // TODO: Upstream this change to master. |
| if (isFinal && parentDC->getSelfClassDecl()) |
| propDecl->getAttrs().add(new (C) FinalAttr(/*Implicit*/ true)); |
| propDecl->setImplicit(); |
| propDecl->copyFormalAccessFrom(Nominal, /*sourceIsParentContext*/ true); |
| propDecl->setInterfaceType(propertyInterfaceType); |
| |
| Pattern *propPat = new (C) NamedPattern(propDecl, /*implicit*/ true); |
| propPat->setType(propertyContextType); |
| |
| propPat = TypedPattern::createImplicit(C, propPat, propertyContextType); |
| propPat->setType(propertyContextType); |
| |
| auto *pbDecl = PatternBindingDecl::createImplicit( |
| C, StaticSpellingKind::None, propPat, /*InitExpr*/ nullptr, parentDC); |
| return {propDecl, pbDecl}; |
| } |
| |
| bool DerivedConformance::checkAndDiagnoseDisallowedContext( |
| ValueDecl *synthesizing) const { |
| // In general, conformances can't be synthesized in extensions across files; |
| // but we have to allow it as a special case for Equatable and Hashable on |
| // enums with no associated values to preserve source compatibility. |
| bool allowCrossfileExtensions = false; |
| if (Protocol->isSpecificProtocol(KnownProtocolKind::Equatable) || |
| Protocol->isSpecificProtocol(KnownProtocolKind::Hashable)) { |
| auto ED = dyn_cast<EnumDecl>(Nominal); |
| allowCrossfileExtensions = ED && ED->hasOnlyCasesWithoutAssociatedValues(); |
| } |
| |
| if (!allowCrossfileExtensions && |
| Nominal->getModuleScopeContext() != |
| getConformanceContext()->getModuleScopeContext()) { |
| TC.diagnose(ConformanceDecl->getLoc(), |
| diag::cannot_synthesize_in_crossfile_extension, |
| getProtocolType()); |
| TC.diagnose(Nominal->getLoc(), diag::kind_declared_here, |
| DescriptiveDeclKind::Type); |
| return true; |
| } |
| |
| // A non-final class can't have an protocol-witnesss initializer in an |
| // extension. |
| if (auto CD = dyn_cast<ClassDecl>(Nominal)) { |
| if (!CD->isFinal() && isa<ConstructorDecl>(synthesizing) && |
| isa<ExtensionDecl>(ConformanceDecl)) { |
| TC.diagnose(ConformanceDecl->getLoc(), |
| diag::cannot_synthesize_init_in_extension_of_nonfinal, |
| getProtocolType(), synthesizing->getFullName()); |
| return true; |
| } |
| } |
| |
| return false; |
| } |