//===--- ASTContext.cpp - ASTContext Implementation -----------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 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/AST/AST.h" #include "swift/AST/ASTMutationListener.h" #include "swift/AST/ConcreteDeclRef.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/ExprHandle.h" #include "swift/AST/KnownProtocols.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/ModuleLoadListener.h" #include "swift/AST/NameLookup.h" #include "swift/Basic/SourceManager.h" #include "llvm/Support/Allocator.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include using namespace swift; ASTMutationListener::~ASTMutationListener() { } ModuleLoadListener::~ModuleLoadListener() { } LazyResolver::~LazyResolver() { } llvm::StringRef swift::getProtocolName(KnownProtocolKind kind) { switch (kind) { #define PROTOCOL(Id) \ case KnownProtocolKind::Id: \ return #Id; #include "swift/AST/KnownProtocols.def" } } 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; llvm::StringMap IdentifierTable; /// The declaration of swift.Slice. NominalTypeDecl *SliceDecl = nullptr; /// The declaration of swift.Optional. NominalTypeDecl *OptionalDecl = nullptr; /// func _doesOptionalHaveValue(v : [inout] Optional) -> T FuncDecl *DoesOptionalHaveValueDecl = nullptr; /// func _getOptionalValue(v : Optional) -> T FuncDecl *GetOptionalValueDecl = nullptr; /// func _injectValueIntoOptional(v : T) -> Optional FuncDecl *InjectValueIntoOptionalDecl = nullptr; /// func _injectNothingIntoOptional() -> Optional FuncDecl *InjectNothingIntoOptionalDecl = nullptr; /// func _getBool(Builtin.Int1) -> Bool FuncDecl *GetBoolDecl = 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. // FIXME: We shouldn't be special-casing Clang. llvm::IntrusiveRefCntPtr ClangModuleLoader; /// \brief The set of AST mutation listeners. SmallVector MutationListeners; /// \brief The set of 'module load' event listeners. SmallVector ModuleLoadListeners; /// \brief Map from Swift declarations to the Clang nodes from which /// they were imported. llvm::DenseMap ClangNodes; /// \brief Structure that captures data that is segregated into different /// arenas. struct Arena { llvm::FoldingSet TupleTypes; llvm::DenseMap MetaTypeTypes; llvm::DenseMap>, FunctionType*> FunctionTypes; llvm::DenseMap, ArrayType*> ArrayTypes; llvm::DenseMap ArraySliceTypes; llvm::DenseMap OptionalTypes; llvm::DenseMap, VecType*> VecTypes; llvm::FoldingSet MatrixTypes; llvm::DenseMap ParenTypes; llvm::DenseMap ReferenceStorageTypes; llvm::DenseMap, LValueType*> LValueTypes; llvm::DenseMap, SubstitutedType *> SubstitutedTypes; llvm::DenseMap, DependentMemberType *> DependentMemberTypes; llvm::FoldingSet EnumTypes; llvm::FoldingSet StructTypes; llvm::FoldingSet ClassTypes; llvm::FoldingSet UnboundGenericTypes; llvm::FoldingSet BoundGenericTypes; }; llvm::DenseMap ModuleTypes; llvm::DenseMap, GenericTypeParamType *> GenericParamTypes; llvm::FoldingSet GenericFunctionTypes; llvm::FoldingSet SILFunctionTypes; llvm::DenseMap IntegerTypes; llvm::FoldingSet ProtocolCompositionTypes; llvm::FoldingSet BuiltinVectorTypes; /// \brief The permanent arena. Arena Permanent; /// FIXME: Move into arena. llvm::DenseMap> BoundGenericSubstitutions; using ConformanceListPair = std::pair>; /// \brief The set of nominal types and extensions thereof known to conform /// to compiler-known protocols. ConformanceListPair KnownProtocolConformances[NumKnownProtocols]; /// The list of normal protocol conformances. /// /// Since these conformances are tied explicitly to the source code, semantic /// analysis is responsible for handling the uniquing. SmallVector NormalConformances; /// The set of specialized protocol conformances. llvm::FoldingSet SpecializedConformances; /// The set of inherited protocol conformances. llvm::FoldingSet InheritedConformances; /// \brief Temporary arena used for a constraint solver. struct ConstraintSolverArena : public Arena { /// \brief The allocator used for all allocations within this arena. llvm::BumpPtrAllocator &Allocator; ConstraintSolverArena(llvm::BumpPtrAllocator &Allocator) : Allocator(Allocator) { } 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; } } }; ASTContext::Implementation::Implementation() : IdentifierTable(Allocator) {} ASTContext::Implementation::~Implementation() { for (auto &cleanup : Cleanups) cleanup(); } ConstraintCheckerArenaRAII:: ConstraintCheckerArenaRAII(ASTContext &self, llvm::BumpPtrAllocator &allocator) : Self(self), Data(self.Impl.CurrentConstraintSolverArena.release()) { Self.Impl.CurrentConstraintSolverArena.reset( new ASTContext::Implementation::ConstraintSolverArena(allocator)); } ConstraintCheckerArenaRAII::~ConstraintCheckerArenaRAII() { Self.Impl.CurrentConstraintSolverArena.reset( (ASTContext::Implementation::ConstraintSolverArena *)Data); } ASTContext::ASTContext(LangOptions &langOpts, SourceManager &SourceMgr, DiagnosticEngine &Diags) : Impl(*new Implementation()), LangOpts(langOpts), SourceMgr(SourceMgr), Diags(Diags), TheBuiltinModule(new (*this) BuiltinModule(getIdentifier("Builtin"), *this)), StdlibModuleName(getIdentifier("swift")), TheErrorType(new (*this, AllocationArena::Permanent) ErrorType(*this)), TheEmptyTupleType(TupleType::get(ArrayRef(), *this)), TheObjectPointerType(new (*this, AllocationArena::Permanent) BuiltinObjectPointerType(*this)), TheObjCPointerType(new (*this, AllocationArena::Permanent) BuiltinObjCPointerType(*this)), TheRawPointerType(new (*this, AllocationArena::Permanent) BuiltinRawPointerType(*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)){ } ASTContext::~ASTContext() { // Tear down protocol conformances. for (auto conformance : Impl.NormalConformances) conformance->~NormalProtocolConformance(); for (auto &conformance : Impl.SpecializedConformances) conformance.~SpecializedProtocolConformance(); 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; } } /// 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); return Identifier(Impl.IdentifierTable.GetOrCreateValue(Str).getKeyData()); } void ASTContext::lookupInSwiftModule( StringRef name, SmallVectorImpl &results) const { // Find the "swift" module. auto module = LoadedModules.find(StdlibModuleName.str()); if (module == LoadedModules.end()) return; // Find all of the declarations with this name in the Swift module. auto identifier = getIdentifier(name); module->second->lookupValue({ }, identifier, NLKind::UnqualifiedLookup, results); } /// Find the generic implementation declaration for the named syntactic-sugar /// type. static NominalTypeDecl *findSyntaxSugarImpl(const ASTContext &ctx, StringRef name) { // 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)) { if (auto params = nominal->getGenericParams()) { if (params->size() == 1) { // We found it. return nominal; } } } } return nullptr; } NominalTypeDecl *ASTContext::getSliceDecl() const { if (!Impl.SliceDecl) Impl.SliceDecl = findSyntaxSugarImpl(*this, "Slice"); return Impl.SliceDecl; } NominalTypeDecl *ASTContext::getOptionalDecl() const { if (!Impl.OptionalDecl) Impl.OptionalDecl = findSyntaxSugarImpl(*this, "Optional"); return Impl.OptionalDecl; } 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 Swift module. SmallVector results; 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) { SmallVector results; ctx.lookupInSwiftModule(name, results); if (results.size() == 1) return dyn_cast(results.front()); 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->getBitWidth() == 1; return false; } FuncDecl *ASTContext::getGetBoolDecl() const { if (Impl.GetBoolDecl) return Impl.GetBoolDecl; // Look for the function. CanType input, output; auto decl = findLibraryIntrinsic(*this, "_getBool"); 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; } /// 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->getType()->getCanonicalType()); if (!fnType || fnType->getAllArchetypes().size() != 1) return false; auto paramType = CanArchetypeType(fnType->getAllArchetypes()[0]); if (paramType->hasRequirements()) return false; param = paramType; input = stripImmediateLabels(fnType.getInput()); output = stripImmediateLabels(fnType.getResult()); return true; } /// Check whether the given type is Optional applied to the given /// type argument. static bool isOptionalType(const ASTContext &ctx, CanType type, CanType arg) { if (auto boundType = dyn_cast(type)) { return (boundType->getDecl() == ctx.getOptionalDecl() && boundType.getGenericArgs().size() == 1 && boundType.getGenericArgs()[0] == arg); } return false; } FuncDecl *ASTContext::getDoesOptionalHaveValueDecl() const { if (Impl.DoesOptionalHaveValueDecl) return Impl.DoesOptionalHaveValueDecl; // Look for a generic function. CanType input, output, param; auto decl = findLibraryIntrinsic(*this, "_doesOptionalHaveValue"); if (!decl || !isGenericIntrinsic(decl, input, output, param)) return nullptr; // Input must be [inout] Optional. auto inputInOut = dyn_cast(input); if (!inputInOut || !isOptionalType(*this, inputInOut.getObjectType(), param)) return nullptr; // Output must be Builtin.Int1. if (!isBuiltinInt1Type(output)) return nullptr; Impl.DoesOptionalHaveValueDecl = decl; return decl; } FuncDecl *ASTContext::getGetOptionalValueDecl() const { if (Impl.GetOptionalValueDecl) return Impl.GetOptionalValueDecl; // Look for the function. CanType input, output, param; auto decl = findLibraryIntrinsic(*this, "_getOptionalValue"); if (!decl || !isGenericIntrinsic(decl, input, output, param)) return nullptr; // Input must be Optional. if (!isOptionalType(*this, input, param)) return nullptr; // Output must be T. if (output != param) return nullptr; Impl.GetOptionalValueDecl = decl; return decl; } FuncDecl *ASTContext::getInjectValueIntoOptionalDecl() const { if (Impl.InjectValueIntoOptionalDecl) return Impl.InjectValueIntoOptionalDecl; // Look for the function. CanType input, output, param; auto decl = findLibraryIntrinsic(*this, "_injectValueIntoOptional"); if (!decl || !isGenericIntrinsic(decl, input, output, param)) return nullptr; // Input must be T. if (input != param) return nullptr; // Output must be Optional. if (!isOptionalType(*this, output, param)) return nullptr; Impl.InjectValueIntoOptionalDecl = decl; return decl; } FuncDecl *ASTContext::getInjectNothingIntoOptionalDecl() const { if (Impl.InjectNothingIntoOptionalDecl) return Impl.InjectNothingIntoOptionalDecl; // Look for the function. CanType input, output, param; auto decl = findLibraryIntrinsic(*this, "_injectNothingIntoOptional"); if (!decl || !isGenericIntrinsic(decl, input, output, param)) return nullptr; // Input must be (). auto inputTuple = dyn_cast(input); if (!inputTuple || inputTuple->getNumElements() != 0) return nullptr; // Output must be Optional. if (!isOptionalType(*this, output, param)) return nullptr; Impl.InjectNothingIntoOptionalDecl = decl; return decl; } bool ASTContext::hasOptionalIntrinsics() const { return getDoesOptionalHaveValueDecl() && getGetOptionalValueDecl() && getInjectValueIntoOptionalDecl() && getInjectNothingIntoOptionalDecl(); } void ASTContext::addMutationListener(ASTMutationListener &listener) { Impl.MutationListeners.push_back(&listener); } void ASTContext::removeMutationListener(ASTMutationListener &listener) { auto known = std::find(Impl.MutationListeners.rbegin(), Impl.MutationListeners.rend(), &listener); assert(known != Impl.MutationListeners.rend() && "listener not registered"); Impl.MutationListeners.erase(known.base()-1); } void ASTContext::addedExternalDecl(Decl *decl) { for (auto listener : Impl.MutationListeners) listener->addedExternalDecl(decl); } void ASTContext::addCleanup(std::function cleanup) { Impl.Cleanups.push_back(std::move(cleanup)); } bool ASTContext::hadError() const { return Diags.hadAnyError(); } Optional> ASTContext::createTrivialSubstitutions(BoundGenericType *BGT) const { assert(BGT->isCanonical() && "Requesting non-canonical substitutions"); ArrayRef Params = BGT->getDecl()->getGenericParams()->getParams(); assert(Params.size() == 1); auto Param = Params[0]; assert(Param.getAsTypeParam()->getArchetype() && "Not type-checked yet"); Substitution Subst; Subst.Archetype = Param.getAsTypeParam()->getArchetype(); Subst.Replacement = BGT->getGenericArgs()[0]; auto Substitutions = AllocateCopy(llvm::makeArrayRef(Subst)); Impl.BoundGenericSubstitutions.insert(std::make_pair(BGT, Substitutions)); return Substitutions; } Optional> ASTContext::getSubstitutions(BoundGenericType* bound) const { assert(bound->isCanonical() && "Requesting non-canonical substitutions"); auto known = Impl.BoundGenericSubstitutions.find(bound); if (known != Impl.BoundGenericSubstitutions.end()) return known->second; // We can trivially create substitutions for Slice and Optional. if (bound->getDecl() == getSliceDecl() || bound->getDecl() == getOptionalDecl()) return createTrivialSubstitutions(bound); return Nothing; } void ASTContext::setSubstitutions(BoundGenericType* Bound, ArrayRef Subs) const { assert(Bound->isCanonical() && "Requesting non-canonical substitutions"); assert(Impl.BoundGenericSubstitutions.count(Bound) == 0 && "Already have substitutions?"); Impl.BoundGenericSubstitutions[Bound] = Subs; } void ASTContext::addModuleLoader(llvm::IntrusiveRefCntPtr loader, bool IsClang) { Impl.ModuleLoaders.push_back(loader); if (IsClang) { assert(!Impl.ClangModuleLoader && "Already have a Clang module loader"); Impl.ClangModuleLoader = std::move(loader); } } void ASTContext::loadExtensions(NominalTypeDecl *nominal, unsigned previousGeneration) { for (auto loader : Impl.ModuleLoaders) { loader->loadExtensions(nominal, previousGeneration); } } llvm::IntrusiveRefCntPtr ASTContext::getClangModuleLoader() const{ return Impl.ClangModuleLoader; } static void recordKnownProtocol(Module *Stdlib, StringRef Name, KnownProtocolKind Kind) { Identifier ID = Stdlib->Ctx.getIdentifier(Name); UnqualifiedLookup Lookup(ID, Stdlib, nullptr, SourceLoc(), /*IsType=*/true); if (auto Proto = dyn_cast_or_null(Lookup.getSingleTypeResult())) Proto->setKnownProtocolKind(Kind); } void ASTContext::recordKnownProtocols(Module *Stdlib) { #define PROTOCOL(Name) \ recordKnownProtocol(Stdlib, #Name, KnownProtocolKind::Name); #include "swift/AST/KnownProtocols.def" } Module * ASTContext::getModule(ArrayRef> modulePath) { assert(!modulePath.empty()); auto moduleID = modulePath[0]; // TODO: Swift submodules. if (modulePath.size() == 1) { if (Module *M = LoadedModules.lookup(moduleID.first.str())) return M; } for (auto importer : Impl.ModuleLoaders) { if (Module *M = importer->loadModule(moduleID.second, modulePath)) { if (modulePath.size() == 1 && modulePath[0].first == StdlibModuleName) recordKnownProtocols(M); return M; } } return nullptr; } void ASTContext::addModuleLoadListener(ModuleLoadListener &Listener) { Impl.ModuleLoadListeners.push_back(&Listener); } void ASTContext::removeModuleLoadListener(ModuleLoadListener &Listener) { auto Known = std::find(Impl.ModuleLoadListeners.rbegin(), Impl.ModuleLoadListeners.rend(), &Listener); assert(Known != Impl.ModuleLoadListeners.rend() && "listener not registered"); Impl.ModuleLoadListeners.erase(Known.base() - 1); } ClangNode ASTContext::getClangNode(Decl *decl) { auto known = Impl.ClangNodes.find(decl); assert(known != Impl.ClangNodes.end() && "No Clang node?"); return known->second; } void ASTContext::setClangNode(Decl *decl, ClangNode node) { Impl.ClangNodes[decl] = node; } void ASTContext::recordConformance(KnownProtocolKind protocolKind, Decl *decl) { assert(isa(decl) || isa(decl)); auto index = static_cast(protocolKind); assert(index < NumKnownProtocols); Impl.KnownProtocolConformances[index].second.push_back(decl); } /// \brief Retrieve the set of nominal types and extensions thereof that /// conform to the given protocol. ArrayRef ASTContext::getTypesThatConformTo(KnownProtocolKind kind) { auto index = static_cast(kind); assert(index < NumKnownProtocols); for (auto loader : Impl.ModuleLoaders) { loader->loadDeclsConformingTo(kind, Impl.KnownProtocolConformances[index].first); } Impl.KnownProtocolConformances[index].first = CurrentGeneration; return Impl.KnownProtocolConformances[index].second; } NormalProtocolConformance * ASTContext::getConformance(Type conformingType, ProtocolDecl *protocol, Module *containingModule, WitnessMap &&witnesses, TypeWitnessMap &&typeWitnesses, InheritedConformanceMap &&inheritedConformances, ArrayRef defaultedDefinitions) { auto result = new (*this) NormalProtocolConformance(conformingType, protocol, containingModule, std::move(witnesses), std::move(typeWitnesses), std::move(inheritedConformances), defaultedDefinitions); Impl.NormalConformances.push_back(result); return result; } SpecializedProtocolConformance * ASTContext::getSpecializedConformance(Type type, ProtocolConformance *generic, ArrayRef substitutions, TypeWitnessMap &&typeWitnesses) { llvm::FoldingSetNodeID id; SpecializedProtocolConformance::Profile(id, type, generic); // Did we already record the specialized conformance? void *insertPos; if (auto result = Impl.SpecializedConformances.FindNodeOrInsertPos(id, insertPos)) return result; // Build a new specialized conformance. auto result = new (*this) SpecializedProtocolConformance(type, generic, substitutions, std::move(typeWitnesses)); Impl.SpecializedConformances.InsertNode(result, insertPos); return result; } InheritedProtocolConformance * ASTContext::getInheritedConformance(Type type, ProtocolConformance *inherited) { llvm::FoldingSetNodeID id; InheritedProtocolConformance::Profile(id, type, inherited); // Did we already record the specialized conformance? void *insertPos; if (auto result = Impl.InheritedConformances.FindNodeOrInsertPos(id, insertPos)) return result; // Build a new specialized conformance. auto result = new (*this) InheritedProtocolConformance(type, inherited); Impl.InheritedConformances.InsertNode(result, insertPos); return result; } //===----------------------------------------------------------------------===// // Type manipulation routines. //===----------------------------------------------------------------------===// // Simple accessors. Type ErrorType::get(const ASTContext &C) { return C.TheErrorType; } BuiltinIntegerType *BuiltinIntegerType::get(unsigned BitWidth, const ASTContext &C) { BuiltinIntegerType *&Result = C.Impl.IntegerTypes[BitWidth]; if (Result == 0) Result = new (C, AllocationArena::Permanent) BuiltinIntegerType(BitWidth,C); return Result; } /// \brief Retrieve the arena from which we should allocate storage for a type. static AllocationArena getArena(bool hasTypeVariable) { return hasTypeVariable? AllocationArena::ConstraintSolver : AllocationArena::Permanent;; } 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) { bool hasTypeVariable = underlying->hasTypeVariable(); auto arena = getArena(hasTypeVariable); ParenType *&Result = C.Impl.getArena(arena).ParenTypes[underlying]; if (Result == 0) { Result = new (C, arena) ParenType(underlying, hasTypeVariable); } 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.getName().get()); ID.AddPointer(Elt.TyAndDefaultOrVarArg.getOpaqueValue()); } } /// 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()) return ParenType::get(C, Fields[0].getType()); bool HasTypeVariable = false; for (const TupleTypeElt &Elt : Fields) { if (Elt.getType() && Elt.getType()->hasTypeVariable()) { HasTypeVariable = true; break; } } auto arena = getArena(HasTypeVariable); 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, HasTypeVariable); C.Impl.getArena(arena).TupleTypes.InsertNode(New, InsertPos); return New; } void UnboundGenericType::Profile(llvm::FoldingSetNodeID &ID, NominalTypeDecl *TheDecl, Type Parent) { ID.AddPointer(TheDecl); ID.AddPointer(Parent.getPointer()); } UnboundGenericType* UnboundGenericType::get(NominalTypeDecl *TheDecl, Type Parent, const ASTContext &C) { llvm::FoldingSetNodeID ID; UnboundGenericType::Profile(ID, TheDecl, Parent); void *InsertPos = 0; bool hasTypeVariable = Parent && Parent->hasTypeVariable(); auto arena = getArena(hasTypeVariable); if (auto unbound = C.Impl.getArena(arena).UnboundGenericTypes .FindNodeOrInsertPos(ID, InsertPos)) return unbound; auto result = new (C, arena) UnboundGenericType(TheDecl, Parent, C, hasTypeVariable); C.Impl.getArena(arena).UnboundGenericTypes.InsertNode(result, InsertPos); return result; } void BoundGenericType::Profile(llvm::FoldingSetNodeID &ID, NominalTypeDecl *TheDecl, Type Parent, ArrayRef GenericArgs, bool &hasTypeVariable) { ID.AddPointer(TheDecl); ID.AddPointer(Parent.getPointer()); if (Parent && Parent->hasTypeVariable()) hasTypeVariable = true; ID.AddInteger(GenericArgs.size()); for (Type Arg : GenericArgs) { ID.AddPointer(Arg.getPointer()); if (Arg->hasTypeVariable()) hasTypeVariable = true; } } BoundGenericType::BoundGenericType(TypeKind theKind, NominalTypeDecl *theDecl, Type parent, ArrayRef genericArgs, const ASTContext *context, bool hasTypeVariable) : TypeBase(theKind, context, hasTypeVariable), TheDecl(theDecl), Parent(parent), GenericArgs(genericArgs) { } BoundGenericType *BoundGenericType::get(NominalTypeDecl *TheDecl, Type Parent, ArrayRef GenericArgs) { ASTContext &C = TheDecl->getDeclContext()->getASTContext(); llvm::FoldingSetNodeID ID; bool HasTypeVariable = false; BoundGenericType::Profile(ID, TheDecl, Parent, GenericArgs, HasTypeVariable); auto arena = getArena(HasTypeVariable); 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, HasTypeVariable); } else if (auto theStruct = dyn_cast(TheDecl)) { newType = new (C, arena) BoundGenericStructType(theStruct, Parent, ArgsCopy, IsCanonical ? &C : 0, HasTypeVariable); } else { auto theEnum = cast(TheDecl); newType = new (C, arena) BoundGenericEnumType(theEnum, Parent, ArgsCopy, IsCanonical ? &C : 0, HasTypeVariable); } 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, bool HasTypeVariable) : NominalType(TypeKind::Enum, &C, TheDecl, Parent, HasTypeVariable) { } EnumType *EnumType::get(EnumDecl *D, Type Parent, const ASTContext &C) { llvm::FoldingSetNodeID id; EnumType::Profile(id, D, Parent); bool hasTypeVariable = Parent && Parent->hasTypeVariable(); auto arena = getArena(hasTypeVariable); 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, hasTypeVariable); 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, bool HasTypeVariable) : NominalType(TypeKind::Struct, &C, TheDecl, Parent, HasTypeVariable) { } StructType *StructType::get(StructDecl *D, Type Parent, const ASTContext &C) { llvm::FoldingSetNodeID id; StructType::Profile(id, D, Parent); bool hasTypeVariable = Parent && Parent->hasTypeVariable(); auto arena = getArena(hasTypeVariable); 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, hasTypeVariable); 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, bool HasTypeVariable) : NominalType(TypeKind::Class, &C, TheDecl, Parent, HasTypeVariable) { } ClassType *ClassType::get(ClassDecl *D, Type Parent, const ASTContext &C) { llvm::FoldingSetNodeID id; ClassType::Profile(id, D, Parent); bool hasTypeVariable = Parent && Parent->hasTypeVariable(); auto arena = getArena(hasTypeVariable); 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, hasTypeVariable); 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 arena = AllocationArena::Permanent; 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); case Ownership::Weak: return entry = new (C, arena) WeakStorageType(T, T->isCanonical() ? &C : 0); } llvm_unreachable("bad ownership"); } MetaTypeType *MetaTypeType::get(Type T, const ASTContext &C) { bool hasTypeVariable = T->hasTypeVariable(); auto arena = getArena(hasTypeVariable); MetaTypeType *&Entry = C.Impl.getArena(arena).MetaTypeTypes[T]; if (Entry) return Entry; return Entry = new (C, arena) MetaTypeType(T, T->isCanonical() ? &C : 0, hasTypeVariable); } MetaTypeType::MetaTypeType(Type T, const ASTContext *C, bool HasTypeVariable) : TypeBase(TypeKind::MetaType, C, HasTypeVariable), InstanceType(T) { } 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); } /// FunctionType::get - Return a uniqued function type with the specified /// input and result. FunctionType *FunctionType::get(Type Input, Type Result, const ExtInfo &Info, const ASTContext &C) { bool hasTypeVariable = Input->hasTypeVariable() || Result->hasTypeVariable(); auto arena = getArena(hasTypeVariable); char attrKey = Info.getFuncAttrKey(); FunctionType *&Entry = C.Impl.getArena(arena).FunctionTypes[{Input, {Result, attrKey} }]; if (Entry) return Entry; return Entry = new (C, arena) FunctionType(Input, Result, hasTypeVariable, Info); } // If the input and result types are canonical, then so is the result. FunctionType::FunctionType(Type input, Type output, bool hasTypeVariable, const ExtInfo &Info) : AnyFunctionType(TypeKind::Function, (input->isCanonical() && output->isCanonical()) ? &input->getASTContext() : 0, input, output, hasTypeVariable, 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, const ASTContext &C) { // FIXME: one day we should do canonicalization properly. bool hasTypeVariable = input->hasTypeVariable() || output->hasTypeVariable(); auto arena = getArena(hasTypeVariable); return new (C, arena) PolymorphicFunctionType(input, output, params, Info, C); } PolymorphicFunctionType::PolymorphicFunctionType(Type input, Type output, GenericParamList *params, const ExtInfo &Info, const ASTContext &C) : AnyFunctionType(TypeKind::PolymorphicFunction, (input->isCanonical() && output->isCanonical()) ?&C : 0, input, output, /*HasTypeVariable=*/false, Info), Params(params) { assert(!input->hasTypeVariable() && !output->hasTypeVariable()); } void GenericFunctionType::Profile(llvm::FoldingSetNodeID &ID, ArrayRef params, ArrayRef requirements, Type input, Type result, const ExtInfo &info) { ID.AddInteger(params.size()); for (auto param : params) ID.AddPointer(param); ID.AddInteger(requirements.size()); for (const auto &req : requirements) { ID.AddInteger(static_cast(req.getKind())); ID.AddPointer(req.getFirstType().getPointer()); ID.AddPointer(req.getSecondType().getPointer()); } ID.AddPointer(input.getPointer()); ID.AddPointer(result.getPointer()); ID.AddInteger(info.getFuncAttrKey()); } GenericFunctionType * GenericFunctionType::get(ArrayRef params, ArrayRef requirements, Type input, Type output, const ExtInfo &info, const ASTContext &ctx) { assert(!input->hasTypeVariable() && !output->hasTypeVariable()); llvm::FoldingSetNodeID id; GenericFunctionType::Profile(id, params, requirements, input, output, info); // 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 = input->isCanonical() && output->isCanonical(); if (isCanonical) { for (auto param : params) { if (!param->isCanonical()) { isCanonical = false; break; } } } if (isCanonical ) { for (const auto &req : requirements) { if (!req.getFirstType()->isCanonical() || !req.getSecondType()->isCanonical()) { isCanonical = false; break; } } } // Allocate storage for the object. size_t bytes = sizeof(GenericFunctionType) + sizeof(GenericTypeParamType *) * params.size() + sizeof(Requirement) * requirements.size(); void *mem = ctx.Allocate(bytes, alignof(GenericFunctionType)); auto result = new (mem) GenericFunctionType(params, requirements, input, output, info, isCanonical? &ctx : nullptr); ctx.Impl.GenericFunctionTypes.InsertNode(result, insertPos); return result; } GenericFunctionType::GenericFunctionType( ArrayRef genericParams, ArrayRef requirements, Type input, Type result, const ExtInfo &info, const ASTContext *ctx) : AnyFunctionType(TypeKind::GenericFunction, ctx, input, result, /*hasTypeVariable=*/false, info), NumGenericParams(genericParams.size()), NumRequirements(requirements.size()) { std::copy(genericParams.begin(), genericParams.end(), getGenericParamsBuffer().data()); std::copy(requirements.begin(), requirements.end(), getRequirementsBuffer().data()); } 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; } void SILFunctionType::Profile(llvm::FoldingSetNodeID &id, GenericParamList *genericParams, ExtInfo info, ParameterConvention calleeConvention, ArrayRef params, SILResultInfo result) { id.AddPointer(genericParams); id.AddInteger(info.getFuncAttrKey()); id.AddInteger(unsigned(calleeConvention)); id.AddInteger(params.size()); for (auto param : params) param.profile(id); result.profile(id); } SILFunctionType *SILFunctionType::get(GenericParamList *genericParams, ExtInfo ext, ParameterConvention callee, ArrayRef params, SILResultInfo result, ASTContext &ctx) { llvm::FoldingSetNodeID id; SILFunctionType::Profile(id, genericParams, ext, callee, params, result); // Do we already have this generic function type? void *insertPos; if (auto result = ctx.Impl.SILFunctionTypes.FindNodeOrInsertPos(id, insertPos)) return result; // All SILFunctionTypes are canonical. // Allocate storage for the object. size_t bytes = sizeof(SILFunctionType) + sizeof(SILParameterInfo) * params.size(); void *mem = ctx.Allocate(bytes, alignof(SILFunctionType)); auto fnType = new (mem) SILFunctionType(genericParams, ext, callee, params, result, ctx); ctx.Impl.SILFunctionTypes.InsertNode(fnType, insertPos); return fnType; } /// Return a uniqued array type with the specified base type and the /// specified size. ArrayType *ArrayType::get(Type BaseType, uint64_t Size, const ASTContext &C) { assert(Size != 0); bool hasTypeVariable = BaseType->hasTypeVariable(); auto arena = getArena(hasTypeVariable); ArrayType *&Entry = C.Impl.getArena(arena).ArrayTypes[std::make_pair(BaseType, Size)]; if (Entry) return Entry; return Entry = new (C, arena) ArrayType(BaseType, Size, hasTypeVariable); } ArrayType::ArrayType(Type base, uint64_t size, bool hasTypeVariable) : TypeBase(TypeKind::Array, base->isCanonical() ? &base->getASTContext() : 0, hasTypeVariable), Base(base), Size(size) {} ArraySliceType *ArraySliceType::get(Type base, const ASTContext &C) { bool hasTypeVariable = base->hasTypeVariable(); auto arena = getArena(hasTypeVariable); ArraySliceType *&entry = C.Impl.getArena(arena).ArraySliceTypes[base]; if (entry) return entry; return entry = new (C, arena) ArraySliceType(C, base, hasTypeVariable); } OptionalType *OptionalType::get(Type base, const ASTContext &C) { bool hasTypeVariable = base->hasTypeVariable(); auto arena = getArena(hasTypeVariable); OptionalType *&entry = C.Impl.getArena(arena).OptionalTypes[base]; if (entry) return entry; return entry = new (C, arena) OptionalType(C, base, hasTypeVariable); } 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; } VecType *VecType::get(Type base, unsigned length, const ASTContext &C) { bool hasTypeVariable = base->hasTypeVariable(); auto arena = getArena(hasTypeVariable); VecType *&entry = C.Impl.getArena(arena).VecTypes[{base, length}]; if (entry) return entry; return entry = new (C, arena) VecType(C, base, length, hasTypeVariable); } MatrixType *MatrixType::get(Type baseTy, unsigned rows, Optional columns, const ASTContext &ctx) { llvm::FoldingSetNodeID id; MatrixType::Profile(id, baseTy, rows, columns); auto arena = getArena(baseTy->hasTypeVariable()); void *insertPos; if (MatrixType *matrixType = ctx.Impl.getArena(arena).MatrixTypes.FindNodeOrInsertPos(id, insertPos)) return matrixType; auto matrixTy = new (ctx, arena) MatrixType(ctx, baseTy, rows, columns, baseTy->hasTypeVariable()); ctx.Impl.getArena(arena).MatrixTypes.InsertNode(matrixTy, insertPos); return matrixTy; } void MatrixType::Profile(llvm::FoldingSetNodeID &id, Type baseType, unsigned rows, Optional columns) { id.AddPointer(baseType.getPointer()); id.AddInteger(rows); id.AddBoolean(static_cast(columns)); if (columns) id.AddInteger(*columns); } ProtocolType::ProtocolType(ProtocolDecl *TheDecl, const ASTContext &Ctx) : NominalType(TypeKind::Protocol, &Ctx, TheDecl, /*Parent=*/Type(), /*HasTypeVariable=*/false) { } LValueType *LValueType::get(Type objectTy, Qual quals, const ASTContext &C) { assert(!objectTy->is() && "can not have ErrorType wrapped inside LValueType"); bool hasTypeVariable = objectTy->hasTypeVariable(); auto arena = getArena(hasTypeVariable); auto key = std::make_pair(objectTy, quals.getOpaqueData()); auto &entry = C.Impl.getArena(arena).LValueTypes[key]; if (entry) return entry; const ASTContext *canonicalContext = objectTy->isCanonical() ? &C : nullptr; return entry = new (C, arena) LValueType(objectTy, quals, canonicalContext, hasTypeVariable); } /// Return a uniqued substituted type. SubstitutedType *SubstitutedType::get(Type Original, Type Replacement, const ASTContext &C) { bool hasTypeVariable = Replacement->hasTypeVariable(); auto arena = getArena(hasTypeVariable); SubstitutedType *&Known = C.Impl.getArena(arena).SubstitutedTypes[{Original, Replacement}]; if (!Known) { Known = new (C, arena) SubstitutedType(Original, Replacement, hasTypeVariable); } return Known; } DependentMemberType *DependentMemberType::get(Type base, Identifier name, const ASTContext &ctx) { bool hasTypeVariable = base->hasTypeVariable(); auto arena = getArena(hasTypeVariable); 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, hasTypeVariable); } return known; } DependentMemberType *DependentMemberType::get(Type base, AssociatedTypeDecl *assocType, const ASTContext &ctx) { bool hasTypeVariable = base->hasTypeVariable(); auto arena = getArena(hasTypeVariable); 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, hasTypeVariable); } return known; } 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); }