| //===--- ASTDemangler.cpp ----------------------------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Defines a builder concept for the TypeDecoder and MetadataReader which builds |
| // AST Types, and a utility function wrapper which takes a mangled string and |
| // feeds it through the TypeDecoder instance. |
| // |
| // The RemoteAST library defines a MetadataReader instance that uses this |
| // concept, together with some additional utilities. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/AST/ASTDemangler.h" |
| |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/ClangModuleLoader.h" |
| #include "swift/AST/Decl.h" |
| #include "swift/AST/GenericSignature.h" |
| #include "swift/AST/Module.h" |
| #include "swift/AST/NameLookup.h" |
| #include "swift/AST/Type.h" |
| #include "swift/AST/TypeCheckRequests.h" |
| #include "swift/AST/Types.h" |
| #include "swift/Demangling/Demangler.h" |
| #include "swift/Demangling/ManglingMacros.h" |
| #include "llvm/ADT/StringSwitch.h" |
| |
| using namespace swift; |
| |
| Type swift::Demangle::getTypeForMangling(ASTContext &ctx, |
| StringRef mangling) { |
| Demangle::Context Dem; |
| auto node = Dem.demangleSymbolAsNode(mangling); |
| if (!node) |
| return Type(); |
| |
| ASTBuilder builder(ctx); |
| return swift::Demangle::decodeMangledType(builder, node).getType(); |
| } |
| |
| TypeDecl *swift::Demangle::getTypeDeclForMangling(ASTContext &ctx, |
| StringRef mangling) { |
| Demangle::Context Dem; |
| auto node = Dem.demangleSymbolAsNode(mangling); |
| if (!node) |
| return nullptr; |
| |
| ASTBuilder builder(ctx); |
| return builder.createTypeDecl(node); |
| } |
| |
| TypeDecl *swift::Demangle::getTypeDeclForUSR(ASTContext &ctx, |
| StringRef usr) { |
| if (!usr.startswith("s:")) |
| return nullptr; |
| |
| std::string mangling(usr); |
| mangling.replace(0, 2, MANGLING_PREFIX_STR); |
| |
| return getTypeDeclForMangling(ctx, mangling); |
| } |
| |
| TypeDecl *ASTBuilder::createTypeDecl(NodePointer node) { |
| if (node->getKind() == Node::Kind::Global) |
| return createTypeDecl(node->getChild(0)); |
| |
| // Special case: associated types are not DeclContexts. |
| if (node->getKind() == Node::Kind::AssociatedTypeRef) { |
| if (node->getNumChildren() != 2) |
| return nullptr; |
| |
| auto *DC = findDeclContext(node->getChild(0)); |
| auto *proto = dyn_cast_or_null<ProtocolDecl>(DC); |
| if (proto == nullptr) |
| return nullptr; |
| |
| auto name = Ctx.getIdentifier(node->getChild(1)->getText()); |
| return proto->getAssociatedType(name); |
| } |
| |
| auto *DC = findDeclContext(node); |
| return dyn_cast_or_null<GenericTypeDecl>(DC); |
| } |
| |
| Type |
| ASTBuilder::createBuiltinType(StringRef builtinName, |
| StringRef mangledName) { |
| if (builtinName.startswith(BUILTIN_TYPE_NAME_PREFIX)) { |
| SmallVector<ValueDecl *, 1> decls; |
| |
| StringRef strippedName = |
| builtinName.drop_front(BUILTIN_TYPE_NAME_PREFIX.size()); |
| Ctx.TheBuiltinModule->lookupValue(Ctx.getIdentifier(strippedName), |
| NLKind::QualifiedLookup, |
| decls); |
| |
| if (decls.size() == 1 && isa<TypeDecl>(decls[0])) |
| return cast<TypeDecl>(decls[0])->getDeclaredInterfaceType(); |
| } |
| |
| return Type(); |
| } |
| |
| GenericTypeDecl *ASTBuilder::createTypeDecl(StringRef mangledName, |
| bool &typeAlias) { |
| Demangle::Demangler Dem; |
| Demangle::NodePointer node = Dem.demangleType(mangledName); |
| if (!node) return nullptr; |
| |
| return createTypeDecl(node, typeAlias); |
| } |
| |
| ProtocolDecl * |
| ASTBuilder::createProtocolDecl(NodePointer node) { |
| bool typeAlias; |
| return dyn_cast_or_null<ProtocolDecl>( |
| createTypeDecl(node, typeAlias)); |
| } |
| |
| Type ASTBuilder::createNominalType(GenericTypeDecl *decl) { |
| auto *nominalDecl = dyn_cast<NominalTypeDecl>(decl); |
| if (!nominalDecl) |
| return Type(); |
| |
| // If the declaration is generic, fail. |
| if (nominalDecl->isGenericContext()) |
| return Type(); |
| |
| return nominalDecl->getDeclaredType(); |
| } |
| |
| Type ASTBuilder::createNominalType(GenericTypeDecl *decl, Type parent) { |
| auto *nominalDecl = dyn_cast<NominalTypeDecl>(decl); |
| if (!nominalDecl) |
| return Type(); |
| |
| // If the declaration is generic, fail. |
| if (auto list = nominalDecl->getGenericParams()) |
| return Type(); |
| |
| // Imported types can be renamed to be members of other (non-generic) |
| // types, but the mangling does not have a parent type. Just use the |
| // declared type directly in this case and skip the parent check below. |
| bool isImported = nominalDecl->hasClangNode() || |
| nominalDecl->getAttrs().hasAttribute<ClangImporterSynthesizedTypeAttr>(); |
| if (isImported && !nominalDecl->isGenericContext()) |
| return nominalDecl->getDeclaredInterfaceType(); |
| |
| // Validate the parent type. |
| if (!validateParentType(nominalDecl, parent)) |
| return Type(); |
| |
| return NominalType::get(nominalDecl, parent, Ctx); |
| } |
| |
| Type ASTBuilder::createTypeAliasType(GenericTypeDecl *decl, Type parent) { |
| auto *aliasDecl = dyn_cast<TypeAliasDecl>(decl); |
| if (!aliasDecl) |
| return Type(); |
| |
| // If the declaration is generic, fail. |
| if (aliasDecl->getGenericParams()) |
| return Type(); |
| |
| // Imported types can be renamed to be members of other (non-generic) |
| // types, but the mangling does not have a parent type. Just use the |
| // declared type directly in this case and skip the parent check below. |
| bool isImported = aliasDecl->hasClangNode() || |
| aliasDecl->getAttrs().hasAttribute<ClangImporterSynthesizedTypeAttr>(); |
| if (isImported && !aliasDecl->isGenericContext()) |
| return aliasDecl->getDeclaredInterfaceType(); |
| |
| // Validate the parent type. |
| if (!validateParentType(aliasDecl, parent)) |
| return Type(); |
| |
| auto declaredType = aliasDecl->getDeclaredInterfaceType(); |
| if (!parent) |
| return declaredType; |
| |
| auto *dc = aliasDecl->getDeclContext(); |
| auto subs = parent->getContextSubstitutionMap(dc->getParentModule(), dc); |
| |
| return declaredType.subst(subs); |
| } |
| |
| static SubstitutionMap |
| createSubstitutionMapFromGenericArgs(GenericSignature genericSig, |
| ArrayRef<Type> args, |
| ModuleDecl *moduleDecl) { |
| if (!genericSig) |
| return SubstitutionMap(); |
| |
| if (genericSig->getGenericParams().size() != args.size()) |
| return SubstitutionMap(); |
| |
| return SubstitutionMap::get( |
| genericSig, |
| [&](SubstitutableType *t) -> Type { |
| auto *gp = cast<GenericTypeParamType>(t); |
| unsigned ordinal = genericSig->getGenericParamOrdinal(gp); |
| if (ordinal < args.size()) |
| return args[ordinal]; |
| return Type(); |
| }, |
| LookUpConformanceInModule(moduleDecl)); |
| } |
| |
| Type ASTBuilder::createBoundGenericType(GenericTypeDecl *decl, |
| ArrayRef<Type> args) { |
| auto *nominalDecl = dyn_cast<NominalTypeDecl>(decl); |
| if (!nominalDecl) |
| return Type(); |
| |
| // If the declaration isn't generic, fail. |
| if (!nominalDecl->isGenericContext()) |
| return Type(); |
| |
| // Build a SubstitutionMap. |
| auto genericSig = nominalDecl->getGenericSignature(); |
| auto subs = createSubstitutionMapFromGenericArgs( |
| genericSig, args, decl->getParentModule()); |
| if (!subs) |
| return Type(); |
| auto origType = nominalDecl->getDeclaredInterfaceType(); |
| |
| // FIXME: We're not checking that the type satisfies the generic |
| // requirements of the signature here. |
| return origType.subst(subs); |
| } |
| |
| Type ASTBuilder::resolveOpaqueType(NodePointer opaqueDescriptor, |
| ArrayRef<ArrayRef<Type>> args, |
| unsigned ordinal) { |
| if (opaqueDescriptor->getKind() == Node::Kind::OpaqueReturnTypeOf) { |
| auto definingDecl = opaqueDescriptor->getChild(0); |
| auto definingGlobal = Factory.createNode(Node::Kind::Global); |
| definingGlobal->addChild(definingDecl, Factory); |
| auto mangledName = mangleNode(definingGlobal); |
| |
| auto moduleNode = findModuleNode(definingDecl); |
| if (!moduleNode) |
| return Type(); |
| auto parentModule = findModule(moduleNode); |
| if (!parentModule) |
| return Type(); |
| |
| auto opaqueDecl = parentModule->lookupOpaqueResultType(mangledName); |
| if (!opaqueDecl) |
| return Type(); |
| // TODO: multiple opaque types |
| assert(ordinal == 0 && "not implemented"); |
| if (ordinal != 0) |
| return Type(); |
| |
| SmallVector<Type, 8> allArgs; |
| for (auto argSet : args) { |
| allArgs.append(argSet.begin(), argSet.end()); |
| } |
| |
| SubstitutionMap subs = createSubstitutionMapFromGenericArgs( |
| opaqueDecl->getGenericSignature(), allArgs, parentModule); |
| return OpaqueTypeArchetypeType::get(opaqueDecl, subs); |
| } |
| |
| // TODO: named opaque types |
| return Type(); |
| } |
| |
| Type ASTBuilder::createBoundGenericType(GenericTypeDecl *decl, |
| ArrayRef<Type> args, |
| Type parent) { |
| // If the declaration isn't generic, fail. |
| if (!decl->getGenericParams()) |
| return Type(); |
| |
| // Validate the parent type. |
| if (!validateParentType(decl, parent)) |
| return Type(); |
| |
| if (auto *nominalDecl = dyn_cast<NominalTypeDecl>(decl)) |
| return BoundGenericType::get(nominalDecl, parent, args); |
| |
| // Combine the substitutions from our parent type with our generic |
| // arguments. |
| TypeSubstitutionMap subs; |
| if (parent) |
| subs = parent->getContextSubstitutions(decl->getDeclContext()); |
| |
| auto *aliasDecl = cast<TypeAliasDecl>(decl); |
| |
| auto genericSig = aliasDecl->getGenericSignature(); |
| for (unsigned i = 0, e = args.size(); i < e; ++i) { |
| auto origTy = genericSig->getInnermostGenericParams()[i]; |
| auto substTy = args[i]; |
| |
| subs[origTy->getCanonicalType()->castTo<GenericTypeParamType>()] = |
| substTy; |
| } |
| |
| // FIXME: This is the wrong module |
| auto *moduleDecl = decl->getParentModule(); |
| auto subMap = SubstitutionMap::get(genericSig, |
| QueryTypeSubstitutionMap{subs}, |
| LookUpConformanceInModule(moduleDecl)); |
| if (!subMap) |
| return Type(); |
| |
| return aliasDecl->getDeclaredInterfaceType().subst(subMap); |
| } |
| |
| Type ASTBuilder::createTupleType(ArrayRef<Type> eltTypes, StringRef labels) { |
| SmallVector<TupleTypeElt, 4> elements; |
| elements.reserve(eltTypes.size()); |
| for (auto eltType : eltTypes) { |
| Identifier label; |
| if (!labels.empty()) { |
| auto split = labels.split(' '); |
| if (!split.first.empty()) |
| label = Ctx.getIdentifier(split.first); |
| labels = split.second; |
| } |
| elements.emplace_back(eltType, label); |
| } |
| |
| return TupleType::get(elements, Ctx); |
| } |
| |
| Type ASTBuilder::createFunctionType( |
| ArrayRef<Demangle::FunctionParam<Type>> params, |
| Type output, FunctionTypeFlags flags) { |
| // The result type must be materializable. |
| if (!output->isMaterializable()) return Type(); |
| |
| llvm::SmallVector<AnyFunctionType::Param, 8> funcParams; |
| for (const auto ¶m : params) { |
| auto type = param.getType(); |
| |
| // All the argument types must be materializable. |
| if (!type->isMaterializable()) |
| return Type(); |
| |
| auto label = Ctx.getIdentifier(param.getLabel()); |
| auto flags = param.getFlags(); |
| auto ownership = flags.getValueOwnership(); |
| auto parameterFlags = ParameterTypeFlags() |
| .withValueOwnership(ownership) |
| .withVariadic(flags.isVariadic()) |
| .withAutoClosure(flags.isAutoClosure()) |
| .withNoDerivative(flags.isNoDerivative()); |
| |
| funcParams.push_back(AnyFunctionType::Param(type, label, parameterFlags)); |
| } |
| |
| FunctionTypeRepresentation representation; |
| switch (flags.getConvention()) { |
| case FunctionMetadataConvention::Swift: |
| representation = FunctionTypeRepresentation::Swift; |
| break; |
| case FunctionMetadataConvention::Block: |
| representation = FunctionTypeRepresentation::Block; |
| break; |
| case FunctionMetadataConvention::Thin: |
| representation = FunctionTypeRepresentation::Thin; |
| break; |
| case FunctionMetadataConvention::CFunctionPointer: |
| representation = FunctionTypeRepresentation::CFunctionPointer; |
| break; |
| } |
| |
| DifferentiabilityKind diffKind; |
| switch (flags.getDifferentiabilityKind()) { |
| case FunctionMetadataDifferentiabilityKind::NonDifferentiable: |
| diffKind = DifferentiabilityKind::NonDifferentiable; |
| break; |
| case FunctionMetadataDifferentiabilityKind::Normal: |
| diffKind = DifferentiabilityKind::Normal; |
| break; |
| case FunctionMetadataDifferentiabilityKind::Linear: |
| diffKind = DifferentiabilityKind::Linear; |
| break; |
| } |
| |
| auto noescape = |
| (representation == FunctionTypeRepresentation::Swift |
| || representation == FunctionTypeRepresentation::Block) |
| && !flags.isEscaping(); |
| |
| const clang::Type *clangFunctionType = nullptr; |
| if (shouldStoreClangType(representation)) |
| clangFunctionType = Ctx.getClangFunctionType(funcParams, output, |
| representation); |
| |
| auto einfo = |
| FunctionType::ExtInfoBuilder(representation, noescape, flags.isThrowing(), |
| diffKind, clangFunctionType) |
| .withAsync(flags.isAsync()) |
| .build(); |
| |
| return FunctionType::get(funcParams, output, einfo); |
| } |
| |
| static ParameterConvention |
| getParameterConvention(ImplParameterConvention conv) { |
| switch (conv) { |
| case Demangle::ImplParameterConvention::Indirect_In: |
| return ParameterConvention::Indirect_In; |
| case Demangle::ImplParameterConvention::Indirect_In_Constant: |
| return ParameterConvention::Indirect_In_Constant; |
| case Demangle::ImplParameterConvention::Indirect_In_Guaranteed: |
| return ParameterConvention::Indirect_In_Guaranteed; |
| case Demangle::ImplParameterConvention::Indirect_Inout: |
| return ParameterConvention::Indirect_Inout; |
| case Demangle::ImplParameterConvention::Indirect_InoutAliasable: |
| return ParameterConvention::Indirect_InoutAliasable; |
| case Demangle::ImplParameterConvention::Direct_Owned: |
| return ParameterConvention::Direct_Owned; |
| case Demangle::ImplParameterConvention::Direct_Unowned: |
| return ParameterConvention::Direct_Unowned; |
| case Demangle::ImplParameterConvention::Direct_Guaranteed: |
| return ParameterConvention::Direct_Guaranteed; |
| } |
| llvm_unreachable("covered switch"); |
| } |
| |
| static SILParameterDifferentiability |
| getParameterDifferentiability(ImplParameterDifferentiability diffKind) { |
| switch (diffKind) { |
| case ImplParameterDifferentiability::DifferentiableOrNotApplicable: |
| return SILParameterDifferentiability::DifferentiableOrNotApplicable; |
| case ImplParameterDifferentiability::NotDifferentiable: |
| return SILParameterDifferentiability::NotDifferentiable; |
| } |
| llvm_unreachable("unknown differentiability kind"); |
| } |
| |
| static ResultConvention getResultConvention(ImplResultConvention conv) { |
| switch (conv) { |
| case Demangle::ImplResultConvention::Indirect: |
| return ResultConvention::Indirect; |
| case Demangle::ImplResultConvention::Owned: |
| return ResultConvention::Owned; |
| case Demangle::ImplResultConvention::Unowned: |
| return ResultConvention::Unowned; |
| case Demangle::ImplResultConvention::UnownedInnerPointer: |
| return ResultConvention::UnownedInnerPointer; |
| case Demangle::ImplResultConvention::Autoreleased: |
| return ResultConvention::Autoreleased; |
| } |
| llvm_unreachable("covered switch"); |
| } |
| |
| static SILResultDifferentiability |
| getResultDifferentiability(ImplResultDifferentiability diffKind) { |
| switch (diffKind) { |
| case ImplResultDifferentiability::DifferentiableOrNotApplicable: |
| return SILResultDifferentiability::DifferentiableOrNotApplicable; |
| case ImplResultDifferentiability::NotDifferentiable: |
| return SILResultDifferentiability::NotDifferentiable; |
| } |
| llvm_unreachable("unknown differentiability kind"); |
| } |
| |
| Type ASTBuilder::createImplFunctionType( |
| Demangle::ImplParameterConvention calleeConvention, |
| ArrayRef<Demangle::ImplFunctionParam<Type>> params, |
| ArrayRef<Demangle::ImplFunctionResult<Type>> results, |
| Optional<Demangle::ImplFunctionResult<Type>> errorResult, |
| ImplFunctionTypeFlags flags) { |
| GenericSignature genericSig; |
| |
| SILCoroutineKind funcCoroutineKind = SILCoroutineKind::None; |
| ParameterConvention funcCalleeConvention = |
| getParameterConvention(calleeConvention); |
| |
| SILFunctionTypeRepresentation representation; |
| switch (flags.getRepresentation()) { |
| case ImplFunctionRepresentation::Thick: |
| representation = SILFunctionTypeRepresentation::Thick; |
| break; |
| case ImplFunctionRepresentation::Block: |
| representation = SILFunctionTypeRepresentation::Block; |
| break; |
| case ImplFunctionRepresentation::Thin: |
| representation = SILFunctionTypeRepresentation::Thin; |
| break; |
| case ImplFunctionRepresentation::CFunctionPointer: |
| representation = SILFunctionTypeRepresentation::CFunctionPointer; |
| break; |
| case ImplFunctionRepresentation::Method: |
| representation = SILFunctionTypeRepresentation::Method; |
| break; |
| case ImplFunctionRepresentation::ObjCMethod: |
| representation = SILFunctionTypeRepresentation::ObjCMethod; |
| break; |
| case ImplFunctionRepresentation::WitnessMethod: |
| representation = SILFunctionTypeRepresentation::WitnessMethod; |
| break; |
| case ImplFunctionRepresentation::Closure: |
| representation = SILFunctionTypeRepresentation::Closure; |
| break; |
| } |
| |
| DifferentiabilityKind diffKind; |
| switch (flags.getDifferentiabilityKind()) { |
| case ImplFunctionDifferentiabilityKind::NonDifferentiable: |
| diffKind = DifferentiabilityKind::NonDifferentiable; |
| break; |
| case ImplFunctionDifferentiabilityKind::Normal: |
| diffKind = DifferentiabilityKind::Normal; |
| break; |
| case ImplFunctionDifferentiabilityKind::Linear: |
| diffKind = DifferentiabilityKind::Linear; |
| break; |
| } |
| |
| llvm::SmallVector<SILParameterInfo, 8> funcParams; |
| llvm::SmallVector<SILYieldInfo, 8> funcYields; |
| llvm::SmallVector<SILResultInfo, 8> funcResults; |
| Optional<SILResultInfo> funcErrorResult; |
| |
| for (const auto ¶m : params) { |
| auto type = param.getType()->getCanonicalType(); |
| auto conv = getParameterConvention(param.getConvention()); |
| auto diffKind = getParameterDifferentiability(param.getDifferentiability()); |
| funcParams.emplace_back(type, conv, diffKind); |
| } |
| |
| for (const auto &result : results) { |
| auto type = result.getType()->getCanonicalType(); |
| auto conv = getResultConvention(result.getConvention()); |
| auto diffKind = getResultDifferentiability(result.getDifferentiability()); |
| funcResults.emplace_back(type, conv, diffKind); |
| } |
| |
| if (errorResult) { |
| auto type = errorResult->getType()->getCanonicalType(); |
| auto conv = getResultConvention(errorResult->getConvention()); |
| funcErrorResult.emplace(type, conv); |
| } |
| |
| const clang::Type *clangFnType = nullptr; |
| if (shouldStoreClangType(representation)) { |
| assert(funcResults.size() <= 1 && funcYields.size() == 0 && |
| "C functions and blocks have at most 1 result and 0 yields."); |
| auto result = |
| funcResults.empty() ? Optional<SILResultInfo>() : funcResults[0]; |
| clangFnType = getASTContext().getCanonicalClangFunctionType( |
| funcParams, result, representation); |
| } |
| auto einfo = SILFunctionType::ExtInfoBuilder( |
| representation, flags.isPseudogeneric(), !flags.isEscaping(), |
| flags.isAsync(), diffKind, clangFnType) |
| .build(); |
| |
| return SILFunctionType::get(genericSig, einfo, funcCoroutineKind, |
| funcCalleeConvention, funcParams, funcYields, |
| funcResults, funcErrorResult, |
| SubstitutionMap(), SubstitutionMap(), Ctx); |
| } |
| |
| Type ASTBuilder::createProtocolCompositionType( |
| ArrayRef<ProtocolDecl *> protocols, |
| Type superclass, |
| bool isClassBound) { |
| std::vector<Type> members; |
| for (auto protocol : protocols) |
| members.push_back(protocol->getDeclaredInterfaceType()); |
| if (superclass && superclass->getClassOrBoundGenericClass()) |
| members.push_back(superclass); |
| return ProtocolCompositionType::get(Ctx, members, isClassBound); |
| } |
| |
| static MetatypeRepresentation |
| getMetatypeRepresentation(ImplMetatypeRepresentation repr) { |
| switch (repr) { |
| case Demangle::ImplMetatypeRepresentation::Thin: |
| return MetatypeRepresentation::Thin; |
| case Demangle::ImplMetatypeRepresentation::Thick: |
| return MetatypeRepresentation::Thick; |
| case Demangle::ImplMetatypeRepresentation::ObjC: |
| return MetatypeRepresentation::ObjC; |
| } |
| llvm_unreachable("covered switch"); |
| } |
| |
| Type ASTBuilder::createExistentialMetatypeType(Type instance, |
| Optional<Demangle::ImplMetatypeRepresentation> repr) { |
| if (!instance->isAnyExistentialType()) |
| return Type(); |
| if (!repr) |
| return ExistentialMetatypeType::get(instance); |
| |
| return ExistentialMetatypeType::get(instance, |
| getMetatypeRepresentation(*repr)); |
| } |
| |
| Type ASTBuilder::createMetatypeType(Type instance, |
| Optional<Demangle::ImplMetatypeRepresentation> repr) { |
| if (!repr) |
| return MetatypeType::get(instance); |
| |
| return MetatypeType::get(instance, getMetatypeRepresentation(*repr)); |
| } |
| |
| Type ASTBuilder::createGenericTypeParameterType(unsigned depth, |
| unsigned index) { |
| return GenericTypeParamType::get(depth, index, Ctx); |
| } |
| |
| Type ASTBuilder::createDependentMemberType(StringRef member, |
| Type base) { |
| auto identifier = Ctx.getIdentifier(member); |
| |
| if (auto *archetype = base->getAs<ArchetypeType>()) { |
| if (archetype->hasNestedType(identifier)) |
| return archetype->getNestedType(identifier); |
| |
| } |
| |
| if (base->isTypeParameter()) { |
| return DependentMemberType::get(base, identifier); |
| } |
| |
| return Type(); |
| } |
| |
| Type ASTBuilder::createDependentMemberType(StringRef member, |
| Type base, |
| ProtocolDecl *protocol) { |
| auto identifier = Ctx.getIdentifier(member); |
| |
| if (auto *archetype = base->getAs<ArchetypeType>()) { |
| if (archetype->hasNestedType(identifier)) |
| return archetype->getNestedType(identifier); |
| } |
| |
| if (base->isTypeParameter()) { |
| if (auto assocType = protocol->getAssociatedType(identifier)) |
| return DependentMemberType::get(base, assocType); |
| } |
| |
| return Type(); |
| } |
| |
| #define REF_STORAGE(Name, ...) \ |
| Type ASTBuilder::create##Name##StorageType(Type base) { \ |
| return Name##StorageType::get(base, Ctx); \ |
| } |
| #include "swift/AST/ReferenceStorage.def" |
| |
| Type ASTBuilder::createSILBoxType(Type base) { |
| return SILBoxType::get(base->getCanonicalType()); |
| } |
| |
| Type ASTBuilder::createObjCClassType(StringRef name) { |
| auto typeDecl = |
| findForeignTypeDecl(name, /*relatedEntityKind*/{}, |
| ForeignModuleKind::Imported, |
| Demangle::Node::Kind::Class); |
| if (!typeDecl) return Type(); |
| return typeDecl->getDeclaredInterfaceType(); |
| } |
| |
| Type ASTBuilder::createBoundGenericObjCClassType(StringRef name, |
| ArrayRef<Type> args) { |
| auto typeDecl = |
| findForeignTypeDecl(name, /*relatedEntityKind*/{}, |
| ForeignModuleKind::Imported, |
| Demangle::Node::Kind::Class); |
| if (!typeDecl || |
| !isa<ClassDecl>(typeDecl)) return Type(); |
| if (!typeDecl->getGenericParams() || |
| typeDecl->getGenericParams()->size() != args.size()) |
| return Type(); |
| |
| Type parent; |
| auto *dc = typeDecl->getDeclContext(); |
| if (dc->isTypeContext()) { |
| if (dc->isGenericContext()) |
| return Type(); |
| parent = dc->getDeclaredInterfaceType(); |
| } |
| |
| return BoundGenericClassType::get(cast<ClassDecl>(typeDecl), |
| parent, args); |
| } |
| |
| ProtocolDecl *ASTBuilder::createObjCProtocolDecl(StringRef name) { |
| auto typeDecl = |
| findForeignTypeDecl(name, /*relatedEntityKind*/{}, |
| ForeignModuleKind::Imported, |
| Demangle::Node::Kind::Protocol); |
| if (auto *protocolDecl = dyn_cast_or_null<ProtocolDecl>(typeDecl)) |
| return protocolDecl; |
| return nullptr; |
| } |
| |
| Type ASTBuilder::createDynamicSelfType(Type selfType) { |
| return DynamicSelfType::get(selfType, Ctx); |
| } |
| |
| Type ASTBuilder::createForeignClassType(StringRef mangledName) { |
| bool typeAlias = false; |
| auto typeDecl = createTypeDecl(mangledName, typeAlias); |
| if (!typeDecl) return Type(); |
| return typeDecl->getDeclaredInterfaceType(); |
| } |
| |
| Type ASTBuilder::getUnnamedForeignClassType() { |
| return Type(); |
| } |
| |
| Type ASTBuilder::getOpaqueType() { |
| return Type(); |
| } |
| |
| Type ASTBuilder::createOptionalType(Type base) { |
| return OptionalType::get(base); |
| } |
| |
| Type ASTBuilder::createArrayType(Type base) { |
| return ArraySliceType::get(base); |
| } |
| |
| Type ASTBuilder::createDictionaryType(Type key, Type value) { |
| return DictionaryType::get(key, value); |
| } |
| |
| Type ASTBuilder::createParenType(Type base) { |
| return ParenType::get(Ctx, base); |
| } |
| |
| bool ASTBuilder::validateParentType(TypeDecl *decl, Type parent) { |
| auto parentDecl = decl->getDeclContext()->getSelfNominalTypeDecl(); |
| |
| // If we don't have a parent type, fast-path. |
| if (!parent) { |
| return parentDecl == nullptr; |
| } |
| |
| // We do have a parent type. If our type doesn't, it's an error. |
| if (!parentDecl) { |
| return false; |
| } |
| |
| if (isa<NominalTypeDecl>(decl)) { |
| // The parent should be a nominal type when desugared. |
| auto *parentNominal = parent->getAnyNominal(); |
| if (!parentNominal || parentNominal != parentDecl) { |
| return false; |
| } |
| } |
| |
| // FIXME: validate that the parent is a correct application of the |
| // enclosing context? |
| return true; |
| } |
| |
| GenericTypeDecl * |
| ASTBuilder::getAcceptableTypeDeclCandidate(ValueDecl *decl, |
| Demangle::Node::Kind kind) { |
| if (kind == Demangle::Node::Kind::Class) { |
| return dyn_cast<ClassDecl>(decl); |
| } else if (kind == Demangle::Node::Kind::Enum) { |
| return dyn_cast<EnumDecl>(decl); |
| } else if (kind == Demangle::Node::Kind::Protocol) { |
| return dyn_cast<ProtocolDecl>(decl); |
| } else if (kind == Demangle::Node::Kind::Structure) { |
| return dyn_cast<StructDecl>(decl); |
| } else { |
| assert(kind == Demangle::Node::Kind::TypeAlias); |
| return dyn_cast<TypeAliasDecl>(decl); |
| } |
| } |
| |
| DeclContext *ASTBuilder::getNotionalDC() { |
| if (!NotionalDC) { |
| NotionalDC = ModuleDecl::create(Ctx.getIdentifier(".RemoteAST"), Ctx); |
| NotionalDC = new (Ctx) TopLevelCodeDecl(NotionalDC); |
| } |
| return NotionalDC; |
| } |
| |
| GenericTypeDecl * |
| ASTBuilder::createTypeDecl(NodePointer node, |
| bool &typeAlias) { |
| auto DC = findDeclContext(node); |
| if (!DC) |
| return nullptr; |
| |
| typeAlias = isa<TypeAliasDecl>(DC); |
| return dyn_cast<GenericTypeDecl>(DC); |
| } |
| |
| ModuleDecl * |
| ASTBuilder::findModule(NodePointer node) { |
| assert(node->getKind() == Demangle::Node::Kind::Module); |
| const auto &moduleName = node->getText(); |
| return Ctx.getModuleByName(moduleName); |
| } |
| |
| Demangle::NodePointer |
| ASTBuilder::findModuleNode(NodePointer node) { |
| auto child = node; |
| while (child->hasChildren() && |
| child->getKind() != Demangle::Node::Kind::Module) { |
| child = child->getFirstChild(); |
| } |
| |
| if (child->getKind() != Demangle::Node::Kind::Module) |
| return nullptr; |
| |
| return child; |
| } |
| |
| Optional<ASTBuilder::ForeignModuleKind> |
| ASTBuilder::getForeignModuleKind(NodePointer node) { |
| if (node->getKind() == Demangle::Node::Kind::DeclContext) |
| return getForeignModuleKind(node->getFirstChild()); |
| |
| if (node->getKind() != Demangle::Node::Kind::Module) |
| return None; |
| |
| return llvm::StringSwitch<Optional<ForeignModuleKind>>(node->getText()) |
| .Case(MANGLING_MODULE_OBJC, ForeignModuleKind::Imported) |
| .Case(MANGLING_MODULE_CLANG_IMPORTER, |
| ForeignModuleKind::SynthesizedByImporter) |
| .Default(None); |
| } |
| |
| CanGenericSignature ASTBuilder::demangleGenericSignature( |
| NominalTypeDecl *nominalDecl, |
| NodePointer node) { |
| SmallVector<Requirement, 2> requirements; |
| |
| for (auto &child : *node) { |
| if (child->getKind() == |
| Demangle::Node::Kind::DependentGenericParamCount) |
| continue; |
| |
| if (child->getNumChildren() != 2) |
| return CanGenericSignature(); |
| auto subjectType = |
| swift::Demangle::decodeMangledType(*this, child->getChild(0)).getType(); |
| if (!subjectType) |
| return CanGenericSignature(); |
| |
| Type constraintType; |
| if (child->getKind() == |
| Demangle::Node::Kind::DependentGenericConformanceRequirement || |
| child->getKind() == |
| Demangle::Node::Kind::DependentGenericSameTypeRequirement) { |
| constraintType = |
| swift::Demangle::decodeMangledType(*this, child->getChild(1)) |
| .getType(); |
| if (!constraintType) |
| return CanGenericSignature(); |
| } |
| |
| switch (child->getKind()) { |
| case Demangle::Node::Kind::DependentGenericConformanceRequirement: { |
| requirements.push_back( |
| Requirement(constraintType->isExistentialType() |
| ? RequirementKind::Conformance |
| : RequirementKind::Superclass, |
| subjectType, constraintType)); |
| break; |
| } |
| case Demangle::Node::Kind::DependentGenericSameTypeRequirement: { |
| requirements.push_back( |
| Requirement(RequirementKind::SameType, |
| subjectType, constraintType)); |
| break; |
| } |
| case Demangle::Node::Kind::DependentGenericLayoutRequirement: { |
| auto kindChild = child->getChild(1); |
| if (kindChild->getKind() != Demangle::Node::Kind::Identifier) |
| return CanGenericSignature(); |
| |
| auto kind = llvm::StringSwitch<Optional< |
| LayoutConstraintKind>>(kindChild->getText()) |
| .Case("U", LayoutConstraintKind::UnknownLayout) |
| .Case("R", LayoutConstraintKind::RefCountedObject) |
| .Case("N", LayoutConstraintKind::NativeRefCountedObject) |
| .Case("C", LayoutConstraintKind::Class) |
| .Case("D", LayoutConstraintKind::NativeClass) |
| .Case("T", LayoutConstraintKind::Trivial) |
| .Cases("E", "e", LayoutConstraintKind::TrivialOfExactSize) |
| .Cases("M", "m", LayoutConstraintKind::TrivialOfAtMostSize) |
| .Default(None); |
| |
| if (!kind) |
| return CanGenericSignature(); |
| |
| LayoutConstraint layout; |
| |
| if (kind != LayoutConstraintKind::TrivialOfExactSize && |
| kind != LayoutConstraintKind::TrivialOfAtMostSize) { |
| layout = LayoutConstraint::getLayoutConstraint(*kind, Ctx); |
| } else { |
| auto size = child->getChild(2)->getIndex(); |
| auto alignment = 0; |
| |
| if (child->getNumChildren() == 4) |
| alignment = child->getChild(3)->getIndex(); |
| |
| layout = LayoutConstraint::getLayoutConstraint(*kind, size, alignment, |
| Ctx); |
| } |
| |
| requirements.push_back( |
| Requirement(RequirementKind::Layout, subjectType, layout)); |
| break; |
| } |
| default: |
| return CanGenericSignature(); |
| } |
| } |
| |
| return evaluateOrDefault(Ctx.evaluator, |
| AbstractGenericSignatureRequest{ |
| nominalDecl->getGenericSignature().getPointer(), |
| {}, |
| std::move(requirements)}, |
| GenericSignature()) |
| .getCanonicalSignature(); |
| } |
| |
| DeclContext * |
| ASTBuilder::findDeclContext(NodePointer node) { |
| switch (node->getKind()) { |
| case Demangle::Node::Kind::DeclContext: |
| case Demangle::Node::Kind::Type: |
| case Demangle::Node::Kind::BoundGenericClass: |
| case Demangle::Node::Kind::BoundGenericEnum: |
| case Demangle::Node::Kind::BoundGenericProtocol: |
| case Demangle::Node::Kind::BoundGenericStructure: |
| case Demangle::Node::Kind::BoundGenericTypeAlias: |
| return findDeclContext(node->getFirstChild()); |
| |
| case Demangle::Node::Kind::Module: |
| return findModule(node); |
| |
| case Demangle::Node::Kind::Class: |
| case Demangle::Node::Kind::Enum: |
| case Demangle::Node::Kind::Protocol: |
| case Demangle::Node::Kind::Structure: |
| case Demangle::Node::Kind::TypeAlias: { |
| const auto &declNameNode = node->getChild(1); |
| |
| // Handle local declarations. |
| if (declNameNode->getKind() == Demangle::Node::Kind::LocalDeclName) { |
| // Find the AST node for the defining module. |
| auto moduleNode = findModuleNode(node); |
| if (!moduleNode) return nullptr; |
| |
| auto module = findModule(moduleNode); |
| if (!module) return nullptr; |
| |
| // Look up the local type by its mangling. |
| auto mangledName = Demangle::mangleNode(node); |
| auto decl = module->lookupLocalType(mangledName); |
| if (!decl) return nullptr; |
| |
| return dyn_cast<DeclContext>(decl); |
| } |
| |
| StringRef name; |
| StringRef relatedEntityKind; |
| Identifier privateDiscriminator; |
| if (declNameNode->getKind() == Demangle::Node::Kind::Identifier) { |
| name = declNameNode->getText(); |
| |
| } else if (declNameNode->getKind() == |
| Demangle::Node::Kind::PrivateDeclName) { |
| name = declNameNode->getChild(1)->getText(); |
| privateDiscriminator = |
| Ctx.getIdentifier(declNameNode->getChild(0)->getText()); |
| |
| } else if (declNameNode->getKind() == |
| Demangle::Node::Kind::RelatedEntityDeclName) { |
| name = declNameNode->getChild(1)->getText(); |
| relatedEntityKind = declNameNode->getFirstChild()->getText(); |
| |
| // Ignore any other decl-name productions for now. |
| } else { |
| return nullptr; |
| } |
| |
| // Do some special logic for foreign type declarations. |
| if (privateDiscriminator.empty()) { |
| if (auto foreignModuleKind = getForeignModuleKind(node->getChild(0))) { |
| return findForeignTypeDecl(name, relatedEntityKind, |
| foreignModuleKind.getValue(), |
| node->getKind()); |
| } |
| } |
| |
| DeclContext *dc = findDeclContext(node->getChild(0)); |
| if (!dc) { |
| return nullptr; |
| } |
| |
| return findTypeDecl(dc, Ctx.getIdentifier(name), |
| privateDiscriminator, node->getKind()); |
| } |
| |
| case Demangle::Node::Kind::Global: |
| return findDeclContext(node->getChild(0)); |
| |
| case Demangle::Node::Kind::Extension: { |
| auto *moduleDecl = dyn_cast_or_null<ModuleDecl>( |
| findDeclContext(node->getChild(0))); |
| if (!moduleDecl) |
| return nullptr; |
| |
| auto *nominalDecl = dyn_cast_or_null<NominalTypeDecl>( |
| findDeclContext(node->getChild(1))); |
| if (!nominalDecl) |
| return nullptr; |
| |
| CanGenericSignature genericSig; |
| if (node->getNumChildren() > 2) |
| genericSig = demangleGenericSignature(nominalDecl, node->getChild(2)); |
| |
| for (auto *ext : nominalDecl->getExtensions()) { |
| if (ext->getParentModule() != moduleDecl) |
| continue; |
| |
| if (!ext->isConstrainedExtension()) { |
| if (!genericSig) |
| return ext; |
| continue; |
| } |
| |
| if (ext->getGenericSignature().getCanonicalSignature() == genericSig) { |
| return ext; |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| // Bail out on other kinds of contexts. |
| default: |
| return nullptr; |
| } |
| } |
| |
| GenericTypeDecl * |
| ASTBuilder::findTypeDecl(DeclContext *dc, |
| Identifier name, |
| Identifier privateDiscriminator, |
| Demangle::Node::Kind kind) { |
| auto module = dc->getParentModule(); |
| |
| // When looking into an extension, look into the nominal instead; the |
| // important thing is that the module, obtained above, is the module |
| // containing the extension and not the module containing the nominal |
| if (isa<ExtensionDecl>(dc)) |
| dc = dc->getSelfNominalTypeDecl(); |
| |
| SmallVector<ValueDecl *, 4> lookupResults; |
| module->lookupMember(lookupResults, dc, name, privateDiscriminator); |
| |
| GenericTypeDecl *result = nullptr; |
| for (auto decl : lookupResults) { |
| // Ignore results that are not the right kind of type declaration. |
| auto *candidate = getAcceptableTypeDeclCandidate(decl, kind); |
| if (!candidate) |
| continue; |
| |
| // Ignore results that aren't actually from the defining module. |
| if (candidate->getParentModule() != module) |
| continue; |
| |
| // This is a viable result. |
| |
| // If we already have a viable result, it's ambiguous, so give up. |
| if (result) return nullptr; |
| result = candidate; |
| } |
| |
| return result; |
| } |
| |
| static Optional<ClangTypeKind> |
| getClangTypeKindForNodeKind(Demangle::Node::Kind kind) { |
| switch (kind) { |
| case Demangle::Node::Kind::Protocol: |
| return ClangTypeKind::ObjCProtocol; |
| case Demangle::Node::Kind::Class: |
| return ClangTypeKind::ObjCClass; |
| case Demangle::Node::Kind::TypeAlias: |
| return ClangTypeKind::Typedef; |
| case Demangle::Node::Kind::Structure: |
| case Demangle::Node::Kind::Enum: |
| return ClangTypeKind::Tag; |
| default: |
| return None; |
| } |
| } |
| |
| GenericTypeDecl *ASTBuilder::findForeignTypeDecl(StringRef name, |
| StringRef relatedEntityKind, |
| ForeignModuleKind foreignKind, |
| Demangle::Node::Kind kind) { |
| // Check to see if we have an importer loaded. |
| auto importer = Ctx.getClangModuleLoader(); |
| if (!importer) |
| return nullptr; |
| |
| // Find the unique declaration that has the right kind. |
| struct Consumer : VisibleDeclConsumer { |
| Demangle::Node::Kind ExpectedKind; |
| GenericTypeDecl *Result = nullptr; |
| bool HadError = false; |
| |
| explicit Consumer(Demangle::Node::Kind kind) : ExpectedKind(kind) {} |
| |
| void foundDecl(ValueDecl *decl, DeclVisibilityKind reason, |
| DynamicLookupInfo dynamicLookupInfo = {}) override { |
| if (HadError) |
| return; |
| if (decl == Result) |
| return; |
| if (!Result) { |
| Result = dyn_cast<GenericTypeDecl>(decl); |
| HadError |= !Result; |
| } else { |
| HadError = true; |
| Result = nullptr; |
| } |
| } |
| } consumer(kind); |
| |
| auto found = [&](TypeDecl *found) { |
| consumer.foundDecl(found, DeclVisibilityKind::VisibleAtTopLevel); |
| }; |
| |
| Optional<ClangTypeKind> lookupKind = getClangTypeKindForNodeKind(kind); |
| if (!lookupKind) |
| return nullptr; |
| |
| switch (foreignKind) { |
| case ForeignModuleKind::SynthesizedByImporter: |
| if (!relatedEntityKind.empty()) { |
| importer->lookupRelatedEntity(name, *lookupKind, relatedEntityKind, |
| found); |
| break; |
| } |
| importer->lookupValue(Ctx.getIdentifier(name), consumer); |
| if (consumer.Result) |
| consumer.Result = getAcceptableTypeDeclCandidate(consumer.Result, kind); |
| break; |
| case ForeignModuleKind::Imported: |
| importer->lookupTypeDecl(name, *lookupKind, found); |
| } |
| |
| return consumer.Result; |
| } |