//===--- ASTContext.cpp - ASTContext Implementation -----------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements the ASTContext class. // //===----------------------------------------------------------------------===// #include "swift/AST/ASTContext.h" #include "swift/Strings.h" #include "swift/AST/ArchetypeBuilder.h" #include "swift/AST/AST.h" #include "swift/AST/ConcreteDeclRef.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExprHandle.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/KnownProtocols.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/NameLookup.h" #include "swift/AST/RawComment.h" #include "swift/AST/TypeCheckerDebugConsumer.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/StringExtras.h" #include "clang/AST/DeclObjC.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "llvm/Support/Allocator.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include #include using namespace swift; LazyResolver::~LazyResolver() = default; void ModuleLoader::anchor() {} void ClangModuleLoader::anchor() {} llvm::StringRef swift::getProtocolName(KnownProtocolKind kind) { switch (kind) { #define PROTOCOL_WITH_NAME(Id, Name) \ case KnownProtocolKind::Id: \ return Name; #include "swift/AST/KnownProtocols.def" } llvm_unreachable("bad KnownProtocolKind"); } namespace { typedef std::tuple ObjCMethodConflict; /// An unsatisfied, optional @objc requirement in a protocol conformance. typedef std::pair ObjCUnsatisfiedOptReq; enum class SearchPathKind : uint8_t { Import = 1 << 0, Framework = 1 << 1 }; } struct ASTContext::Implementation { Implementation(); ~Implementation(); llvm::BumpPtrAllocator Allocator; // used in later initializations /// The set of cleanups to be called when the ASTContext is destroyed. std::vector> Cleanups; /// The last resolver. LazyResolver *Resolver = nullptr; llvm::StringMap IdentifierTable; /// The declaration of Swift.Bool. NominalTypeDecl *BoolDecl = nullptr; /// The declaration of Swift.Int. NominalTypeDecl *IntDecl = nullptr; /// The declaration of Swift.UInt. NominalTypeDecl *UIntDecl = nullptr; /// The declaration of Swift.Float. NominalTypeDecl *FloatDecl = nullptr; /// The declaration of Swift.Double. NominalTypeDecl *DoubleDecl = nullptr; /// The declaration of Swift.String. NominalTypeDecl *StringDecl = nullptr; /// The declaration of Swift.Array. NominalTypeDecl *ArrayDecl = nullptr; /// The declaration of Swift.Set. NominalTypeDecl *SetDecl = nullptr; /// The declaration of Swift.Sequence. NominalTypeDecl *SequenceDecl = nullptr; /// The declaration of Swift.Dictionary. NominalTypeDecl *DictionaryDecl = nullptr; /// The declaration of Swift.Optional. EnumDecl *OptionalDecl = nullptr; /// The declaration of Swift.Optional.Some. EnumElementDecl *OptionalSomeDecl = nullptr; /// The declaration of Swift.Optional.None. EnumElementDecl *OptionalNoneDecl = nullptr; /// The declaration of Swift.OptionSet. NominalTypeDecl *OptionSetDecl = nullptr; /// The declaration of Swift.ImplicitlyUnwrappedOptional.Some. EnumElementDecl *ImplicitlyUnwrappedOptionalSomeDecl = nullptr; /// The declaration of Swift.ImplicitlyUnwrappedOptional.None. EnumElementDecl *ImplicitlyUnwrappedOptionalNoneDecl = nullptr; /// The declaration of Swift.UnsafeMutablePointer. NominalTypeDecl *UnsafeMutablePointerDecl = nullptr; VarDecl *UnsafeMutablePointerMemoryDecl = nullptr; /// The declaration of Swift.UnsafePointer. NominalTypeDecl *UnsafePointerDecl = nullptr; VarDecl *UnsafePointerMemoryDecl = nullptr; /// The declaration of Swift.AutoreleasingUnsafeMutablePointer. NominalTypeDecl *AutoreleasingUnsafeMutablePointerDecl = nullptr; VarDecl *AutoreleasingUnsafeMutablePointerMemoryDecl = nullptr; /// The declaration of Swift.Unmanaged NominalTypeDecl *UnmanagedDecl = nullptr; /// The declaration of Swift.Void. TypeAliasDecl *VoidDecl = nullptr; /// The declaration of Swift.Any. TypeAliasDecl *AnyDecl = nullptr; /// The declaration of ObjectiveC.ObjCBool. StructDecl *ObjCBoolDecl = nullptr; // Declare cached declarations for each of the known declarations. #define FUNC_DECL(Name, Id) FuncDecl *Get##Name = nullptr; #include "swift/AST/KnownDecls.def" /// func _stdlib_Optional_isSome(v: Optional) -> Bool FuncDecl *OptionalIsSomeSomeDecls[NumOptionalTypeKinds] = {}; /// func _stdlib_Optional_unwrapped(v: Optional) -> T FuncDecl *OptionalUnwrappedDecls[NumOptionalTypeKinds] = {}; /// The declaration of Swift.ImplicitlyUnwrappedOptional. EnumDecl *ImplicitlyUnwrappedOptionalDecl = nullptr; /// func _getBool(Builtin.Int1) -> Bool FuncDecl *GetBoolDecl = nullptr; /// func ==(Int, Int) -> Bool FuncDecl *EqualIntDecl = nullptr; /// func _unimplemented_initializer(className: StaticString). FuncDecl *UnimplementedInitializerDecl = nullptr; /// func _undefined(msg: StaticString, file: StaticString, line: UInt) -> T FuncDecl *UndefinedDecl = nullptr; /// func _stdlib_isOSVersionAtLeast(Builtin.Word,Builtin.Word, Builtin.word) // -> Builtin.Int1 FuncDecl *IsOSVersionAtLeastDecl = nullptr; /// \brief The set of known protocols, lazily populated as needed. ProtocolDecl *KnownProtocols[NumKnownProtocols] = { }; /// \brief The various module loaders that import external modules into this /// ASTContext. SmallVector, 4> ModuleLoaders; /// \brief The module loader used to load Clang modules. ClangModuleLoader *TheClangModuleLoader = nullptr; /// \brief Map from Swift declarations to raw comments. llvm::DenseMap RawComments; /// \brief Map from Swift declarations to brief comments. llvm::DenseMap BriefComments; /// \brief Map from local declarations to their discriminators. /// Missing entries implicitly have value 0. llvm::DenseMap LocalDiscriminators; /// \brief Map from declarations to foreign error conventions. /// This applies to both actual imported functions and to @objc functions. llvm::DenseMap ForeignErrorConventions; /// Map from normal protocol conformances to diagnostics that have /// been delayed until the conformance is fully checked. llvm::DenseMap> DelayedConformanceDiags; /// Conformance loaders for declarations that have them. llvm::DenseMap> ConformanceLoaders; /// \brief A cached unused pattern-binding initializer context. PatternBindingInitializer *UnusedPatternBindingContext = nullptr; /// \brief A cached unused default-argument initializer context. DefaultArgumentInitializer *UnusedDefaultArgumentContext = nullptr; /// Mapping from archetypes with lazily-resolved nested types to the /// archetype builder and potential archetype corresponding to that /// archetype. llvm::DenseMap> LazyArchetypes; /// \brief Stored archetype builders. llvm::DenseMap, std::unique_ptr> ArchetypeBuilders; /// The set of property names that show up in the defining module of a /// class. llvm::DenseMap, std::unique_ptr> AllProperties; /// The set of property names that show up in the defining module of /// an Objective-C class. llvm::DenseMap, std::unique_ptr> AllPropertiesObjC; /// \brief Structure that captures data that is segregated into different /// arenas. struct Arena { llvm::FoldingSet TupleTypes; llvm::DenseMap, MetatypeType*> MetatypeTypes; llvm::DenseMap, ExistentialMetatypeType*> ExistentialMetatypeTypes; llvm::DenseMap>, FunctionType*> FunctionTypes; llvm::DenseMap ArraySliceTypes; llvm::DenseMap, DictionaryType *> DictionaryTypes; llvm::DenseMap OptionalTypes; llvm::DenseMap ImplicitlyUnwrappedOptionalTypes; llvm::DenseMap ParenTypes; llvm::DenseMap ReferenceStorageTypes; llvm::DenseMap LValueTypes; llvm::DenseMap InOutTypes; llvm::DenseMap, SubstitutedType *> SubstitutedTypes; llvm::DenseMap, DependentMemberType *> DependentMemberTypes; llvm::DenseMap DynamicSelfTypes; llvm::FoldingSet EnumTypes; llvm::FoldingSet StructTypes; llvm::FoldingSet ClassTypes; llvm::FoldingSet UnboundGenericTypes; llvm::FoldingSet BoundGenericTypes; llvm::DenseMap, ArrayRef> BoundGenericSubstitutions; /// The set of normal protocol conformances. llvm::FoldingSet NormalConformances; /// The set of specialized protocol conformances. llvm::FoldingSet SpecializedConformances; /// The set of inherited protocol conformances. llvm::FoldingSet InheritedConformances; ~Arena() { for (auto &conformance : SpecializedConformances) conformance.~SpecializedProtocolConformance(); for (auto &conformance : InheritedConformances) conformance.~InheritedProtocolConformance(); // Call the normal conformance destructors last since they could be // referenced by the other conformance types. for (auto &conformance : NormalConformances) conformance.~NormalProtocolConformance(); } size_t getTotalMemory() const; }; llvm::DenseMap ModuleTypes; llvm::DenseMap, GenericTypeParamType *> GenericParamTypes; llvm::FoldingSet GenericFunctionTypes; llvm::FoldingSet SILFunctionTypes; llvm::DenseMap SILBlockStorageTypes; llvm::DenseMap SILBoxTypes; llvm::DenseMap IntegerTypes; llvm::FoldingSet ProtocolCompositionTypes; llvm::FoldingSet BuiltinVectorTypes; llvm::FoldingSet GenericSignatures; llvm::FoldingSet CompoundNames; llvm::DenseMap OpenedExistentialArchetypes; /// List of Objective-C member conflicts we have found during type checking. std::vector ObjCMethodConflicts; /// List of optional @objc protocol requirements that have gone /// unsatisfied, which might conflict with other Objective-C methods. std::vector ObjCUnsatisfiedOptReqs; /// List of Objective-C methods created by the type checker (and not /// by the Clang importer or deserialized), which is used for /// checking unintended Objective-C overrides. std::vector ObjCMethods; llvm::StringMap> SearchPathsSet; /// \brief The permanent arena. Arena Permanent; /// Temporary arena used for a constraint solver. struct ConstraintSolverArena : public Arena { /// The allocator used for all allocations within this arena. llvm::BumpPtrAllocator &Allocator; /// Callback used to get a type member of a type variable. GetTypeVariableMemberCallback GetTypeMember; ConstraintSolverArena(llvm::BumpPtrAllocator &allocator, GetTypeVariableMemberCallback &&getTypeMember) : Allocator(allocator), GetTypeMember(std::move(getTypeMember)) { } ConstraintSolverArena(const ConstraintSolverArena &) = delete; ConstraintSolverArena(ConstraintSolverArena &&) = delete; ConstraintSolverArena &operator=(const ConstraintSolverArena &) = delete; ConstraintSolverArena &operator=(ConstraintSolverArena &&) = delete; }; /// \brief The current constraint solver arena, if any. std::unique_ptr CurrentConstraintSolverArena; Arena &getArena(AllocationArena arena) { switch (arena) { case AllocationArena::Permanent: return Permanent; case AllocationArena::ConstraintSolver: assert(CurrentConstraintSolverArena && "No constraint solver active?"); return *CurrentConstraintSolverArena; } llvm_unreachable("bad AllocationArena"); } }; ASTContext::Implementation::Implementation() : IdentifierTable(Allocator) {} ASTContext::Implementation::~Implementation() { for (auto &cleanup : Cleanups) cleanup(); } ConstraintCheckerArenaRAII:: ConstraintCheckerArenaRAII(ASTContext &self, llvm::BumpPtrAllocator &allocator, GetTypeVariableMemberCallback getTypeMember) : Self(self), Data(self.Impl.CurrentConstraintSolverArena.release()) { Self.Impl.CurrentConstraintSolverArena.reset( new ASTContext::Implementation::ConstraintSolverArena( allocator, std::move(getTypeMember))); } ConstraintCheckerArenaRAII::~ConstraintCheckerArenaRAII() { Self.Impl.CurrentConstraintSolverArena.reset( (ASTContext::Implementation::ConstraintSolverArena *)Data); } static Module *createBuiltinModule(ASTContext &ctx) { auto M = Module::create(ctx.getIdentifier("Builtin"), ctx); M->addFile(*new (ctx) BuiltinUnit(*M)); return M; } ASTContext::ASTContext(LangOptions &langOpts, SearchPathOptions &SearchPathOpts, SourceManager &SourceMgr, DiagnosticEngine &Diags) : Impl(*new Implementation()), LangOpts(langOpts), SearchPathOpts(SearchPathOpts), SourceMgr(SourceMgr), Diags(Diags), TheBuiltinModule(createBuiltinModule(*this)), StdlibModuleName(getIdentifier(STDLIB_NAME)), SwiftShimsModuleName(getIdentifier(SWIFT_SHIMS_NAME)), TypeCheckerDebug(new StderrTypeCheckerDebugConsumer()), TheErrorType(new (*this, AllocationArena::Permanent) ErrorType(*this)), TheUnresolvedType(new (*this, AllocationArena::Permanent) UnresolvedType(*this)), TheEmptyTupleType(TupleType::get(ArrayRef(), *this)), TheNativeObjectType(new (*this, AllocationArena::Permanent) BuiltinNativeObjectType(*this)), TheBridgeObjectType(new (*this, AllocationArena::Permanent) BuiltinBridgeObjectType(*this)), TheUnknownObjectType(new (*this, AllocationArena::Permanent) BuiltinUnknownObjectType(*this)), TheRawPointerType(new (*this, AllocationArena::Permanent) BuiltinRawPointerType(*this)), TheUnsafeValueBufferType(new (*this, AllocationArena::Permanent) BuiltinUnsafeValueBufferType(*this)), TheIEEE32Type(new (*this, AllocationArena::Permanent) BuiltinFloatType(BuiltinFloatType::IEEE32,*this)), TheIEEE64Type(new (*this, AllocationArena::Permanent) BuiltinFloatType(BuiltinFloatType::IEEE64,*this)), TheIEEE16Type(new (*this, AllocationArena::Permanent) BuiltinFloatType(BuiltinFloatType::IEEE16,*this)), TheIEEE80Type(new (*this, AllocationArena::Permanent) BuiltinFloatType(BuiltinFloatType::IEEE80,*this)), TheIEEE128Type(new (*this, AllocationArena::Permanent) BuiltinFloatType(BuiltinFloatType::IEEE128, *this)), ThePPC128Type(new (*this, AllocationArena::Permanent) BuiltinFloatType(BuiltinFloatType::PPC128, *this)) { // Initialize all of the known identifiers. #define IDENTIFIER_WITH_NAME(Name, IdStr) Id_##Name = getIdentifier(IdStr); #include "swift/AST/KnownIdentifiers.def" // Record the initial set of search paths. for (StringRef path : SearchPathOpts.ImportSearchPaths) Impl.SearchPathsSet[path] |= SearchPathKind::Import; for (StringRef path : SearchPathOpts.FrameworkSearchPaths) Impl.SearchPathsSet[path] |= SearchPathKind::Framework; } ASTContext::~ASTContext() { delete &Impl; } llvm::BumpPtrAllocator &ASTContext::getAllocator(AllocationArena arena) const { switch (arena) { case AllocationArena::Permanent: return Impl.Allocator; case AllocationArena::ConstraintSolver: assert(Impl.CurrentConstraintSolverArena.get() != nullptr); return Impl.CurrentConstraintSolverArena->Allocator; } llvm_unreachable("bad AllocationArena"); } LazyResolver *ASTContext::getLazyResolver() const { return Impl.Resolver; } /// Set the lazy resolver for this context. void ASTContext::setLazyResolver(LazyResolver *resolver) { if (resolver) { assert(Impl.Resolver == nullptr && "already have a resolver"); Impl.Resolver = resolver; } else { assert(Impl.Resolver != nullptr && "no resolver to remove"); Impl.Resolver = resolver; } } /// getIdentifier - Return the uniqued and AST-Context-owned version of the /// specified string. Identifier ASTContext::getIdentifier(StringRef Str) const { // Make sure null pointers stay null. if (Str.data() == nullptr) return Identifier(0); auto I = Impl.IdentifierTable.insert(std::make_pair(Str, char())).first; return Identifier(I->getKeyData()); } void ASTContext::lookupInSwiftModule( StringRef name, SmallVectorImpl &results) const { Module *M = getStdlibModule(); if (!M) return; // Find all of the declarations with this name in the Swift module. auto identifier = getIdentifier(name); M->lookupValue({ }, identifier, NLKind::UnqualifiedLookup, results); } /// Find the generic implementation declaration for the named syntactic-sugar /// type. static NominalTypeDecl *findStdlibType(const ASTContext &ctx, StringRef name, unsigned genericParams) { // Find all of the declarations with this name in the Swift module. SmallVector results; ctx.lookupInSwiftModule(name, results); for (auto result : results) { if (auto nominal = dyn_cast(result)) { auto params = nominal->getGenericParams(); if (genericParams == (params == nullptr ? 0 : params->size())) { // We found it. return nominal; } } } return nullptr; } NominalTypeDecl *ASTContext::getBoolDecl() const { if (!Impl.BoolDecl) Impl.BoolDecl = findStdlibType(*this, "Bool", 0); return Impl.BoolDecl; } NominalTypeDecl *ASTContext::getIntDecl() const { if (!Impl.IntDecl) Impl.IntDecl = findStdlibType(*this, "Int", 0); return Impl.IntDecl; } NominalTypeDecl *ASTContext::getUIntDecl() const { if (!Impl.UIntDecl) Impl.UIntDecl = findStdlibType(*this, "UInt", 0); return Impl.UIntDecl; } NominalTypeDecl *ASTContext::getFloatDecl() const { if (!Impl.FloatDecl) Impl.FloatDecl = findStdlibType(*this, "Float", 0); return Impl.FloatDecl; } NominalTypeDecl *ASTContext::getDoubleDecl() const { if (!Impl.DoubleDecl) Impl.DoubleDecl = findStdlibType(*this, "Double", 0); return Impl.DoubleDecl; } NominalTypeDecl *ASTContext::getStringDecl() const { if (!Impl.StringDecl) Impl.StringDecl = findStdlibType(*this, "String", 0); return Impl.StringDecl; } CanType ASTContext::getExceptionType() const { if (auto exn = getErrorProtocolDecl()) { return exn->getDeclaredType()->getCanonicalType(); } else { // Use Builtin.NativeObject just as a stand-in. return TheNativeObjectType; } } NominalTypeDecl *ASTContext::getErrorProtocolDecl() const { return getProtocol(KnownProtocolKind::ErrorProtocol); } NominalTypeDecl *ASTContext::getArrayDecl() const { if (!Impl.ArrayDecl) Impl.ArrayDecl = findStdlibType(*this, "Array", 1); return Impl.ArrayDecl; } NominalTypeDecl *ASTContext::getSetDecl() const { if (!Impl.SetDecl) Impl.SetDecl = findStdlibType(*this, "Set", 1); return Impl.SetDecl; } NominalTypeDecl *ASTContext::getSequenceDecl() const { if (!Impl.SequenceDecl) Impl.SequenceDecl = findStdlibType(*this, "Sequence", 1); return Impl.SequenceDecl; } NominalTypeDecl *ASTContext::getDictionaryDecl() const { if (!Impl.DictionaryDecl) Impl.DictionaryDecl = findStdlibType(*this, "Dictionary", 2); return Impl.DictionaryDecl; } EnumDecl *ASTContext::getOptionalDecl(OptionalTypeKind kind) const { switch (kind) { case OTK_None: llvm_unreachable("not optional"); case OTK_ImplicitlyUnwrappedOptional: return getImplicitlyUnwrappedOptionalDecl(); case OTK_Optional: return getOptionalDecl(); } } EnumDecl *ASTContext::getOptionalDecl() const { if (!Impl.OptionalDecl) Impl.OptionalDecl = dyn_cast_or_null(findStdlibType(*this, "Optional", 1)); return Impl.OptionalDecl; } static EnumElementDecl *findEnumElement(EnumDecl *e, Identifier name) { for (auto elt : e->getAllElements()) { if (elt->getName() == name) return elt; } return nullptr; } EnumElementDecl *ASTContext::getOptionalSomeDecl(OptionalTypeKind kind) const { switch (kind) { case OTK_Optional: return getOptionalSomeDecl(); case OTK_ImplicitlyUnwrappedOptional: return getImplicitlyUnwrappedOptionalSomeDecl(); case OTK_None: llvm_unreachable("getting Some decl for non-optional type?"); } llvm_unreachable("bad OTK"); } EnumElementDecl *ASTContext::getOptionalNoneDecl(OptionalTypeKind kind) const { switch (kind) { case OTK_Optional: return getOptionalNoneDecl(); case OTK_ImplicitlyUnwrappedOptional: return getImplicitlyUnwrappedOptionalNoneDecl(); case OTK_None: llvm_unreachable("getting None decl for non-optional type?"); } llvm_unreachable("bad OTK"); } EnumElementDecl *ASTContext::getOptionalSomeDecl() const { if (!Impl.OptionalSomeDecl) Impl.OptionalSomeDecl = findEnumElement(getOptionalDecl(), Id_some); return Impl.OptionalSomeDecl; } EnumElementDecl *ASTContext::getOptionalNoneDecl() const { if (!Impl.OptionalNoneDecl) Impl.OptionalNoneDecl = findEnumElement(getOptionalDecl(), Id_none); return Impl.OptionalNoneDecl; } EnumDecl *ASTContext::getImplicitlyUnwrappedOptionalDecl() const { if (!Impl.ImplicitlyUnwrappedOptionalDecl) Impl.ImplicitlyUnwrappedOptionalDecl = dyn_cast_or_null( findStdlibType(*this, "ImplicitlyUnwrappedOptional", 1)); return Impl.ImplicitlyUnwrappedOptionalDecl; } EnumElementDecl *ASTContext::getImplicitlyUnwrappedOptionalSomeDecl() const { if (!Impl.ImplicitlyUnwrappedOptionalSomeDecl) Impl.ImplicitlyUnwrappedOptionalSomeDecl = findEnumElement(getImplicitlyUnwrappedOptionalDecl(), Id_some); return Impl.ImplicitlyUnwrappedOptionalSomeDecl; } EnumElementDecl *ASTContext::getImplicitlyUnwrappedOptionalNoneDecl() const { if (!Impl.ImplicitlyUnwrappedOptionalNoneDecl) Impl.ImplicitlyUnwrappedOptionalNoneDecl = findEnumElement(getImplicitlyUnwrappedOptionalDecl(), Id_none); return Impl.ImplicitlyUnwrappedOptionalNoneDecl; } NominalTypeDecl *ASTContext::getOptionSetDecl() const { if (!Impl.OptionSetDecl) Impl.OptionSetDecl = findStdlibType(*this, "OptionSet", 1); return Impl.OptionSetDecl; } NominalTypeDecl *ASTContext::getUnsafeMutablePointerDecl() const { if (!Impl.UnsafeMutablePointerDecl) Impl.UnsafeMutablePointerDecl = findStdlibType( *this, "UnsafeMutablePointer", 1); return Impl.UnsafeMutablePointerDecl; } NominalTypeDecl *ASTContext::getUnsafePointerDecl() const { if (!Impl.UnsafePointerDecl) Impl.UnsafePointerDecl = findStdlibType(*this, "UnsafePointer", 1); return Impl.UnsafePointerDecl; } NominalTypeDecl *ASTContext::getAutoreleasingUnsafeMutablePointerDecl() const { if (!Impl.AutoreleasingUnsafeMutablePointerDecl) Impl.AutoreleasingUnsafeMutablePointerDecl = findStdlibType(*this, "AutoreleasingUnsafeMutablePointer", 1); return Impl.AutoreleasingUnsafeMutablePointerDecl; } NominalTypeDecl *ASTContext::getUnmanagedDecl() const { if (!Impl.UnmanagedDecl) Impl.UnmanagedDecl = findStdlibType(*this, "Unmanaged", 1); return Impl.UnmanagedDecl; } static VarDecl *getPointeeProperty(VarDecl *&cache, NominalTypeDecl *(ASTContext::*getNominal)() const, const ASTContext &ctx) { if (cache) return cache; // There must be a generic type with one argument. NominalTypeDecl *nominal = (ctx.*getNominal)(); if (!nominal) return nullptr; auto generics = nominal->getGenericParams(); if (!generics) return nullptr; if (generics->size() != 1) return nullptr; // There must be a property named "pointee". auto identifier = ctx.getIdentifier("pointee"); auto results = nominal->lookupDirect(identifier); if (results.size() != 1) return nullptr; // The property must have type T. VarDecl *property = dyn_cast(results[0]); if (!property) return nullptr; if (!property->getType()->isEqual(generics->getPrimaryArchetypes()[0])) return nullptr; cache = property; return property; } VarDecl * ASTContext::getPointerPointeePropertyDecl(PointerTypeKind ptrKind) const { switch (ptrKind) { case PTK_UnsafeMutablePointer: return getPointeeProperty(Impl.UnsafeMutablePointerMemoryDecl, &ASTContext::getUnsafeMutablePointerDecl, *this); case PTK_UnsafePointer: return getPointeeProperty(Impl.UnsafePointerMemoryDecl, &ASTContext::getUnsafePointerDecl, *this); case PTK_AutoreleasingUnsafeMutablePointer: return getPointeeProperty(Impl.AutoreleasingUnsafeMutablePointerMemoryDecl, &ASTContext::getAutoreleasingUnsafeMutablePointerDecl, *this); } llvm_unreachable("bad pointer kind"); } TypeAliasDecl *ASTContext::getVoidDecl() const { if (Impl.VoidDecl) { return Impl.VoidDecl; } // Go find 'Void' in the Swift module. SmallVector results; lookupInSwiftModule("Void", results); for (auto result : results) { if (auto typeAlias = dyn_cast(result)) { Impl.VoidDecl = typeAlias; return typeAlias; } } return Impl.VoidDecl; } TypeAliasDecl *ASTContext::getAnyDecl() const { if (Impl.AnyDecl) { return Impl.AnyDecl; } // Go find 'Any' in the Swift module. SmallVector results; lookupInSwiftModule("Any", results); for (auto result : results) { if (auto typeAlias = dyn_cast(result)) { Impl.AnyDecl = typeAlias; break; } } return Impl.AnyDecl; } StructDecl *ASTContext::getObjCBoolDecl() { if (!Impl.ObjCBoolDecl) { SmallVector results; if (Module *M = getModuleByName(Id_ObjectiveC.str())) { M->lookupValue({ }, getIdentifier("ObjCBool"), NLKind::UnqualifiedLookup, results); for (auto result : results) { if (auto structDecl = dyn_cast(result)) { if (structDecl->getGenericParams() == nullptr) { Impl.ObjCBoolDecl = structDecl; break; } } } } } return Impl.ObjCBoolDecl; } ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const { // Check whether we've already looked for and cached this protocol. unsigned index = (unsigned)kind; assert(index < NumKnownProtocols && "Number of known protocols is wrong"); if (Impl.KnownProtocols[index]) return Impl.KnownProtocols[index]; // Find all of the declarations with this name in the appropriate module. SmallVector results; // _BridgedNSError is in the Foundation module. if (kind == KnownProtocolKind::BridgedNSError) { Module *foundation = const_cast(this)->getLoadedModule(Id_Foundation); if (!foundation) return nullptr; auto identifier = getIdentifier(getProtocolName(kind)); foundation->lookupValue({ }, identifier, NLKind::UnqualifiedLookup, results); } else { lookupInSwiftModule(getProtocolName(kind), results); } for (auto result : results) { if (auto protocol = dyn_cast(result)) { Impl.KnownProtocols[index] = protocol; return protocol; } } return nullptr; } /// Find the implementation for the given "intrinsic" library function. static FuncDecl *findLibraryIntrinsic(const ASTContext &ctx, StringRef name, LazyResolver *resolver) { SmallVector results; ctx.lookupInSwiftModule(name, results); if (results.size() == 1) { if (auto FD = dyn_cast(results.front())) { if (resolver) resolver->resolveDeclSignature(FD); return FD; } } return nullptr; } static CanType stripImmediateLabels(CanType type) { while (auto tuple = dyn_cast(type)) { if (tuple->getNumElements() == 1) { type = tuple.getElementType(0); } else { break; } } return type; } /// Check whether the given function is non-generic. static bool isNonGenericIntrinsic(FuncDecl *fn, CanType &input, CanType &output) { auto fnType = dyn_cast(fn->getType()->getCanonicalType()); if (!fnType) return false; input = stripImmediateLabels(fnType.getInput()); output = stripImmediateLabels(fnType.getResult()); return true; } /// Check whether the given type is Builtin.Int1. static bool isBuiltinInt1Type(CanType type) { if (auto intType = dyn_cast(type)) return intType->isFixedWidth() && intType->getFixedWidth() == 1; return false; } /// Check whether the given type is Builtin.Word. static bool isBuiltinWordType(CanType type) { if (auto intType = dyn_cast(type)) return intType->getWidth().isPointerWidth(); return false; } FuncDecl *ASTContext::getGetBoolDecl(LazyResolver *resolver) const { if (Impl.GetBoolDecl) return Impl.GetBoolDecl; // Look for the function. CanType input, output; auto decl = findLibraryIntrinsic(*this, "_getBool", resolver); if (!decl || !isNonGenericIntrinsic(decl, input, output)) return nullptr; // Input must be Builtin.Int1 if (!isBuiltinInt1Type(input)) return nullptr; // Output must be a global type named Bool. auto nominalType = dyn_cast(output); if (!nominalType || nominalType.getParent() || nominalType->getDecl()->getName().str() != "Bool") return nullptr; Impl.GetBoolDecl = decl; return decl; } FuncDecl *ASTContext::getEqualIntDecl(LazyResolver *resolver) const { if (Impl.EqualIntDecl) return Impl.EqualIntDecl; CanType intType = getIntDecl()->getDeclaredType().getCanonicalTypeOrNull(); CanType boolType = getBoolDecl()->getDeclaredType().getCanonicalTypeOrNull(); SmallVector equalFuncs; lookupInSwiftModule("==", equalFuncs); // Find the overload for Int. for (ValueDecl *vd : equalFuncs) { // All "==" decls should be functions, but who knows... FuncDecl *funcDecl = dyn_cast(vd); if (!funcDecl) continue; if (resolver) resolver->resolveDeclSignature(funcDecl); CanType input, resultType; if (!isNonGenericIntrinsic(funcDecl, input, resultType)) continue; // Check for the signature: (Int, Int) -> Bool auto tType = dyn_cast(input.getPointer()); assert(tType); if (tType->getNumElements() != 2) continue; CanType argType1 = tType->getElementType(0).getCanonicalTypeOrNull(); CanType argType2 = tType->getElementType(1).getCanonicalTypeOrNull(); if (argType1 == intType && argType2 == intType && resultType == boolType) { Impl.EqualIntDecl = funcDecl; return funcDecl; } } return nullptr; } FuncDecl * ASTContext::getUnimplementedInitializerDecl(LazyResolver *resolver) const { if (Impl.UnimplementedInitializerDecl) return Impl.UnimplementedInitializerDecl; // Look for the function. CanType input, output; auto decl = findLibraryIntrinsic(*this, "_unimplemented_initializer", resolver); if (!decl || !isNonGenericIntrinsic(decl, input, output)) return nullptr; // FIXME: Check inputs and outputs. Impl.UnimplementedInitializerDecl = decl; return decl; } FuncDecl * ASTContext::getUndefinedDecl(LazyResolver *resolver) const { if (Impl.UndefinedDecl) return Impl.UndefinedDecl; // Look for the function. CanType input, output; auto decl = findLibraryIntrinsic(*this, "_undefined", resolver); if (!decl) return nullptr; Impl.UndefinedDecl = decl; return decl; } FuncDecl *ASTContext::getIsOSVersionAtLeastDecl(LazyResolver *resolver) const { if (Impl.IsOSVersionAtLeastDecl) return Impl.IsOSVersionAtLeastDecl; // Look for the function. CanType input, output; auto decl = findLibraryIntrinsic(*this, "_stdlib_isOSVersionAtLeast", resolver); if (!decl || !isNonGenericIntrinsic(decl, input, output)) return nullptr; // Input must be (Builtin.Word, Builtin.Word, Builtin.Word) auto inputTuple = dyn_cast(input); if (!inputTuple || inputTuple->getNumElements() != 3 || !isBuiltinWordType( inputTuple->getElementType(0).getCanonicalTypeOrNull()) || !isBuiltinWordType( inputTuple->getElementType(1).getCanonicalTypeOrNull()) || !isBuiltinWordType( inputTuple->getElementType(2).getCanonicalTypeOrNull())) { return nullptr; } // Output must be Builtin.Int1 if (!isBuiltinInt1Type(output)) return nullptr; Impl.IsOSVersionAtLeastDecl = decl; return decl; } /// Check whether the given function is generic over a single, /// unconstrained archetype. static bool isGenericIntrinsic(FuncDecl *fn, CanType &input, CanType &output, CanType ¶m) { auto fnType = dyn_cast(fn->getInterfaceType()->getCanonicalType()); if (!fnType || fnType->getGenericParams().size() != 1) return false; bool hasRequirements = std::any_of(fnType->getRequirements().begin(), fnType->getRequirements().end(), [](const Requirement &req) -> bool { return req.getKind() != RequirementKind::WitnessMarker; }); if (hasRequirements) return false; param = CanGenericTypeParamType(fnType->getGenericParams().front()); input = stripImmediateLabels(fnType.getInput()); output = stripImmediateLabels(fnType.getResult()); return true; } // Find library intrinsic function. static FuncDecl *findLibraryFunction(const ASTContext &ctx, FuncDecl *&cache, StringRef name, LazyResolver *resolver) { if (cache) return cache; // Look for a generic function. cache = findLibraryIntrinsic(ctx, name, resolver); return cache; } #define FUNC_DECL(Name, Id) \ FuncDecl *ASTContext::get##Name(LazyResolver *resolver) const { \ return findLibraryFunction(*this, Impl.Get##Name, Id, resolver); \ } #include "swift/AST/KnownDecls.def" /// Check whether the given type is Optional applied to the given /// type argument. static bool isOptionalType(const ASTContext &ctx, OptionalTypeKind optionalKind, CanType type, CanType arg) { if (auto boundType = dyn_cast(type)) { return (boundType->getDecl()->classifyAsOptionalType() == optionalKind && boundType.getGenericArgs().size() == 1 && boundType.getGenericArgs()[0] == arg); } return false; } /// Turn an OptionalTypeKind into an index into one of the caches. static unsigned asIndex(OptionalTypeKind optionalKind) { assert(optionalKind && "passed a non-optional type kind?"); return unsigned(optionalKind) - 1; } #define getOptionalIntrinsicName(PREFIX, KIND, SUFFIX) \ ((KIND) == OTK_Optional \ ? (PREFIX "Optional" SUFFIX) \ : (PREFIX "ImplicitlyUnwrappedOptional" SUFFIX)) FuncDecl *ASTContext::getOptionalIsSomeDecl( LazyResolver *resolver, OptionalTypeKind optionalKind) const { auto &cache = Impl.OptionalIsSomeSomeDecls[asIndex(optionalKind)]; if (cache) return cache; auto name = getOptionalIntrinsicName("_stdlib_", optionalKind, "_isSome"); // Look for a generic function. CanType input, output, param; auto decl = findLibraryIntrinsic(*this, name, resolver); if (!decl || !isGenericIntrinsic(decl, input, output, param)) return nullptr; // Input must be Optional. if (!isOptionalType(*this, optionalKind, input, param)) return nullptr; // Output must be a global type named Bool. auto nominalType = dyn_cast(output); if (!nominalType || nominalType.getParent() || nominalType->getDecl()->getName().str() != "Bool") return nullptr; cache = decl; return decl; } FuncDecl *ASTContext::getOptionalUnwrappedDecl(LazyResolver *resolver, OptionalTypeKind optionalKind) const { auto &cache = Impl.OptionalUnwrappedDecls[asIndex(optionalKind)]; if (cache) return cache; auto name = getOptionalIntrinsicName( "_stdlib_", optionalKind, "_unwrapped"); // Look for the function. CanType input, output, param; auto decl = findLibraryIntrinsic(*this, name, resolver); if (!decl || !isGenericIntrinsic(decl, input, output, param)) return nullptr; // Input must be Optional. if (!isOptionalType(*this, optionalKind, input, param)) return nullptr; // Output must be T. if (output != param) return nullptr; cache = decl; return decl; } static bool hasOptionalIntrinsics(const ASTContext &ctx, LazyResolver *resolver, OptionalTypeKind optionalKind) { return ctx.getOptionalIsSomeDecl(resolver, optionalKind) && ctx.getOptionalUnwrappedDecl(resolver, optionalKind); } bool ASTContext::hasOptionalIntrinsics(LazyResolver *resolver) const { return getOptionalDecl() && getOptionalSomeDecl() && getOptionalNoneDecl() && ::hasOptionalIntrinsics(*this, resolver, OTK_Optional) && ::hasOptionalIntrinsics(*this, resolver, OTK_ImplicitlyUnwrappedOptional); } bool ASTContext::hasPointerArgumentIntrinsics(LazyResolver *resolver) const { return getUnsafeMutablePointerDecl() && getUnsafePointerDecl() && (!LangOpts.EnableObjCInterop || getAutoreleasingUnsafeMutablePointerDecl()) && getConvertPointerToPointerArgument(resolver) && getConvertMutableArrayToPointerArgument(resolver) && getConvertConstArrayToPointerArgument(resolver) && getConvertConstStringToUTF8PointerArgument(resolver) && getConvertInOutToPointerArgument(resolver); } bool ASTContext::hasArrayLiteralIntrinsics(LazyResolver *resolver) const { return getArrayDecl() && getAllocateUninitializedArray(resolver) && getDeallocateUninitializedArray(resolver); } void ASTContext::addExternalDecl(Decl *decl) { ExternalDefinitions.insert(decl); } void ASTContext::addCleanup(std::function cleanup) { Impl.Cleanups.push_back(std::move(cleanup)); } bool ASTContext::hadError() const { return Diags.hadAnyError(); } /// \brief Retrieve the arena from which we should allocate storage for a type. static AllocationArena getArena(RecursiveTypeProperties properties) { bool hasTypeVariable = properties.hasTypeVariable(); return hasTypeVariable? AllocationArena::ConstraintSolver : AllocationArena::Permanent; } Optional> ASTContext::createTrivialSubstitutions(BoundGenericType *BGT, DeclContext *gpContext) const { assert(gpContext && "No generic parameter context"); assert(BGT->isCanonical() && "Requesting non-canonical substitutions"); auto Params = gpContext->getGenericParamsOfContext()->getParams(); assert(Params.size() == 1); auto Param = Params[0]; assert(Param->getArchetype() && "Not type-checked yet"); (void) Param; Substitution Subst(BGT->getGenericArgs()[0], {}); auto Substitutions = AllocateCopy(llvm::makeArrayRef(Subst)); auto arena = getArena(BGT->getRecursiveProperties()); Impl.getArena(arena).BoundGenericSubstitutions .insert(std::make_pair(std::make_pair(BGT, gpContext), Substitutions)); return Substitutions; } Optional> ASTContext::getSubstitutions(BoundGenericType* bound, DeclContext *gpContext) const { assert(gpContext && "Missing generic parameter context"); auto arena = getArena(bound->getRecursiveProperties()); assert(bound->isCanonical() && "Requesting non-canonical substitutions"); auto &boundGenericSubstitutions = Impl.getArena(arena).BoundGenericSubstitutions; auto known = boundGenericSubstitutions.find({bound, gpContext}); if (known != boundGenericSubstitutions.end()) return known->second; // We can trivially create substitutions for Array and Optional. if (bound->getDecl() == getArrayDecl() || bound->getDecl() == getOptionalDecl()) return createTrivialSubstitutions(bound, gpContext); return None; } void ASTContext::setSubstitutions(BoundGenericType* Bound, DeclContext *gpContext, ArrayRef Subs) const { auto arena = getArena(Bound->getRecursiveProperties()); auto &boundGenericSubstitutions = Impl.getArena(arena).BoundGenericSubstitutions; assert(Bound->isCanonical() && "Requesting non-canonical substitutions"); assert(boundGenericSubstitutions.count({Bound, gpContext}) == 0 && "Already have substitutions?"); boundGenericSubstitutions[{Bound, gpContext}] = Subs; } Type ASTContext::getTypeVariableMemberType(TypeVariableType *baseTypeVar, AssociatedTypeDecl *assocType) { auto &arena = *Impl.CurrentConstraintSolverArena; return arena.GetTypeMember(baseTypeVar, assocType); } void ASTContext::addSearchPath(StringRef searchPath, bool isFramework) { OptionSet &loaded = Impl.SearchPathsSet[searchPath]; auto kind = isFramework ? SearchPathKind::Framework : SearchPathKind::Import; if (loaded.contains(kind)) return; loaded |= kind; if (isFramework) SearchPathOpts.FrameworkSearchPaths.push_back(searchPath); else SearchPathOpts.ImportSearchPaths.push_back(searchPath); if (auto *clangLoader = getClangModuleLoader()) clangLoader->addSearchPath(searchPath, isFramework); } void ASTContext::addModuleLoader(std::unique_ptr loader, bool IsClang) { if (IsClang) { assert(!Impl.TheClangModuleLoader && "Already have a Clang module loader"); Impl.TheClangModuleLoader = static_cast(loader.get()); } Impl.ModuleLoaders.push_back(std::move(loader)); } void ASTContext::loadExtensions(NominalTypeDecl *nominal, unsigned previousGeneration) { for (auto &loader : Impl.ModuleLoaders) { loader->loadExtensions(nominal, previousGeneration); } } void ASTContext::loadObjCMethods( ClassDecl *classDecl, ObjCSelector selector, bool isInstanceMethod, unsigned previousGeneration, llvm::TinyPtrVector &methods) { for (auto &loader : Impl.ModuleLoaders) { loader->loadObjCMethods(classDecl, selector, isInstanceMethod, previousGeneration, methods); } } void ASTContext::verifyAllLoadedModules() const { #ifndef NDEBUG for (auto &loader : Impl.ModuleLoaders) loader->verifyAllModules(); for (auto &topLevelModulePair : LoadedModules) { Module *M = topLevelModulePair.second; bool hasAnyFileUnits = std::any_of(M->getFiles().begin(), M->getFiles().end(), [](const FileUnit *file) { return !isa(file); }); if (!hasAnyFileUnits) assert(M->failedToLoad()); } #endif } ClangModuleLoader *ASTContext::getClangModuleLoader() const { return Impl.TheClangModuleLoader; } static void recordKnownProtocol(Module *Stdlib, StringRef Name, KnownProtocolKind Kind) { Identifier ID = Stdlib->getASTContext().getIdentifier(Name); UnqualifiedLookup Lookup(ID, Stdlib, nullptr, /*NonCascading=*/true, SourceLoc(), /*IsType=*/true); if (auto Proto = dyn_cast_or_null(Lookup.getSingleTypeResult())) Proto->setKnownProtocolKind(Kind); } void ASTContext::recordKnownProtocols(Module *Stdlib) { #define PROTOCOL_WITH_NAME(Id, Name) \ recordKnownProtocol(Stdlib, Name, KnownProtocolKind::Id); #include "swift/AST/KnownProtocols.def" } Module *ASTContext::getLoadedModule( ArrayRef> ModulePath) const { assert(!ModulePath.empty()); // TODO: Swift submodules. if (ModulePath.size() == 1) { return getLoadedModule(ModulePath[0].first); } return nullptr; } Module *ASTContext::getLoadedModule(Identifier ModuleName) const { return LoadedModules.lookup(ModuleName); } void ASTContext::getVisibleTopLevelClangModules( SmallVectorImpl &Modules) const { getClangModuleLoader()->getClangPreprocessor().getHeaderSearchInfo(). collectAllModules(Modules); } ArchetypeBuilder *ASTContext::getOrCreateArchetypeBuilder( CanGenericSignature sig, ModuleDecl *mod) { // Check whether we already have an archetype builder for this // signature and module. auto known = Impl.ArchetypeBuilders.find({sig, mod}); if (known != Impl.ArchetypeBuilders.end()) return known->second.get(); // Create a new archetype builder with the given signature. auto builder = new ArchetypeBuilder(*mod, Diags); builder->addGenericSignature(sig, /*adoptArchetypes=*/false, /*treatRequirementsAsExplicit=*/true); // Store this archetype builder. Impl.ArchetypeBuilders[{sig, mod}] = std::unique_ptr(builder); return builder; } void ASTContext::setArchetypeBuilder(CanGenericSignature sig, ModuleDecl *mod, std::unique_ptr builder) { if (Impl.ArchetypeBuilders.find({sig, mod}) == Impl.ArchetypeBuilders.end()) { Impl.ArchetypeBuilders[{sig, mod}] = move(builder); } } Module * ASTContext::getModule(ArrayRef> ModulePath) { assert(!ModulePath.empty()); if (auto *M = getLoadedModule(ModulePath)) return M; auto moduleID = ModulePath[0]; for (auto &importer : Impl.ModuleLoaders) { if (Module *M = importer->loadModule(moduleID.second, ModulePath)) { if (ModulePath.size() == 1 && (ModulePath[0].first == StdlibModuleName || ModulePath[0].first == Id_Foundation)) recordKnownProtocols(M); return M; } } return nullptr; } Module *ASTContext::getModuleByName(StringRef ModuleName) { SmallVector, 4> AccessPath; while (!ModuleName.empty()) { StringRef SubModuleName; std::tie(SubModuleName, ModuleName) = ModuleName.split('.'); AccessPath.push_back({ getIdentifier(SubModuleName), SourceLoc() }); } return getModule(AccessPath); } Module *ASTContext::getStdlibModule(bool loadIfAbsent) { if (TheStdlibModule) return TheStdlibModule; if (loadIfAbsent) { auto mutableThis = const_cast(this); TheStdlibModule = mutableThis->getModule({ std::make_pair(StdlibModuleName, SourceLoc()) }); } else { TheStdlibModule = getLoadedModule(StdlibModuleName); } return TheStdlibModule; } Optional ASTContext::getRawComment(const Decl *D) { auto Known = Impl.RawComments.find(D); if (Known == Impl.RawComments.end()) return None; return Known->second; } void ASTContext::setRawComment(const Decl *D, RawComment RC) { Impl.RawComments[D] = RC; } Optional ASTContext::getBriefComment(const Decl *D) { auto Known = Impl.BriefComments.find(D); if (Known == Impl.BriefComments.end()) return None; return Known->second; } void ASTContext::setBriefComment(const Decl *D, StringRef Comment) { Impl.BriefComments[D] = Comment; } unsigned ValueDecl::getLocalDiscriminator() const { assert(getDeclContext()->isLocalContext()); auto &discriminators = getASTContext().Impl.LocalDiscriminators; auto it = discriminators.find(this); if (it == discriminators.end()) return 0; return it->second; } void ValueDecl::setLocalDiscriminator(unsigned index) { assert(getDeclContext()->isLocalContext()); if (!index) { assert(!getASTContext().Impl.LocalDiscriminators.count(this)); return; } getASTContext().Impl.LocalDiscriminators.insert({this, index}); } PatternBindingInitializer * ASTContext::createPatternBindingContext(DeclContext *parent) { // Check for an existing context we can re-use. if (auto existing = Impl.UnusedPatternBindingContext) { Impl.UnusedPatternBindingContext = nullptr; existing->reset(parent); return existing; } return new (*this) PatternBindingInitializer(parent); } void ASTContext::destroyPatternBindingContext(PatternBindingInitializer *DC) { // There isn't much value in caching more than one of these. Impl.UnusedPatternBindingContext = DC; } DefaultArgumentInitializer * ASTContext::createDefaultArgumentContext(DeclContext *fn, unsigned index) { // Check for an existing context we can re-use. if (auto existing = Impl.UnusedDefaultArgumentContext) { Impl.UnusedDefaultArgumentContext = nullptr; existing->reset(fn, index); return existing; } return new (*this) DefaultArgumentInitializer(fn, index); } void ASTContext::destroyDefaultArgumentContext(DefaultArgumentInitializer *DC) { // There isn't much value in caching more than one of these. Impl.UnusedDefaultArgumentContext = DC; } NormalProtocolConformance * ASTContext::getBehaviorConformance(Type conformingType, Type conformingInterfaceType, ProtocolDecl *protocol, SourceLoc loc, AbstractStorageDecl *storage, ProtocolConformanceState state) { auto conformance = new (*this, AllocationArena::Permanent) NormalProtocolConformance(conformingType, conformingInterfaceType, protocol, loc, storage, state); return conformance; } NormalProtocolConformance * ASTContext::getConformance(Type conformingType, ProtocolDecl *protocol, SourceLoc loc, DeclContext *dc, ProtocolConformanceState state) { llvm::FoldingSetNodeID id; NormalProtocolConformance::Profile(id, protocol, dc); // Did we already record the normal conformance? void *insertPos; auto &normalConformances = Impl.getArena(AllocationArena::Permanent).NormalConformances; if (auto result = normalConformances.FindNodeOrInsertPos(id, insertPos)) return result; // Build a new normal protocol conformance. auto result = new (*this, AllocationArena::Permanent) NormalProtocolConformance(conformingType, protocol, loc, dc, state); normalConformances.InsertNode(result, insertPos); return result; } SpecializedProtocolConformance * ASTContext::getSpecializedConformance(Type type, ProtocolConformance *generic, ArrayRef substitutions) { llvm::FoldingSetNodeID id; SpecializedProtocolConformance::Profile(id, type, generic); // Figure out which arena this conformance should go into. AllocationArena arena = getArena(type->getRecursiveProperties()); // Did we already record the specialized conformance? void *insertPos; auto &specializedConformances = Impl.getArena(arena).SpecializedConformances; if (auto result = specializedConformances.FindNodeOrInsertPos(id, insertPos)) return result; // Build a new specialized conformance. substitutions = AllocateCopy(substitutions, arena); auto result = new (*this, arena) SpecializedProtocolConformance(type, generic, substitutions); specializedConformances.InsertNode(result, insertPos); return result; } InheritedProtocolConformance * ASTContext::getInheritedConformance(Type type, ProtocolConformance *inherited) { llvm::FoldingSetNodeID id; InheritedProtocolConformance::Profile(id, type, inherited); // Figure out which arena this conformance should go into. AllocationArena arena = getArena(type->getRecursiveProperties()); // Did we already record the normal protocol conformance? void *insertPos; auto &inheritedConformances = Impl.getArena(arena).InheritedConformances; if (auto result = inheritedConformances.FindNodeOrInsertPos(id, insertPos)) return result; // Build a new normal protocol conformance. auto result = new (*this, arena) InheritedProtocolConformance(type, inherited); inheritedConformances.InsertNode(result, insertPos); return result; } void ASTContext::recordConformanceLoader(Decl *decl, LazyMemberLoader *resolver, uint64_t contextData) { assert(Impl.ConformanceLoaders.count(decl) == 0 && "already recorded conformance loader"); Impl.ConformanceLoaders[decl] = { resolver, contextData }; } std::pair ASTContext::takeConformanceLoader( Decl *decl) { auto known = Impl.ConformanceLoaders.find(decl); auto result = known->second; Impl.ConformanceLoaders.erase(known); return result; } void ASTContext::addDelayedConformanceDiag( NormalProtocolConformance *conformance, DelayedConformanceDiag fn) { Impl.DelayedConformanceDiags[conformance].push_back(std::move(fn)); } std::vector ASTContext::takeDelayedConformanceDiags(NormalProtocolConformance *conformance){ std::vector result; auto known = Impl.DelayedConformanceDiags.find(conformance); if (known != Impl.DelayedConformanceDiags.end()) { result = std::move(known->second); Impl.DelayedConformanceDiags.erase(known); } return result; } size_t ASTContext::getTotalMemory() const { size_t Size = sizeof(*this) + // LoadedModules ? // ExternalDefinitions ? llvm::capacity_in_bytes(CanonicalGenericTypeParamTypeNames) + // RemappedTypes ? sizeof(Impl) + Impl.Allocator.getTotalMemory() + Impl.Cleanups.capacity() + llvm::capacity_in_bytes(Impl.ModuleLoaders) + llvm::capacity_in_bytes(Impl.RawComments) + llvm::capacity_in_bytes(Impl.BriefComments) + llvm::capacity_in_bytes(Impl.LocalDiscriminators) + llvm::capacity_in_bytes(Impl.ModuleTypes) + llvm::capacity_in_bytes(Impl.GenericParamTypes) + // Impl.GenericFunctionTypes ? // Impl.SILFunctionTypes ? llvm::capacity_in_bytes(Impl.SILBlockStorageTypes) + llvm::capacity_in_bytes(Impl.SILBoxTypes) + llvm::capacity_in_bytes(Impl.IntegerTypes) + // Impl.ProtocolCompositionTypes ? // Impl.BuiltinVectorTypes ? // Impl.GenericSignatures ? // Impl.CompoundNames ? Impl.OpenedExistentialArchetypes.getMemorySize() + Impl.Permanent.getTotalMemory(); Size += getSolverMemory(); return Size; } size_t ASTContext::getSolverMemory() const { size_t Size = 0; if (Impl.CurrentConstraintSolverArena) { Size += Impl.CurrentConstraintSolverArena->getTotalMemory(); } return Size; } size_t ASTContext::Implementation::Arena::getTotalMemory() const { return sizeof(*this) + // TupleTypes ? llvm::capacity_in_bytes(MetatypeTypes) + llvm::capacity_in_bytes(ExistentialMetatypeTypes) + llvm::capacity_in_bytes(FunctionTypes) + llvm::capacity_in_bytes(ArraySliceTypes) + llvm::capacity_in_bytes(DictionaryTypes) + llvm::capacity_in_bytes(OptionalTypes) + llvm::capacity_in_bytes(ImplicitlyUnwrappedOptionalTypes) + llvm::capacity_in_bytes(ParenTypes) + llvm::capacity_in_bytes(ReferenceStorageTypes) + llvm::capacity_in_bytes(LValueTypes) + llvm::capacity_in_bytes(InOutTypes) + llvm::capacity_in_bytes(SubstitutedTypes) + llvm::capacity_in_bytes(DependentMemberTypes) + llvm::capacity_in_bytes(DynamicSelfTypes) + // EnumTypes ? // StructTypes ? // ClassTypes ? // UnboundGenericTypes ? // BoundGenericTypes ? llvm::capacity_in_bytes(BoundGenericSubstitutions); // NormalConformances ? // SpecializedConformances ? // InheritedConformances ? } namespace { /// Produce a deterministic ordering of the given declarations. class OrderDeclarations { SourceManager &SrcMgr; public: OrderDeclarations(SourceManager &srcMgr) : SrcMgr(srcMgr) { } bool operator()(ValueDecl *lhs, ValueDecl *rhs) const { // If the declarations come from different modules, order based on the // module. Module *lhsModule = lhs->getDeclContext()->getParentModule(); Module *rhsModule = rhs->getDeclContext()->getParentModule(); if (lhsModule != rhsModule) { return lhsModule->getName().str() < rhsModule->getName().str(); } // If the two declarations are in the same source file, order based on // location within that source file. SourceFile *lhsSF = lhs->getDeclContext()->getParentSourceFile(); SourceFile *rhsSF = rhs->getDeclContext()->getParentSourceFile(); if (lhsSF == rhsSF) { // If only one location is valid, the valid location comes first. if (lhs->getLoc().isValid() != rhs->getLoc().isValid()) { return lhs->getLoc().isValid(); } // Prefer the declaration that comes first in the source file. return SrcMgr.isBeforeInBuffer(lhs->getLoc(), rhs->getLoc()); } // The declarations are in different source files (or unknown source // files) of the same module. Order based on name. // FIXME: This isn't a total ordering. return lhs->getFullName() < rhs->getFullName(); } }; /// Produce a deterministic ordering of the given declarations with /// a bias that favors declarations in the given source file and /// members of a class. class OrderDeclarationsWithSourceFileAndClassBias { SourceManager &SrcMgr; SourceFile &SF; public: OrderDeclarationsWithSourceFileAndClassBias(SourceManager &srcMgr, SourceFile &sf) : SrcMgr(srcMgr), SF(sf) { } bool operator()(ValueDecl *lhs, ValueDecl *rhs) const { // Check whether the declarations are in a class. bool lhsInClass = isa(lhs->getDeclContext()); bool rhsInClass = isa(rhs->getDeclContext()); if (lhsInClass != rhsInClass) return lhsInClass; // If the two declarations are in different source files, and one of those // source files is the source file we're biasing toward, prefer that // declaration. SourceFile *lhsSF = lhs->getDeclContext()->getParentSourceFile(); SourceFile *rhsSF = rhs->getDeclContext()->getParentSourceFile(); if (lhsSF != rhsSF) { if (lhsSF == &SF) return true; if (rhsSF == &SF) return false; } // Fall back to the normal deterministic ordering. return OrderDeclarations(SrcMgr)(lhs, rhs); } }; } /// Compute the information used to describe an Objective-C redeclaration. std::pair swift::getObjCMethodDiagInfo( AbstractFunctionDecl *member) { if (isa(member)) return { 0 + member->isImplicit(), member->getFullName() }; if (isa(member)) return { 2 + member->isImplicit(), member->getFullName() }; auto func = cast(member); switch (func->getAccessorKind()) { case AccessorKind::IsAddressor: case AccessorKind::IsDidSet: case AccessorKind::IsMaterializeForSet: case AccessorKind::IsMutableAddressor: case AccessorKind::IsWillSet: llvm_unreachable("Not an Objective-C entry point"); case AccessorKind::IsGetter: if (auto var = dyn_cast(func->getAccessorStorageDecl())) return { 5, var->getFullName() }; return { 6, Identifier() }; case AccessorKind::IsSetter: if (auto var = dyn_cast(func->getAccessorStorageDecl())) return { 7, var->getFullName() }; return { 8, Identifier() }; case AccessorKind::NotAccessor: // Normal method. return { 4, func->getFullName() }; } } void ASTContext::diagnoseAttrsRequiringFoundation(SourceFile &SF) { bool ImportsFoundationModule = false; if (SF.Kind == SourceFileKind::SIL || !LangOpts.EnableObjCAttrRequiresFoundation) return; SF.forAllVisibleModules([&](Module::ImportedModule import) { if (import.second->getName() == Id_Foundation) ImportsFoundationModule = true; }); if (ImportsFoundationModule) return; for (auto &Attr : SF.AttrsRequiringFoundation) { // If we've already diagnosed this attribute, keep going. if (!Attr.second) continue; Diags.diagnose(Attr.second->getLocation(), diag::attr_used_without_required_module, Attr.second, Id_Foundation) .highlight(Attr.second->getRangeWithAt()); // Don't diagnose this again. Attr.second = nullptr; } } void ASTContext::recordObjCMethod(AbstractFunctionDecl *func) { // If this method comes from Objective-C, ignore it. if (func->hasClangNode()) return; Impl.ObjCMethods.push_back(func); } /// Lookup for an Objective-C method with the given selector in the /// given class type or any of its superclasses. static AbstractFunctionDecl *lookupObjCMethodInType( Type classType, ObjCSelector selector, bool isInstanceMethod, bool isInitializer, SourceManager &srcMgr, bool inheritingInits = true) { // Dig out the declaration of the class. auto classDecl = classType->getClassOrBoundGenericClass(); if (!classDecl) return nullptr; // Look for an Objective-C method in this class. auto methods = classDecl->lookupDirect(selector, isInstanceMethod); if (!methods.empty()) { // If we aren't inheriting initializers, remove any initializers from the // list. if (!inheritingInits && std::find_if(methods.begin(), methods.end(), [](AbstractFunctionDecl *func) { return isa(func); }) != methods.end()) { SmallVector nonInitMethods; std::copy_if(methods.begin(), methods.end(), std::back_inserter(nonInitMethods), [&](AbstractFunctionDecl *func) { return !isa(func); }); if (nonInitMethods.empty()) return nullptr; return *std::min_element(nonInitMethods.begin(), nonInitMethods.end(), OrderDeclarations(srcMgr)); } return *std::min_element(methods.begin(), methods.end(), OrderDeclarations(srcMgr)); } // Recurse into the superclass. if (!classDecl->hasSuperclass()) return nullptr; // Determine whether we are (still) inheriting initializers. inheritingInits = inheritingInits && classDecl->inheritsSuperclassInitializers(nullptr); if (isInitializer && !inheritingInits) return nullptr; return lookupObjCMethodInType(classDecl->getSuperclass(), selector, isInstanceMethod, isInitializer, srcMgr, inheritingInits); } void AbstractFunctionDecl::setForeignErrorConvention( const ForeignErrorConvention &conv) { assert(isBodyThrowing() && "setting error convention on non-throwing decl"); auto &conventionsMap = getASTContext().Impl.ForeignErrorConventions; assert(!conventionsMap.count(this) && "error convention already set"); conventionsMap.insert({this, conv}); } Optional AbstractFunctionDecl::getForeignErrorConvention() const { if (!isObjC() || !isBodyThrowing()) return None; auto &conventionsMap = getASTContext().Impl.ForeignErrorConventions; auto it = conventionsMap.find(this); if (it == conventionsMap.end()) return None; return it->second; } bool ASTContext::diagnoseUnintendedObjCMethodOverrides(SourceFile &sf) { // Capture the methods in this source file. llvm::SmallVector methods; auto captureMethodInSourceFile = [&](AbstractFunctionDecl *method) -> bool { if (method->getDeclContext()->getParentSourceFile() == &sf) { methods.push_back(method); return true; } return false; }; Impl.ObjCMethods.erase(std::remove_if(Impl.ObjCMethods.begin(), Impl.ObjCMethods.end(), captureMethodInSourceFile), Impl.ObjCMethods.end()); // If no Objective-C methods were defined in this file, we're done. if (methods.empty()) return false; // Sort the methods by declaration order. std::sort(methods.begin(), methods.end(), OrderDeclarations(SourceMgr)); // For each Objective-C method declared in this file, check whether // it overrides something in one of its superclasses. We // intentionally don't respect access control here, since everything // is visible to the Objective-C runtime. bool diagnosedAny = false; for (auto method : methods) { // If the method has an @objc override, we don't need to do any // more checking. if (auto overridden = method->getOverriddenDecl()) { if (overridden->isObjC()) continue; } // Skip deinitializers. if (isa(method)) continue; // Skip invalid declarations. if (method->isInvalid()) continue; // Skip declarations with an invalid 'override' attribute on them. if (auto attr = method->getAttrs().getAttribute(true)) { if (attr->isInvalid()) continue; } auto classDecl = method->getDeclContext()->getAsClassOrClassExtensionContext(); if (!classDecl) continue; // error-recovery path, only if (!classDecl->hasSuperclass()) continue; // Look for a method that we have overridden in one of our // superclasses. // Note: This should be treated as a lookup for intra-module dependency // purposes, but a subclass already depends on its superclasses and any // extensions for many other reasons. auto selector = method->getObjCSelector(nullptr); AbstractFunctionDecl *overriddenMethod = lookupObjCMethodInType(classDecl->getSuperclass(), selector, method->isObjCInstanceMethod(), isa(method), SourceMgr); if (!overriddenMethod) continue; // Ignore stub implementations. if (auto overriddenCtor = dyn_cast(overriddenMethod)) { if (overriddenCtor->hasStubImplementation()) continue; } // Diagnose the override. auto methodDiagInfo = getObjCMethodDiagInfo(method); auto overriddenDiagInfo = getObjCMethodDiagInfo(overriddenMethod); Diags.diagnose(method, diag::objc_override_other, methodDiagInfo.first, methodDiagInfo.second, overriddenDiagInfo.first, overriddenDiagInfo.second, selector, overriddenMethod->getDeclContext() ->getDeclaredInterfaceType()); const ValueDecl *overriddenDecl = overriddenMethod; if (overriddenMethod->isImplicit()) if (auto func = dyn_cast(overriddenMethod)) if (auto storage = func->getAccessorStorageDecl()) overriddenDecl = storage; Diags.diagnose(overriddenDecl, diag::objc_declared_here, overriddenDiagInfo.first, overriddenDiagInfo.second); diagnosedAny = true; } return diagnosedAny; } void ASTContext::recordObjCMethodConflict(ClassDecl *classDecl, ObjCSelector selector, bool isInstance) { Impl.ObjCMethodConflicts.push_back(std::make_tuple(classDecl, selector, isInstance)); } /// Retrieve the source file for the given Objective-C member conflict. static MutableArrayRef getObjCMethodConflictDecls(const ObjCMethodConflict &conflict) { ClassDecl *classDecl = std::get<0>(conflict); ObjCSelector selector = std::get<1>(conflict); bool isInstanceMethod = std::get<2>(conflict); return classDecl->lookupDirect(selector, isInstanceMethod); } /// Given a set of conflicting Objective-C methods, remove any methods /// that are legitimately overridden in Objective-C, i.e., because /// they occur in different modules, one is defined in the class, and /// the other is defined in an extension (category) thereof. static void removeValidObjCConflictingMethods( MutableArrayRef &methods) { // Erase any invalid or stub declarations. We don't want to complain about // them, because we might already have complained about // redeclarations based on Swift matching. auto newEnd = std::remove_if(methods.begin(), methods.end(), [&](AbstractFunctionDecl *method) { if (method->isInvalid()) return true; if (auto func = dyn_cast(method)) { if (func->isAccessor()) { return func->getAccessorStorageDecl() ->isInvalid(); } return false; } if (auto ctor = dyn_cast(method)) { if (ctor->hasStubImplementation()) return true; return false; } return false; }); methods = methods.slice(0, newEnd - methods.begin()); } /// Determine whether the should associate a conflict among the given /// set of methods with the specified source file. static bool shouldAssociateConflictWithSourceFile( SourceFile &sf, ArrayRef methods) { bool anyInSourceFile = false; bool anyInOtherSourceFile = false; bool anyClassMethodsInSourceFile = false; for (auto method : methods) { // Skip methods in the class itself; we want to only diagnose // those if there is a conflict within that file. if (isa(method->getDeclContext())) { if (method->getParentSourceFile() == &sf) anyClassMethodsInSourceFile = true; continue; } if (method->getParentSourceFile() == &sf) anyInSourceFile = true; else anyInOtherSourceFile = true; } return anyInSourceFile || (!anyInOtherSourceFile && anyClassMethodsInSourceFile); } bool ASTContext::diagnoseObjCMethodConflicts(SourceFile &sf) { // If there were no conflicts, we're done. if (Impl.ObjCMethodConflicts.empty()) return false; // Partition the set of conflicts to put the conflicts that involve // this source file at the end. auto firstLocalConflict = std::partition(Impl.ObjCMethodConflicts.begin(), Impl.ObjCMethodConflicts.end(), [&](const ObjCMethodConflict &conflict) -> bool { auto decls = getObjCMethodConflictDecls(conflict); if (shouldAssociateConflictWithSourceFile(sf, decls)) { // It's in this source file. Sort the conflict // declarations. We'll use this later. std::sort( decls.begin(), decls.end(), OrderDeclarationsWithSourceFileAndClassBias( SourceMgr, sf)); return false; } return true; }); // If there were no local conflicts, we're done. unsigned numLocalConflicts = Impl.ObjCMethodConflicts.end() - firstLocalConflict; if (numLocalConflicts == 0) return false; // Sort the set of conflicts so we get a deterministic order for // diagnostics. We use the first conflicting declaration in each set to // perform the sort. MutableArrayRef localConflicts(&*firstLocalConflict, numLocalConflicts); std::sort(localConflicts.begin(), localConflicts.end(), [&](const ObjCMethodConflict &lhs, const ObjCMethodConflict &rhs) { OrderDeclarations ordering(SourceMgr); return ordering(getObjCMethodConflictDecls(lhs)[1], getObjCMethodConflictDecls(rhs)[1]); }); // Diagnose each conflict. bool anyConflicts = false; for (const ObjCMethodConflict &conflict : localConflicts) { ObjCSelector selector = std::get<1>(conflict); auto methods = getObjCMethodConflictDecls(conflict); // Prune out cases where it is acceptable to have a conflict. removeValidObjCConflictingMethods(methods); if (methods.size() < 2) continue; // Diagnose the conflict. anyConflicts = true; // If the first method has a valid source location but the first conflicting // declaration does not, swap them so the primary diagnostic has a useful // source location. if (methods[1]->getLoc().isInvalid() && methods[0]->getLoc().isValid()) { std::swap(methods[0], methods[1]); } auto originalMethod = methods.front(); auto conflictingMethods = methods.slice(1); auto origDiagInfo = getObjCMethodDiagInfo(originalMethod); for (auto conflictingDecl : conflictingMethods) { auto diagInfo = getObjCMethodDiagInfo(conflictingDecl); const ValueDecl *originalDecl = originalMethod; if (originalMethod->isImplicit()) if (auto func = dyn_cast(originalMethod)) if (auto storage = func->getAccessorStorageDecl()) originalDecl = storage; if (diagInfo == origDiagInfo) { Diags.diagnose(conflictingDecl, diag::objc_redecl_same, diagInfo.first, diagInfo.second, selector); Diags.diagnose(originalDecl, diag::invalid_redecl_prev, originalDecl->getName()); } else { Diags.diagnose(conflictingDecl, diag::objc_redecl, diagInfo.first, diagInfo.second, origDiagInfo.first, origDiagInfo.second, selector); Diags.diagnose(originalDecl, diag::objc_declared_here, origDiagInfo.first, origDiagInfo.second); } } } // Erase the local conflicts from the list of conflicts. Impl.ObjCMethodConflicts.erase(firstLocalConflict, Impl.ObjCMethodConflicts.end()); return anyConflicts; } void ASTContext::recordObjCUnsatisfiedOptReq(DeclContext *dc, AbstractFunctionDecl *req) { Impl.ObjCUnsatisfiedOptReqs.push_back(ObjCUnsatisfiedOptReq(dc, req)); } /// Retrieve the source location associated with this declaration /// context. static SourceLoc getDeclContextLoc(DeclContext *dc) { if (auto ext = dyn_cast(dc)) return ext->getLoc(); return cast(dc)->getLoc(); } bool ASTContext::diagnoseObjCUnsatisfiedOptReqConflicts(SourceFile &sf) { // If there are no unsatisfied, optional @objc requirements, we're done. if (Impl.ObjCUnsatisfiedOptReqs.empty()) return false; // Partition the set of unsatisfied requirements to put the // conflicts that involve this source file at the end. auto firstLocalReq = std::partition(Impl.ObjCUnsatisfiedOptReqs.begin(), Impl.ObjCUnsatisfiedOptReqs.end(), [&](const ObjCUnsatisfiedOptReq &unsatisfied) -> bool { return &sf != unsatisfied.first->getParentSourceFile(); }); // If there were no local unsatisfied requirements, we're done. unsigned numLocalReqs = Impl.ObjCUnsatisfiedOptReqs.end() - firstLocalReq; if (numLocalReqs == 0) return false; // Sort the set of local unsatisfied requirements, so we get a // deterministic order for diagnostics. MutableArrayRef localReqs(&*firstLocalReq, numLocalReqs); std::sort(localReqs.begin(), localReqs.end(), [&](const ObjCUnsatisfiedOptReq &lhs, const ObjCUnsatisfiedOptReq &rhs) -> bool { return SourceMgr.isBeforeInBuffer(getDeclContextLoc(lhs.first), getDeclContextLoc(rhs.first)); }); // Check each of the unsatisfied optional requirements. bool anyDiagnosed = false; for (const auto &unsatisfied : localReqs) { // Check whether there is a conflict here. ClassDecl *classDecl = unsatisfied.first->getAsClassOrClassExtensionContext(); auto req = unsatisfied.second; auto selector = req->getObjCSelector(); bool isInstanceMethod = req->isInstanceMember(); // FIXME: Also look in superclasses? auto conflicts = classDecl->lookupDirect(selector, isInstanceMethod); if (conflicts.empty()) continue; // Diagnose the conflict. auto reqDiagInfo = getObjCMethodDiagInfo(unsatisfied.second); auto conflictDiagInfo = getObjCMethodDiagInfo(conflicts[0]); auto protocolName = cast(req->getDeclContext())->getFullName(); Diags.diagnose(conflicts[0], diag::objc_optional_requirement_conflict, conflictDiagInfo.first, conflictDiagInfo.second, reqDiagInfo.first, reqDiagInfo.second, selector, protocolName); Diags.diagnose(getDeclContextLoc(unsatisfied.first), diag::protocol_conformance_here, true, classDecl->getFullName(), protocolName); Diags.diagnose(req, diag::protocol_requirement_here, reqDiagInfo.second); anyDiagnosed = true; } // Erase the local unsatisfied requirements from the list. Impl.ObjCUnsatisfiedOptReqs.erase(firstLocalReq, Impl.ObjCUnsatisfiedOptReqs.end()); return anyDiagnosed; } Optional swift::getKnownFoundationEntity(StringRef name){ return llvm::StringSwitch>(name) #define FOUNDATION_ENTITY(Name) .Case(#Name, KnownFoundationEntity::Name) #include "swift/AST/KnownFoundationEntities.def" .Default(None); } bool swift::nameConflictsWithStandardLibrary(KnownFoundationEntity entity) { switch (entity) { case KnownFoundationEntity::NSArray: case KnownFoundationEntity::NSDictionary: case KnownFoundationEntity::NSInteger: case KnownFoundationEntity::NSRange: case KnownFoundationEntity::NSSet: case KnownFoundationEntity::NSString: return true; case KnownFoundationEntity::NSCopying: case KnownFoundationEntity::NSError: case KnownFoundationEntity::NSErrorPointer: case KnownFoundationEntity::NSNumber: case KnownFoundationEntity::NSObject: case KnownFoundationEntity::NSStringEncoding: case KnownFoundationEntity::NSUInteger: case KnownFoundationEntity::NSURL: case KnownFoundationEntity::NSZone: return false; } } StringRef ASTContext::getSwiftName(KnownFoundationEntity kind) { StringRef objcName; switch (kind) { #define FOUNDATION_ENTITY(Name) case KnownFoundationEntity::Name: \ objcName = #Name; \ break; #include "swift/AST/KnownFoundationEntities.def" } // If we're omitting needless words and the name won't conflict with // something in the standard library, strip the prefix off the Swift // name. if (LangOpts.OmitNeedlessWords && LangOpts.StripNSPrefix && !nameConflictsWithStandardLibrary(kind)) return objcName.substr(2); return objcName; } void ASTContext::dumpArchetypeContext(ArchetypeType *archetype, unsigned indent) const { dumpArchetypeContext(archetype, llvm::errs(), indent); } void ASTContext::dumpArchetypeContext(ArchetypeType *archetype, llvm::raw_ostream &os, unsigned indent) const { auto knownDC = ArchetypeContexts.find(archetype); if (knownDC != ArchetypeContexts.end()) knownDC->second->printContext(os, indent); } //===----------------------------------------------------------------------===// // Type manipulation routines. //===----------------------------------------------------------------------===// // Simple accessors. Type ErrorType::get(const ASTContext &C) { return C.TheErrorType; } BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth, const ASTContext &C) { BuiltinIntegerType *&Result = C.Impl.IntegerTypes[BitWidth]; if (Result == 0) Result = new (C, AllocationArena::Permanent) BuiltinIntegerType(BitWidth,C); return Result; } BuiltinVectorType *BuiltinVectorType::get(const ASTContext &context, Type elementType, unsigned numElements) { llvm::FoldingSetNodeID id; BuiltinVectorType::Profile(id, elementType, numElements); void *insertPos; if (BuiltinVectorType *vecType = context.Impl.BuiltinVectorTypes.FindNodeOrInsertPos(id, insertPos)) return vecType; assert(elementType->isCanonical() && "Non-canonical builtin vector?"); BuiltinVectorType *vecTy = new (context, AllocationArena::Permanent) BuiltinVectorType(context, elementType, numElements); context.Impl.BuiltinVectorTypes.InsertNode(vecTy, insertPos); return vecTy; } ParenType *ParenType::get(const ASTContext &C, Type underlying) { auto properties = underlying->getRecursiveProperties(); auto arena = getArena(properties); ParenType *&Result = C.Impl.getArena(arena).ParenTypes[underlying]; if (Result == 0) { Result = new (C, arena) ParenType(underlying, properties); } return Result; } CanTupleType TupleType::getEmpty(const ASTContext &C) { return cast(CanType(C.TheEmptyTupleType)); } void TupleType::Profile(llvm::FoldingSetNodeID &ID, ArrayRef Fields) { ID.AddInteger(Fields.size()); for (const TupleTypeElt &Elt : Fields) { ID.AddPointer(Elt.NameAndVariadic.getOpaqueValue()); ID.AddPointer(Elt.getType().getPointer()); ID.AddInteger(static_cast(Elt.getDefaultArgKind())); } } /// getTupleType - Return the uniqued tuple type with the specified elements. Type TupleType::get(ArrayRef Fields, const ASTContext &C) { if (Fields.size() == 1 && !Fields[0].isVararg() && !Fields[0].hasName() && Fields[0].getDefaultArgKind() == DefaultArgumentKind::None) return ParenType::get(C, Fields[0].getType()); RecursiveTypeProperties properties; for (const TupleTypeElt &Elt : Fields) { if (Elt.getType()) properties |= Elt.getType()->getRecursiveProperties(); if (Elt.getDefaultArgKind() != DefaultArgumentKind::None) properties |= RecursiveTypeProperties::HasDefaultParameter; } auto arena = getArena(properties); void *InsertPos = 0; // Check to see if we've already seen this tuple before. llvm::FoldingSetNodeID ID; TupleType::Profile(ID, Fields); if (TupleType *TT = C.Impl.getArena(arena).TupleTypes.FindNodeOrInsertPos(ID,InsertPos)) return TT; // Make a copy of the fields list into ASTContext owned memory. TupleTypeElt *FieldsCopy = C.AllocateCopy(Fields.begin(), Fields.end(), arena); bool IsCanonical = true; // All canonical elts means this is canonical. for (const TupleTypeElt &Elt : Fields) { if (Elt.getType().isNull() || !Elt.getType()->isCanonical()) { IsCanonical = false; break; } } Fields = ArrayRef(FieldsCopy, Fields.size()); TupleType *New = new (C, arena) TupleType(Fields, IsCanonical ? &C : 0, properties); C.Impl.getArena(arena).TupleTypes.InsertNode(New, InsertPos); return New; } void UnboundGenericType::Profile(llvm::FoldingSetNodeID &ID, GenericTypeDecl *TheDecl, Type Parent) { ID.AddPointer(TheDecl); ID.AddPointer(Parent.getPointer()); } UnboundGenericType *UnboundGenericType:: get(GenericTypeDecl *TheDecl, Type Parent, const ASTContext &C) { llvm::FoldingSetNodeID ID; UnboundGenericType::Profile(ID, TheDecl, Parent); void *InsertPos = 0; RecursiveTypeProperties properties; if (Parent) properties |= Parent->getRecursiveProperties(); auto arena = getArena(properties); if (auto unbound = C.Impl.getArena(arena).UnboundGenericTypes .FindNodeOrInsertPos(ID, InsertPos)) return unbound; auto result = new (C, arena) UnboundGenericType(TheDecl, Parent, C, properties); C.Impl.getArena(arena).UnboundGenericTypes.InsertNode(result, InsertPos); return result; } void BoundGenericType::Profile(llvm::FoldingSetNodeID &ID, NominalTypeDecl *TheDecl, Type Parent, ArrayRef GenericArgs, RecursiveTypeProperties &properties) { ID.AddPointer(TheDecl); ID.AddPointer(Parent.getPointer()); if (Parent) properties |= Parent->getRecursiveProperties(); ID.AddInteger(GenericArgs.size()); for (Type Arg : GenericArgs) { ID.AddPointer(Arg.getPointer()); properties |= Arg->getRecursiveProperties(); } } BoundGenericType::BoundGenericType(TypeKind theKind, NominalTypeDecl *theDecl, Type parent, ArrayRef genericArgs, const ASTContext *context, RecursiveTypeProperties properties) : TypeBase(theKind, context, properties), TheDecl(theDecl), Parent(parent), GenericArgs(genericArgs) { } BoundGenericType *BoundGenericType::get(NominalTypeDecl *TheDecl, Type Parent, ArrayRef GenericArgs) { ASTContext &C = TheDecl->getDeclContext()->getASTContext(); llvm::FoldingSetNodeID ID; RecursiveTypeProperties properties; BoundGenericType::Profile(ID, TheDecl, Parent, GenericArgs, properties); auto arena = getArena(properties); void *InsertPos = 0; if (BoundGenericType *BGT = C.Impl.getArena(arena).BoundGenericTypes.FindNodeOrInsertPos(ID, InsertPos)) return BGT; ArrayRef ArgsCopy = C.AllocateCopy(GenericArgs, arena); bool IsCanonical = !Parent || Parent->isCanonical(); if (IsCanonical) { for (Type Arg : GenericArgs) { if (!Arg->isCanonical()) { IsCanonical = false; break; } } } BoundGenericType *newType; if (auto theClass = dyn_cast(TheDecl)) { newType = new (C, arena) BoundGenericClassType(theClass, Parent, ArgsCopy, IsCanonical ? &C : 0, properties); } else if (auto theStruct = dyn_cast(TheDecl)) { newType = new (C, arena) BoundGenericStructType(theStruct, Parent, ArgsCopy, IsCanonical ? &C : 0, properties); } else { auto theEnum = cast(TheDecl); newType = new (C, arena) BoundGenericEnumType(theEnum, Parent, ArgsCopy, IsCanonical ? &C : 0, properties); } C.Impl.getArena(arena).BoundGenericTypes.InsertNode(newType, InsertPos); return newType; } NominalType *NominalType::get(NominalTypeDecl *D, Type Parent, const ASTContext &C) { switch (D->getKind()) { case DeclKind::Enum: return EnumType::get(cast(D), Parent, C); case DeclKind::Struct: return StructType::get(cast(D), Parent, C); case DeclKind::Class: return ClassType::get(cast(D), Parent, C); case DeclKind::Protocol: { return ProtocolType::get(cast(D), C); } default: llvm_unreachable("Not a nominal declaration!"); } } EnumType::EnumType(EnumDecl *TheDecl, Type Parent, const ASTContext &C, RecursiveTypeProperties properties) : NominalType(TypeKind::Enum, &C, TheDecl, Parent, properties) { } EnumType *EnumType::get(EnumDecl *D, Type Parent, const ASTContext &C) { llvm::FoldingSetNodeID id; EnumType::Profile(id, D, Parent); RecursiveTypeProperties properties; if (Parent) properties |= Parent->getRecursiveProperties(); auto arena = getArena(properties); void *insertPos = 0; if (auto enumTy = C.Impl.getArena(arena).EnumTypes.FindNodeOrInsertPos(id, insertPos)) return enumTy; auto enumTy = new (C, arena) EnumType(D, Parent, C, properties); C.Impl.getArena(arena).EnumTypes.InsertNode(enumTy, insertPos); return enumTy; } void EnumType::Profile(llvm::FoldingSetNodeID &ID, EnumDecl *D, Type Parent) { ID.AddPointer(D); ID.AddPointer(Parent.getPointer()); } StructType::StructType(StructDecl *TheDecl, Type Parent, const ASTContext &C, RecursiveTypeProperties properties) : NominalType(TypeKind::Struct, &C, TheDecl, Parent, properties) { } StructType *StructType::get(StructDecl *D, Type Parent, const ASTContext &C) { llvm::FoldingSetNodeID id; StructType::Profile(id, D, Parent); RecursiveTypeProperties properties; if (Parent) properties |= Parent->getRecursiveProperties(); auto arena = getArena(properties); void *insertPos = 0; if (auto structTy = C.Impl.getArena(arena).StructTypes.FindNodeOrInsertPos(id, insertPos)) return structTy; auto structTy = new (C, arena) StructType(D, Parent, C, properties); C.Impl.getArena(arena).StructTypes.InsertNode(structTy, insertPos); return structTy; } void StructType::Profile(llvm::FoldingSetNodeID &ID, StructDecl *D, Type Parent) { ID.AddPointer(D); ID.AddPointer(Parent.getPointer()); } ClassType::ClassType(ClassDecl *TheDecl, Type Parent, const ASTContext &C, RecursiveTypeProperties properties) : NominalType(TypeKind::Class, &C, TheDecl, Parent, properties) { } ClassType *ClassType::get(ClassDecl *D, Type Parent, const ASTContext &C) { llvm::FoldingSetNodeID id; ClassType::Profile(id, D, Parent); RecursiveTypeProperties properties; if (Parent) properties |= Parent->getRecursiveProperties(); auto arena = getArena(properties); void *insertPos = 0; if (auto classTy = C.Impl.getArena(arena).ClassTypes.FindNodeOrInsertPos(id, insertPos)) return classTy; auto classTy = new (C, arena) ClassType(D, Parent, C, properties); C.Impl.getArena(arena).ClassTypes.InsertNode(classTy, insertPos); return classTy; } void ClassType::Profile(llvm::FoldingSetNodeID &ID, ClassDecl *D, Type Parent) { ID.AddPointer(D); ID.AddPointer(Parent.getPointer()); } ProtocolCompositionType * ProtocolCompositionType::build(const ASTContext &C, ArrayRef Protocols) { // Check to see if we've already seen this protocol composition before. void *InsertPos = 0; llvm::FoldingSetNodeID ID; ProtocolCompositionType::Profile(ID, Protocols); if (ProtocolCompositionType *Result = C.Impl.ProtocolCompositionTypes.FindNodeOrInsertPos(ID, InsertPos)) return Result; bool isCanonical = true; for (Type t : Protocols) { if (!t->isCanonical()) isCanonical = false; } // Create a new protocol composition type. ProtocolCompositionType *New = new (C, AllocationArena::Permanent) ProtocolCompositionType(isCanonical ? &C : nullptr, C.AllocateCopy(Protocols)); C.Impl.ProtocolCompositionTypes.InsertNode(New, InsertPos); return New; } ReferenceStorageType *ReferenceStorageType::get(Type T, Ownership ownership, const ASTContext &C) { assert(ownership != Ownership::Strong && "ReferenceStorageType is unnecessary for strong ownership"); assert(!T->hasTypeVariable()); // not meaningful in type-checker auto properties = T->getRecursiveProperties(); auto arena = getArena(properties); auto key = uintptr_t(T.getPointer()) | unsigned(ownership); auto &entry = C.Impl.getArena(arena).ReferenceStorageTypes[key]; if (entry) return entry; switch (ownership) { case Ownership::Strong: llvm_unreachable("not possible"); case Ownership::Unowned: return entry = new (C, arena) UnownedStorageType(T, T->isCanonical() ? &C : 0, properties); case Ownership::Weak: return entry = new (C, arena) WeakStorageType(T, T->isCanonical() ? &C : 0, properties); case Ownership::Unmanaged: return entry = new (C, arena) UnmanagedStorageType(T, T->isCanonical() ? &C : 0, properties); } llvm_unreachable("bad ownership"); } AnyMetatypeType::AnyMetatypeType(TypeKind kind, const ASTContext *C, RecursiveTypeProperties properties, Type instanceType, Optional repr) : TypeBase(kind, C, properties), InstanceType(instanceType) { if (repr) { AnyMetatypeTypeBits.Representation = static_cast(*repr) + 1; } else { AnyMetatypeTypeBits.Representation = 0; } } MetatypeType *MetatypeType::get(Type T, Optional Repr, const ASTContext &Ctx) { auto properties = T->getRecursiveProperties(); auto arena = getArena(properties); char reprKey; if (Repr.hasValue()) reprKey = static_cast(*Repr) + 1; else reprKey = 0; MetatypeType *&Entry = Ctx.Impl.getArena(arena).MetatypeTypes[{T, reprKey}]; if (Entry) return Entry; return Entry = new (Ctx, arena) MetatypeType(T, T->isCanonical() ? &Ctx : 0, properties, Repr); } MetatypeType::MetatypeType(Type T, const ASTContext *C, RecursiveTypeProperties properties, Optional repr) : AnyMetatypeType(TypeKind::Metatype, C, properties, T, repr) { } ExistentialMetatypeType * ExistentialMetatypeType::get(Type T, Optional repr, const ASTContext &ctx) { auto properties = T->getRecursiveProperties(); auto arena = getArena(properties); char reprKey; if (repr.hasValue()) reprKey = static_cast(*repr) + 1; else reprKey = 0; auto &entry = ctx.Impl.getArena(arena).ExistentialMetatypeTypes[{T, reprKey}]; if (entry) return entry; return entry = new (ctx, arena) ExistentialMetatypeType(T, T->isCanonical() ? &ctx : 0, properties, repr); } ExistentialMetatypeType::ExistentialMetatypeType(Type T, const ASTContext *C, RecursiveTypeProperties properties, Optional repr) : AnyMetatypeType(TypeKind::ExistentialMetatype, C, properties, T, repr) { if (repr) { assert(*repr != MetatypeRepresentation::Thin && "creating a thin existential metatype?"); assert(getASTContext().LangOpts.EnableObjCInterop || *repr != MetatypeRepresentation::ObjC); } } ModuleType *ModuleType::get(Module *M) { ASTContext &C = M->getASTContext(); ModuleType *&Entry = C.Impl.ModuleTypes[M]; if (Entry) return Entry; return Entry = new (C, AllocationArena::Permanent) ModuleType(M, C); } DynamicSelfType *DynamicSelfType::get(Type selfType, const ASTContext &ctx) { auto properties = selfType->getRecursiveProperties(); assert(properties.isMaterializable() && "non-materializable dynamic self?"); auto arena = getArena(properties); auto &dynamicSelfTypes = ctx.Impl.getArena(arena).DynamicSelfTypes; auto known = dynamicSelfTypes.find(selfType); if (known != dynamicSelfTypes.end()) return known->second; auto result = new (ctx, arena) DynamicSelfType(selfType, ctx, properties); dynamicSelfTypes.insert({selfType, result}); return result; } static void checkFunctionRecursiveProperties(Type Input, Type Result) { // TODO: Would be nice to be able to assert these, but they trip during // constraint solving: //assert(!Input->getRecursiveProperties().isLValue() // && "function should not take lvalues directly as parameters"); //assert(Result->getRecursiveProperties().isMaterializable() // && "function return should be materializable"); } static RecursiveTypeProperties getFunctionRecursiveProperties(Type Input, Type Result) { checkFunctionRecursiveProperties(Input, Result); auto properties = Input->getRecursiveProperties() | Result->getRecursiveProperties(); properties &= ~RecursiveTypeProperties::IsNotMaterializable; return properties; } // For now, generic function types cannot be dependent (in fact, // they erase dependence) or contain type variables, and they're // always materializable. static RecursiveTypeProperties getGenericFunctionRecursiveProperties(Type Input, Type Result) { checkFunctionRecursiveProperties(Input, Result); static_assert(RecursiveTypeProperties::BitWidth == 10, "revisit this if you add new recursive type properties"); RecursiveTypeProperties properties; if (Result->getRecursiveProperties().hasDynamicSelf()) properties |= RecursiveTypeProperties::HasDynamicSelf; return properties; } AnyFunctionType *AnyFunctionType::withExtInfo(ExtInfo info) const { if (isa(this)) return FunctionType::get(getInput(), getResult(), info); if (auto *polyFnTy = dyn_cast(this)) return PolymorphicFunctionType::get(getInput(), getResult(), &polyFnTy->getGenericParams(), info); if (auto *genFnTy = dyn_cast(this)) return GenericFunctionType::get(genFnTy->getGenericSignature(), getInput(), getResult(), info); static_assert(3 - 1 == static_cast(TypeKind::Last_AnyFunctionType) - static_cast(TypeKind::First_AnyFunctionType), "unhandled function type"); llvm_unreachable("unhandled function type"); } FunctionType *FunctionType::get(Type Input, Type Result, const ExtInfo &Info) { auto properties = getFunctionRecursiveProperties(Input, Result); auto arena = getArena(properties); uint16_t attrKey = Info.getFuncAttrKey(); const ASTContext &C = Input->getASTContext(); FunctionType *&Entry = C.Impl.getArena(arena).FunctionTypes[{Input, {Result, attrKey} }]; if (Entry) return Entry; return Entry = new (C, arena) FunctionType(Input, Result, properties, Info); } // If the input and result types are canonical, then so is the result. FunctionType::FunctionType(Type input, Type output, RecursiveTypeProperties properties, const ExtInfo &Info) : AnyFunctionType(TypeKind::Function, (input->isCanonical() && output->isCanonical()) ? &input->getASTContext() : 0, input, output, properties, Info) { } /// FunctionType::get - Return a uniqued function type with the specified /// input and result. PolymorphicFunctionType *PolymorphicFunctionType::get(Type input, Type output, GenericParamList *params, const ExtInfo &Info) { auto properties = getFunctionRecursiveProperties(input, output); auto arena = getArena(properties); const ASTContext &C = input->getASTContext(); return new (C, arena) PolymorphicFunctionType(input, output, params, Info, C, properties); } PolymorphicFunctionType::PolymorphicFunctionType(Type input, Type output, GenericParamList *params, const ExtInfo &Info, const ASTContext &C, RecursiveTypeProperties properties) : AnyFunctionType(TypeKind::PolymorphicFunction, (input->isCanonical() && output->isCanonical()) ?&C : 0, input, output, properties, Info), Params(params) { assert(!input->hasTypeVariable() && !output->hasTypeVariable()); } void GenericFunctionType::Profile(llvm::FoldingSetNodeID &ID, GenericSignature *sig, Type input, Type result, const ExtInfo &info) { ID.AddPointer(sig); ID.AddPointer(input.getPointer()); ID.AddPointer(result.getPointer()); ID.AddInteger(info.getFuncAttrKey()); } GenericFunctionType * GenericFunctionType::get(GenericSignature *sig, Type input, Type output, const ExtInfo &info) { assert(sig && "no generic signature for generic function type?!"); assert(!input->hasTypeVariable() && !output->hasTypeVariable()); llvm::FoldingSetNodeID id; GenericFunctionType::Profile(id, sig, input, output, info); const ASTContext &ctx = input->getASTContext(); // Do we already have this generic function type? void *insertPos; if (auto result = ctx.Impl.GenericFunctionTypes.FindNodeOrInsertPos(id, insertPos)) return result; // We have to construct this generic function type. Determine whether // it's canonical. bool isCanonical = sig->isCanonical() && input->isCanonical() && output->isCanonical(); // Allocate storage for the object. void *mem = ctx.Allocate(sizeof(GenericFunctionType), alignof(GenericFunctionType)); auto properties = getGenericFunctionRecursiveProperties(input, output); auto result = new (mem) GenericFunctionType(sig, input, output, info, isCanonical ? &ctx : nullptr, properties); ctx.Impl.GenericFunctionTypes.InsertNode(result, insertPos); return result; } GenericFunctionType::GenericFunctionType( GenericSignature *sig, Type input, Type result, const ExtInfo &info, const ASTContext *ctx, RecursiveTypeProperties properties) : AnyFunctionType(TypeKind::GenericFunction, ctx, input, result, properties, info), Signature(sig) {} GenericTypeParamType *GenericTypeParamType::get(unsigned depth, unsigned index, const ASTContext &ctx) { auto known = ctx.Impl.GenericParamTypes.find({ depth, index }); if (known != ctx.Impl.GenericParamTypes.end()) return known->second; auto result = new (ctx, AllocationArena::Permanent) GenericTypeParamType(depth, index, ctx); ctx.Impl.GenericParamTypes[{depth, index}] = result; return result; } ArrayRef GenericFunctionType::getGenericParams() const{ return Signature->getGenericParams(); } /// Retrieve the requirements of this polymorphic function type. ArrayRef GenericFunctionType::getRequirements() const { return Signature->getRequirements(); } void SILFunctionType::Profile(llvm::FoldingSetNodeID &id, GenericSignature *genericParams, ExtInfo info, ParameterConvention calleeConvention, ArrayRef params, ArrayRef results, Optional errorResult) { id.AddPointer(genericParams); id.AddInteger(info.getFuncAttrKey()); id.AddInteger(unsigned(calleeConvention)); id.AddInteger(params.size()); for (auto param : params) param.profile(id); id.AddInteger(results.size()); for (auto result : results) result.profile(id); // Just allow the profile length to implicitly distinguish the // presence of an error result. if (errorResult) errorResult->profile(id); } SILFunctionType::SILFunctionType(GenericSignature *genericSig, ExtInfo ext, ParameterConvention calleeConvention, ArrayRef params, ArrayRef allResults, ArrayRef directResults, ArrayRef indirectResults, Optional errorResult, const ASTContext &ctx, RecursiveTypeProperties properties) : TypeBase(TypeKind::SILFunction, &ctx, properties), GenericSig(genericSig) { bool hasCombinedResults = (!directResults.empty() && !indirectResults.empty()); SILFunctionTypeBits.HasErrorResult = errorResult.hasValue(); SILFunctionTypeBits.HasCombinedResults = hasCombinedResults; SILFunctionTypeBits.ExtInfo = ext.Bits; NumParameters = params.size(); NumDirectResults = directResults.size(); NumIndirectResults = indirectResults.size(); assert(!isIndirectParameter(calleeConvention)); SILFunctionTypeBits.CalleeConvention = unsigned(calleeConvention); memcpy(getMutableParameters().data(), params.data(), params.size() * sizeof(SILParameterInfo)); memcpy(getMutableAllResults().data(), allResults.data(), allResults.size() * sizeof(SILResultInfo)); if (hasCombinedResults) { memcpy(getMutableDirectResults().data(), directResults.data(), directResults.size() * sizeof(SILResultInfo)); memcpy(getMutableIndirectResults().data(), indirectResults.data(), indirectResults.size() * sizeof(SILResultInfo)); } if (errorResult) getMutableErrorResult() = *errorResult; if (hasSILResultCache()) getMutableSILResultCache() = CanType(); #ifndef NDEBUG // Make sure the interface types are sane. if (genericSig) { for (auto gparam : genericSig->getGenericParams()) { (void)gparam; assert(gparam->isCanonical() && "generic signature is not canonicalized"); } for (auto param : getParameters()) { (void)param; assert(!param.getType().findIf([](Type t) { return t->is() && !t->castTo()->getSelfProtocol(); }) && "interface type of generic type should not contain context archetypes"); } for (auto result : getAllResults()) { (void)result; assert(!result.getType().findIf([](Type t) { return t->is(); }) && "interface type of generic type should not contain context archetypes"); } if (hasErrorResult()) { assert(!getErrorResult().getType().findIf([](Type t) { return t->is(); }) && "interface type of generic type should not contain context archetypes"); } } // Make sure the direct and indirect results are sane. assert(allResults.size() == directResults.size() + indirectResults.size()); unsigned directIndex = 0, indirectIndex = 0; for (auto result : allResults) { if (result.isDirect()) { assert(directResults[directIndex++] == result); } else { assert(indirectResults[indirectIndex++] == result); } } #endif } CanSILBlockStorageType SILBlockStorageType::get(CanType captureType) { ASTContext &ctx = captureType->getASTContext(); auto found = ctx.Impl.SILBlockStorageTypes.find(captureType); if (found != ctx.Impl.SILBlockStorageTypes.end()) return CanSILBlockStorageType(found->second); void *mem = ctx.Allocate(sizeof(SILBlockStorageType), alignof(SILBlockStorageType)); SILBlockStorageType *storageTy = new (mem) SILBlockStorageType(captureType); ctx.Impl.SILBlockStorageTypes.insert({captureType, storageTy}); return CanSILBlockStorageType(storageTy); } CanSILBoxType SILBoxType::get(CanType boxType) { ASTContext &ctx = boxType->getASTContext(); auto found = ctx.Impl.SILBoxTypes.find(boxType); if (found != ctx.Impl.SILBoxTypes.end()) return CanSILBoxType(found->second); void *mem = ctx.Allocate(sizeof(SILBlockStorageType), alignof(SILBlockStorageType)); auto storageTy = new (mem) SILBoxType(boxType); ctx.Impl.SILBoxTypes.insert({boxType, storageTy}); return CanSILBoxType(storageTy); } CanSILFunctionType SILFunctionType::get(GenericSignature *genericSig, ExtInfo ext, ParameterConvention callee, ArrayRef params, ArrayRef allResults, Optional errorResult, const ASTContext &ctx) { llvm::FoldingSetNodeID id; SILFunctionType::Profile(id, genericSig, ext, callee, params, allResults, errorResult); // Do we already have this generic function type? void *insertPos; if (auto result = ctx.Impl.SILFunctionTypes.FindNodeOrInsertPos(id, insertPos)) return CanSILFunctionType(result); // All SILFunctionTypes are canonical. SmallVector directResults; SmallVector indirectResults; for (auto result : allResults) { if (result.isDirect()) { directResults.push_back(result); } else { indirectResults.push_back(result); } } bool hasCombinedResults = (!directResults.empty() && !indirectResults.empty()); // Allocate storage for the object. size_t bytes = sizeof(SILFunctionType) + sizeof(SILParameterInfo) * params.size() + sizeof(SILResultInfo) * allResults.size() + (hasCombinedResults ? sizeof(SILResultInfo) * allResults.size() : 0) + (errorResult ? sizeof(SILResultInfo) : 0) + (directResults.size() > 1 ? sizeof(CanType) : 0); void *mem = ctx.Allocate(bytes, alignof(SILFunctionType)); RecursiveTypeProperties properties; static_assert(RecursiveTypeProperties::BitWidth == 10, "revisit this if you add new recursive type properties"); for (auto ¶m : params) properties |= param.getType()->getRecursiveProperties(); for (auto &result : allResults) properties |= result.getType()->getRecursiveProperties(); if (errorResult) properties |= errorResult->getType()->getRecursiveProperties(); // FIXME: If we ever have first-class polymorphic values, we'll need to // revisit this. if (genericSig) properties.removeHasTypeParameter(); auto fnType = new (mem) SILFunctionType(genericSig, ext, callee, params, allResults, directResults, indirectResults, errorResult, ctx, properties); ctx.Impl.SILFunctionTypes.InsertNode(fnType, insertPos); return CanSILFunctionType(fnType); } ArraySliceType *ArraySliceType::get(Type base) { auto properties = base->getRecursiveProperties(); auto arena = getArena(properties); const ASTContext &C = base->getASTContext(); ArraySliceType *&entry = C.Impl.getArena(arena).ArraySliceTypes[base]; if (entry) return entry; return entry = new (C, arena) ArraySliceType(C, base, properties); } DictionaryType *DictionaryType::get(Type keyType, Type valueType) { auto properties = keyType->getRecursiveProperties() | valueType->getRecursiveProperties(); auto arena = getArena(properties); const ASTContext &C = keyType->getASTContext(); DictionaryType *&entry = C.Impl.getArena(arena).DictionaryTypes[{keyType, valueType}]; if (entry) return entry; return entry = new (C, arena) DictionaryType(C, keyType, valueType, properties); } Type OptionalType::get(OptionalTypeKind which, Type valueType) { switch (which) { // It wouldn't be unreasonable for this method to just ignore // OTK_None if we made code more convenient to write. case OTK_None: llvm_unreachable("building a non-optional type!"); case OTK_Optional: return OptionalType::get(valueType); case OTK_ImplicitlyUnwrappedOptional: return ImplicitlyUnwrappedOptionalType::get(valueType); } llvm_unreachable("bad optional type kind"); } OptionalType *OptionalType::get(Type base) { auto properties = base->getRecursiveProperties(); auto arena = getArena(properties); const ASTContext &C = base->getASTContext(); OptionalType *&entry = C.Impl.getArena(arena).OptionalTypes[base]; if (entry) return entry; return entry = new (C, arena) OptionalType(C, base, properties); } ImplicitlyUnwrappedOptionalType *ImplicitlyUnwrappedOptionalType::get(Type base) { auto properties = base->getRecursiveProperties(); auto arena = getArena(properties); const ASTContext &C = base->getASTContext(); auto *&entry = C.Impl.getArena(arena).ImplicitlyUnwrappedOptionalTypes[base]; if (entry) return entry; return entry = new (C, arena) ImplicitlyUnwrappedOptionalType(C, base, properties); } ProtocolType *ProtocolType::get(ProtocolDecl *D, const ASTContext &C) { if (auto declaredTy = D->getDeclaredType()) return declaredTy->castTo(); auto protoTy = new (C, AllocationArena::Permanent) ProtocolType(D, C); D->setDeclaredType(protoTy); return protoTy; } ProtocolType::ProtocolType(ProtocolDecl *TheDecl, const ASTContext &Ctx) : NominalType(TypeKind::Protocol, &Ctx, TheDecl, /*Parent=*/Type(), RecursiveTypeProperties()) { } LValueType *LValueType::get(Type objectTy) { assert(!objectTy->is() && "cannot have ErrorType wrapped inside LValueType"); assert(!objectTy->is() && !objectTy->is() && "cannot have 'inout' or @lvalue wrapped inside an @lvalue"); auto properties = objectTy->getRecursiveProperties() | RecursiveTypeProperties::IsLValue; auto arena = getArena(properties); auto &C = objectTy->getASTContext(); auto &entry = C.Impl.getArena(arena).LValueTypes[objectTy]; if (entry) return entry; const ASTContext *canonicalContext = objectTy->isCanonical() ? &C : nullptr; return entry = new (C, arena) LValueType(objectTy, canonicalContext, properties); } InOutType *InOutType::get(Type objectTy) { assert(!objectTy->is() && "cannot have ErrorType wrapped inside InOutType"); assert(!objectTy->is() && !objectTy->is() && "cannot have 'inout' or @lvalue wrapped inside an 'inout'"); auto properties = objectTy->getRecursiveProperties() | RecursiveTypeProperties::HasInOut; properties &= ~RecursiveTypeProperties::IsLValue; auto arena = getArena(properties); auto &C = objectTy->getASTContext(); auto &entry = C.Impl.getArena(arena).InOutTypes[objectTy]; if (entry) return entry; const ASTContext *canonicalContext = objectTy->isCanonical() ? &C : nullptr; return entry = new (C, arena) InOutType(objectTy, canonicalContext, properties); } /// Return a uniqued substituted type. SubstitutedType *SubstitutedType::get(Type Original, Type Replacement, const ASTContext &C) { auto properties = Replacement->getRecursiveProperties(); auto arena = getArena(properties); SubstitutedType *&Known = C.Impl.getArena(arena).SubstitutedTypes[{Original, Replacement}]; if (!Known) { Known = new (C, arena) SubstitutedType(Original, Replacement, properties); } return Known; } DependentMemberType *DependentMemberType::get(Type base, Identifier name, const ASTContext &ctx) { auto properties = base->getRecursiveProperties(); properties |= RecursiveTypeProperties::HasTypeParameter; auto arena = getArena(properties); llvm::PointerUnion stored(name); auto *&known = ctx.Impl.getArena(arena).DependentMemberTypes[ {base, stored.getOpaqueValue()}]; if (!known) { const ASTContext *canonicalCtx = base->isCanonical() ? &ctx : nullptr; known = new (ctx, arena) DependentMemberType(base, name, canonicalCtx, properties); } return known; } DependentMemberType *DependentMemberType::get(Type base, AssociatedTypeDecl *assocType, const ASTContext &ctx) { auto properties = base->getRecursiveProperties(); properties |= RecursiveTypeProperties::HasTypeParameter; auto arena = getArena(properties); llvm::PointerUnion stored(assocType); auto *&known = ctx.Impl.getArena(arena).DependentMemberTypes[ {base, stored.getOpaqueValue()}]; if (!known) { const ASTContext *canonicalCtx = base->isCanonical() ? &ctx : nullptr; known = new (ctx, arena) DependentMemberType(base, assocType, canonicalCtx, properties); } return known; } CanArchetypeType ArchetypeType::getOpened(Type existential, Optional knownID) { auto &ctx = existential->getASTContext(); auto &openedExistentialArchetypes = ctx.Impl.OpenedExistentialArchetypes; // If we know the ID already... if (knownID) { // ... and we already have an archetype for that ID, return it. auto found = openedExistentialArchetypes.find(*knownID); if (found != openedExistentialArchetypes.end()) { auto result = found->second; assert(result->getOpenedExistentialType()->isEqual(existential) && "Retrieved the wrong opened existential type?"); return CanArchetypeType(result); } } else { // Create a new ID. knownID = UUID::fromTime(); } auto arena = AllocationArena::Permanent; llvm::SmallVector conformsTo; assert(existential->isExistentialType()); existential->getAnyExistentialTypeProtocols(conformsTo); // Tail-allocate space for the UUID. void *archetypeBuf = ctx.Allocate(totalSizeToAlloc(1), alignof(ArchetypeType), arena); auto result = ::new (archetypeBuf) ArchetypeType(ctx, existential, ctx.AllocateCopy(conformsTo), existential->getSuperclass(nullptr)); result->setOpenedExistentialID(*knownID); openedExistentialArchetypes[*knownID] = result; return CanArchetypeType(result); } CanType ArchetypeType::getAnyOpened(Type existential) { if (auto metatypeTy = existential->getAs()) { auto instanceTy = metatypeTy->getInstanceType(); return CanMetatypeType::get(ArchetypeType::getAnyOpened(instanceTy)); } assert(existential->isExistentialType()); return ArchetypeType::getOpened(existential); } void *ExprHandle::operator new(size_t Bytes, ASTContext &C, unsigned Alignment) { return C.Allocate(Bytes, Alignment); } ExprHandle *ExprHandle::get(ASTContext &Context, Expr *E) { return new (Context) ExprHandle(E); } void TypeLoc::setInvalidType(ASTContext &C) { TAndValidBit.setPointerAndInt(ErrorType::get(C), true); } namespace { class raw_capturing_ostream : public raw_ostream { std::string Message; uint64_t Pos; CapturingTypeCheckerDebugConsumer &Listener; public: raw_capturing_ostream(CapturingTypeCheckerDebugConsumer &Listener) : Listener(Listener) {} ~raw_capturing_ostream() { flush(); } void write_impl(const char *Ptr, size_t Size) override { Message.append(Ptr, Size); Pos += Size; // Check if we have at least one complete line. size_t LastNewline = StringRef(Message).rfind('\n'); if (LastNewline == StringRef::npos) return; Listener.handleMessage(StringRef(Message.data(), LastNewline + 1)); Message.erase(0, LastNewline + 1); } uint64_t current_pos() const override { return Pos; } }; } // unnamed namespace TypeCheckerDebugConsumer::~TypeCheckerDebugConsumer() { } CapturingTypeCheckerDebugConsumer::CapturingTypeCheckerDebugConsumer() : Log(new raw_capturing_ostream(*this)) { Log->SetUnbuffered(); } CapturingTypeCheckerDebugConsumer::~CapturingTypeCheckerDebugConsumer() { delete Log; } void GenericSignature::Profile(llvm::FoldingSetNodeID &ID, ArrayRef genericParams, ArrayRef requirements) { for (auto p : genericParams) ID.AddPointer(p); for (auto &reqt : requirements) { ID.AddPointer(reqt.getFirstType().getPointer()); if (reqt.getKind() != RequirementKind::WitnessMarker) ID.AddPointer(reqt.getSecondType().getPointer()); ID.AddInteger(unsigned(reqt.getKind())); } } GenericSignature *GenericSignature::get(ArrayRef params, ArrayRef requirements, bool isKnownCanonical) { if (params.empty() && requirements.empty()) return nullptr; // Check for an existing generic signature. llvm::FoldingSetNodeID ID; GenericSignature::Profile(ID, params, requirements); auto &ctx = getASTContext(params, requirements); void *insertPos; if (auto *sig = ctx.Impl.GenericSignatures.FindNodeOrInsertPos(ID, insertPos)) { if (isKnownCanonical) sig->CanonicalSignatureOrASTContext = &ctx; return sig; } // Allocate and construct the new signature. size_t bytes = totalSizeToAlloc( params.size(), requirements.size()); void *mem = ctx.Allocate(bytes, alignof(GenericSignature)); auto newSig = new (mem) GenericSignature(params, requirements, isKnownCanonical); ctx.Impl.GenericSignatures.InsertNode(newSig, insertPos); return newSig; } void DeclName::CompoundDeclName::Profile(llvm::FoldingSetNodeID &id, Identifier baseName, ArrayRef argumentNames) { id.AddPointer(baseName.get()); id.AddInteger(argumentNames.size()); for (auto arg : argumentNames) id.AddPointer(arg.get()); } void DeclName::initialize(ASTContext &C, Identifier baseName, ArrayRef argumentNames) { if (argumentNames.size() == 0) { SimpleOrCompound = IdentifierAndCompound(baseName, true); return; } llvm::FoldingSetNodeID id; CompoundDeclName::Profile(id, baseName, argumentNames); void *insert = nullptr; if (CompoundDeclName *compoundName = C.Impl.CompoundNames.FindNodeOrInsertPos(id, insert)) { SimpleOrCompound = compoundName; return; } size_t size = CompoundDeclName::totalSizeToAlloc(argumentNames.size()); auto buf = C.Allocate(size, alignof(CompoundDeclName)); auto compoundName = new (buf) CompoundDeclName(baseName,argumentNames.size()); std::uninitialized_copy(argumentNames.begin(), argumentNames.end(), compoundName->getArgumentNames().begin()); SimpleOrCompound = compoundName; C.Impl.CompoundNames.InsertNode(compoundName, insert); } /// Build a compound value name given a base name and a set of argument names /// extracted from a parameter list. DeclName::DeclName(ASTContext &C, Identifier baseName, ParameterList *paramList) { SmallVector names; for (auto P : *paramList) names.push_back(P->getArgumentName()); initialize(C, baseName, names); } Optional ASTContext::getBridgedToObjC(const DeclContext *dc, Type type, LazyResolver *resolver) const { if (type->isBridgeableObjectType()) return type; // Whitelist certain types even if Foundation is not imported, to ensure // that casts from AnyObject to one of these types are not optimized away. bool knownBridgedToObjC = false; if (auto ntd = type->getAnyNominal()) { knownBridgedToObjC = (ntd == getBoolDecl() || ntd == getIntDecl() || ntd == getUIntDecl() || ntd == getFloatDecl() || ntd == getDoubleDecl() || ntd == getArrayDecl() || ntd == getDictionaryDecl() || ntd == getSetDecl() || ntd == getStringDecl()); } // If the type is generic, check whether its generic arguments are also // bridged to Objective-C. if (auto bgt = type->getAs()) { for (auto arg : bgt->getGenericArgs()) { if (arg->hasTypeVariable()) continue; if (!getBridgedToObjC(dc, arg, resolver)) return None; } } if (auto metaTy = type->getAs()) if (metaTy->getInstanceType()->mayHaveSuperclass()) return type; if (auto existentialMetaTy = type->getAs()) if (existentialMetaTy->getInstanceType()->isObjCExistentialType()) return type; // Retrieve the _BridgedToObjectiveC protocol. auto bridgedProto = getProtocol(KnownProtocolKind::ObjectiveCBridgeable); if (!bridgedProto) return None; // Check whether the type conforms to _BridgedToObjectiveC. auto conformance = dc->getParentModule()->lookupConformance(type, bridgedProto, resolver); switch (conformance.getInt()) { case ConformanceKind::Conforms: // The type conforms, and we know the conformance, so we can look up the // bridged type below. break; case ConformanceKind::UncheckedConforms: // The type conforms, but we don't have a conformance yet. Return // Optional(nullptr) to signal this. return Type(); case ConformanceKind::DoesNotConform: // If we haven't imported Foundation but this is a whitelisted type, // behave as above. if (knownBridgedToObjC) return Type(); return None; } // Find the type we bridge to. return ProtocolConformance::getTypeWitnessByName(type, conformance.getPointer(), getIdentifier("_ObjectiveCType"), resolver); } std::pair ASTContext::getLazyArchetype(const ArchetypeType *archetype) { auto known = Impl.LazyArchetypes.find(archetype); assert(known != Impl.LazyArchetypes.end()); return known->second; } void ASTContext::registerLazyArchetype( const ArchetypeType *archetype, ArchetypeBuilder &builder, ArchetypeBuilder::PotentialArchetype *potentialArchetype) { assert(Impl.LazyArchetypes.count(archetype) == 0); Impl.LazyArchetypes[archetype] = { &builder, potentialArchetype }; } void ASTContext::unregisterLazyArchetype(const ArchetypeType *archetype) { auto known = Impl.LazyArchetypes.find(archetype); assert(known != Impl.LazyArchetypes.end()); Impl.LazyArchetypes.erase(known); } const InheritedNameSet *ASTContext::getAllPropertyNames(ClassDecl *classDecl, bool forInstance) { // If this class was defined in Objective-C, perform the lookup based on // the Objective-C class. if (auto objcClass = dyn_cast_or_null( classDecl->getClangDecl())) { return getAllPropertyNames( const_cast(objcClass), forInstance); } // If we already have this information, return it. auto known = Impl.AllProperties.find({classDecl, forInstance}); if (known != Impl.AllProperties.end()) return known->second.get(); // Otherwise, get information from our superclass first. if (auto resolver = getLazyResolver()) resolver->resolveSuperclass(classDecl); const InheritedNameSet *parentSet = nullptr; if (auto superclass = classDecl->getSuperclass()) { if (auto superclassDecl = superclass->getClassOrBoundGenericClass()) { parentSet = getAllPropertyNames(superclassDecl, forInstance); } } // Create the set of properties. known = Impl.AllProperties.insert( { std::pair(classDecl, forInstance), llvm::make_unique(parentSet) }).first; // Local function to add properties from the given set. auto addProperties = [&](DeclRange members) { for (auto member : members) { auto var = dyn_cast(member); if (!var || var->getName().empty()) continue; if (var->isInstanceMember() != forInstance) continue; known->second->add(var->getName().str()); } }; // Collect property names from the class. addProperties(classDecl->getMembers()); // Collect property names from all extensions in the same module as the class. auto module = classDecl->getParentModule(); for (auto ext : classDecl->getExtensions()) { if (ext->getParentModule() != module) continue; addProperties(ext->getMembers()); } return known->second.get(); } const InheritedNameSet *ASTContext::getAllPropertyNames( clang::ObjCInterfaceDecl *classDecl, bool forInstance) { classDecl = classDecl->getCanonicalDecl(); // If we already have this information, return it. auto known = Impl.AllPropertiesObjC.find({classDecl, forInstance}); if (known != Impl.AllPropertiesObjC.end()) return known->second.get(); // Otherwise, get information from our superclass first. const InheritedNameSet *parentSet = nullptr; if (auto superclassDecl = classDecl->getSuperClass()) { parentSet = getAllPropertyNames(superclassDecl, forInstance); } // Create the set of properties. known = Impl.AllPropertiesObjC.insert( { std::pair(classDecl, forInstance), llvm::make_unique(parentSet) }).first; // Local function to add properties from the given set. auto addProperties = [&](clang::DeclContext::decl_range members) { for (auto member : members) { // Add Objective-C property names. if (auto property = dyn_cast(member)) { if (forInstance) known->second->add(property->getName()); continue; } // Add no-parameter, non-void method names. if (auto method = dyn_cast(member)) { if (method->getSelector().isUnarySelector() && !method->getReturnType()->isVoidType() && !method->hasRelatedResultType() && method->isInstanceMethod() == forInstance) { known->second->add(method->getSelector().getNameForSlot(0)); continue; } } } }; // Dig out the class definition. auto classDef = classDecl->getDefinition(); if (!classDef) return known->second.get(); // Collect property names from the class definition. addProperties(classDef->decls()); // Dig out the module that owns the class definition. auto module = classDef->getImportedOwningModule(); if (module) module = module->getTopLevelModule(); // Collect property names from all categories and extensions in the same // module as the class. for (auto category : classDef->known_categories()) { auto categoryModule = category->getImportedOwningModule(); if (categoryModule) categoryModule = categoryModule->getTopLevelModule(); if (module != categoryModule) continue; addProperties(category->decls()); } return known->second.get(); }