| //===--- TypeCheckDecl.cpp - Type Checking for Declarations ---------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2018 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements semantic analysis for declarations. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "CodeSynthesis.h" |
| #include "DerivedConformances.h" |
| #include "TypeChecker.h" |
| #include "TypeCheckAccess.h" |
| #include "TypeCheckAvailability.h" |
| #include "TypeCheckConcurrency.h" |
| #include "TypeCheckDecl.h" |
| #include "TypeCheckObjC.h" |
| #include "TypeCheckType.h" |
| #include "MiscDiagnostics.h" |
| #include "swift/AST/AccessScope.h" |
| #include "swift/AST/ASTPrinter.h" |
| #include "swift/AST/ASTVisitor.h" |
| #include "swift/AST/ASTWalker.h" |
| #include "swift/AST/ExistentialLayout.h" |
| #include "swift/AST/Expr.h" |
| #include "swift/AST/ForeignErrorConvention.h" |
| #include "swift/AST/GenericEnvironment.h" |
| #include "swift/AST/GenericSignatureBuilder.h" |
| #include "swift/AST/Initializer.h" |
| #include "swift/AST/NameLookup.h" |
| #include "swift/AST/OperatorNameLookup.h" |
| #include "swift/AST/PrettyStackTrace.h" |
| #include "swift/AST/PropertyWrappers.h" |
| #include "swift/AST/ProtocolConformance.h" |
| #include "swift/AST/SourceFile.h" |
| #include "swift/AST/TypeWalker.h" |
| #include "swift/Basic/Statistic.h" |
| #include "swift/Parse/Lexer.h" |
| #include "swift/Parse/Parser.h" |
| #include "swift/Sema/IDETypeChecking.h" |
| #include "swift/Serialization/SerializedModuleLoader.h" |
| #include "swift/Strings.h" |
| #include "swift/AST/NameLookupRequests.h" |
| #include "swift/AST/TypeCheckRequests.h" |
| #include "swift/Basic/Defer.h" |
| #include "llvm/ADT/APFloat.h" |
| #include "llvm/ADT/APInt.h" |
| #include "llvm/ADT/APSInt.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/ADT/Twine.h" |
| #include "llvm/Support/Compiler.h" |
| #include "llvm/Support/DJB.h" |
| |
| using namespace swift; |
| |
| #define DEBUG_TYPE "Serialization" |
| |
| STATISTIC(NumLazyRequirementSignaturesLoaded, |
| "# of lazily-deserialized requirement signatures loaded"); |
| |
| #undef DEBUG_TYPE |
| #define DEBUG_TYPE "TypeCheckDecl" |
| |
| namespace { |
| |
| /// Used during enum raw value checking to identify duplicate raw values. |
| /// Character, string, float, and integer literals are all keyed by value. |
| /// Float and integer literals are additionally keyed by numeric equivalence. |
| struct RawValueKey { |
| enum class Kind : uint8_t { |
| String, Float, Int, Bool, Tombstone, Empty |
| } kind; |
| |
| struct IntValueTy { |
| uint64_t v0; |
| uint64_t v1; |
| |
| IntValueTy(const APInt &bits) { |
| APInt bits128 = bits.sextOrTrunc(128); |
| assert(bits128.getBitWidth() <= 128); |
| const uint64_t *data = bits128.getRawData(); |
| v0 = data[0]; |
| v1 = data[1]; |
| } |
| }; |
| |
| struct FloatValueTy { |
| uint64_t v0; |
| uint64_t v1; |
| }; |
| |
| // FIXME: doesn't accommodate >64-bit or signed raw integer or float values. |
| union { |
| StringRef stringValue; |
| IntValueTy intValue; |
| FloatValueTy floatValue; |
| bool boolValue; |
| }; |
| |
| explicit RawValueKey(LiteralExpr *expr) { |
| switch (expr->getKind()) { |
| case ExprKind::IntegerLiteral: |
| kind = Kind::Int; |
| intValue = IntValueTy(cast<IntegerLiteralExpr>(expr)->getValue()); |
| return; |
| case ExprKind::FloatLiteral: { |
| APFloat value = cast<FloatLiteralExpr>(expr)->getValue(); |
| llvm::APSInt asInt(127, /*isUnsigned=*/false); |
| bool isExact = false; |
| APFloat::opStatus status = |
| value.convertToInteger(asInt, APFloat::rmTowardZero, &isExact); |
| if (asInt.getBitWidth() <= 128 && status == APFloat::opOK && isExact) { |
| kind = Kind::Int; |
| intValue = IntValueTy(asInt); |
| return; |
| } |
| APInt bits = value.bitcastToAPInt(); |
| const uint64_t *data = bits.getRawData(); |
| if (bits.getBitWidth() == 80) { |
| kind = Kind::Float; |
| floatValue = FloatValueTy{ data[0], data[1] }; |
| } else { |
| assert(bits.getBitWidth() == 64); |
| kind = Kind::Float; |
| floatValue = FloatValueTy{ data[0], 0 }; |
| } |
| return; |
| } |
| case ExprKind::StringLiteral: |
| kind = Kind::String; |
| stringValue = cast<StringLiteralExpr>(expr)->getValue(); |
| return; |
| |
| case ExprKind::BooleanLiteral: |
| kind = Kind::Bool; |
| boolValue = cast<BooleanLiteralExpr>(expr)->getValue(); |
| return; |
| |
| default: |
| llvm_unreachable("not a valid literal expr for raw value"); |
| } |
| } |
| |
| explicit RawValueKey(Kind k) : kind(k) { |
| assert((k == Kind::Tombstone || k == Kind::Empty) |
| && "this ctor is only for creating DenseMap special values"); |
| } |
| }; |
| |
| /// Used during enum raw value checking to identify the source of a raw value, |
| /// which may have been derived by auto-incrementing, for diagnostic purposes. |
| struct RawValueSource { |
| /// The decl that has the raw value. |
| EnumElementDecl *sourceElt; |
| /// If the sourceDecl didn't explicitly name a raw value, this is the most |
| /// recent preceding decl with an explicit raw value. This is used to |
| /// diagnose 'autoincrementing from' messages. |
| EnumElementDecl *lastExplicitValueElt; |
| }; |
| |
| } // end anonymous namespace |
| |
| namespace llvm { |
| |
| template<> |
| class DenseMapInfo<RawValueKey> { |
| public: |
| static RawValueKey getEmptyKey() { |
| return RawValueKey(RawValueKey::Kind::Empty); |
| } |
| static RawValueKey getTombstoneKey() { |
| return RawValueKey(RawValueKey::Kind::Tombstone); |
| } |
| static unsigned getHashValue(RawValueKey k) { |
| switch (k.kind) { |
| case RawValueKey::Kind::Float: |
| // Hash as bits. We want to treat distinct but IEEE-equal values as not |
| // equal. |
| return DenseMapInfo<uint64_t>::getHashValue(k.floatValue.v0) ^ |
| DenseMapInfo<uint64_t>::getHashValue(k.floatValue.v1); |
| case RawValueKey::Kind::Int: |
| return DenseMapInfo<uint64_t>::getHashValue(k.intValue.v0) & |
| DenseMapInfo<uint64_t>::getHashValue(k.intValue.v1); |
| case RawValueKey::Kind::String: |
| return DenseMapInfo<StringRef>::getHashValue(k.stringValue); |
| case RawValueKey::Kind::Bool: |
| return DenseMapInfo<uint64_t>::getHashValue(k.boolValue); |
| case RawValueKey::Kind::Empty: |
| case RawValueKey::Kind::Tombstone: |
| return 0; |
| } |
| |
| llvm_unreachable("Unhandled RawValueKey in switch."); |
| } |
| static bool isEqual(RawValueKey a, RawValueKey b) { |
| if (a.kind != b.kind) |
| return false; |
| switch (a.kind) { |
| case RawValueKey::Kind::Float: |
| // Hash as bits. We want to treat distinct but IEEE-equal values as not |
| // equal. |
| return a.floatValue.v0 == b.floatValue.v0 && |
| a.floatValue.v1 == b.floatValue.v1; |
| case RawValueKey::Kind::Int: |
| return a.intValue.v0 == b.intValue.v0 && |
| a.intValue.v1 == b.intValue.v1; |
| case RawValueKey::Kind::String: |
| return a.stringValue.equals(b.stringValue); |
| case RawValueKey::Kind::Bool: |
| return a.boolValue == b.boolValue; |
| case RawValueKey::Kind::Empty: |
| case RawValueKey::Kind::Tombstone: |
| return true; |
| } |
| |
| llvm_unreachable("Unhandled RawValueKey in switch."); |
| } |
| }; |
| |
| } // namespace llvm |
| |
| static bool canSkipCircularityCheck(NominalTypeDecl *decl) { |
| // Don't bother checking imported or deserialized decls. |
| return decl->hasClangNode() || decl->wasDeserialized(); |
| } |
| |
| bool |
| HasCircularInheritedProtocolsRequest::evaluate(Evaluator &evaluator, |
| ProtocolDecl *decl) const { |
| if (canSkipCircularityCheck(decl)) |
| return false; |
| |
| bool anyObject = false; |
| auto inherited = getDirectlyInheritedNominalTypeDecls(decl, anyObject); |
| for (auto &found : inherited) { |
| auto *protoDecl = dyn_cast<ProtocolDecl>(found.Item); |
| if (!protoDecl) |
| continue; |
| |
| // If we have a cycle, handle it and return true. |
| auto result = evaluator(HasCircularInheritedProtocolsRequest{protoDecl}); |
| if (!result) { |
| using Error = CyclicalRequestError<HasCircularInheritedProtocolsRequest>; |
| llvm::handleAllErrors(result.takeError(), [](const Error &E) {}); |
| return true; |
| } |
| |
| // If the underlying request handled a cycle and returned true, bail. |
| if (*result) |
| return true; |
| } |
| return false; |
| } |
| |
| bool |
| HasCircularRawValueRequest::evaluate(Evaluator &evaluator, |
| EnumDecl *decl) const { |
| if (canSkipCircularityCheck(decl) || !decl->hasRawType()) |
| return false; |
| |
| auto *inherited = decl->getRawType()->getEnumOrBoundGenericEnum(); |
| if (!inherited) |
| return false; |
| |
| // If we have a cycle, handle it and return true. |
| auto result = evaluator(HasCircularRawValueRequest{inherited}); |
| if (!result) { |
| using Error = CyclicalRequestError<HasCircularRawValueRequest>; |
| llvm::handleAllErrors(result.takeError(), [](const Error &E) {}); |
| return true; |
| } |
| return result.get(); |
| } |
| |
| namespace { |
| // The raw values of this enum must be kept in sync with |
| // diag::implicitly_final_cannot_be_open. |
| enum class ImplicitlyFinalReason : unsigned { |
| /// A property was declared with 'let'. |
| Let, |
| /// The containing class is final. |
| FinalClass, |
| /// A member was declared as 'static'. |
| Static |
| }; |
| } |
| |
| static bool inferFinalAndDiagnoseIfNeeded(ValueDecl *D, ClassDecl *cls, |
| StaticSpellingKind staticSpelling) { |
| // Are there any reasons to infer 'final'? Prefer 'static' over the class |
| // being final for the purposes of diagnostics. |
| Optional<ImplicitlyFinalReason> reason; |
| if (staticSpelling == StaticSpellingKind::KeywordStatic) { |
| reason = ImplicitlyFinalReason::Static; |
| |
| if (auto finalAttr = D->getAttrs().getAttribute<FinalAttr>()) { |
| auto finalRange = finalAttr->getRange(); |
| if (finalRange.isValid()) { |
| auto &context = D->getASTContext(); |
| context.Diags.diagnose(finalRange.Start, diag::static_decl_already_final) |
| .fixItRemove(finalRange); |
| } |
| } |
| } else if (cls->isFinal()) { |
| reason = ImplicitlyFinalReason::FinalClass; |
| } |
| |
| if (!reason) |
| return false; |
| |
| if (D->getFormalAccess() == AccessLevel::Open) { |
| auto &context = D->getASTContext(); |
| auto diagID = diag::implicitly_final_cannot_be_open; |
| if (!context.isSwiftVersionAtLeast(5)) |
| diagID = diag::implicitly_final_cannot_be_open_swift4; |
| auto inFlightDiag = context.Diags.diagnose(D, diagID, |
| static_cast<unsigned>(reason.getValue())); |
| fixItAccess(inFlightDiag, D, AccessLevel::Public); |
| } |
| |
| return true; |
| } |
| |
| /// Runtime-replacable accessors are dynamic when their storage declaration |
| /// is dynamic and they were explicitly defined or they are implicitly defined |
| /// getter/setter because no accessor was defined. |
| static bool doesAccessorNeedDynamicAttribute(AccessorDecl *accessor) { |
| auto kind = accessor->getAccessorKind(); |
| auto storage = accessor->getStorage(); |
| bool isObjC = storage->isObjC(); |
| |
| switch (kind) { |
| case AccessorKind::Get: { |
| auto readImpl = storage->getReadImpl(); |
| if (!isObjC && |
| (readImpl == ReadImplKind::Read || readImpl == ReadImplKind::Address)) |
| return false; |
| return storage->isDynamic(); |
| } |
| case AccessorKind::Set: { |
| auto writeImpl = storage->getWriteImpl(); |
| if (!isObjC && (writeImpl == WriteImplKind::Modify || |
| writeImpl == WriteImplKind::MutableAddress || |
| writeImpl == WriteImplKind::StoredWithObservers)) |
| return false; |
| return storage->isDynamic(); |
| } |
| case AccessorKind::Read: |
| if (!isObjC && storage->getReadImpl() == ReadImplKind::Read) |
| return storage->isDynamic(); |
| return false; |
| case AccessorKind::Modify: { |
| if (!isObjC && storage->getWriteImpl() == WriteImplKind::Modify) |
| return storage->isDynamic(); |
| return false; |
| } |
| case AccessorKind::MutableAddress: { |
| if (!isObjC && storage->getWriteImpl() == WriteImplKind::MutableAddress) |
| return storage->isDynamic(); |
| return false; |
| } |
| case AccessorKind::Address: { |
| if (!isObjC && storage->getReadImpl() == ReadImplKind::Address) |
| return storage->isDynamic(); |
| return false; |
| } |
| case AccessorKind::DidSet: |
| case AccessorKind::WillSet: |
| if (!isObjC && |
| storage->getWriteImpl() == WriteImplKind::StoredWithObservers) |
| return storage->isDynamic(); |
| return false; |
| } |
| llvm_unreachable("covered switch"); |
| } |
| |
| CtorInitializerKind |
| InitKindRequest::evaluate(Evaluator &evaluator, ConstructorDecl *decl) const { |
| auto &diags = decl->getASTContext().Diags; |
| |
| // Convenience inits are only allowed on classes and in extensions thereof. |
| if (decl->getAttrs().hasAttribute<ConvenienceAttr>()) { |
| if (auto nominal = decl->getDeclContext()->getSelfNominalTypeDecl()) { |
| auto classDecl = dyn_cast<ClassDecl>(nominal); |
| |
| // Forbid convenience inits on Foreign CF types, as Swift does not yet |
| // support user-defined factory inits. |
| if (classDecl && |
| classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType) { |
| diags.diagnose(decl->getLoc(), diag::cfclass_convenience_init); |
| } |
| |
| if (!classDecl) { |
| auto ConvenienceLoc = |
| decl->getAttrs().getAttribute<ConvenienceAttr>()->getLocation(); |
| |
| // Produce a tailored diagnostic for structs and enums. |
| bool isStruct = dyn_cast<StructDecl>(nominal) != nullptr; |
| if (isStruct || dyn_cast<EnumDecl>(nominal)) { |
| diags.diagnose(decl->getLoc(), diag::enumstruct_convenience_init, |
| isStruct ? "structs" : "enums") |
| .fixItRemove(ConvenienceLoc); |
| } else { |
| diags.diagnose(decl->getLoc(), diag::nonclass_convenience_init, |
| nominal->getName()) |
| .fixItRemove(ConvenienceLoc); |
| } |
| return CtorInitializerKind::Designated; |
| } |
| } |
| |
| return CtorInitializerKind::Convenience; |
| |
| } else if (auto nominal = decl->getDeclContext()->getSelfNominalTypeDecl()) { |
| // A designated init for a class must be written within the class itself. |
| // |
| // This is because designated initializers of classes get a vtable entry, |
| // and extensions cannot add vtable entries to the extended type. |
| // |
| // If we implement the ability for extensions defined in the same module |
| // (or the same file) to add vtable entries, we can re-evaluate this |
| // restriction. |
| if (isa<ClassDecl>(nominal) && !decl->isSynthesized() && |
| isa<ExtensionDecl>(decl->getDeclContext()) && |
| !(decl->getAttrs().hasAttribute<DynamicReplacementAttr>())) { |
| if (cast<ClassDecl>(nominal)->getForeignClassKind() == ClassDecl::ForeignKind::CFType) { |
| diags.diagnose(decl->getLoc(), |
| diag::cfclass_designated_init_in_extension, |
| nominal->getName()); |
| return CtorInitializerKind::Designated; |
| } else { |
| diags.diagnose(decl->getLoc(), |
| diag::designated_init_in_extension, |
| nominal->getName()) |
| .fixItInsert(decl->getLoc(), "convenience "); |
| return CtorInitializerKind::Convenience; |
| } |
| } |
| |
| if (decl->getDeclContext()->getExtendedProtocolDecl()) { |
| return CtorInitializerKind::Convenience; |
| } |
| } |
| |
| return CtorInitializerKind::Designated; |
| } |
| |
| BodyInitKindAndExpr |
| BodyInitKindRequest::evaluate(Evaluator &evaluator, |
| ConstructorDecl *decl) const { |
| |
| struct FindReferenceToInitializer : ASTWalker { |
| const ConstructorDecl *Decl; |
| BodyInitKind Kind = BodyInitKind::None; |
| ApplyExpr *InitExpr = nullptr; |
| ASTContext &ctx; |
| |
| FindReferenceToInitializer(const ConstructorDecl *decl, |
| ASTContext &ctx) |
| : Decl(decl), ctx(ctx) { } |
| |
| bool walkToDeclPre(class Decl *D) override { |
| // Don't walk into further nominal decls. |
| return !isa<NominalTypeDecl>(D); |
| } |
| |
| std::pair<bool, Expr*> walkToExprPre(Expr *E) override { |
| // Don't walk into closures. |
| if (isa<ClosureExpr>(E)) |
| return { false, E }; |
| |
| // Look for calls of a constructor on self or super. |
| auto apply = dyn_cast<ApplyExpr>(E); |
| if (!apply) |
| return { true, E }; |
| |
| auto Callee = apply->getSemanticFn(); |
| |
| Expr *arg; |
| |
| if (isa<OtherConstructorDeclRefExpr>(Callee)) { |
| arg = apply->getArg(); |
| } else if (auto *CRE = dyn_cast<ConstructorRefCallExpr>(Callee)) { |
| arg = CRE->getArg(); |
| } else if (auto *dotExpr = dyn_cast<UnresolvedDotExpr>(Callee)) { |
| if (dotExpr->getName().getBaseName() != DeclBaseName::createConstructor()) |
| return { true, E }; |
| |
| arg = dotExpr->getBase(); |
| } else { |
| // Not a constructor call. |
| return { true, E }; |
| } |
| |
| // Look for a base of 'self' or 'super'. |
| arg = arg->getSemanticsProvidingExpr(); |
| |
| auto myKind = BodyInitKind::None; |
| if (arg->isSuperExpr()) |
| myKind = BodyInitKind::Chained; |
| else if (arg->isSelfExprOf(Decl, /*sameBase*/true)) |
| myKind = BodyInitKind::Delegating; |
| else if (auto *declRef = dyn_cast<UnresolvedDeclRefExpr>(arg)) { |
| // FIXME: We can see UnresolvedDeclRefExprs here because we have |
| // not yet run preCheckExpression() on the entire function body |
| // yet. |
| // |
| // We could consider pre-checking more eagerly. |
| auto name = declRef->getName(); |
| auto loc = declRef->getLoc(); |
| if (name.isSimpleName(ctx.Id_self)) { |
| auto *otherSelfDecl = |
| ASTScope::lookupSingleLocalDecl(Decl->getParentSourceFile(), |
| name.getFullName(), loc); |
| if (otherSelfDecl == Decl->getImplicitSelfDecl()) |
| myKind = BodyInitKind::Delegating; |
| } |
| } |
| |
| if (myKind == BodyInitKind::None) |
| return { true, E }; |
| |
| if (Kind == BodyInitKind::None) { |
| Kind = myKind; |
| |
| InitExpr = apply; |
| return { true, E }; |
| } |
| |
| // If the kind changed, complain. |
| if (Kind != myKind) { |
| // The kind changed. Complain. |
| ctx.Diags.diagnose(E->getLoc(), diag::init_delegates_and_chains); |
| ctx.Diags.diagnose(InitExpr->getLoc(), diag::init_delegation_or_chain, |
| Kind == BodyInitKind::Chained); |
| } |
| |
| return { true, E }; |
| } |
| }; |
| |
| auto &ctx = decl->getASTContext(); |
| FindReferenceToInitializer finder(decl, ctx); |
| decl->getBody()->walk(finder); |
| |
| // get the kind out of the finder. |
| auto Kind = finder.Kind; |
| |
| auto *NTD = decl->getDeclContext()->getSelfNominalTypeDecl(); |
| |
| // Protocol extension and enum initializers are always delegating. |
| if (Kind == BodyInitKind::None) { |
| if (isa<ProtocolDecl>(NTD) || isa<EnumDecl>(NTD)) { |
| Kind = BodyInitKind::Delegating; |
| } |
| } |
| |
| // Struct initializers that cannot see the layout of the struct type are |
| // always delegating. This occurs if the struct type is not fixed layout, |
| // and the constructor is either inlinable or defined in another module. |
| if (Kind == BodyInitKind::None && isa<StructDecl>(NTD)) { |
| // Note: This is specifically not using isFormallyResilient. We relax this |
| // rule for structs in non-resilient modules so that they can have inlinable |
| // constructors, as long as those constructors don't reference private |
| // declarations. |
| if (NTD->isResilient() && |
| decl->getResilienceExpansion() == ResilienceExpansion::Minimal) { |
| Kind = BodyInitKind::Delegating; |
| |
| } else if (isa<ExtensionDecl>(decl->getDeclContext())) { |
| // Prior to Swift 5, cross-module initializers were permitted to be |
| // non-delegating. However, if the struct isn't fixed-layout, we have to |
| // be delegating because, well, we don't know the layout. |
| // A dynamic replacement is permitted to be non-delegating. |
| if (NTD->isResilient() || |
| (ctx.isSwiftVersionAtLeast(5) && |
| !decl->getAttrs().getAttribute<DynamicReplacementAttr>())) { |
| if (decl->getParentModule() != NTD->getParentModule()) |
| Kind = BodyInitKind::Delegating; |
| } |
| } |
| } |
| |
| // If we didn't find any delegating or chained initializers, check whether |
| // the initializer was explicitly marked 'convenience'. |
| if (Kind == BodyInitKind::None && |
| decl->getAttrs().hasAttribute<ConvenienceAttr>()) |
| Kind = BodyInitKind::Delegating; |
| |
| // If we still don't know, check whether we have a class with a superclass: it |
| // gets an implicit chained initializer. |
| if (Kind == BodyInitKind::None) { |
| if (auto classDecl = decl->getDeclContext()->getSelfClassDecl()) { |
| if (classDecl->hasSuperclass()) |
| Kind = BodyInitKind::ImplicitChained; |
| } |
| } |
| |
| return BodyInitKindAndExpr(Kind, finder.InitExpr); |
| } |
| |
| bool |
| ProtocolRequiresClassRequest::evaluate(Evaluator &evaluator, |
| ProtocolDecl *decl) const { |
| // Quick check: @objc protocols require a class. |
| if (decl->isObjC()) |
| return true; |
| |
| // Determine the set of nominal types that this protocol inherits. |
| bool anyObject = false; |
| auto allInheritedNominals = |
| getDirectlyInheritedNominalTypeDecls(decl, anyObject); |
| |
| // Quick check: do we inherit AnyObject? |
| if (anyObject) |
| return true; |
| |
| // Look through all of the inherited nominals for a superclass or a |
| // class-bound protocol. |
| for (const auto &found : allInheritedNominals) { |
| // Superclass bound. |
| if (isa<ClassDecl>(found.Item)) |
| return true; |
| |
| // A protocol that might be class-constrained. |
| if (auto proto = dyn_cast<ProtocolDecl>(found.Item)) { |
| if (proto->requiresClass()) |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| bool |
| ExistentialConformsToSelfRequest::evaluate(Evaluator &evaluator, |
| ProtocolDecl *decl) const { |
| // If it's not @objc, it conforms to itself only if it has a self-conformance |
| // witness table. |
| if (!decl->isObjC()) |
| return decl->requiresSelfConformanceWitnessTable(); |
| |
| // Check whether this protocol conforms to itself. |
| for (auto member : decl->getMembers()) { |
| if (member->isInvalid()) continue; |
| |
| if (auto vd = dyn_cast<ValueDecl>(member)) { |
| // A protocol cannot conform to itself if it has static members. |
| if (!vd->isInstanceMember()) |
| return false; |
| } |
| } |
| |
| // Check whether any of the inherited protocols fail to conform to themselves. |
| for (auto proto : decl->getInheritedProtocols()) { |
| if (!proto->existentialConformsToSelf()) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool |
| ExistentialTypeSupportedRequest::evaluate(Evaluator &evaluator, |
| ProtocolDecl *decl) const { |
| // ObjC protocols can always be existential. |
| if (decl->isObjC()) |
| return true; |
| |
| for (auto member : decl->getMembers()) { |
| // Existential types cannot be used if the protocol has an associated type. |
| if (isa<AssociatedTypeDecl>(member)) |
| return false; |
| |
| // For value members, look at their type signatures. |
| if (auto valueMember = dyn_cast<ValueDecl>(member)) { |
| if (!decl->isAvailableInExistential(valueMember)) |
| return false; |
| } |
| } |
| |
| // Check whether all of the inherited protocols support existential types. |
| for (auto proto : decl->getInheritedProtocols()) { |
| if (!proto->existentialTypeSupported()) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool |
| IsFinalRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { |
| if (isa<ClassDecl>(decl)) |
| return decl->getAttrs().hasAttribute<FinalAttr>(); |
| |
| auto cls = decl->getDeclContext()->getSelfClassDecl(); |
| if (!cls) |
| return false; |
| |
| switch (decl->getKind()) { |
| case DeclKind::Var: { |
| // Properties are final if they are declared 'static' or a 'let' |
| auto *VD = cast<VarDecl>(decl); |
| |
| // Backing storage for 'lazy' or property wrappers is always final. |
| if (VD->isLazyStorageProperty() || |
| VD->getOriginalWrappedProperty(PropertyWrapperSynthesizedPropertyKind::Backing)) |
| return true; |
| |
| // Property wrapper storage wrappers are final if the original property |
| // is final. |
| if (auto *original = VD->getOriginalWrappedProperty( |
| PropertyWrapperSynthesizedPropertyKind::Projection)) { |
| if (original->isFinal()) |
| return true; |
| } |
| |
| if (VD->getDeclContext()->getSelfClassDecl()) { |
| // If this variable is a class member, mark it final if the |
| // class is final, or if it was declared with 'let'. |
| auto *PBD = VD->getParentPatternBinding(); |
| if (PBD && inferFinalAndDiagnoseIfNeeded(decl, cls, PBD->getStaticSpelling())) |
| return true; |
| |
| if (VD->isLet()) { |
| if (VD->getFormalAccess() == AccessLevel::Open) { |
| auto &context = decl->getASTContext(); |
| auto diagID = diag::implicitly_final_cannot_be_open; |
| if (!context.isSwiftVersionAtLeast(5)) |
| diagID = diag::implicitly_final_cannot_be_open_swift4; |
| auto inFlightDiag = |
| context.Diags.diagnose(decl, diagID, |
| static_cast<unsigned>(ImplicitlyFinalReason::Let)); |
| fixItAccess(inFlightDiag, decl, AccessLevel::Public); |
| } |
| |
| return true; |
| } |
| } |
| |
| break; |
| } |
| |
| case DeclKind::Func: { |
| // Methods declared 'static' are final. |
| auto staticSpelling = cast<FuncDecl>(decl)->getStaticSpelling(); |
| if (inferFinalAndDiagnoseIfNeeded(decl, cls, staticSpelling)) |
| return true; |
| break; |
| } |
| |
| case DeclKind::Accessor: |
| if (auto accessor = dyn_cast<AccessorDecl>(decl)) { |
| switch (accessor->getAccessorKind()) { |
| case AccessorKind::DidSet: |
| case AccessorKind::WillSet: |
| // Observing accessors are marked final if in a class. |
| return true; |
| |
| case AccessorKind::Read: |
| case AccessorKind::Modify: |
| case AccessorKind::Get: |
| case AccessorKind::Set: { |
| // Coroutines and accessors are final if their storage is. |
| auto storage = accessor->getStorage(); |
| if (storage->isFinal()) |
| return true; |
| break; |
| } |
| |
| default: |
| break; |
| } |
| } |
| break; |
| |
| case DeclKind::Subscript: { |
| // Member subscripts. |
| auto staticSpelling = cast<SubscriptDecl>(decl)->getStaticSpelling(); |
| if (inferFinalAndDiagnoseIfNeeded(decl, cls, staticSpelling)) |
| return true; |
| break; |
| } |
| |
| default: |
| break; |
| } |
| |
| if (decl->getAttrs().hasAttribute<FinalAttr>()) |
| return true; |
| |
| return false; |
| } |
| |
| bool |
| IsStaticRequest::evaluate(Evaluator &evaluator, FuncDecl *decl) const { |
| if (auto *accessor = dyn_cast<AccessorDecl>(decl)) |
| return accessor->getStorage()->isStatic(); |
| |
| bool result = (decl->getStaticLoc().isValid() || |
| decl->getStaticSpelling() != StaticSpellingKind::None); |
| auto *dc = decl->getDeclContext(); |
| if (!result && |
| decl->isOperator() && |
| dc->isTypeContext()) { |
| const auto operatorName = decl->getBaseIdentifier(); |
| if (auto ED = dyn_cast<ExtensionDecl>(dc->getAsDecl())) { |
| decl->diagnose(diag::nonstatic_operator_in_extension, operatorName, |
| ED->getExtendedTypeRepr() != nullptr, |
| ED->getExtendedTypeRepr()) |
| .fixItInsert(decl->getAttributeInsertionLoc(/*forModifier=*/true), |
| "static "); |
| } else { |
| auto *NTD = cast<NominalTypeDecl>(dc->getAsDecl()); |
| decl->diagnose(diag::nonstatic_operator_in_nominal, operatorName, |
| NTD->getName()) |
| .fixItInsert(decl->getAttributeInsertionLoc(/*forModifier=*/true), |
| "static "); |
| } |
| result = true; |
| } |
| |
| return result; |
| } |
| |
| bool |
| IsDynamicRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { |
| // If we can't infer dynamic here, don't. |
| if (!DeclAttribute::canAttributeAppearOnDecl(DAK_Dynamic, decl)) |
| return false; |
| |
| // Add dynamic if -enable-implicit-dynamic was requested. |
| TypeChecker::addImplicitDynamicAttribute(decl); |
| |
| // If 'dynamic' was explicitly specified, check it. |
| if (decl->getAttrs().hasAttribute<DynamicAttr>()) { |
| return true; |
| } |
| |
| if (auto accessor = dyn_cast<AccessorDecl>(decl)) { |
| // Runtime-replacable accessors are dynamic when their storage declaration |
| // is dynamic and they were explicitly defined or they are implicitly defined |
| // getter/setter because no accessor was defined. |
| return doesAccessorNeedDynamicAttribute(accessor); |
| } |
| |
| // The 'NSManaged' attribute implies 'dynamic'. |
| // FIXME: Use a semantic check for NSManaged rather than looking for the |
| // attribute (which could be ill-formed). |
| if (decl->getAttrs().hasAttribute<NSManagedAttr>()) |
| return true; |
| |
| // The presence of 'final' blocks the inference of 'dynamic'. |
| if (decl->isFinal()) |
| return false; |
| |
| // Types are never 'dynamic'. |
| if (isa<TypeDecl>(decl)) |
| return false; |
| |
| // A non-@objc entity is never 'dynamic'. |
| if (!decl->isObjC()) |
| return false; |
| |
| // @objc declarations in class extensions are implicitly dynamic. |
| // This is intended to enable overriding the declarations. |
| auto dc = decl->getDeclContext(); |
| if (isa<ExtensionDecl>(dc) && dc->getSelfClassDecl()) |
| return true; |
| |
| // If any of the declarations overridden by this declaration are dynamic |
| // or were imported from Objective-C, this declaration is dynamic. |
| // Don't do this if the declaration is not exposed to Objective-C; that's |
| // currently the (only) manner in which one can make an override of a |
| // dynamic declaration non-dynamic. |
| auto overriddenDecls = evaluateOrDefault(evaluator, |
| OverriddenDeclsRequest{decl}, {}); |
| for (auto overridden : overriddenDecls) { |
| if (overridden->isDynamic() || overridden->hasClangNode()) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| ArrayRef<Requirement> |
| RequirementSignatureRequest::evaluate(Evaluator &evaluator, |
| ProtocolDecl *proto) const { |
| ASTContext &ctx = proto->getASTContext(); |
| |
| // First check if we have a deserializable requirement signature. |
| if (proto->hasLazyRequirementSignature()) { |
| ++NumLazyRequirementSignaturesLoaded; |
| // FIXME: (transitional) increment the redundant "always-on" counter. |
| if (ctx.Stats) |
| ++ctx.Stats->getFrontendCounters().NumLazyRequirementSignaturesLoaded; |
| |
| auto contextData = static_cast<LazyProtocolData *>( |
| ctx.getOrCreateLazyContextData(proto, nullptr)); |
| |
| SmallVector<Requirement, 8> requirements; |
| contextData->loader->loadRequirementSignature( |
| proto, contextData->requirementSignatureData, requirements); |
| if (requirements.empty()) |
| return None; |
| return ctx.AllocateCopy(requirements); |
| } |
| |
| GenericSignatureBuilder builder(proto->getASTContext()); |
| |
| // Add all of the generic parameters. |
| for (auto gp : *proto->getGenericParams()) |
| builder.addGenericParameter(gp); |
| |
| // Add the conformance of 'self' to the protocol. |
| auto selfType = |
| proto->getSelfInterfaceType()->castTo<GenericTypeParamType>(); |
| auto requirement = |
| Requirement(RequirementKind::Conformance, selfType, |
| proto->getDeclaredInterfaceType()); |
| |
| builder.addRequirement( |
| requirement, |
| GenericSignatureBuilder::RequirementSource::forRequirementSignature( |
| builder, selfType, proto), |
| nullptr); |
| |
| auto reqSignature = std::move(builder).computeGenericSignature( |
| SourceLoc(), |
| /*allowConcreteGenericPArams=*/false, |
| /*allowBuilderToMove=*/false); |
| return reqSignature->getRequirements(); |
| } |
| |
| Type |
| DefaultDefinitionTypeRequest::evaluate(Evaluator &evaluator, |
| AssociatedTypeDecl *assocType) const { |
| if (assocType->Resolver) { |
| auto defaultType = assocType->Resolver->loadAssociatedTypeDefault( |
| assocType, assocType->ResolverContextData); |
| assocType->Resolver = nullptr; |
| return defaultType; |
| } |
| |
| TypeRepr *defaultDefinition = assocType->getDefaultDefinitionTypeRepr(); |
| if (defaultDefinition) { |
| return TypeResolution::forInterface(assocType->getDeclContext(), None, |
| // Diagnose unbound generics. |
| /*unboundTyOpener*/ nullptr) |
| .resolveType(defaultDefinition); |
| } |
| |
| return Type(); |
| } |
| |
| bool |
| NeedsNewVTableEntryRequest::evaluate(Evaluator &evaluator, |
| AbstractFunctionDecl *decl) const { |
| auto *dc = decl->getDeclContext(); |
| if (!isa<ClassDecl>(dc)) |
| return true; |
| |
| // Destructors always use a fixed vtable entry. |
| if (isa<DestructorDecl>(decl)) |
| return false; |
| |
| assert(isa<FuncDecl>(decl) || isa<ConstructorDecl>(decl)); |
| |
| // Final members are always be called directly. |
| // Dynamic methods are always accessed by objc_msgSend(). |
| if (decl->isFinal() || decl->shouldUseObjCDispatch() || decl->hasClangNode()) |
| return false; |
| |
| auto &ctx = dc->getASTContext(); |
| |
| // Initializers are not normally inherited, but required initializers can |
| // be overridden for invocation from dynamic types, and convenience initializers |
| // are conditionally inherited when all designated initializers are available, |
| // working by dynamically invoking the designated initializer implementation |
| // from the subclass. Convenience initializers can also override designated |
| // initializer implementations from their superclass. |
| if (auto ctor = dyn_cast<ConstructorDecl>(decl)) { |
| if (!ctor->isRequired() && !ctor->isDesignatedInit()) { |
| return false; |
| } |
| |
| // Stub constructors don't appear in the vtable. |
| if (ctor->hasStubImplementation()) |
| return false; |
| } |
| |
| if (auto *accessor = dyn_cast<AccessorDecl>(decl)) { |
| // Check to see if it's one of the opaque accessors for the declaration. |
| auto storage = accessor->getStorage(); |
| if (!storage->requiresOpaqueAccessor(accessor->getAccessorKind())) |
| return false; |
| } |
| |
| auto base = decl->getOverriddenDecl(); |
| |
| if (!base || base->hasClangNode() || base->shouldUseObjCDispatch()) |
| return true; |
| |
| // As above, convenience initializers are not formally overridable in Swift |
| // vtables, although same-named initializers are modeled as overriding for |
| // various QoI and objc interop reasons. Even if we "override" a non-required |
| // convenience init, we still need a distinct vtable entry. |
| if (auto baseCtor = dyn_cast<ConstructorDecl>(base)) { |
| if (!baseCtor->isRequired() && !baseCtor->isDesignatedInit()) { |
| return true; |
| } |
| } |
| |
| // If the base is less visible than the override, we might need a vtable |
| // entry since callers of the override might not be able to see the base |
| // at all. |
| if (decl->isEffectiveLinkageMoreVisibleThan(base)) |
| return true; |
| |
| using Direction = ASTContext::OverrideGenericSignatureReqCheck; |
| if (!ctx.overrideGenericSignatureReqsSatisfied( |
| base, decl, Direction::BaseReqSatisfiedByDerived)) { |
| return true; |
| } |
| |
| // If this method is an ABI compatible override, then we don't need a new |
| // vtable entry. Otherwise, if it's not ABI compatible, for example if the |
| // base has a more general AST type, then we need a new entry. Note that an |
| // abstraction change is OK; we don't want to add a whole new vtable entry |
| // just because an @in parameter becomes @owned, or whatever. |
| auto isABICompatibleOverride = |
| evaluateOrDefault(evaluator, IsABICompatibleOverrideRequest{decl}, false); |
| return !isABICompatibleOverride; |
| } |
| |
| /// Given the raw value literal expression for an enum case, produces the |
| /// auto-incremented raw value for the subsequent case, or returns null if |
| /// the value is not auto-incrementable. |
| static LiteralExpr *getAutomaticRawValueExpr(AutomaticEnumValueKind valueKind, |
| EnumElementDecl *forElt, |
| LiteralExpr *prevValue) { |
| auto &Ctx = forElt->getASTContext(); |
| switch (valueKind) { |
| case AutomaticEnumValueKind::None: |
| Ctx.Diags.diagnose(forElt->getLoc(), |
| diag::enum_non_integer_convertible_raw_type_no_value); |
| return nullptr; |
| |
| case AutomaticEnumValueKind::String: |
| return new (Ctx) StringLiteralExpr(forElt->getNameStr(), SourceLoc(), |
| /*Implicit=*/true); |
| |
| case AutomaticEnumValueKind::Integer: |
| // If there was no previous value, start from zero. |
| if (!prevValue) { |
| return new (Ctx) IntegerLiteralExpr("0", SourceLoc(), |
| /*Implicit=*/true); |
| } |
| |
| if (auto intLit = dyn_cast<IntegerLiteralExpr>(prevValue)) { |
| APInt nextVal = intLit->getRawValue().sextOrSelf(128) + 1; |
| bool negative = nextVal.slt(0); |
| if (negative) |
| nextVal = -nextVal; |
| |
| llvm::SmallString<10> nextValStr; |
| nextVal.toStringSigned(nextValStr); |
| auto expr = new (Ctx) |
| IntegerLiteralExpr(Ctx.AllocateCopy(StringRef(nextValStr)), |
| forElt->getLoc(), /*Implicit=*/true); |
| if (negative) |
| expr->setNegative(forElt->getLoc()); |
| |
| return expr; |
| } |
| |
| Ctx.Diags.diagnose(forElt->getLoc(), |
| diag::enum_non_integer_raw_value_auto_increment); |
| return nullptr; |
| } |
| |
| llvm_unreachable("Unhandled AutomaticEnumValueKind in switch."); |
| } |
| |
| Optional<AutomaticEnumValueKind> |
| swift::computeAutomaticEnumValueKind(EnumDecl *ED) { |
| Type rawTy = ED->getRawType(); |
| assert(rawTy && "Cannot compute value kind without raw type!"); |
| |
| if (ED->getGenericEnvironmentOfContext() != nullptr) |
| rawTy = ED->mapTypeIntoContext(rawTy); |
| |
| // Swift enums require that the raw type is convertible from one of the |
| // primitive literal protocols. |
| auto conformsToProtocol = [&](KnownProtocolKind protoKind) { |
| ProtocolDecl *proto = ED->getASTContext().getProtocol(protoKind); |
| return TypeChecker::conformsToProtocol(rawTy, proto, ED->getDeclContext()); |
| }; |
| |
| static auto otherLiteralProtocolKinds = { |
| KnownProtocolKind::ExpressibleByFloatLiteral, |
| KnownProtocolKind::ExpressibleByUnicodeScalarLiteral, |
| KnownProtocolKind::ExpressibleByExtendedGraphemeClusterLiteral, |
| }; |
| |
| if (conformsToProtocol(KnownProtocolKind::ExpressibleByIntegerLiteral)) { |
| return AutomaticEnumValueKind::Integer; |
| } else if (conformsToProtocol(KnownProtocolKind::ExpressibleByStringLiteral)){ |
| return AutomaticEnumValueKind::String; |
| } else if (std::any_of(otherLiteralProtocolKinds.begin(), |
| otherLiteralProtocolKinds.end(), |
| conformsToProtocol)) { |
| return AutomaticEnumValueKind::None; |
| } else { |
| return None; |
| } |
| } |
| |
| evaluator::SideEffect |
| EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, |
| TypeResolutionStage stage) const { |
| Type rawTy = ED->getRawType(); |
| if (!rawTy) { |
| return std::make_tuple<>(); |
| } |
| |
| if (!computeAutomaticEnumValueKind(ED)) { |
| return std::make_tuple<>(); |
| } |
| |
| if (ED->getGenericEnvironmentOfContext() != nullptr) |
| rawTy = ED->mapTypeIntoContext(rawTy); |
| if (rawTy->hasError()) |
| return std::make_tuple<>(); |
| |
| // Check the raw values of the cases. |
| LiteralExpr *prevValue = nullptr; |
| EnumElementDecl *lastExplicitValueElt = nullptr; |
| |
| // Keep a map we can use to check for duplicate case values. |
| llvm::SmallDenseMap<RawValueKey, RawValueSource, 8> uniqueRawValues; |
| |
| // Make the raw member accesses explicit. |
| auto uncheckedRawValueOf = [](EnumElementDecl *EED) -> LiteralExpr * { |
| return EED->RawValueExpr; |
| }; |
| |
| Optional<AutomaticEnumValueKind> valueKind; |
| for (auto elt : ED->getAllElements()) { |
| // If the element has been diagnosed up to now, skip it. |
| if (elt->isInvalid()) |
| continue; |
| |
| if (uncheckedRawValueOf(elt)) { |
| if (!uncheckedRawValueOf(elt)->isImplicit()) |
| lastExplicitValueElt = elt; |
| } else if (!ED->SemanticFlags.contains(EnumDecl::HasFixedRawValues)) { |
| // Try to pull out the automatic enum value kind. If that fails, bail. |
| if (!valueKind) { |
| valueKind = computeAutomaticEnumValueKind(ED); |
| if (!valueKind) { |
| elt->setInvalid(); |
| return std::make_tuple<>(); |
| } |
| } |
| |
| // If the enum element has no explicit raw value, try to |
| // autoincrement from the previous value, or start from zero if this |
| // is the first element. |
| auto nextValue = getAutomaticRawValueExpr(*valueKind, elt, prevValue); |
| if (!nextValue) { |
| elt->setInvalid(); |
| break; |
| } |
| elt->setRawValueExpr(nextValue); |
| } |
| prevValue = uncheckedRawValueOf(elt); |
| assert(prevValue && "continued without setting raw value of enum case"); |
| |
| switch (stage) { |
| case TypeResolutionStage::Structural: |
| // We're only interested in computing the complete set of raw values, |
| // so we can skip type checking. |
| continue; |
| default: |
| // Continue on to type check the raw value. |
| break; |
| } |
| |
| |
| { |
| Expr *exprToCheck = prevValue; |
| if (TypeChecker::typeCheckExpression( |
| exprToCheck, ED, |
| /*contextualInfo=*/{rawTy, CTP_EnumCaseRawValue})) { |
| checkEnumElementActorIsolation(elt, exprToCheck); |
| TypeChecker::checkEnumElementEffects(elt, exprToCheck); |
| } |
| } |
| |
| // If we didn't find a valid initializer (maybe the initial value was |
| // incompatible with the raw value type) mark the entry as being erroneous. |
| if (!prevValue->getType() || prevValue->getType()->hasError()) { |
| elt->setInvalid(); |
| continue; |
| } |
| |
| |
| // If the raw values of the enum case are fixed, then we trust our callers |
| // to have set things up correctly. This comes up with imported enums |
| // and deserialized @objc enums which always have their raw values setup |
| // beforehand. |
| if (ED->SemanticFlags.contains(EnumDecl::HasFixedRawValues)) |
| continue; |
| |
| // Using magic literals like #file as raw value is not supported right now. |
| // TODO: We could potentially support #file, #function, #line and #column. |
| auto &Diags = ED->getASTContext().Diags; |
| SourceLoc diagLoc = uncheckedRawValueOf(elt)->isImplicit() |
| ? elt->getLoc() |
| : uncheckedRawValueOf(elt)->getLoc(); |
| if (auto magicLiteralExpr = |
| dyn_cast<MagicIdentifierLiteralExpr>(prevValue)) { |
| auto kindString = |
| magicLiteralExpr->getKindString(magicLiteralExpr->getKind()); |
| Diags.diagnose(diagLoc, diag::enum_raw_value_magic_literal, kindString); |
| elt->setInvalid(); |
| continue; |
| } |
| |
| // Check that the raw value is unique. |
| RawValueKey key{prevValue}; |
| RawValueSource source{elt, lastExplicitValueElt}; |
| |
| auto insertIterPair = uniqueRawValues.insert({key, source}); |
| if (insertIterPair.second) |
| continue; |
| |
| // Diagnose the duplicate value. |
| Diags.diagnose(diagLoc, diag::enum_raw_value_not_unique); |
| assert(lastExplicitValueElt && |
| "should not be able to have non-unique raw values when " |
| "relying on autoincrement"); |
| if (lastExplicitValueElt != elt && |
| valueKind == AutomaticEnumValueKind::Integer) { |
| Diags.diagnose(uncheckedRawValueOf(lastExplicitValueElt)->getLoc(), |
| diag::enum_raw_value_incrementing_from_here); |
| } |
| |
| RawValueSource prevSource = insertIterPair.first->second; |
| auto foundElt = prevSource.sourceElt; |
| diagLoc = uncheckedRawValueOf(foundElt)->isImplicit() |
| ? foundElt->getLoc() : uncheckedRawValueOf(foundElt)->getLoc(); |
| Diags.diagnose(diagLoc, diag::enum_raw_value_used_here); |
| if (foundElt != prevSource.lastExplicitValueElt && |
| valueKind == AutomaticEnumValueKind::Integer) { |
| if (prevSource.lastExplicitValueElt) |
| Diags.diagnose(uncheckedRawValueOf(prevSource.lastExplicitValueElt) |
| ->getLoc(), |
| diag::enum_raw_value_incrementing_from_here); |
| else |
| Diags.diagnose(ED->getAllElements().front()->getLoc(), |
| diag::enum_raw_value_incrementing_from_zero); |
| } |
| } |
| return std::make_tuple<>(); |
| } |
| |
| const ConstructorDecl * |
| swift::findNonImplicitRequiredInit(const ConstructorDecl *CD) { |
| while (CD->isImplicit()) { |
| auto *overridden = CD->getOverriddenDecl(); |
| if (!overridden || !overridden->isRequired()) |
| break; |
| CD = overridden; |
| } |
| return CD; |
| } |
| |
| /// For building the higher-than component of the diagnostic path, |
| /// we use the visited set, which we've embellished with information |
| /// about how we reached a particular node. This is reasonable because |
| /// we need to maintain the set anyway. |
| static void buildHigherThanPath( |
| PrecedenceGroupDecl *last, |
| const llvm::DenseMap<PrecedenceGroupDecl *, PrecedenceGroupDecl *> |
| &visitedFrom, |
| raw_ostream &out) { |
| auto it = visitedFrom.find(last); |
| assert(it != visitedFrom.end()); |
| auto from = it->second; |
| if (from) { |
| buildHigherThanPath(from, visitedFrom, out); |
| } |
| out << last->getName() << " -> "; |
| } |
| |
| /// For building the lower-than component of the diagnostic path, |
| /// we just do a depth-first search to find a path. |
| static bool buildLowerThanPath(PrecedenceGroupDecl *start, |
| PrecedenceGroupDecl *target, raw_ostream &out) { |
| if (start == target) { |
| out << start->getName(); |
| return true; |
| } |
| |
| if (start->isInvalid()) |
| return false; |
| |
| for (auto &rel : start->getLowerThan()) { |
| if (rel.Group && buildLowerThanPath(rel.Group, target, out)) { |
| out << " -> " << start->getName(); |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| static void checkPrecedenceCircularity(DiagnosticEngine &D, |
| PrecedenceGroupDecl *PGD) { |
| // Don't diagnose if this group is already marked invalid. |
| if (PGD->isInvalid()) |
| return; |
| |
| // The cycle doesn't necessarily go through this specific group, |
| // so we need a proper visited set to avoid infinite loops. We |
| // also record a back-reference so that we can easily reconstruct |
| // the cycle. |
| llvm::DenseMap<PrecedenceGroupDecl *, PrecedenceGroupDecl *> visitedFrom; |
| SmallVector<PrecedenceGroupDecl *, 4> stack; |
| |
| // Fill out the targets set. |
| llvm::SmallPtrSet<PrecedenceGroupDecl *, 4> targets; |
| stack.push_back(PGD); |
| do { |
| auto cur = stack.pop_back_val(); |
| |
| // If we reach an invalid node, just bail out. |
| if (cur->isInvalid()) { |
| PGD->setInvalid(); |
| return; |
| } |
| |
| targets.insert(cur); |
| |
| for (auto &rel : cur->getLowerThan()) { |
| if (!rel.Group) |
| continue; |
| |
| // We can't have cycles in the lower-than relationship |
| // because it has to point outside of the module. |
| |
| stack.push_back(rel.Group); |
| } |
| } while (!stack.empty()); |
| |
| // Make sure that the PGD is its own source. |
| visitedFrom.insert({PGD, nullptr}); |
| |
| stack.push_back(PGD); |
| do { |
| auto cur = stack.pop_back_val(); |
| |
| // If we reach an invalid node, just bail out. |
| if (cur->isInvalid()) { |
| PGD->setInvalid(); |
| return; |
| } |
| |
| for (auto &rel : cur->getHigherThan()) { |
| if (!rel.Group) |
| continue; |
| |
| // Check whether we've reached a target declaration. |
| if (!targets.count(rel.Group)) { |
| // If not, check whether we've visited this group before. |
| if (visitedFrom.insert({rel.Group, cur}).second) { |
| // If not, add it to the queue. |
| stack.push_back(rel.Group); |
| } |
| |
| // Note that we'll silently ignore cycles that don't go through PGD. |
| // We should eventually process the groups that are involved. |
| continue; |
| } |
| |
| // Otherwise, we have something to report. |
| SmallString<128> path; |
| { |
| llvm::raw_svector_ostream str(path); |
| |
| // Build the higherThan portion of the path (PGD -> cur). |
| buildHigherThanPath(cur, visitedFrom, str); |
| |
| // Build the lowerThan portion of the path (rel.Group -> PGD). |
| buildLowerThanPath(PGD, rel.Group, str); |
| } |
| |
| D.diagnose(PGD->getHigherThanLoc(), |
| diag::higher_than_precedence_group_cycle, path); |
| PGD->setInvalid(); |
| return; |
| } |
| } while (!stack.empty()); |
| } |
| |
| static PrecedenceGroupDecl *lookupPrecedenceGroupForRelation( |
| DeclContext *dc, PrecedenceGroupDecl::Relation rel, |
| PrecedenceGroupDescriptor::PathDirection direction) { |
| auto &ctx = dc->getASTContext(); |
| PrecedenceGroupDescriptor desc{dc, rel.Name, rel.NameLoc, direction}; |
| auto result = ctx.evaluator(ValidatePrecedenceGroupRequest{desc}); |
| if (!result) { |
| // Handle a cycle error specially. We don't want to default to an empty |
| // result, as we don't want to emit an error about not finding a precedence |
| // group. |
| using Error = CyclicalRequestError<ValidatePrecedenceGroupRequest>; |
| llvm::handleAllErrors(result.takeError(), [](const Error &E) {}); |
| return nullptr; |
| } |
| return PrecedenceGroupLookupResult(dc, rel.Name, std::move(*result)) |
| .getSingleOrDiagnose(rel.NameLoc); |
| } |
| |
| void swift::validatePrecedenceGroup(PrecedenceGroupDecl *PGD) { |
| assert(PGD && "Cannot validate a null precedence group!"); |
| if (PGD->isInvalid()) |
| return; |
| |
| auto &Diags = PGD->getASTContext().Diags; |
| auto *dc = PGD->getDeclContext(); |
| |
| // Validate the higherThan relationships. |
| bool addedHigherThan = false; |
| for (auto &rel : PGD->getMutableHigherThan()) { |
| if (rel.Group) |
| continue; |
| |
| // TODO: Requestify the lookup of a relation's group. |
| rel.Group = lookupPrecedenceGroupForRelation( |
| dc, rel, PrecedenceGroupDescriptor::HigherThan); |
| if (rel.Group) { |
| addedHigherThan = true; |
| } else { |
| PGD->setInvalid(); |
| } |
| } |
| |
| // Validate the lowerThan relationships. |
| for (auto &rel : PGD->getMutableLowerThan()) { |
| if (rel.Group) |
| continue; |
| |
| auto *group = lookupPrecedenceGroupForRelation( |
| dc, rel, PrecedenceGroupDescriptor::LowerThan); |
| rel.Group = group; |
| |
| // If we didn't find anything, try doing a raw lookup for the group before |
| // diagnosing the 'lowerThan' within the same-module restriction. This can |
| // allow us to diagnose even if we have a precedence group cycle. |
| if (!group) |
| group = dc->lookupPrecedenceGroup(rel.Name).getSingle(); |
| |
| if (group && |
| group->getDeclContext()->getParentModule() == dc->getParentModule()) { |
| if (!PGD->isInvalid()) { |
| Diags.diagnose(rel.NameLoc, diag::precedence_group_lower_within_module); |
| Diags.diagnose(group->getNameLoc(), diag::kind_declared_here, |
| DescriptiveDeclKind::PrecedenceGroup); |
| } |
| PGD->setInvalid(); |
| } |
| |
| if (!rel.Group) |
| PGD->setInvalid(); |
| } |
| |
| // Try to diagnose trickier cycles that request evaluation alone can't catch. |
| if (addedHigherThan) |
| checkPrecedenceCircularity(Diags, PGD); |
| } |
| |
| TinyPtrVector<PrecedenceGroupDecl *> ValidatePrecedenceGroupRequest::evaluate( |
| Evaluator &eval, PrecedenceGroupDescriptor descriptor) const { |
| auto groups = descriptor.dc->lookupPrecedenceGroup(descriptor.ident); |
| for (auto *group : groups) |
| validatePrecedenceGroup(group); |
| |
| // Return the raw results vector, which will get wrapped back in a |
| // PrecedenceGroupLookupResult by the TypeChecker entry point. This dance |
| // avoids unnecessarily caching the name and context for the lookup. |
| return std::move(groups).get(); |
| } |
| |
| PrecedenceGroupLookupResult |
| TypeChecker::lookupPrecedenceGroup(DeclContext *dc, Identifier name, |
| SourceLoc nameLoc) { |
| auto groups = evaluateOrDefault( |
| dc->getASTContext().evaluator, |
| ValidatePrecedenceGroupRequest({dc, name, nameLoc, None}), {}); |
| return PrecedenceGroupLookupResult(dc, name, std::move(groups)); |
| } |
| |
| static NominalTypeDecl *resolveSingleNominalTypeDecl( |
| DeclContext *DC, SourceLoc loc, Identifier ident, ASTContext &Ctx, |
| TypeResolutionFlags flags = TypeResolutionFlags(0)) { |
| auto *TyR = new (Ctx) SimpleIdentTypeRepr(DeclNameLoc(loc), |
| DeclNameRef(ident)); |
| |
| const auto options = |
| TypeResolutionOptions(TypeResolverContext::TypeAliasDecl) | flags; |
| |
| const auto result = |
| TypeResolution::forInterface(DC, options, |
| // FIXME: Should unbound generics be allowed |
| // to appear amongst designated types? |
| /*unboundTyOpener*/ nullptr) |
| .resolveType(TyR); |
| |
| if (result->hasError()) |
| return nullptr; |
| return result->getAnyNominal(); |
| } |
| |
| bool swift::checkDesignatedTypes(OperatorDecl *OD, |
| ArrayRef<Located<Identifier>> identifiers) { |
| auto &ctx = OD->getASTContext(); |
| auto *DC = OD->getDeclContext(); |
| |
| SmallVector<NominalTypeDecl *, 1> designatedNominalTypes; |
| for (auto ident : identifiers) { |
| auto *decl = resolveSingleNominalTypeDecl(DC, ident.Loc, ident.Item, ctx); |
| if (!decl) |
| return true; |
| |
| designatedNominalTypes.push_back(decl); |
| } |
| |
| OD->setDesignatedNominalTypes(ctx.AllocateCopy(designatedNominalTypes)); |
| return false; |
| } |
| |
| /// Validate the given operator declaration. |
| /// |
| /// This establishes key invariants, such as an InfixOperatorDecl's |
| /// reference to its precedence group and the transitive validity of that |
| /// group. |
| PrecedenceGroupDecl * |
| OperatorPrecedenceGroupRequest::evaluate(Evaluator &evaluator, |
| InfixOperatorDecl *IOD) const { |
| auto &ctx = IOD->getASTContext(); |
| auto *dc = IOD->getDeclContext(); |
| |
| auto enableOperatorDesignatedTypes = |
| ctx.TypeCheckerOpts.EnableOperatorDesignatedTypes; |
| |
| PrecedenceGroupDecl *group = nullptr; |
| |
| auto identifiers = IOD->getIdentifiers(); |
| if (!identifiers.empty()) { |
| auto name = identifiers[0].Item; |
| auto loc = identifiers[0].Loc; |
| |
| auto canResolveType = [&]() -> bool { |
| return enableOperatorDesignatedTypes && |
| resolveSingleNominalTypeDecl(dc, loc, name, ctx, |
| TypeResolutionFlags::SilenceErrors); |
| }; |
| |
| // Make sure not to diagnose in the case where we failed to find a |
| // precedencegroup, but we could resolve a type instead. |
| auto groups = TypeChecker::lookupPrecedenceGroup(dc, name, loc); |
| if (groups.hasResults() || !canResolveType()) { |
| group = groups.getSingleOrDiagnose(loc); |
| identifiers = identifiers.slice(1); |
| } |
| } |
| |
| // Unless operator designed types are enabled, the parser will ensure that |
| // only one identifier is allowed in the clause, which we should have just |
| // handled. |
| assert(identifiers.empty() || enableOperatorDesignatedTypes); |
| |
| if (!group) { |
| auto groups = TypeChecker::lookupPrecedenceGroup( |
| dc, ctx.Id_DefaultPrecedence, SourceLoc()); |
| group = groups.getSingleOrDiagnose(IOD->getLoc(), /*forBuiltin*/ true); |
| } |
| |
| auto nominalTypes = IOD->getDesignatedNominalTypes(); |
| if (nominalTypes.empty() && enableOperatorDesignatedTypes) { |
| if (checkDesignatedTypes(IOD, identifiers)) { |
| IOD->setInvalid(); |
| } |
| } |
| return group; |
| } |
| |
| SelfAccessKind |
| SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { |
| if (FD->getAttrs().getAttribute<MutatingAttr>(true)) { |
| if (!FD->isInstanceMember() || !FD->getDeclContext()->hasValueSemantics()) { |
| // If this decl is on a class-constrained protocol extension, then |
| // respect the explicit mutatingness. Otherwise, we would throw an |
| // error. |
| if (FD->getDeclContext()->isClassConstrainedProtocolExtension()) |
| return SelfAccessKind::Mutating; |
| return SelfAccessKind::NonMutating; |
| } |
| return SelfAccessKind::Mutating; |
| } else if (FD->getAttrs().hasAttribute<NonMutatingAttr>()) { |
| return SelfAccessKind::NonMutating; |
| } else if (FD->getAttrs().hasAttribute<ConsumingAttr>()) { |
| return SelfAccessKind::Consuming; |
| } |
| |
| if (auto *AD = dyn_cast<AccessorDecl>(FD)) { |
| // Non-static set/willSet/didSet/mutableAddress default to mutating. |
| // get/address default to non-mutating. |
| switch (AD->getAccessorKind()) { |
| case AccessorKind::Address: |
| case AccessorKind::Get: |
| case AccessorKind::Read: |
| break; |
| |
| case AccessorKind::MutableAddress: |
| case AccessorKind::Set: |
| case AccessorKind::Modify: |
| if (AD->isInstanceMember() && AD->getDeclContext()->hasValueSemantics()) |
| return SelfAccessKind::Mutating; |
| break; |
| |
| case AccessorKind::WillSet: |
| case AccessorKind::DidSet: { |
| auto *storage =AD->getStorage(); |
| if (storage->isSetterMutating()) |
| return SelfAccessKind::Mutating; |
| |
| break; |
| } |
| } |
| } |
| |
| return SelfAccessKind::NonMutating; |
| } |
| |
| bool TypeChecker::isAvailabilitySafeForConformance( |
| ProtocolDecl *proto, ValueDecl *requirement, ValueDecl *witness, |
| DeclContext *dc, AvailabilityContext &requirementInfo) { |
| |
| // We assume conformances in |
| // non-SourceFiles have already been checked for availability. |
| if (!dc->getParentSourceFile()) |
| return true; |
| |
| auto &Context = proto->getASTContext(); |
| NominalTypeDecl *conformingDecl = dc->getSelfNominalTypeDecl(); |
| assert(conformingDecl && "Must have conforming declaration"); |
| |
| // Make sure that any access of the witness through the protocol |
| // can only occur when the witness is available. That is, make sure that |
| // on every version where the conforming declaration is available, if the |
| // requirement is available then the witness is available as well. |
| // We do this by checking that (an over-approximation of) the intersection of |
| // the requirement's available range with both the conforming declaration's |
| // available range and the protocol's available range is fully contained in |
| // (an over-approximation of) the intersection of the witnesses's available |
| // range with both the conforming type's available range and the protocol |
| // declaration's available range. |
| AvailabilityContext witnessInfo = |
| AvailabilityInference::availableRange(witness, Context); |
| requirementInfo = AvailabilityInference::availableRange(requirement, Context); |
| |
| AvailabilityContext infoForConformingDecl = |
| overApproximateAvailabilityAtLocation(conformingDecl->getLoc(), |
| conformingDecl); |
| |
| // Constrain over-approximates intersection of version ranges. |
| witnessInfo.constrainWith(infoForConformingDecl); |
| requirementInfo.constrainWith(infoForConformingDecl); |
| |
| AvailabilityContext infoForProtocolDecl = |
| overApproximateAvailabilityAtLocation(proto->getLoc(), proto); |
| |
| witnessInfo.constrainWith(infoForProtocolDecl); |
| requirementInfo.constrainWith(infoForProtocolDecl); |
| |
| return requirementInfo.isContainedIn(witnessInfo); |
| } |
| |
| // Returns 'nullptr' if this is the setter's 'newValue' parameter; |
| // otherwise, returns the corresponding parameter of the subscript |
| // declaration. |
| static ParamDecl *getOriginalParamFromAccessor(AbstractStorageDecl *storage, |
| AccessorDecl *accessor, |
| ParamDecl *param) { |
| auto *accessorParams = accessor->getParameters(); |
| unsigned startIndex = 0; |
| |
| switch (accessor->getAccessorKind()) { |
| case AccessorKind::DidSet: |
| case AccessorKind::WillSet: |
| return nullptr; |
| |
| case AccessorKind::Set: |
| if (param == accessorParams->get(0)) { |
| // This is the 'newValue' parameter. |
| return nullptr; |
| } |
| |
| startIndex = 1; |
| break; |
| |
| default: |
| startIndex = 0; |
| break; |
| } |
| |
| // If the parameter is not the 'newValue' parameter to a setter, it |
| // must be a subscript index parameter (or we have an invalid AST). |
| auto *subscript = cast<SubscriptDecl>(storage); |
| auto *subscriptParams = subscript->getIndices(); |
| |
| auto where = llvm::find_if(*accessorParams, |
| [param](ParamDecl *other) { |
| return other == param; |
| }); |
| assert(where != accessorParams->end()); |
| unsigned index = where - accessorParams->begin(); |
| |
| return subscriptParams->get(index - startIndex); |
| } |
| |
| bool |
| IsImplicitlyUnwrappedOptionalRequest::evaluate(Evaluator &evaluator, |
| ValueDecl *decl) const { |
| TypeRepr *TyR = nullptr; |
| |
| switch (decl->getKind()) { |
| case DeclKind::Func: { |
| TyR = cast<FuncDecl>(decl)->getResultTypeRepr(); |
| break; |
| } |
| |
| case DeclKind::Accessor: { |
| auto *accessor = cast<AccessorDecl>(decl); |
| if (!accessor->isGetter()) |
| break; |
| |
| auto *storage = accessor->getStorage(); |
| if (auto *subscript = dyn_cast<SubscriptDecl>(storage)) |
| TyR = subscript->getElementTypeRepr(); |
| else |
| TyR = cast<VarDecl>(storage)->getTypeReprOrParentPatternTypeRepr(); |
| break; |
| } |
| |
| case DeclKind::Subscript: |
| TyR = cast<SubscriptDecl>(decl)->getElementTypeRepr(); |
| break; |
| |
| case DeclKind::Param: { |
| auto *param = cast<ParamDecl>(decl); |
| if (param->isSelfParameter()) |
| return false; |
| |
| if (auto *accessor = dyn_cast<AccessorDecl>(param->getDeclContext())) { |
| auto *storage = accessor->getStorage(); |
| auto *originalParam = getOriginalParamFromAccessor( |
| storage, accessor, param); |
| if (originalParam == nullptr) { |
| // This is the setter's newValue parameter. |
| return storage->isImplicitlyUnwrappedOptional(); |
| } |
| |
| if (param != originalParam) { |
| // This is the 'subscript(...) { get { ... } set { ... } }' case. |
| // This means we cloned the parameter list for each accessor. |
| // Delegate to the original parameter. |
| return originalParam->isImplicitlyUnwrappedOptional(); |
| } |
| |
| // This is the 'subscript(...) { <<body of getter>> }' case. |
| // The subscript and the getter share their ParamDecls. |
| // Fall through. |
| } |
| |
| // Handle eg, 'inout Int!' or '__owned NSObject!'. |
| TyR = param->getTypeRepr(); |
| if (auto *STR = dyn_cast_or_null<SpecifierTypeRepr>(TyR)) |
| TyR = STR->getBase(); |
| break; |
| } |
| |
| case DeclKind::Var: |
| TyR = cast<VarDecl>(decl)->getTypeReprOrParentPatternTypeRepr(); |
| break; |
| |
| default: |
| break; |
| } |
| |
| return (TyR && TyR->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional); |
| } |
| |
| /// Validate the underlying type of the given typealias. |
| Type |
| UnderlyingTypeRequest::evaluate(Evaluator &evaluator, |
| TypeAliasDecl *typeAlias) const { |
| TypeResolutionOptions options((typeAlias->getGenericParams() |
| ? TypeResolverContext::GenericTypeAliasDecl |
| : TypeResolverContext::TypeAliasDecl)); |
| |
| // This can happen when code completion is attempted inside |
| // of typealias underlying type e.g. `typealias F = () -> Int#^TOK^#` |
| auto *underlyingRepr = typeAlias->getUnderlyingTypeRepr(); |
| if (!underlyingRepr) { |
| typeAlias->setInvalid(); |
| return ErrorType::get(typeAlias->getASTContext()); |
| } |
| |
| const auto result = TypeResolution::forInterface(typeAlias, options, |
| /*unboundTyOpener*/ nullptr) |
| .resolveType(underlyingRepr); |
| |
| if (result->hasError()) { |
| typeAlias->setInvalid(); |
| return ErrorType::get(typeAlias->getASTContext()); |
| } |
| return result; |
| } |
| |
| /// Bind the given function declaration, which declares an operator, to the |
| /// corresponding operator declaration. |
| OperatorDecl * |
| FunctionOperatorRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const { |
| auto &C = FD->getASTContext(); |
| auto &diags = C.Diags; |
| const auto operatorName = FD->getBaseIdentifier(); |
| |
| // Check for static/final/class when we're in a type. |
| auto dc = FD->getDeclContext(); |
| if (dc->isTypeContext()) { |
| if (auto classDecl = dc->getSelfClassDecl()) { |
| // For a class, we also need the function or class to be 'final'. |
| if (!classDecl->isFinal() && !FD->isFinal() && |
| FD->getStaticLoc().isValid() && |
| FD->getStaticSpelling() != StaticSpellingKind::KeywordStatic) { |
| FD->diagnose(diag::nonfinal_operator_in_class, |
| operatorName, dc->getDeclaredInterfaceType()) |
| .fixItInsert(FD->getAttributeInsertionLoc(/*forModifier=*/true), |
| "final "); |
| FD->getAttrs().add(new (C) FinalAttr(/*IsImplicit=*/true)); |
| } |
| } |
| } else if (!dc->isModuleScopeContext()) { |
| FD->diagnose(diag::operator_in_local_scope); |
| } |
| |
| NullablePtr<OperatorDecl> op; |
| if (FD->isUnaryOperator()) { |
| if (FD->getAttrs().hasAttribute<PrefixAttr>()) { |
| op = FD->lookupPrefixOperator(operatorName); |
| } else if (FD->getAttrs().hasAttribute<PostfixAttr>()) { |
| op = FD->lookupPostfixOperator(operatorName); |
| } else { |
| auto *prefixOp = FD->lookupPrefixOperator(operatorName); |
| auto *postfixOp = FD->lookupPostfixOperator(operatorName); |
| |
| // If we found both prefix and postfix, or neither prefix nor postfix, |
| // complain. We can't fix this situation. |
| if (static_cast<bool>(prefixOp) == static_cast<bool>(postfixOp)) { |
| diags.diagnose(FD, diag::declared_unary_op_without_attribute); |
| |
| // If we found both, point at them. |
| if (prefixOp) { |
| diags.diagnose(prefixOp, diag::unary_operator_declaration_here, |
| /*isPostfix*/ false) |
| .fixItInsert(FD->getLoc(), "prefix "); |
| diags.diagnose(postfixOp, diag::unary_operator_declaration_here, |
| /*isPostfix*/ true) |
| .fixItInsert(FD->getLoc(), "postfix "); |
| } else { |
| // FIXME: Introduce a Fix-It that adds the operator declaration? |
| } |
| |
| // FIXME: Errors could cascade here, because name lookup for this |
| // operator won't find this declaration. |
| return nullptr; |
| } |
| |
| // We found only one operator declaration, so we know whether this |
| // should be a prefix or a postfix operator. |
| |
| // Fix the AST and determine the insertion text. |
| const char *insertionText; |
| auto &C = FD->getASTContext(); |
| auto isPostfix = static_cast<bool>(postfixOp); |
| if (isPostfix) { |
| insertionText = "postfix "; |
| op = postfixOp; |
| FD->getAttrs().add(new (C) PostfixAttr(/*implicit*/false)); |
| } else { |
| insertionText = "prefix "; |
| op = prefixOp; |
| FD->getAttrs().add(new (C) PrefixAttr(/*implicit*/false)); |
| } |
| |
| // Emit diagnostic with the Fix-It. |
| diags.diagnose(FD->getFuncLoc(), diag::unary_op_missing_prepos_attribute, |
| isPostfix) |
| .fixItInsert(FD->getFuncLoc(), insertionText); |
| op.get()->diagnose(diag::unary_operator_declaration_here, isPostfix); |
| } |
| } else if (FD->isBinaryOperator()) { |
| auto results = FD->lookupInfixOperator(operatorName); |
| |
| // If we have an ambiguity, diagnose and return. Otherwise fall through, as |
| // we have a custom diagnostic for missing operator decls. |
| if (results.isAmbiguous()) { |
| results.diagnoseAmbiguity(FD->getLoc()); |
| return nullptr; |
| } |
| op = results.getSingle(); |
| } else { |
| diags.diagnose(FD, diag::invalid_arg_count_for_operator); |
| return nullptr; |
| } |
| |
| if (!op) { |
| SourceLoc insertionLoc; |
| if (isa<SourceFile>(FD->getParent())) { |
| // Parent context is SourceFile, insertion location is start of func |
| // declaration or unary operator |
| if (FD->isUnaryOperator()) { |
| insertionLoc = FD->getAttrs().getStartLoc(); |
| } else { |
| insertionLoc = FD->getStartLoc(); |
| } |
| } else { |
| // Find the topmost non-file decl context and insert there. |
| for (DeclContext *CurContext = FD->getLocalContext(); |
| !isa<SourceFile>(CurContext); |
| CurContext = CurContext->getParent()) { |
| // Skip over non-decl contexts (e.g. closure expresssions) |
| if (auto *D = CurContext->getAsDecl()) |
| insertionLoc = D->getStartLoc(); |
| } |
| } |
| |
| SmallString<128> insertion; |
| { |
| llvm::raw_svector_ostream str(insertion); |
| assert(FD->isUnaryOperator() || FD->isBinaryOperator()); |
| if (FD->isUnaryOperator()) { |
| if (FD->getAttrs().hasAttribute<PrefixAttr>()) |
| str << "prefix operator "; |
| else |
| str << "postfix operator "; |
| } else { |
| str << "infix operator "; |
| } |
| |
| str << operatorName.str() << " : <# Precedence Group #>\n"; |
| } |
| InFlightDiagnostic opDiagnostic = |
| diags.diagnose(FD, diag::declared_operator_without_operator_decl); |
| if (insertionLoc.isValid()) |
| opDiagnostic.fixItInsert(insertionLoc, insertion); |
| return nullptr; |
| } |
| return op.get(); |
| } |
| |
| bool swift::isMemberOperator(FuncDecl *decl, Type type) { |
| // Check that member operators reference the type of 'Self'. |
| if (decl->isInvalid()) |
| return true; |
| |
| auto *DC = decl->getDeclContext(); |
| auto selfNominal = DC->getSelfNominalTypeDecl(); |
| |
| // Check the parameters for a reference to 'Self'. |
| bool isProtocol = selfNominal && isa<ProtocolDecl>(selfNominal); |
| for (auto param : *decl->getParameters()) { |
| // Look through a metatype reference, if there is one. |
| auto paramType = param->getInterfaceType()->getMetatypeInstanceType(); |
| |
| auto nominal = paramType->getAnyNominal(); |
| if (type.isNull()) { |
| // Is it the same nominal type? |
| if (selfNominal && nominal == selfNominal) |
| return true; |
| } else { |
| // Is it the same nominal type? Or a generic (which may or may not match)? |
| if (paramType->is<GenericTypeParamType>() || |
| nominal == type->getAnyNominal()) |
| return true; |
| } |
| |
| if (isProtocol) { |
| // For a protocol, is it the 'Self' type parameter? |
| if (auto genericParam = paramType->getAs<GenericTypeParamType>()) |
| if (genericParam->isEqual(DC->getSelfInterfaceType())) |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| static Type buildAddressorResultType(AccessorDecl *addressor, |
| Type valueType) { |
| assert(addressor->getAccessorKind() == AccessorKind::Address || |
| addressor->getAccessorKind() == AccessorKind::MutableAddress); |
| |
| PointerTypeKind pointerKind = |
| (addressor->getAccessorKind() == AccessorKind::Address) |
| ? PTK_UnsafePointer |
| : PTK_UnsafeMutablePointer; |
| return valueType->wrapInPointer(pointerKind); |
| } |
| |
| Type |
| ResultTypeRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { |
| auto &ctx = decl->getASTContext(); |
| |
| // Accessors always inherit their result type from their storage. |
| if (auto *accessor = dyn_cast<AccessorDecl>(decl)) { |
| auto *storage = accessor->getStorage(); |
| |
| switch (accessor->getAccessorKind()) { |
| // For getters, set the result type to the value type. |
| case AccessorKind::Get: |
| return storage->getValueInterfaceType(); |
| |
| // For setters and observers, set the old/new value parameter's type |
| // to the value type. |
| case AccessorKind::DidSet: |
| case AccessorKind::WillSet: |
| case AccessorKind::Set: |
| return TupleType::getEmpty(ctx); |
| |
| // Addressor result types can get complicated because of the owner. |
| case AccessorKind::Address: |
| case AccessorKind::MutableAddress: |
| return buildAddressorResultType(accessor, storage->getValueInterfaceType()); |
| |
| // Coroutine accessors don't mention the value type directly. |
| // If we add yield types to the function type, we'll need to update this. |
| case AccessorKind::Read: |
| case AccessorKind::Modify: |
| return TupleType::getEmpty(ctx); |
| } |
| } |
| |
| TypeRepr *resultTyRepr = nullptr; |
| if (const auto *const funcDecl = dyn_cast<FuncDecl>(decl)) { |
| resultTyRepr = funcDecl->getResultTypeRepr(); |
| } else { |
| resultTyRepr = cast<SubscriptDecl>(decl)->getElementTypeRepr(); |
| } |
| |
| // Nothing to do if there's no result type. |
| if (resultTyRepr == nullptr) |
| return TupleType::getEmpty(ctx); |
| |
| // Handle opaque types. |
| if (decl->getOpaqueResultTypeRepr()) { |
| auto *opaqueDecl = decl->getOpaqueResultTypeDecl(); |
| return (opaqueDecl |
| ? opaqueDecl->getDeclaredInterfaceType() |
| : ErrorType::get(ctx)); |
| } |
| |
| const auto options = |
| TypeResolutionOptions(TypeResolverContext::FunctionResult); |
| auto *const dc = decl->getInnermostDeclContext(); |
| return TypeResolution::forInterface(dc, options, /*unboundTyOpener*/ nullptr) |
| .resolveType(resultTyRepr); |
| } |
| |
| ParamSpecifier |
| ParamSpecifierRequest::evaluate(Evaluator &evaluator, |
| ParamDecl *param) const { |
| auto *dc = param->getDeclContext(); |
| |
| if (param->isSelfParameter()) { |
| auto selfParam = computeSelfParam(cast<AbstractFunctionDecl>(dc), |
| /*isInitializingCtor*/true, |
| /*wantDynamicSelf*/false); |
| return (selfParam.getParameterFlags().isInOut() |
| ? ParamSpecifier::InOut |
| : ParamSpecifier::Default); |
| } |
| |
| if (auto *accessor = dyn_cast<AccessorDecl>(dc)) { |
| auto *storage = accessor->getStorage(); |
| auto *originalParam = getOriginalParamFromAccessor( |
| storage, accessor, param); |
| if (originalParam == nullptr) { |
| // This is the setter's newValue parameter. Note that even though |
| // the AST uses the 'Default' specifier, SIL will lower this to a |
| // +1 parameter. |
| return ParamSpecifier::Default; |
| } |
| |
| if (param != originalParam) { |
| // This is the 'subscript(...) { get { ... } set { ... } }' case. |
| // This means we cloned the parameter list for each accessor. |
| // Delegate to the original parameter. |
| return originalParam->getSpecifier(); |
| } |
| |
| // This is the 'subscript(...) { <<body of getter>> }' case. |
| // The subscript and the getter share their ParamDecls. |
| // Fall through. |
| } |
| |
| auto typeRepr = param->getTypeRepr(); |
| assert(typeRepr != nullptr && "Should call setSpecifier() on " |
| "synthesized parameter declarations"); |
| |
| auto *nestedRepr = typeRepr; |
| |
| // Look through parens here; other than parens, specifiers |
| // must appear at the top level of a parameter type. |
| while (auto *tupleRepr = dyn_cast<TupleTypeRepr>(nestedRepr)) { |
| if (!tupleRepr->isParenType()) |
| break; |
| nestedRepr = tupleRepr->getElementType(0); |
| } |
| |
| if (isa<InOutTypeRepr>(nestedRepr) && |
| param->isDefaultArgument()) { |
| auto &ctx = param->getASTContext(); |
| ctx.Diags.diagnose(param->getStructuralDefaultExpr()->getLoc(), |
| swift::diag::cannot_provide_default_value_inout, |
| param->getName()); |
| return ParamSpecifier::Default; |
| } |
| |
| if (isa<InOutTypeRepr>(nestedRepr)) { |
| return ParamSpecifier::InOut; |
| } else if (isa<SharedTypeRepr>(nestedRepr)) { |
| return ParamSpecifier::Shared; |
| } else if (isa<OwnedTypeRepr>(nestedRepr)) { |
| return ParamSpecifier::Owned; |
| } |
| |
| return ParamSpecifier::Default; |
| } |
| |
| static Type validateParameterType(ParamDecl *decl) { |
| auto *dc = decl->getDeclContext(); |
| |
| TypeResolutionOptions options(None); |
| OpenUnboundGenericTypeFn unboundTyOpener = nullptr; |
| if (isa<AbstractClosureExpr>(dc)) { |
| options = TypeResolutionOptions(TypeResolverContext::ClosureExpr); |
| options |= TypeResolutionFlags::AllowUnspecifiedTypes; |
| unboundTyOpener = [](auto unboundTy) { |
| // FIXME: Don't let unbound generic types escape type resolution. |
| // For now, just return the unbound generic type. |
| return unboundTy; |
| }; |
| } else if (isa<AbstractFunctionDecl>(dc)) { |
| options = TypeResolutionOptions(TypeResolverContext::AbstractFunctionDecl); |
| } else if (isa<SubscriptDecl>(dc)) { |
| options = TypeResolutionOptions(TypeResolverContext::SubscriptDecl); |
| } else { |
| assert(isa<EnumElementDecl>(dc)); |
| options = TypeResolutionOptions(TypeResolverContext::EnumElementDecl); |
| } |
| |
| // If the element is a variadic parameter, resolve the parameter type as if |
| // it were in non-parameter position, since we want functions to be |
| // @escaping in this case. |
| options.setContext(decl->isVariadic() ? |
| TypeResolverContext::VariadicFunctionInput : |
| TypeResolverContext::FunctionInput); |
| options |= TypeResolutionFlags::Direct; |
| |
| if (dc->isInSpecializeExtensionContext()) |
| options |= TypeResolutionFlags::AllowUsableFromInline; |
| |
| const auto resolution = |
| TypeResolution::forInterface(dc, options, unboundTyOpener); |
| auto Ty = resolution.resolveType(decl->getTypeRepr()); |
| |
| auto &ctx = dc->getASTContext(); |
| if (Ty->hasError()) { |
| decl->setInvalid(); |
| return ErrorType::get(ctx); |
| } |
| |
| if (decl->isVariadic()) { |
| Ty = TypeChecker::getArraySliceType(decl->getStartLoc(), Ty); |
| if (Ty->hasError()) { |
| decl->setInvalid(); |
| return ErrorType::get(ctx); |
| } |
| |
| // Disallow variadic parameters in enum elements. |
| if (options.getBaseContext() == TypeResolverContext::EnumElementDecl) { |
| decl->diagnose(diag::enum_element_ellipsis); |
| decl->setInvalid(); |
| return ErrorType::get(ctx); |
| } |
| } |
| |
| return Ty; |
| } |
| |
| Type |
| InterfaceTypeRequest::evaluate(Evaluator &eval, ValueDecl *D) const { |
| auto &Context = D->getASTContext(); |
| |
| TypeChecker::checkForForbiddenPrefix(Context, D->getBaseName()); |
| |
| switch (D->getKind()) { |
| case DeclKind::Import: |
| case DeclKind::Extension: |
| case DeclKind::PatternBinding: |
| case DeclKind::EnumCase: |
| case DeclKind::TopLevelCode: |
| case DeclKind::InfixOperator: |
| case DeclKind::PrefixOperator: |
| case DeclKind::PostfixOperator: |
| case DeclKind::PrecedenceGroup: |
| case DeclKind::IfConfig: |
| case DeclKind::PoundDiagnostic: |
| case DeclKind::MissingMember: |
| case DeclKind::Module: |
| case DeclKind::OpaqueType: |
| case DeclKind::GenericTypeParam: |
| llvm_unreachable("should not get here"); |
| return Type(); |
| |
| case DeclKind::AssociatedType: { |
| auto assocType = cast<AssociatedTypeDecl>(D); |
| auto interfaceTy = assocType->getDeclaredInterfaceType(); |
| return MetatypeType::get(interfaceTy, Context); |
| } |
| |
| case DeclKind::TypeAlias: { |
| auto typeAlias = cast<TypeAliasDecl>(D); |
| |
| auto genericSig = typeAlias->getGenericSignature(); |
| SubstitutionMap subs; |
| if (genericSig) |
| subs = genericSig->getIdentitySubstitutionMap(); |
| |
| Type parent; |
| auto parentDC = typeAlias->getDeclContext(); |
| if (parentDC->isTypeContext()) |
| parent = parentDC->getSelfInterfaceType(); |
| auto sugaredType = TypeAliasType::get(typeAlias, parent, subs, |
| typeAlias->getUnderlyingType()); |
| return MetatypeType::get(sugaredType, Context); |
| } |
| |
| case DeclKind::Enum: |
| case DeclKind::Struct: |
| case DeclKind::Class: |
| case DeclKind::Protocol: { |
| auto nominal = cast<NominalTypeDecl>(D); |
| Type declaredInterfaceTy = nominal->getDeclaredInterfaceType(); |
| return MetatypeType::get(declaredInterfaceTy, Context); |
| } |
| |
| case DeclKind::Param: { |
| auto *PD = cast<ParamDecl>(D); |
| if (PD->isSelfParameter()) { |
| auto *AFD = cast<AbstractFunctionDecl>(PD->getDeclContext()); |
| auto selfParam = computeSelfParam(AFD, |
| /*isInitializingCtor*/true, |
| /*wantDynamicSelf*/true); |
| return selfParam.getPlainType(); |
| } |
| |
| if (auto *accessor = dyn_cast<AccessorDecl>(PD->getDeclContext())) { |
| auto *storage = accessor->getStorage(); |
| auto *originalParam = getOriginalParamFromAccessor( |
| storage, accessor, PD); |
| if (originalParam == nullptr) { |
| return storage->getValueInterfaceType(); |
| } |
| |
| if (originalParam != PD) { |
| return originalParam->getInterfaceType(); |
| } |
| } |
| |
| if (!PD->getTypeRepr()) |
| return Type(); |
| |
| return validateParameterType(PD); |
| } |
| |
| case DeclKind::Var: { |
| auto *VD = cast<VarDecl>(D); |
| auto *namingPattern = VD->getNamingPattern(); |
| if (!namingPattern) { |
| return ErrorType::get(Context); |
| } |
| |
| Type interfaceType = namingPattern->getType(); |
| if (interfaceType->hasArchetype()) |
| interfaceType = interfaceType->mapTypeOutOfContext(); |
| |
| // In SIL mode, VarDecls are written as having reference storage types. |
| if (!interfaceType->is<ReferenceStorageType>()) { |
| if (auto *attr = VD->getAttrs().getAttribute<ReferenceOwnershipAttr>()) |
| interfaceType = |
| TypeChecker::checkReferenceOwnershipAttr(VD, interfaceType, attr); |
| } |
| |
| return interfaceType; |
| } |
| |
| case DeclKind::Func: |
| case DeclKind::Accessor: |
| case DeclKind::Constructor: |
| case DeclKind::Destructor: { |
| // If this is a didSet, then we need to check whether the body references |
| // the implicit 'oldValue' parameter or not, in order to correctly |
| // compute the interface type. |
| if (auto AD = dyn_cast<AccessorDecl>(D)) { |
| (void)AD->isSimpleDidSet(); |
| } |
| |
| auto *AFD = cast<AbstractFunctionDecl>(D); |
| |
| auto sig = AFD->getGenericSignature(); |
| bool hasSelf = AFD->hasImplicitSelfDecl(); |
| |
| AnyFunctionType::ExtInfoBuilder infoBuilder; |
| |
| // Result |
| Type resultTy; |
| if (auto fn = dyn_cast<FuncDecl>(D)) { |
| resultTy = fn->getResultInterfaceType(); |
| } else if (auto ctor = dyn_cast<ConstructorDecl>(D)) { |
| resultTy = ctor->getResultInterfaceType(); |
| } else { |
| assert(isa<DestructorDecl>(D)); |
| resultTy = TupleType::getEmpty(AFD->getASTContext()); |
| } |
| |
| // (Args...) -> Result |
| Type funcTy; |
| |
| { |
| SmallVector<AnyFunctionType::Param, 4> argTy; |
| AFD->getParameters()->getParams(argTy); |
| |
| infoBuilder = infoBuilder.withAsync(AFD->hasAsync()); |
| // 'throws' only applies to the innermost function. |
| infoBuilder = infoBuilder.withThrows(AFD->hasThrows()); |
| // Defer bodies must not escape. |
| if (auto fd = dyn_cast<FuncDecl>(D)) |
| infoBuilder = infoBuilder.withNoEscape(fd->isDeferBody()); |
| auto info = infoBuilder.build(); |
| |
| if (sig && !hasSelf) { |
| funcTy = GenericFunctionType::get(sig, argTy, resultTy, info); |
| } else { |
| funcTy = FunctionType::get(argTy, resultTy, info); |
| } |
| } |
| |
| // (Self) -> (Args...) -> Result |
| if (hasSelf) { |
| // Substitute in our own 'self' parameter. |
| auto selfParam = computeSelfParam(AFD); |
| if (sig) |
| funcTy = GenericFunctionType::get(sig, {selfParam}, funcTy); |
| else |
| funcTy = FunctionType::get({selfParam}, funcTy); |
| } |
| |
| return funcTy; |
| } |
| |
| case DeclKind::Subscript: { |
| auto *SD = cast<SubscriptDecl>(D); |
| |
| auto elementTy = SD->getElementInterfaceType(); |
| |
| SmallVector<AnyFunctionType::Param, 2> argTy; |
| SD->getIndices()->getParams(argTy); |
| |
| Type funcTy; |
| if (auto sig = SD->getGenericSignature()) |
| funcTy = GenericFunctionType::get(sig, argTy, elementTy); |
| else |
| funcTy = FunctionType::get(argTy, elementTy); |
| |
| return funcTy; |
| } |
| |
| case DeclKind::EnumElement: { |
| auto *EED = cast<EnumElementDecl>(D); |
| |
| auto *ED = EED->getParentEnum(); |
| |
| // The type of the enum element is either (Self.Type) -> Self |
| // or (Self.Type) -> (Args...) -> Self. |
| auto resultTy = ED->getDeclaredInterfaceType(); |
| |
| AnyFunctionType::Param selfTy(MetatypeType::get(resultTy, Context)); |
| |
| if (auto *PL = EED->getParameterList()) { |
| SmallVector<AnyFunctionType::Param, 4> argTy; |
| PL->getParams(argTy); |
| |
| resultTy = FunctionType::get(argTy, resultTy); |
| } |
| |
| if (auto genericSig = ED->getGenericSignature()) |
| resultTy = GenericFunctionType::get(genericSig, {selfTy}, resultTy); |
| else |
| resultTy = FunctionType::get({selfTy}, resultTy); |
| |
| return resultTy; |
| } |
| } |
| llvm_unreachable("invalid decl kind"); |
| } |
| |
| NamedPattern * |
| NamingPatternRequest::evaluate(Evaluator &evaluator, VarDecl *VD) const { |
| auto &Context = VD->getASTContext(); |
| auto *PBD = VD->getParentPatternBinding(); |
| // FIXME: In order for this request to properly express its dependencies, |
| // all of the places that allow variable bindings need to also use pattern |
| // binding decls. Otherwise, we'll have to go digging around in case |
| // statements and patterns to find named patterns. |
| if (PBD) { |
| // FIXME: For now, this works because PatternBindingEntryRequest fills in |
| // the naming pattern as a side effect in this case, and TypeCheckStmt |
| // and TypeCheckPattern handle the others. But that's all really gross. |
| unsigned i = PBD->getPatternEntryIndexForVarDecl(VD); |
| (void)evaluateOrDefault(evaluator, |
| PatternBindingEntryRequest{PBD, i}, |
| nullptr); |
| if (PBD->isInvalid()) { |
| VD->getParentPattern()->setType(ErrorType::get(Context)); |
| setBoundVarsTypeError(VD->getParentPattern(), Context); |
| return nullptr; |
| } |
| } else if (!VD->getParentPatternStmt() && !VD->getParentVarDecl()) { |
| // No parent? That's an error. |
| return nullptr; |
| } |
| |
| // Go digging for the named pattern that declares this variable. |
| auto *namingPattern = VD->NamingPattern; |
| if (!namingPattern) { |
| auto *canVD = VD->getCanonicalVarDecl(); |
| namingPattern = canVD->NamingPattern; |
| } |
| |
| if (!namingPattern) { |
| // Try type checking parent control statement. |
| if (auto parentStmt = VD->getParentPatternStmt()) { |
| if (auto CS = dyn_cast<CaseStmt>(parentStmt)) |
| parentStmt = CS->getParentStmt(); |
| ASTNode node(parentStmt); |
| TypeChecker::typeCheckASTNode(node, VD->getDeclContext(), |
| /*LeaveBodyUnchecked=*/true); |
| namingPattern = VD->getCanonicalVarDecl()->NamingPattern; |
| } |
| } |
| |
| if (!namingPattern) { |
| // HACK: If no other diagnostic applies, emit a generic diagnostic about |
| // a variable being unbound. We can't do better than this at the |
| // moment because TypeCheckPattern does not reliably invalidate parts of |
| // the pattern AST on failure. |
| // |
| // Once that's through, this will only fire during circular validation. |
| if (VD->hasInterfaceType() && |
| !VD->isInvalid() && !VD->getParentPattern()->isImplicit()) { |
| VD->diagnose(diag::variable_bound_by_no_pattern, VD->getName()); |
| } |
| |
| VD->getParentPattern()->setType(ErrorType::get(Context)); |
| setBoundVarsTypeError(VD->getParentPattern(), Context); |
| return nullptr; |
| } |
| |
| if (!namingPattern->hasType()) { |
| namingPattern->setType(ErrorType::get(Context)); |
| setBoundVarsTypeError(namingPattern, Context); |
| } |
| |
| return namingPattern; |
| } |
| |
| namespace { |
| |
| // Utility class for deterministically ordering vtable entries for |
| // synthesized methods. |
| struct SortedFuncList { |
| using Key = std::tuple<DeclName, std::string>; |
| using Entry = std::pair<Key, AbstractFunctionDecl *>; |
| SmallVector<Entry, 2> elts; |
| bool sorted = false; |
| |
| void add(AbstractFunctionDecl *afd) { |
| assert(!isa<AccessorDecl>(afd)); |
| |
| Key key{afd->getName(), afd->getInterfaceType().getString()}; |
| elts.emplace_back(key, afd); |
| } |
| |
| bool empty() { return elts.empty(); } |
| |
| void sort() { |
| assert(!sorted); |
| sorted = true; |
| std::sort(elts.begin(), |
| elts.end(), |
| [](const Entry &lhs, const Entry &rhs) -> bool { |
| return lhs.first < rhs.first; |
| }); |
| } |
| |
| decltype(elts)::const_iterator begin() const { |
| assert(sorted); |
| return elts.begin(); |
| } |
| |
| decltype(elts)::const_iterator end() const { |
| assert(sorted); |
| return elts.end(); |
| } |
| }; |
| |
| } // end namespace |
| |
| ArrayRef<Decl *> |
| SemanticMembersRequest::evaluate(Evaluator &evaluator, |
| IterableDeclContext *idc) const { |
| auto dc = cast<DeclContext>(idc->getDecl()); |
| auto &Context = dc->getASTContext(); |
| SmallVector<Decl *, 8> result; |
| |
| if (!dc->getParentSourceFile()) { |
| auto members = idc->getMembers(); |
| result.append(members.begin(), members.end()); |
| return Context.AllocateCopy(result); |
| } |
| |
| auto nominal = dyn_cast<NominalTypeDecl>(idc); |
| |
| if (nominal) { |
| // We need to add implicit initializers because they |
| // affect vtable layout. |
| TypeChecker::addImplicitConstructors(nominal); |
| } |
| |
| // Force any derivable conformances in this context. This ensures that any |
| // synthesized members will approach in the member list. |
| for (auto conformance : idc->getLocalConformances()) { |
| if (conformance->getState() == ProtocolConformanceState::Incomplete && |
| conformance->getProtocol()->getKnownDerivableProtocolKind()) |
| TypeChecker::checkConformance(conformance->getRootNormalConformance()); |
| } |
| |
| // If the type conforms to Encodable or Decodable, even via an extension, |
| // the CodingKeys enum is synthesized as a member of the type itself. |
| // Force it into existence. |
| if (nominal) { |
| (void) evaluateOrDefault(Context.evaluator, |
| ResolveImplicitMemberRequest{nominal, |
| ImplicitMemberAction::ResolveCodingKeys}, |
| {}); |
| } |
| |
| // If the decl has a @main attribute, we need to force synthesis of the |
| // $main function. |
| (void) evaluateOrDefault( |
| Context.evaluator, |
| SynthesizeMainFunctionRequest{const_cast<Decl *>(idc->getDecl())}, |
| nullptr); |
| |
| for (auto *member : idc->getMembers()) { |
| if (auto *var = dyn_cast<VarDecl>(member)) { |
| // The projected storage wrapper ($foo) might have dynamically-dispatched |
| // accessors, so force them to be synthesized. |
| if (var->hasAttachedPropertyWrapper()) |
| (void) var->getPropertyWrapperBackingProperty(); |
| } |
| } |
| |
| SortedFuncList synthesizedMembers; |
| |
| for (auto *member : idc->getMembers()) { |
| if (auto *afd = dyn_cast<AbstractFunctionDecl>(member)) { |
| // If this is a witness to Actor.enqueue(partialTask:), put it at the |
| // beginning of the vtable. |
| if (auto func = dyn_cast<FuncDecl>(afd)) { |
| if (func->isActorEnqueuePartialTaskWitness()) { |
| result.insert(result.begin(), func); |
| continue; |
| } |
| } |
| |
| // Add synthesized members to a side table and sort them by their mangled |
| // name, since they could have been added to the class in any order. |
| if (afd->isSynthesized()) { |
| synthesizedMembers.add(afd); |
| continue; |
| } |
| } |
| |
| result.push_back(member); |
| } |
| |
| if (!synthesizedMembers.empty()) { |
| synthesizedMembers.sort(); |
| |
| for (const auto &pair : synthesizedMembers) |
| result.push_back(pair.second); |
| } |
| |
| return Context.AllocateCopy(result); |
| } |
| |
| bool TypeChecker::isPassThroughTypealias(TypeAliasDecl *typealias, |
| Type underlyingType, |
| NominalTypeDecl *nominal) { |
| // Pass-through only makes sense when the typealias refers to a nominal |
| // type. |
| if (!nominal) return false; |
| |
| // Check that the nominal type and the typealias are either both generic |
| // at this level or neither are. |
| if (nominal->isGeneric() != typealias->isGeneric()) |
| return false; |
| |
| // Make sure either both have generic signatures or neither do. |
| auto nominalSig = nominal->getGenericSignature(); |
| auto typealiasSig = typealias->getGenericSignature(); |
| if (static_cast<bool>(nominalSig) != static_cast<bool>(typealiasSig)) |
| return false; |
| |
| // If neither is generic, we're done: it's a pass-through alias. |
| if (!nominalSig) return true; |
| |
| // Check that the type parameters are the same the whole way through. |
| auto nominalGenericParams = nominalSig->getGenericParams(); |
| auto typealiasGenericParams = typealiasSig->getGenericParams(); |
| if (nominalGenericParams.size() != typealiasGenericParams.size()) |
| return false; |
| if (!std::equal(nominalGenericParams.begin(), nominalGenericParams.end(), |
| typealiasGenericParams.begin(), |
| [](GenericTypeParamType *gp1, GenericTypeParamType *gp2) { |
| return gp1->isEqual(gp2); |
| })) |
| return false; |
| |
| // If neither is generic at this level, we have a pass-through typealias. |
| if (!typealias->isGeneric()) return true; |
| |
| auto boundGenericType = underlyingType->getAs<BoundGenericType>(); |
| if (!boundGenericType) return false; |
| |
| // If our arguments line up with our innermost generic parameters, it's |
| // a passthrough typealias. |
| auto innermostGenericParams = typealiasSig->getInnermostGenericParams(); |
| auto boundArgs = boundGenericType->getGenericArgs(); |
| if (boundArgs.size() != innermostGenericParams.size()) |
| return false; |
| |
| return std::equal(boundArgs.begin(), boundArgs.end(), |
| innermostGenericParams.begin(), |
| [](Type arg, GenericTypeParamType *gp) { |
| return arg->isEqual(gp); |
| }); |
| } |
| |
| static bool isNonGenericTypeAliasType(Type type) { |
| // A non-generic typealias can extend a specialized type. |
| if (auto *aliasType = dyn_cast<TypeAliasType>(type.getPointer())) |
| return aliasType->getDecl()->getGenericContextDepth() == (unsigned)-1; |
| |
| return false; |
| } |
| |
| Type |
| ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const { |
| auto error = [&ext]() { |
| ext->setInvalid(); |
| return ErrorType::get(ext->getASTContext()); |
| }; |
| |
| // If we didn't parse a type, fill in an error type and bail out. |
| auto *extendedRepr = ext->getExtendedTypeRepr(); |
| if (!extendedRepr) |
| return error(); |
| |
| // Compute the extended type. |
| TypeResolutionOptions options(TypeResolverContext::ExtensionBinding); |
| if (ext->isInSpecializeExtensionContext()) |
| options |= TypeResolutionFlags::AllowUsableFromInline; |
| const auto resolution = TypeResolution::forStructural( |
| ext->getDeclContext(), options, |
| [](auto unboundTy) { |
| // FIXME: Don't let unbound generic types escape type resolution. |
| // For now, just return the unbound generic type. |
| return unboundTy; |
| }); |
| |
| const auto extendedType = resolution.resolveType(extendedRepr); |
| |
| if (extendedType->hasError()) |
| return error(); |
| |
| // Hack to allow extending a generic typealias. |
| if (auto *unboundGeneric = extendedType->getAs<UnboundGenericType>()) { |
| if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(unboundGeneric->getDecl())) { |
| // Nested Hack to break cycles if this is called before validation has |
| // finished. |
| if (aliasDecl->hasInterfaceType()) { |
| auto extendedNominal = |
| aliasDecl->getDeclaredInterfaceType()->getAnyNominal(); |
| if (extendedNominal) |
| return TypeChecker::isPassThroughTypealias( |
| aliasDecl, aliasDecl->getUnderlyingType(), extendedNominal) |
| ? extendedType |
| : extendedNominal->getDeclaredType(); |
| } else { |
| if (auto ty = aliasDecl->getStructuralType() |
| ->getAs<NominalOrBoundGenericNominalType>()) |
| return TypeChecker::isPassThroughTypealias(aliasDecl, ty, |
| ty->getDecl()) |
| ? extendedType |
| : ty->getDecl()->getDeclaredType(); |
| } |
| } |
| } |
| |
| auto &diags = ext->getASTContext().Diags; |
| |
| // Cannot extend a metatype. |
| if (extendedType->is<AnyMetatypeType>()) { |
| diags.diagnose(ext->getLoc(), diag::extension_metatype, extendedType) |
| .highlight(extendedRepr->getSourceRange()); |
| return error(); |
| } |
| |
| // Cannot extend function types, tuple types, etc. |
| if (!extendedType->getAnyNominal()) { |
| diags.diagnose(ext->getLoc(), diag::non_nominal_extension, extendedType) |
| .highlight(extendedRepr->getSourceRange()); |
| return error(); |
| } |
| |
| // Cannot extend a bound generic type, unless it's referenced via a |
| // non-generic typealias type. |
| if (extendedType->isSpecialized() && |
| !isNonGenericTypeAliasType(extendedType)) { |
| diags.diagnose(ext->getLoc(), diag::extension_specialization, |
| extendedType->getAnyNominal()->getName()) |
| .highlight(extendedRepr->getSourceRange()); |
| return error(); |
| } |
| |
| return extendedType; |
| } |