| //===--- SILFunctionType.cpp - Giving SIL types to AST functions ----------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the native Swift ownership transfer conventions |
| // and works in concert with the importer to give the correct |
| // conventions to imported functions and types. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #define DEBUG_TYPE "libsil" |
| #include "swift/AST/AnyFunctionRef.h" |
| #include "swift/AST/CanTypeVisitor.h" |
| #include "swift/AST/Decl.h" |
| #include "swift/AST/DiagnosticsSIL.h" |
| #include "swift/AST/ForeignInfo.h" |
| #include "swift/AST/GenericEnvironment.h" |
| #include "swift/AST/GenericSignatureBuilder.h" |
| #include "swift/AST/Module.h" |
| #include "swift/AST/ModuleLoader.h" |
| #include "swift/AST/ProtocolConformance.h" |
| #include "swift/ClangImporter/ClangImporter.h" |
| #include "swift/SIL/SILModule.h" |
| #include "swift/SIL/SILType.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/Attr.h" |
| #include "clang/AST/DeclCXX.h" |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/Analysis/DomainSpecific/CocoaConventions.h" |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/Compiler.h" |
| #include "llvm/Support/Debug.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/SaveAndRestore.h" |
| |
| using namespace swift; |
| using namespace swift::Lowering; |
| |
| SILType SILFunctionType::substInterfaceType(SILModule &M, |
| SILType interfaceType, |
| TypeExpansionContext context) const { |
| // Apply pattern substitutions first, then invocation substitutions. |
| if (auto subs = getPatternSubstitutions()) |
| interfaceType = interfaceType.subst(M, subs, context); |
| if (auto subs = getInvocationSubstitutions()) |
| interfaceType = interfaceType.subst(M, subs, context); |
| return interfaceType; |
| } |
| |
| CanSILFunctionType SILFunctionType::getUnsubstitutedType(SILModule &M) const { |
| auto mutableThis = const_cast<SILFunctionType*>(this); |
| |
| // If we have no substitutions, there's nothing to do. |
| if (!hasPatternSubstitutions() && !hasInvocationSubstitutions()) |
| return CanSILFunctionType(mutableThis); |
| |
| // Otherwise, substitute the component types. |
| |
| SmallVector<SILParameterInfo, 4> params; |
| SmallVector<SILYieldInfo, 4> yields; |
| SmallVector<SILResultInfo, 4> results; |
| Optional<SILResultInfo> errorResult; |
| |
| auto subs = getCombinedSubstitutions(); |
| auto substComponentType = [&](CanType type) { |
| if (!type->hasTypeParameter()) return type; |
| return SILType::getPrimitiveObjectType(type) |
| .subst(M, subs).getASTType(); |
| }; |
| |
| for (auto param : getParameters()) { |
| params.push_back(param.map(substComponentType)); |
| } |
| |
| for (auto yield : getYields()) { |
| yields.push_back(yield.map(substComponentType)); |
| } |
| |
| for (auto result : getResults()) { |
| results.push_back(result.map(substComponentType)); |
| } |
| |
| if (auto error = getOptionalErrorResult()) { |
| errorResult = error->map(substComponentType); |
| } |
| |
| auto signature = isPolymorphic() ? getInvocationGenericSignature() |
| : CanGenericSignature(); |
| return SILFunctionType::get(signature, |
| getExtInfo(), |
| getCoroutineKind(), |
| getCalleeConvention(), |
| params, yields, results, errorResult, |
| SubstitutionMap(), |
| SubstitutionMap(), |
| mutableThis->getASTContext(), |
| getWitnessMethodConformanceOrInvalid()); |
| } |
| |
| CanType SILParameterInfo::getArgumentType(SILModule &M, |
| const SILFunctionType *t, |
| TypeExpansionContext context) const { |
| // TODO: We should always require a function type. |
| if (t) |
| return t |
| ->substInterfaceType( |
| M, SILType::getPrimitiveAddressType(getInterfaceType()), context) |
| .getASTType(); |
| |
| return getInterfaceType(); |
| } |
| |
| CanType SILResultInfo::getReturnValueType(SILModule &M, |
| const SILFunctionType *t, |
| TypeExpansionContext context) const { |
| // TODO: We should always require a function type. |
| if (t) |
| return t |
| ->substInterfaceType( |
| M, SILType::getPrimitiveAddressType(getInterfaceType()), context) |
| .getASTType(); |
| |
| return getInterfaceType(); |
| } |
| |
| SILType |
| SILFunctionType::getDirectFormalResultsType(SILModule &M, |
| TypeExpansionContext context) { |
| CanType type; |
| if (getNumDirectFormalResults() == 0) { |
| type = getASTContext().TheEmptyTupleType; |
| } else if (getNumDirectFormalResults() == 1) { |
| type = getSingleDirectFormalResult().getReturnValueType(M, this, context); |
| } else { |
| auto &cache = getMutableFormalResultsCache(); |
| if (cache) { |
| type = cache; |
| } else { |
| SmallVector<TupleTypeElt, 4> elts; |
| for (auto result : getResults()) |
| if (!result.isFormalIndirect()) |
| elts.push_back(result.getReturnValueType(M, this, context)); |
| type = CanType(TupleType::get(elts, getASTContext())); |
| cache = type; |
| } |
| } |
| return SILType::getPrimitiveObjectType(type); |
| } |
| |
| SILType SILFunctionType::getAllResultsInterfaceType() { |
| CanType type; |
| if (getNumResults() == 0) { |
| type = getASTContext().TheEmptyTupleType; |
| } else if (getNumResults() == 1) { |
| type = getResults()[0].getInterfaceType(); |
| } else { |
| auto &cache = getMutableAllResultsCache(); |
| if (cache) { |
| type = cache; |
| } else { |
| SmallVector<TupleTypeElt, 4> elts; |
| for (auto result : getResults()) |
| elts.push_back(result.getInterfaceType()); |
| type = CanType(TupleType::get(elts, getASTContext())); |
| cache = type; |
| } |
| } |
| return SILType::getPrimitiveObjectType(type); |
| } |
| |
| SILType SILFunctionType::getAllResultsSubstType(SILModule &M, |
| TypeExpansionContext context) { |
| return substInterfaceType(M, getAllResultsInterfaceType(), context); |
| } |
| |
| SILType SILFunctionType::getFormalCSemanticResult(SILModule &M) { |
| assert(getLanguage() == SILFunctionLanguage::C); |
| assert(getNumResults() <= 1); |
| return getDirectFormalResultsType(M, TypeExpansionContext::minimal()); |
| } |
| |
| CanType |
| SILFunctionType::getSelfInstanceType(SILModule &M, |
| TypeExpansionContext context) const { |
| auto selfTy = getSelfParameter().getArgumentType(M, this, context); |
| |
| // If this is a static method, get the instance type. |
| if (auto metaTy = dyn_cast<AnyMetatypeType>(selfTy)) |
| return metaTy.getInstanceType(); |
| |
| return selfTy; |
| } |
| |
| ClassDecl * |
| SILFunctionType::getWitnessMethodClass(SILModule &M, |
| TypeExpansionContext context) const { |
| // TODO: When witnesses use substituted types, we'd get this from the |
| // substitution map. |
| auto selfTy = getSelfInstanceType(M, context); |
| auto genericSig = getSubstGenericSignature(); |
| if (auto paramTy = dyn_cast<GenericTypeParamType>(selfTy)) { |
| assert(paramTy->getDepth() == 0 && paramTy->getIndex() == 0); |
| auto superclass = genericSig->getSuperclassBound(paramTy); |
| if (superclass) |
| return superclass->getClassOrBoundGenericClass(); |
| } |
| |
| return nullptr; |
| } |
| |
| IndexSubset * |
| SILFunctionType::getDifferentiabilityParameterIndices() { |
| assert(isDifferentiable() && "Must be a differentiable function"); |
| SmallVector<unsigned, 8> paramIndices; |
| for (auto paramAndIndex : enumerate(getParameters())) |
| if (paramAndIndex.value().getDifferentiability() != |
| SILParameterDifferentiability::NotDifferentiable) |
| paramIndices.push_back(paramAndIndex.index()); |
| return IndexSubset::get(getASTContext(), getNumParameters(), paramIndices); |
| } |
| |
| IndexSubset *SILFunctionType::getDifferentiabilityResultIndices() { |
| assert(isDifferentiable() && "Must be a differentiable function"); |
| SmallVector<unsigned, 8> resultIndices; |
| // Check formal results. |
| for (auto resultAndIndex : enumerate(getResults())) |
| if (resultAndIndex.value().getDifferentiability() != |
| SILResultDifferentiability::NotDifferentiable) |
| resultIndices.push_back(resultAndIndex.index()); |
| // Check `inout` parameters. |
| for (auto inoutParamAndIndex : enumerate(getIndirectMutatingParameters())) |
| // FIXME(TF-1305): The `getResults().empty()` condition is a hack. |
| // |
| // Currently, an `inout` parameter can either be: |
| // 1. Both a differentiability parameter and a differentiability result. |
| // 2. `@noDerivative`: neither a differentiability parameter nor a |
| // differentiability result. |
| // However, there is no way to represent an `inout` parameter that: |
| // 3. Is a differentiability result but not a differentiability parameter. |
| // 4. Is a differentiability parameter but not a differentiability result. |
| // This case is not currently expressible and does not yet have clear use |
| // cases, so supporting it is a non-goal. |
| // |
| // See TF-1305 for solution ideas. For now, `@noDerivative` `inout` |
| // parameters are not treated as differentiability results, unless the |
| // original function has no formal results, in which case all `inout` |
| // parameters are treated as differentiability results. |
| if (getResults().empty() || |
| inoutParamAndIndex.value().getDifferentiability() != |
| SILParameterDifferentiability::NotDifferentiable) |
| resultIndices.push_back(getNumResults() + inoutParamAndIndex.index()); |
| auto numSemanticResults = |
| getNumResults() + getNumIndirectMutatingParameters(); |
| return IndexSubset::get(getASTContext(), numSemanticResults, resultIndices); |
| } |
| |
| CanSILFunctionType |
| SILFunctionType::getWithDifferentiability(DifferentiabilityKind kind, |
| IndexSubset *parameterIndices, |
| IndexSubset *resultIndices) { |
| assert(kind != DifferentiabilityKind::NonDifferentiable && |
| "Differentiability kind must be normal or linear"); |
| SmallVector<SILParameterInfo, 8> newParameters; |
| for (auto paramAndIndex : enumerate(getParameters())) { |
| auto ¶m = paramAndIndex.value(); |
| unsigned index = paramAndIndex.index(); |
| newParameters.push_back(param.getWithDifferentiability( |
| index < parameterIndices->getCapacity() && |
| parameterIndices->contains(index) |
| ? SILParameterDifferentiability::DifferentiableOrNotApplicable |
| : SILParameterDifferentiability::NotDifferentiable)); |
| } |
| SmallVector<SILResultInfo, 8> newResults; |
| for (auto resultAndIndex : enumerate(getResults())) { |
| auto &result = resultAndIndex.value(); |
| unsigned index = resultAndIndex.index(); |
| newResults.push_back(result.getWithDifferentiability( |
| index < resultIndices->getCapacity() && resultIndices->contains(index) |
| ? SILResultDifferentiability::DifferentiableOrNotApplicable |
| : SILResultDifferentiability::NotDifferentiable)); |
| } |
| auto newExtInfo = |
| getExtInfo().intoBuilder().withDifferentiabilityKind(kind).build(); |
| return get(getInvocationGenericSignature(), newExtInfo, getCoroutineKind(), |
| getCalleeConvention(), newParameters, getYields(), newResults, |
| getOptionalErrorResult(), getPatternSubstitutions(), |
| getInvocationSubstitutions(), getASTContext(), |
| getWitnessMethodConformanceOrInvalid()); |
| } |
| |
| CanSILFunctionType SILFunctionType::getWithoutDifferentiability() { |
| if (!isDifferentiable()) |
| return CanSILFunctionType(this); |
| auto nondiffExtInfo = |
| getExtInfo() |
| .intoBuilder() |
| .withDifferentiabilityKind(DifferentiabilityKind::NonDifferentiable) |
| .build(); |
| SmallVector<SILParameterInfo, 8> newParams; |
| for (auto ¶m : getParameters()) |
| newParams.push_back(param.getWithDifferentiability( |
| SILParameterDifferentiability::DifferentiableOrNotApplicable)); |
| SmallVector<SILResultInfo, 8> newResults; |
| for (auto &result : getResults()) |
| newResults.push_back(result.getWithDifferentiability( |
| SILResultDifferentiability::DifferentiableOrNotApplicable)); |
| return SILFunctionType::get( |
| getInvocationGenericSignature(), nondiffExtInfo, getCoroutineKind(), |
| getCalleeConvention(), newParams, getYields(), newResults, |
| getOptionalErrorResult(), getPatternSubstitutions(), |
| getInvocationSubstitutions(), getASTContext()); |
| } |
| |
| /// Collects the differentiability parameters of the given original function |
| /// type in `diffParams`. |
| static void |
| getDifferentiabilityParameters(SILFunctionType *originalFnTy, |
| IndexSubset *parameterIndices, |
| SmallVectorImpl<SILParameterInfo> &diffParams) { |
| // Returns true if `index` is a differentiability parameter index. |
| auto isDiffParamIndex = [&](unsigned index) -> bool { |
| return index < parameterIndices->getCapacity() && |
| parameterIndices->contains(index); |
| }; |
| // Calculate differentiability parameter infos. |
| for (auto valueAndIndex : enumerate(originalFnTy->getParameters())) |
| if (isDiffParamIndex(valueAndIndex.index())) |
| diffParams.push_back(valueAndIndex.value()); |
| } |
| |
| /// Collects the semantic results of the given function type in |
| /// `originalResults`. The semantic results are formal results followed by |
| /// `inout` parameters, in type order. |
| static void |
| getSemanticResults(SILFunctionType *functionType, IndexSubset *parameterIndices, |
| IndexSubset *&inoutParameterIndices, |
| SmallVectorImpl<SILResultInfo> &originalResults) { |
| auto &C = functionType->getASTContext(); |
| SmallVector<unsigned, 4> inoutParamIndices; |
| // Collect original formal results. |
| originalResults.append(functionType->getResults().begin(), |
| functionType->getResults().end()); |
| // Collect original `inout` parameters. |
| for (auto i : range(functionType->getNumParameters())) { |
| auto param = functionType->getParameters()[i]; |
| if (!param.isIndirectInOut()) |
| continue; |
| inoutParamIndices.push_back(i); |
| originalResults.push_back( |
| SILResultInfo(param.getInterfaceType(), ResultConvention::Indirect)); |
| } |
| inoutParameterIndices = |
| IndexSubset::get(C, parameterIndices->getCapacity(), inoutParamIndices); |
| } |
| |
| /// Returns the differential type for the given original function type, |
| /// parameter indices, and result index. |
| static CanSILFunctionType getAutoDiffDifferentialType( |
| SILFunctionType *originalFnTy, IndexSubset *parameterIndices, |
| IndexSubset *resultIndices, LookupConformanceFn lookupConformance, |
| TypeConverter &TC) { |
| // Given the tangent type and the corresponding original parameter's |
| // convention, returns the tangent parameter's convention. |
| auto getTangentParameterConvention = |
| [&](CanType tanType, |
| ParameterConvention origParamConv) -> ParameterConvention { |
| tanType = |
| tanType->getCanonicalType(originalFnTy->getSubstGenericSignature()); |
| AbstractionPattern pattern(originalFnTy->getSubstGenericSignature(), |
| tanType); |
| auto &tl = |
| TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); |
| // When the tangent type is address only, we must ensure that the tangent |
| // parameter's convention is indirect. |
| if (tl.isAddressOnly() && !isIndirectFormalParameter(origParamConv)) { |
| switch (origParamConv) { |
| case ParameterConvention::Direct_Guaranteed: |
| return ParameterConvention::Indirect_In_Guaranteed; |
| case ParameterConvention::Direct_Owned: |
| case ParameterConvention::Direct_Unowned: |
| return ParameterConvention::Indirect_In; |
| default: |
| llvm_unreachable("unhandled parameter convention"); |
| } |
| } |
| return origParamConv; |
| }; |
| |
| // Given the tangent type and the corresponding original result's convention, |
| // returns the tangent result's convention. |
| auto getTangentResultConvention = |
| [&](CanType tanType, |
| ResultConvention origResConv) -> ResultConvention { |
| tanType = |
| tanType->getCanonicalType(originalFnTy->getSubstGenericSignature()); |
| AbstractionPattern pattern(originalFnTy->getSubstGenericSignature(), |
| tanType); |
| auto &tl = |
| TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); |
| // When the tangent type is address only, we must ensure that the tangent |
| // result's convention is indirect. |
| if (tl.isAddressOnly() && !isIndirectFormalResult(origResConv)) { |
| switch (origResConv) { |
| case ResultConvention::Unowned: |
| case ResultConvention::Owned: |
| return ResultConvention::Indirect; |
| default: |
| llvm_unreachable("unhandled result convention"); |
| } |
| } |
| return origResConv; |
| }; |
| |
| auto &ctx = originalFnTy->getASTContext(); |
| SmallVector<GenericTypeParamType *, 4> substGenericParams; |
| SmallVector<Requirement, 4> substRequirements; |
| SmallVector<Type, 4> substReplacements; |
| SmallVector<ProtocolConformanceRef, 4> substConformances; |
| |
| IndexSubset *inoutParamIndices; |
| SmallVector<SILResultInfo, 2> originalResults; |
| getSemanticResults(originalFnTy, parameterIndices, inoutParamIndices, |
| originalResults); |
| |
| SmallVector<SILParameterInfo, 4> diffParams; |
| getDifferentiabilityParameters(originalFnTy, parameterIndices, diffParams); |
| SmallVector<SILParameterInfo, 8> differentialParams; |
| for (auto ¶m : diffParams) { |
| auto paramTan = |
| param.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); |
| assert(paramTan && "Parameter type does not have a tangent space?"); |
| auto paramTanType = paramTan->getCanonicalType(); |
| auto paramConv = getTangentParameterConvention(paramTanType, |
| param.getConvention()); |
| if (!paramTanType->hasArchetype() && !paramTanType->hasTypeParameter()) { |
| differentialParams.push_back( |
| {paramTan->getCanonicalType(), paramConv}); |
| } else { |
| auto gpIndex = substGenericParams.size(); |
| auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); |
| substGenericParams.push_back(gpType); |
| substReplacements.push_back(paramTanType); |
| differentialParams.push_back({gpType, paramConv}); |
| } |
| } |
| SmallVector<SILResultInfo, 1> differentialResults; |
| for (auto resultIndex : resultIndices->getIndices()) { |
| // Handle formal original result. |
| if (resultIndex < originalFnTy->getNumResults()) { |
| auto &result = originalResults[resultIndex]; |
| auto resultTan = |
| result.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); |
| assert(resultTan && "Result type does not have a tangent space?"); |
| auto resultTanType = resultTan->getCanonicalType(); |
| auto resultConv = |
| getTangentResultConvention(resultTanType, result.getConvention()); |
| if (!resultTanType->hasArchetype() && |
| !resultTanType->hasTypeParameter()) { |
| differentialResults.push_back( |
| {resultTan->getCanonicalType(), resultConv}); |
| } else { |
| auto gpIndex = substGenericParams.size(); |
| auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); |
| substGenericParams.push_back(gpType); |
| substReplacements.push_back(resultTanType); |
| differentialResults.push_back({gpType, resultConv}); |
| } |
| continue; |
| } |
| // Handle original `inout` parameter. |
| auto inoutParamIndex = resultIndex - originalFnTy->getNumResults(); |
| auto inoutParamIt = std::next( |
| originalFnTy->getIndirectMutatingParameters().begin(), inoutParamIndex); |
| auto paramIndex = |
| std::distance(originalFnTy->getParameters().begin(), &*inoutParamIt); |
| // If the original `inout` parameter is a differentiability parameter, then |
| // it already has a corresponding differential parameter. Skip adding a |
| // corresponding differential result. |
| if (parameterIndices->contains(paramIndex)) |
| continue; |
| auto inoutParam = originalFnTy->getParameters()[paramIndex]; |
| auto paramTan = inoutParam.getInterfaceType()->getAutoDiffTangentSpace( |
| lookupConformance); |
| assert(paramTan && "Parameter type does not have a tangent space?"); |
| differentialResults.push_back( |
| {paramTan->getCanonicalType(), ResultConvention::Indirect}); |
| } |
| |
| SubstitutionMap substitutions; |
| if (!substGenericParams.empty()) { |
| auto genericSig = |
| GenericSignature::get(substGenericParams, substRequirements) |
| .getCanonicalSignature(); |
| substitutions = |
| SubstitutionMap::get(genericSig, llvm::makeArrayRef(substReplacements), |
| llvm::makeArrayRef(substConformances)); |
| } |
| return SILFunctionType::get( |
| GenericSignature(), SILFunctionType::ExtInfo(), SILCoroutineKind::None, |
| ParameterConvention::Direct_Guaranteed, differentialParams, {}, |
| differentialResults, None, substitutions, |
| /*invocationSubstitutions*/ SubstitutionMap(), ctx); |
| } |
| |
| /// Returns the pullback type for the given original function type, parameter |
| /// indices, and result index. |
| static CanSILFunctionType getAutoDiffPullbackType( |
| SILFunctionType *originalFnTy, IndexSubset *parameterIndices, |
| IndexSubset *resultIndices, LookupConformanceFn lookupConformance, |
| TypeConverter &TC) { |
| auto &ctx = originalFnTy->getASTContext(); |
| SmallVector<GenericTypeParamType *, 4> substGenericParams; |
| SmallVector<Requirement, 4> substRequirements; |
| SmallVector<Type, 4> substReplacements; |
| SmallVector<ProtocolConformanceRef, 4> substConformances; |
| |
| IndexSubset *inoutParamIndices; |
| SmallVector<SILResultInfo, 2> originalResults; |
| getSemanticResults(originalFnTy, parameterIndices, inoutParamIndices, |
| originalResults); |
| |
| // Given a type, returns its formal SIL parameter info. |
| auto getTangentParameterConventionForOriginalResult = |
| [&](CanType tanType, |
| ResultConvention origResConv) -> ParameterConvention { |
| tanType = |
| tanType->getCanonicalType(originalFnTy->getSubstGenericSignature()); |
| AbstractionPattern pattern(originalFnTy->getSubstGenericSignature(), |
| tanType); |
| auto &tl = |
| TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); |
| ParameterConvention conv; |
| switch (origResConv) { |
| case ResultConvention::Unowned: |
| case ResultConvention::UnownedInnerPointer: |
| case ResultConvention::Owned: |
| case ResultConvention::Autoreleased: |
| if (tl.isAddressOnly()) { |
| conv = ParameterConvention::Indirect_In_Guaranteed; |
| } else { |
| conv = tl.isTrivial() ? ParameterConvention::Direct_Unowned |
| : ParameterConvention::Direct_Guaranteed; |
| } |
| break; |
| case ResultConvention::Indirect: |
| conv = ParameterConvention::Indirect_In_Guaranteed; |
| break; |
| } |
| return conv; |
| }; |
| |
| // Given a type, returns its formal SIL result info. |
| auto getTangentResultConventionForOriginalParameter = |
| [&](CanType tanType, |
| ParameterConvention origParamConv) -> ResultConvention { |
| tanType = |
| tanType->getCanonicalType(originalFnTy->getSubstGenericSignature()); |
| AbstractionPattern pattern(originalFnTy->getSubstGenericSignature(), |
| tanType); |
| auto &tl = |
| TC.getTypeLowering(pattern, tanType, TypeExpansionContext::minimal()); |
| ResultConvention conv; |
| switch (origParamConv) { |
| case ParameterConvention::Direct_Owned: |
| case ParameterConvention::Direct_Guaranteed: |
| case ParameterConvention::Direct_Unowned: |
| if (tl.isAddressOnly()) { |
| conv = ResultConvention::Indirect; |
| } else { |
| conv = tl.isTrivial() ? ResultConvention::Unowned |
| : ResultConvention::Owned; |
| } |
| break; |
| case ParameterConvention::Indirect_In: |
| case ParameterConvention::Indirect_Inout: |
| case ParameterConvention::Indirect_In_Constant: |
| case ParameterConvention::Indirect_In_Guaranteed: |
| case ParameterConvention::Indirect_InoutAliasable: |
| conv = ResultConvention::Indirect; |
| break; |
| } |
| return conv; |
| }; |
| |
| // Collect pullback parameters. |
| SmallVector<SILParameterInfo, 1> pullbackParams; |
| for (auto resultIndex : resultIndices->getIndices()) { |
| // Handle formal original result. |
| if (resultIndex < originalFnTy->getNumResults()) { |
| auto &origRes = originalResults[resultIndex]; |
| auto resultTan = origRes.getInterfaceType()->getAutoDiffTangentSpace( |
| lookupConformance); |
| assert(resultTan && "Result type does not have a tangent space?"); |
| auto resultTanType = resultTan->getCanonicalType(); |
| auto paramTanConvention = getTangentParameterConventionForOriginalResult( |
| resultTanType, origRes.getConvention()); |
| if (!resultTanType->hasArchetype() && |
| !resultTanType->hasTypeParameter()) { |
| auto resultTanType = resultTan->getCanonicalType(); |
| pullbackParams.push_back({resultTanType, paramTanConvention}); |
| } else { |
| auto gpIndex = substGenericParams.size(); |
| auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); |
| substGenericParams.push_back(gpType); |
| substReplacements.push_back(resultTanType); |
| pullbackParams.push_back({gpType, paramTanConvention}); |
| } |
| continue; |
| } |
| // Handle original `inout` parameter. |
| auto inoutParamIndex = resultIndex - originalFnTy->getNumResults(); |
| auto inoutParamIt = std::next( |
| originalFnTy->getIndirectMutatingParameters().begin(), inoutParamIndex); |
| auto paramIndex = |
| std::distance(originalFnTy->getParameters().begin(), &*inoutParamIt); |
| auto inoutParam = originalFnTy->getParameters()[paramIndex]; |
| auto paramTan = inoutParam.getInterfaceType()->getAutoDiffTangentSpace( |
| lookupConformance); |
| assert(paramTan && "Parameter type does not have a tangent space?"); |
| // The pullback parameter convention depends on whether the original `inout` |
| // paramater is a differentiability parameter. |
| // - If yes, the pullback parameter convention is `@inout`. |
| // - If no, the pullback parameter convention is `@in_guaranteed`. |
| bool isWrtInoutParameter = parameterIndices->contains(paramIndex); |
| auto paramTanConvention = isWrtInoutParameter |
| ? inoutParam.getConvention() |
| : ParameterConvention::Indirect_In_Guaranteed; |
| auto paramTanType = paramTan->getCanonicalType(); |
| if (!paramTanType->hasArchetype() && !paramTanType->hasTypeParameter()) { |
| pullbackParams.push_back( |
| SILParameterInfo(paramTanType, paramTanConvention)); |
| } else { |
| auto gpIndex = substGenericParams.size(); |
| auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); |
| substGenericParams.push_back(gpType); |
| substReplacements.push_back(paramTanType); |
| pullbackParams.push_back({gpType, paramTanConvention}); |
| } |
| } |
| |
| // Collect pullback results. |
| SmallVector<SILParameterInfo, 4> diffParams; |
| getDifferentiabilityParameters(originalFnTy, parameterIndices, diffParams); |
| SmallVector<SILResultInfo, 8> pullbackResults; |
| for (auto ¶m : diffParams) { |
| // Skip `inout` parameters, which semantically behave as original results |
| // and always appear as pullback parameters. |
| if (param.isIndirectInOut()) |
| continue; |
| auto paramTan = |
| param.getInterfaceType()->getAutoDiffTangentSpace(lookupConformance); |
| assert(paramTan && "Parameter type does not have a tangent space?"); |
| auto paramTanType = paramTan->getCanonicalType(); |
| auto resultTanConvention = getTangentResultConventionForOriginalParameter( |
| paramTanType, param.getConvention()); |
| if (!paramTanType->hasArchetype() && !paramTanType->hasTypeParameter()) { |
| pullbackResults.push_back({paramTanType, resultTanConvention}); |
| } else { |
| auto gpIndex = substGenericParams.size(); |
| auto gpType = CanGenericTypeParamType::get(0, gpIndex, ctx); |
| substGenericParams.push_back(gpType); |
| substReplacements.push_back(paramTanType); |
| pullbackResults.push_back({gpType, resultTanConvention}); |
| } |
| } |
| SubstitutionMap substitutions; |
| if (!substGenericParams.empty()) { |
| auto genericSig = |
| GenericSignature::get(substGenericParams, substRequirements) |
| .getCanonicalSignature(); |
| substitutions = |
| SubstitutionMap::get(genericSig, llvm::makeArrayRef(substReplacements), |
| llvm::makeArrayRef(substConformances)); |
| } |
| return SILFunctionType::get( |
| GenericSignature(), SILFunctionType::ExtInfo(), SILCoroutineKind::None, |
| ParameterConvention::Direct_Guaranteed, pullbackParams, {}, |
| pullbackResults, None, substitutions, |
| /*invocationSubstitutions*/ SubstitutionMap(), ctx); |
| } |
| |
| /// Constrains the `original` function type according to differentiability |
| /// requirements: |
| /// - All differentiability parameters are constrained to conform to |
| /// `Differentiable`. |
| /// - The invocation generic signature is replaced by the |
| /// `constrainedInvocationGenSig` argument. |
| static SILFunctionType *getConstrainedAutoDiffOriginalFunctionType( |
| SILFunctionType *original, IndexSubset *parameterIndices, |
| LookupConformanceFn lookupConformance, |
| CanGenericSignature constrainedInvocationGenSig) { |
| auto originalInvocationGenSig = original->getInvocationGenericSignature(); |
| if (!originalInvocationGenSig) { |
| assert(!constrainedInvocationGenSig || |
| constrainedInvocationGenSig->areAllParamsConcrete() && |
| "derivative function cannot have invocation generic signature " |
| "when original function doesn't"); |
| return original; |
| } |
| |
| assert(!original->getPatternSubstitutions() && |
| "cannot constrain substituted function type"); |
| if (!constrainedInvocationGenSig) |
| constrainedInvocationGenSig = originalInvocationGenSig; |
| if (!constrainedInvocationGenSig) |
| return original; |
| constrainedInvocationGenSig = |
| autodiff::getConstrainedDerivativeGenericSignature( |
| original, parameterIndices, constrainedInvocationGenSig, |
| lookupConformance) |
| .getCanonicalSignature(); |
| |
| SmallVector<SILParameterInfo, 4> newParameters; |
| newParameters.reserve(original->getNumParameters()); |
| for (auto ¶m : original->getParameters()) { |
| newParameters.push_back( |
| param.getWithInterfaceType(param.getInterfaceType()->getCanonicalType( |
| constrainedInvocationGenSig))); |
| } |
| |
| SmallVector<SILResultInfo, 4> newResults; |
| newResults.reserve(original->getNumResults()); |
| for (auto &result : original->getResults()) { |
| newResults.push_back( |
| result.getWithInterfaceType(result.getInterfaceType()->getCanonicalType( |
| constrainedInvocationGenSig))); |
| } |
| return SILFunctionType::get( |
| constrainedInvocationGenSig->areAllParamsConcrete() |
| ? GenericSignature() |
| : constrainedInvocationGenSig, |
| original->getExtInfo(), original->getCoroutineKind(), |
| original->getCalleeConvention(), newParameters, original->getYields(), |
| newResults, original->getOptionalErrorResult(), |
| /*patternSubstitutions*/ SubstitutionMap(), |
| /*invocationSubstitutions*/ SubstitutionMap(), original->getASTContext(), |
| original->getWitnessMethodConformanceOrInvalid()); |
| } |
| |
| CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( |
| IndexSubset *parameterIndices, IndexSubset *resultIndices, |
| AutoDiffDerivativeFunctionKind kind, TypeConverter &TC, |
| LookupConformanceFn lookupConformance, |
| CanGenericSignature derivativeFnInvocationGenSig, |
| bool isReabstractionThunk) { |
| assert(parameterIndices); |
| assert(!parameterIndices->isEmpty() && "Parameter indices must not be empty"); |
| assert(resultIndices); |
| assert(!resultIndices->isEmpty() && "Result indices must not be empty"); |
| auto &ctx = getASTContext(); |
| |
| // Look up result in cache. |
| SILAutoDiffDerivativeFunctionKey key{this, |
| parameterIndices, |
| resultIndices, |
| kind, |
| derivativeFnInvocationGenSig, |
| isReabstractionThunk}; |
| auto insertion = |
| ctx.SILAutoDiffDerivativeFunctions.try_emplace(key, CanSILFunctionType()); |
| auto &cachedResult = insertion.first->getSecond(); |
| if (!insertion.second) |
| return cachedResult; |
| |
| SILFunctionType *constrainedOriginalFnTy = |
| getConstrainedAutoDiffOriginalFunctionType(this, parameterIndices, |
| lookupConformance, |
| derivativeFnInvocationGenSig); |
| // Compute closure type. |
| CanSILFunctionType closureType; |
| switch (kind) { |
| case AutoDiffDerivativeFunctionKind::JVP: |
| closureType = |
| getAutoDiffDifferentialType(constrainedOriginalFnTy, parameterIndices, |
| resultIndices, lookupConformance, TC); |
| break; |
| case AutoDiffDerivativeFunctionKind::VJP: |
| closureType = |
| getAutoDiffPullbackType(constrainedOriginalFnTy, parameterIndices, |
| resultIndices, lookupConformance, TC); |
| break; |
| } |
| // Compute the derivative function parameters. |
| SmallVector<SILParameterInfo, 4> newParameters; |
| newParameters.reserve(constrainedOriginalFnTy->getNumParameters()); |
| for (auto ¶m : constrainedOriginalFnTy->getParameters()) { |
| newParameters.push_back(param); |
| } |
| // Reabstraction thunks have a function-typed parameter (the function to |
| // reabstract) as their last parameter. Reabstraction thunk JVPs/VJPs have a |
| // `@differentiable` function-typed last parameter instead. |
| if (isReabstractionThunk) { |
| assert(!parameterIndices->contains(getNumParameters() - 1) && |
| "Function-typed parameter should not be wrt"); |
| auto fnParam = newParameters.back(); |
| auto fnParamType = dyn_cast<SILFunctionType>(fnParam.getInterfaceType()); |
| assert(fnParamType); |
| auto diffFnType = fnParamType->getWithDifferentiability( |
| DifferentiabilityKind::Normal, parameterIndices, resultIndices); |
| newParameters.back() = fnParam.getWithInterfaceType(diffFnType); |
| } |
| |
| // Compute the derivative function results. |
| SmallVector<SILResultInfo, 4> newResults; |
| newResults.reserve(getNumResults() + 1); |
| for (auto &result : constrainedOriginalFnTy->getResults()) { |
| newResults.push_back(result); |
| } |
| newResults.push_back({closureType, ResultConvention::Owned}); |
| |
| // Compute the derivative function ExtInfo. |
| // If original function is `@convention(c)`, the derivative function should |
| // have `@convention(thin)`. IRGen does not support `@convention(c)` functions |
| // with multiple results. |
| auto extInfo = constrainedOriginalFnTy->getExtInfo(); |
| if (getRepresentation() == SILFunctionTypeRepresentation::CFunctionPointer) |
| extInfo = extInfo.withRepresentation(SILFunctionTypeRepresentation::Thin); |
| |
| // Put everything together to get the derivative function type. Then, store in |
| // cache and return. |
| cachedResult = SILFunctionType::get( |
| constrainedOriginalFnTy->getSubstGenericSignature(), extInfo, |
| constrainedOriginalFnTy->getCoroutineKind(), |
| constrainedOriginalFnTy->getCalleeConvention(), newParameters, |
| constrainedOriginalFnTy->getYields(), newResults, |
| constrainedOriginalFnTy->getOptionalErrorResult(), |
| /*patternSubstitutions*/ SubstitutionMap(), |
| /*invocationSubstitutions*/ SubstitutionMap(), |
| constrainedOriginalFnTy->getASTContext(), |
| constrainedOriginalFnTy->getWitnessMethodConformanceOrInvalid()); |
| return cachedResult; |
| } |
| |
| CanSILFunctionType SILFunctionType::getAutoDiffTransposeFunctionType( |
| IndexSubset *parameterIndices, Lowering::TypeConverter &TC, |
| LookupConformanceFn lookupConformance, |
| CanGenericSignature transposeFnGenSig) { |
| // Get the "constrained" transpose function generic signature. |
| if (!transposeFnGenSig) |
| transposeFnGenSig = getSubstGenericSignature(); |
| transposeFnGenSig = autodiff::getConstrainedDerivativeGenericSignature( |
| this, parameterIndices, transposeFnGenSig, |
| lookupConformance, /*isLinear*/ true) |
| .getCanonicalSignature(); |
| |
| // Given a type, returns its formal SIL parameter info. |
| auto getParameterInfoForOriginalResult = |
| [&](const SILResultInfo &result) -> SILParameterInfo { |
| AbstractionPattern pattern(transposeFnGenSig, result.getInterfaceType()); |
| auto &tl = TC.getTypeLowering(pattern, result.getInterfaceType(), |
| TypeExpansionContext::minimal()); |
| ParameterConvention newConv; |
| switch (result.getConvention()) { |
| case ResultConvention::Owned: |
| case ResultConvention::Autoreleased: |
| newConv = tl.isTrivial() ? ParameterConvention::Direct_Unowned |
| : ParameterConvention::Direct_Guaranteed; |
| break; |
| case ResultConvention::Unowned: |
| case ResultConvention::UnownedInnerPointer: |
| newConv = ParameterConvention::Direct_Unowned; |
| break; |
| case ResultConvention::Indirect: |
| newConv = ParameterConvention::Indirect_In_Guaranteed; |
| break; |
| } |
| return {result.getInterfaceType(), newConv}; |
| }; |
| |
| // Given a type, returns its formal SIL result info. |
| auto getResultInfoForOriginalParameter = |
| [&](const SILParameterInfo ¶m) -> SILResultInfo { |
| AbstractionPattern pattern(transposeFnGenSig, param.getInterfaceType()); |
| auto &tl = TC.getTypeLowering(pattern, param.getInterfaceType(), |
| TypeExpansionContext::minimal()); |
| ResultConvention newConv; |
| switch (param.getConvention()) { |
| case ParameterConvention::Direct_Owned: |
| case ParameterConvention::Direct_Guaranteed: |
| case ParameterConvention::Direct_Unowned: |
| newConv = |
| tl.isTrivial() ? ResultConvention::Unowned : ResultConvention::Owned; |
| break; |
| case ParameterConvention::Indirect_In: |
| case ParameterConvention::Indirect_Inout: |
| case ParameterConvention::Indirect_In_Constant: |
| case ParameterConvention::Indirect_In_Guaranteed: |
| case ParameterConvention::Indirect_InoutAliasable: |
| newConv = ResultConvention::Indirect; |
| break; |
| } |
| return {param.getInterfaceType(), newConv}; |
| }; |
| |
| SmallVector<SILParameterInfo, 4> newParameters; |
| SmallVector<SILResultInfo, 4> newResults; |
| for (auto pair : llvm::enumerate(getParameters())) { |
| auto index = pair.index(); |
| auto param = pair.value(); |
| if (parameterIndices->contains(index)) |
| newResults.push_back(getResultInfoForOriginalParameter(param)); |
| else |
| newParameters.push_back(param); |
| } |
| for (auto &res : getResults()) |
| newParameters.push_back(getParameterInfoForOriginalResult(res)); |
| return SILFunctionType::get( |
| getInvocationGenericSignature(), getExtInfo(), getCoroutineKind(), |
| getCalleeConvention(), newParameters, getYields(), newResults, |
| getOptionalErrorResult(), getPatternSubstitutions(), |
| /*invocationSubstitutions*/ {}, getASTContext()); |
| } |
| |
| static CanType getKnownType(Optional<CanType> &cacheSlot, ASTContext &C, |
| StringRef moduleName, StringRef typeName) { |
| if (!cacheSlot) { |
| cacheSlot = ([&] { |
| ModuleDecl *mod = C.getLoadedModule(C.getIdentifier(moduleName)); |
| if (!mod) |
| return CanType(); |
| |
| // Do a general qualified lookup instead of a direct lookupValue because |
| // some of the types we want are reexported through overlays and |
| // lookupValue would only give us types actually declared in the overlays |
| // themselves. |
| SmallVector<ValueDecl *, 2> decls; |
| mod->lookupQualified(mod, DeclNameRef(C.getIdentifier(typeName)), |
| NL_QualifiedDefault, decls); |
| if (decls.size() != 1) |
| return CanType(); |
| |
| const auto *typeDecl = dyn_cast<TypeDecl>(decls.front()); |
| if (!typeDecl) |
| return CanType(); |
| |
| return typeDecl->getDeclaredInterfaceType()->getCanonicalType(); |
| })(); |
| } |
| CanType t = *cacheSlot; |
| |
| // It is possible that we won't find a bridging type (e.g. String) when we're |
| // parsing the stdlib itself. |
| if (t) { |
| LLVM_DEBUG(llvm::dbgs() << "Bridging type " << moduleName << '.' << typeName |
| << " mapped to "; |
| if (t) |
| t->print(llvm::dbgs()); |
| else |
| llvm::dbgs() << "<null>"; |
| llvm::dbgs() << '\n'); |
| } |
| return t; |
| } |
| |
| #define BRIDGING_KNOWN_TYPE(BridgedModule,BridgedType) \ |
| CanType TypeConverter::get##BridgedType##Type() { \ |
| return getKnownType(BridgedType##Ty, Context, \ |
| #BridgedModule, #BridgedType); \ |
| } |
| #include "swift/SIL/BridgedTypes.def" |
| |
| /// Adjust a function type to have a slightly different type. |
| CanAnyFunctionType |
| Lowering::adjustFunctionType(CanAnyFunctionType t, |
| AnyFunctionType::ExtInfo extInfo) { |
| if (t->getExtInfo().isEqualTo(extInfo, useClangTypes(t))) |
| return t; |
| return CanAnyFunctionType(t->withExtInfo(extInfo)); |
| } |
| |
| /// Adjust a function type to have a slightly different type. |
| CanSILFunctionType |
| Lowering::adjustFunctionType(CanSILFunctionType type, |
| SILFunctionType::ExtInfo extInfo, |
| ParameterConvention callee, |
| ProtocolConformanceRef witnessMethodConformance) { |
| if (type->getExtInfo().isEqualTo(extInfo, useClangTypes(type)) && |
| type->getCalleeConvention() == callee && |
| type->getWitnessMethodConformanceOrInvalid() == witnessMethodConformance) |
| return type; |
| |
| return SILFunctionType::get(type->getInvocationGenericSignature(), |
| extInfo, type->getCoroutineKind(), callee, |
| type->getParameters(), type->getYields(), |
| type->getResults(), |
| type->getOptionalErrorResult(), |
| type->getPatternSubstitutions(), |
| type->getInvocationSubstitutions(), |
| type->getASTContext(), |
| witnessMethodConformance); |
| } |
| |
| CanSILFunctionType |
| SILFunctionType::getWithRepresentation(Representation repr) { |
| return getWithExtInfo(getExtInfo().withRepresentation(repr)); |
| } |
| |
| CanSILFunctionType SILFunctionType::getWithExtInfo(ExtInfo newExt) { |
| auto oldExt = getExtInfo(); |
| if (newExt.isEqualTo(oldExt, useClangTypes(this))) |
| return CanSILFunctionType(this); |
| |
| auto calleeConvention = |
| (newExt.hasContext() |
| ? (oldExt.hasContext() |
| ? getCalleeConvention() |
| : Lowering::DefaultThickCalleeConvention) |
| : ParameterConvention::Direct_Unowned); |
| |
| return get(getInvocationGenericSignature(), newExt, getCoroutineKind(), |
| calleeConvention, getParameters(), getYields(), getResults(), |
| getOptionalErrorResult(), getPatternSubstitutions(), |
| getInvocationSubstitutions(), getASTContext(), |
| getWitnessMethodConformanceOrInvalid()); |
| } |
| |
| namespace { |
| |
| enum class ConventionsKind : uint8_t { |
| Default = 0, |
| DefaultBlock = 1, |
| ObjCMethod = 2, |
| CFunctionType = 3, |
| CFunction = 4, |
| ObjCSelectorFamily = 5, |
| Deallocator = 6, |
| Capture = 7, |
| CXXMethod = 8, |
| }; |
| |
| class Conventions { |
| ConventionsKind kind; |
| |
| protected: |
| virtual ~Conventions() = default; |
| |
| public: |
| Conventions(ConventionsKind k) : kind(k) {} |
| |
| ConventionsKind getKind() const { return kind; } |
| |
| virtual ParameterConvention |
| getIndirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const = 0; |
| virtual ParameterConvention |
| getDirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const = 0; |
| virtual ParameterConvention getCallee() const = 0; |
| virtual ResultConvention getResult(const TypeLowering &resultTL) const = 0; |
| virtual ParameterConvention |
| getIndirectSelfParameter(const AbstractionPattern &type) const = 0; |
| virtual ParameterConvention |
| getDirectSelfParameter(const AbstractionPattern &type) const = 0; |
| |
| // Helpers that branch based on a value ownership. |
| ParameterConvention getIndirect(ValueOwnership ownership, bool forSelf, |
| unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const { |
| switch (ownership) { |
| case ValueOwnership::Default: |
| if (forSelf) |
| return getIndirectSelfParameter(type); |
| return getIndirectParameter(index, type, substTL); |
| case ValueOwnership::InOut: |
| return ParameterConvention::Indirect_Inout; |
| case ValueOwnership::Shared: |
| return ParameterConvention::Indirect_In_Guaranteed; |
| case ValueOwnership::Owned: |
| return ParameterConvention::Indirect_In; |
| } |
| llvm_unreachable("unhandled ownership"); |
| } |
| |
| ParameterConvention getDirect(ValueOwnership ownership, bool forSelf, |
| unsigned index, const AbstractionPattern &type, |
| const TypeLowering &substTL) const { |
| switch (ownership) { |
| case ValueOwnership::Default: |
| if (forSelf) |
| return getDirectSelfParameter(type); |
| return getDirectParameter(index, type, substTL); |
| case ValueOwnership::InOut: |
| return ParameterConvention::Indirect_Inout; |
| case ValueOwnership::Shared: |
| return ParameterConvention::Direct_Guaranteed; |
| case ValueOwnership::Owned: |
| return ParameterConvention::Direct_Owned; |
| } |
| llvm_unreachable("unhandled ownership"); |
| } |
| }; |
| |
| /// A structure for building the substituted generic signature of a lowered type. |
| /// |
| /// Where the abstraction pattern for a lowered type involves substitutable types, we extract those positions |
| /// out into generic arguments. This signature only needs to consider the general calling convention, |
| /// so it can reduce away protocol and base class constraints aside from |
| /// `AnyObject`. We want similar-shaped generic function types to remain |
| /// canonically equivalent, like `(T, U) -> ()`, `(T, T) -> ()`, |
| /// `(U, T) -> ()` or `(T, T.A) -> ()` when given substitutions that produce |
| /// the same function types, so we also introduce a new generic argument for |
| /// each position where we see a dependent type, and canonicalize the order in |
| /// which we see independent generic arguments. |
| class SubstFunctionTypeCollector { |
| public: |
| TypeConverter &TC; |
| TypeExpansionContext Expansion; |
| CanGenericSignature GenericSig; |
| bool Enabled; |
| |
| SmallVector<GenericTypeParamType *, 4> substGenericParams; |
| SmallVector<Requirement, 4> substRequirements; |
| SmallVector<Type, 4> substReplacements; |
| SmallVector<ProtocolConformanceRef, 4> substConformances; |
| |
| SubstFunctionTypeCollector(TypeConverter &TC, TypeExpansionContext context, |
| CanGenericSignature genericSig, bool enabled) |
| : TC(TC), Expansion(context), GenericSig(genericSig), Enabled(enabled) { |
| } |
| SubstFunctionTypeCollector(const SubstFunctionTypeCollector &) = delete; |
| |
| // Add a substitution for a fresh type variable, with the given replacement |
| // type and layout constraint. |
| CanType addSubstitution(LayoutConstraint layout, |
| CanType substType, |
| ArchetypeType *upperBound, |
| ArrayRef<ProtocolConformanceRef> substTypeConformances) { |
| auto paramIndex = substGenericParams.size(); |
| auto param = CanGenericTypeParamType::get(0, paramIndex, TC.Context); |
| |
| // Expand the bound type according to the expansion context. |
| if (Expansion.shouldLookThroughOpaqueTypeArchetypes() |
| && substType->hasOpaqueArchetype()) { |
| substType = substOpaqueTypesWithUnderlyingTypes(substType, Expansion); |
| } |
| |
| substGenericParams.push_back(param); |
| substReplacements.push_back(substType); |
| |
| LayoutConstraint upperBoundLayout; |
| Type upperBoundSuperclass; |
| ArrayRef<ProtocolDecl*> upperBoundConformances; |
| |
| // If the parameter is in a position with upper bound constraints, such |
| // as a generic nominal type with type constraints on its arguments, then |
| // preserve the constraints from that upper bound. |
| if (upperBound) { |
| upperBoundSuperclass = upperBound->getSuperclass(); |
| upperBoundConformances = upperBound->getConformsTo(); |
| upperBoundLayout = upperBound->getLayoutConstraint(); |
| } |
| |
| if (upperBoundSuperclass) { |
| upperBoundSuperclass = upperBoundSuperclass->mapTypeOutOfContext(); |
| substRequirements.push_back( |
| Requirement(RequirementKind::Superclass, param, upperBoundSuperclass)); |
| } |
| |
| // Preserve the layout constraint, if any, on the archetype in the |
| // generic signature, generalizing away some constraints that |
| // shouldn't affect ABI substitutability. |
| if (layout) { |
| switch (layout->getKind()) { |
| // Keep these layout constraints as is. |
| case LayoutConstraintKind::RefCountedObject: |
| case LayoutConstraintKind::TrivialOfAtMostSize: |
| break; |
| |
| case LayoutConstraintKind::UnknownLayout: |
| case LayoutConstraintKind::Trivial: |
| // These constraints don't really constrain the ABI, so we can |
| // eliminate them. |
| layout = LayoutConstraint(); |
| break; |
| |
| // Replace these specific constraints with one of the more general |
| // constraints above. |
| case LayoutConstraintKind::NativeClass: |
| case LayoutConstraintKind::Class: |
| case LayoutConstraintKind::NativeRefCountedObject: |
| // These can all be generalized to RefCountedObject. |
| layout = LayoutConstraint::getLayoutConstraint( |
| LayoutConstraintKind::RefCountedObject); |
| break; |
| |
| case LayoutConstraintKind::TrivialOfExactSize: |
| // Generalize to TrivialOfAtMostSize. |
| layout = LayoutConstraint::getLayoutConstraint( |
| LayoutConstraintKind::TrivialOfAtMostSize, |
| layout->getTrivialSizeInBits(), |
| layout->getAlignmentInBits(), |
| TC.Context); |
| break; |
| } |
| |
| if (layout) { |
| // Pick the more specific of the upper bound layout and the layout |
| // we chose above. |
| if (upperBoundLayout) { |
| layout = layout.merge(upperBoundLayout); |
| } |
| |
| substRequirements.push_back( |
| Requirement(RequirementKind::Layout, param, layout)); |
| } |
| } |
| |
| for (unsigned i : indices(upperBoundConformances)) { |
| auto proto = upperBoundConformances[i]; |
| auto conformance = substTypeConformances[i]; |
| substRequirements.push_back(Requirement(RequirementKind::Conformance, param, |
| proto->getDeclaredInterfaceType())); |
| substConformances.push_back(conformance); |
| } |
| |
| return param; |
| } |
| |
| /// Given the destructured original abstraction pattern and substituted type for a destructured |
| /// parameter or result, introduce substituted generic parameters and requirements as needed for |
| /// the lowered type, and return the substituted type in terms of the substituted generic signature. |
| CanType getSubstitutedInterfaceType(AbstractionPattern origType, |
| CanType substType) { |
| if (!Enabled) |
| return substType; |
| |
| // Replace every dependent type we see with a fresh type variable in |
| // the substituted signature, substituted by the corresponding concrete |
| // type. |
| |
| // The entire original context could be a generic parameter. |
| if (origType.isTypeParameter() || |
| origType.isOpaqueFunctionOrOpaqueDerivativeFunction()) { |
| return addSubstitution(origType.getLayoutConstraint(), substType, |
| nullptr, {}); |
| } |
| |
| auto origContextType = origType.getType(); |
| |
| // If the substituted type is a subclass of the abstraction pattern |
| // type, build substitutions for any type parameters in it. This only |
| // comes up when lowering override types for vtable entries. |
| auto areDifferentClasses = [](Type a, Type b) -> bool { |
| if (auto dynA = a->getAs<DynamicSelfType>()) { |
| a = dynA->getSelfType(); |
| } |
| if (auto dynB = b->getAs<DynamicSelfType>()) { |
| b = dynB->getSelfType(); |
| } |
| if (auto aClass = a->getClassOrBoundGenericClass()) { |
| if (auto bClass = b->getClassOrBoundGenericClass()) { |
| return aClass != bClass; |
| } |
| } |
| |
| return false; |
| }; |
| |
| bool substituteBindingsInSubstType = false; |
| if (areDifferentClasses(substType, origContextType)) { |
| substituteBindingsInSubstType = true; |
| } |
| if (auto substMeta = dyn_cast<MetatypeType>(substType)) { |
| if (auto origMeta = dyn_cast<MetatypeType>(origContextType)) { |
| if (areDifferentClasses(substMeta->getInstanceType(), |
| origMeta->getInstanceType())) { |
| substituteBindingsInSubstType = true; |
| } |
| } |
| } |
| |
| CanGenericSignature origSig = origType.getGenericSignature(); |
| if (substituteBindingsInSubstType) { |
| origContextType = substType; |
| origSig = TC.getCurGenericSignature(); |
| assert((!substType->hasTypeParameter() || origSig) && |
| "lowering mismatched interface types in a context without " |
| "a generic signature"); |
| } |
| |
| if (!origContextType->hasTypeParameter() |
| && !origContextType->hasArchetype()) { |
| // If the abstraction pattern doesn't have substitutable positions, nor |
| // should the concrete type. |
| assert(!substType->hasTypeParameter() |
| && !substType->hasArchetype()); |
| return substType; |
| } |
| |
| // Extract structural substitutions. |
| if (origContextType->hasTypeParameter()) { |
| origContextType = origSig->getGenericEnvironment() |
| ->mapTypeIntoContext(origContextType) |
| ->getCanonicalType(); |
| } |
| |
| auto result = origContextType |
| ->substituteBindingsTo(substType, |
| [&](ArchetypeType *archetype, |
| CanType binding, |
| ArchetypeType *upperBound, |
| ArrayRef<ProtocolConformanceRef> bindingConformances) -> CanType { |
| return addSubstitution(archetype->getLayoutConstraint(), |
| binding, |
| upperBound, |
| bindingConformances); |
| }); |
| |
| assert(result && "substType was not bindable to abstraction pattern type?"); |
| return result; |
| } |
| }; |
| |
| /// A visitor for breaking down formal result types into a SILResultInfo |
| /// and possibly some number of indirect-out SILParameterInfos, |
| /// matching the abstraction patterns of the original type. |
| class DestructureResults { |
| TypeConverter &TC; |
| const Conventions &Convs; |
| SmallVectorImpl<SILResultInfo> &Results; |
| TypeExpansionContext context; |
| SubstFunctionTypeCollector &Subst; |
| |
| public: |
| DestructureResults(TypeExpansionContext context, TypeConverter &TC, |
| const Conventions &conventions, |
| SmallVectorImpl<SILResultInfo> &results, |
| SubstFunctionTypeCollector &subst) |
| : TC(TC), Convs(conventions), Results(results), context(context), |
| Subst(subst) {} |
| |
| void destructure(AbstractionPattern origType, CanType substType) { |
| // Recur into tuples. |
| if (origType.isTuple()) { |
| auto substTupleType = cast<TupleType>(substType); |
| for (auto eltIndex : indices(substTupleType.getElementTypes())) { |
| AbstractionPattern origEltType = |
| origType.getTupleElementType(eltIndex); |
| CanType substEltType = substTupleType.getElementType(eltIndex); |
| destructure(origEltType, substEltType); |
| } |
| return; |
| } |
| |
| auto substInterfaceType = Subst.getSubstitutedInterfaceType(origType, |
| substType); |
| |
| auto &substResultTLForConvention = TC.getTypeLowering( |
| origType, substInterfaceType, TypeExpansionContext::minimal()); |
| auto &substResultTL = TC.getTypeLowering(origType, substInterfaceType, |
| context); |
| |
| |
| // Determine the result convention. |
| ResultConvention convention; |
| if (isFormallyReturnedIndirectly(origType, substType, |
| substResultTLForConvention)) { |
| convention = ResultConvention::Indirect; |
| } else { |
| convention = Convs.getResult(substResultTLForConvention); |
| |
| // Reduce conventions for trivial types to an unowned convention. |
| if (substResultTL.isTrivial()) { |
| switch (convention) { |
| case ResultConvention::Indirect: |
| case ResultConvention::Unowned: |
| case ResultConvention::UnownedInnerPointer: |
| // Leave these as-is. |
| break; |
| |
| case ResultConvention::Autoreleased: |
| case ResultConvention::Owned: |
| // These aren't distinguishable from unowned for trivial types. |
| convention = ResultConvention::Unowned; |
| break; |
| } |
| } |
| } |
| |
| SILResultInfo result(substResultTL.getLoweredType().getASTType(), |
| convention); |
| Results.push_back(result); |
| } |
| |
| /// Query whether the original type is returned indirectly for the purpose |
| /// of reabstraction given complete lowering information about its |
| /// substitution. |
| bool isFormallyReturnedIndirectly(AbstractionPattern origType, |
| CanType substType, |
| const TypeLowering &substTL) { |
| // If the substituted type is returned indirectly, so must the |
| // unsubstituted type. |
| if ((origType.isTypeParameter() |
| && !origType.isConcreteType() |
| && !origType.requiresClass()) |
| || substTL.isAddressOnly()) { |
| return true; |
| |
| // Functions are always returned directly. |
| } else if (origType.isOpaqueFunctionOrOpaqueDerivativeFunction()) { |
| return false; |
| |
| // If the substitution didn't change the type, then a negative |
| // response to the above is determinative as well. |
| } else if (origType.getType() == substType && |
| !origType.getType()->hasTypeParameter()) { |
| return false; |
| |
| // Otherwise, query specifically for the original type. |
| } else { |
| return SILType::isFormallyReturnedIndirectly( |
| origType.getType(), TC, origType.getGenericSignature()); |
| } |
| } |
| }; |
| |
| static bool isClangTypeMoreIndirectThanSubstType(TypeConverter &TC, |
| const clang::Type *clangTy, |
| CanType substTy) { |
| // A const pointer argument might have been imported as |
| // UnsafePointer, COpaquePointer, or a CF foreign class. |
| // (An ObjC class type wouldn't be const-qualified.) |
| if (clangTy->isPointerType() |
| && clangTy->getPointeeType().isConstQualified()) { |
| // Peek through optionals. |
| if (auto substObjTy = substTy.getOptionalObjectType()) |
| substTy = substObjTy; |
| |
| // Void pointers aren't usefully indirectable. |
| if (clangTy->isVoidPointerType()) |
| return false; |
| |
| if (auto eltTy = substTy->getAnyPointerElementType()) |
| return isClangTypeMoreIndirectThanSubstType(TC, |
| clangTy->getPointeeType().getTypePtr(), CanType(eltTy)); |
| |
| if (substTy->getAnyNominal() == |
| TC.Context.getOpaquePointerDecl()) |
| // TODO: We could conceivably have an indirect opaque ** imported |
| // as COpaquePointer. That shouldn't ever happen today, though, |
| // since we only ever indirect the 'self' parameter of functions |
| // imported as methods. |
| return false; |
| |
| if (clangTy->getPointeeType()->getAs<clang::RecordType>()) { |
| // CF type as foreign class |
| if (substTy->getClassOrBoundGenericClass() && |
| substTy->getClassOrBoundGenericClass()->getForeignClassKind() == |
| ClassDecl::ForeignKind::CFType) { |
| return false; |
| } |
| } |
| |
| // swift_newtypes are always passed directly |
| if (auto typedefTy = clangTy->getAs<clang::TypedefType>()) { |
| if (typedefTy->getDecl()->getAttr<clang::SwiftNewtypeAttr>()) |
| return false; |
| } |
| |
| return true; |
| } |
| return false; |
| } |
| |
| static bool isFormallyPassedIndirectly(TypeConverter &TC, |
| AbstractionPattern origType, |
| CanType substType, |
| const TypeLowering &substTL) { |
| // If the C type of the argument is a const pointer, but the Swift type |
| // isn't, treat it as indirect. |
| if (origType.isClangType() |
| && isClangTypeMoreIndirectThanSubstType(TC, origType.getClangType(), |
| substType)) { |
| return true; |
| } |
| |
| // If the substituted type is passed indirectly, so must the |
| // unsubstituted type. |
| if ((origType.isTypeParameter() && !origType.isConcreteType() |
| && !origType.requiresClass()) |
| || substTL.isAddressOnly()) { |
| return true; |
| |
| // If the substitution didn't change the type, then a negative |
| // response to the above is determinative as well. |
| } else if (origType.getType() == substType && |
| !origType.getType()->hasTypeParameter()) { |
| return false; |
| |
| // Otherwise, query specifically for the original type. |
| } else { |
| return SILType::isFormallyPassedIndirectly( |
| origType.getType(), TC, origType.getGenericSignature()); |
| } |
| } |
| |
| /// A visitor for turning formal input types into SILParameterInfos, matching |
| /// the abstraction patterns of the original type. |
| /// |
| /// If the original abstraction pattern is fully opaque, we must pass the |
| /// function's parameters and results indirectly, as if the original type were |
| /// the most general function signature (expressed entirely in generic |
| /// parameters) which can be substituted to equal the given signature. |
| /// |
| /// See the comment in AbstractionPattern.h for details. |
| class DestructureInputs { |
| TypeExpansionContext expansion; |
| TypeConverter &TC; |
| const Conventions &Convs; |
| const ForeignInfo &Foreign; |
| struct ForeignSelfInfo { |
| AbstractionPattern OrigSelfParam; |
| AnyFunctionType::CanParam SubstSelfParam; |
| }; |
| Optional<ForeignSelfInfo> ForeignSelf; |
| AbstractionPattern TopLevelOrigType = AbstractionPattern::getInvalid(); |
| SmallVectorImpl<SILParameterInfo> &Inputs; |
| SubstFunctionTypeCollector &Subst; |
| unsigned NextOrigParamIndex = 0; |
| public: |
| DestructureInputs(TypeExpansionContext expansion, TypeConverter &TC, |
| const Conventions &conventions, const ForeignInfo &foreign, |
| SmallVectorImpl<SILParameterInfo> &inputs, |
| SubstFunctionTypeCollector &subst) |
| : expansion(expansion), TC(TC), Convs(conventions), Foreign(foreign), |
| Inputs(inputs), Subst(subst) {} |
| |
| void destructure(AbstractionPattern origType, |
| CanAnyFunctionType::CanParamArrayRef params, |
| SILExtInfoBuilder extInfoBuilder) { |
| visitTopLevelParams(origType, params, extInfoBuilder); |
| } |
| |
| private: |
| /// Query whether the original type is address-only given complete |
| /// lowering information about its substitution. |
| bool isFormallyPassedIndirectly(AbstractionPattern origType, |
| CanType substType, |
| const TypeLowering &substTL) { |
| return ::isFormallyPassedIndirectly(TC, origType, substType, substTL); |
| } |
| |
| /// This is a special entry point that allows destructure inputs to handle |
| /// self correctly. |
| void visitTopLevelParams(AbstractionPattern origType, |
| CanAnyFunctionType::CanParamArrayRef params, |
| SILExtInfoBuilder extInfoBuilder) { |
| unsigned numEltTypes = params.size(); |
| |
| bool hasSelf = |
| (extInfoBuilder.hasSelfParam() || Foreign.Self.isImportAsMember()); |
| unsigned numNonSelfParams = (hasSelf ? numEltTypes - 1 : numEltTypes); |
| TopLevelOrigType = origType; |
| // If we have a foreign-self, install handleSelf as the handler. |
| if (Foreign.Self.isInstance()) { |
| assert(hasSelf && numEltTypes > 0); |
| ForeignSelf = ForeignSelfInfo{origType.getFunctionParamType(numNonSelfParams), |
| params[numNonSelfParams]}; |
| } |
| |
| // Add any foreign parameters that are positioned here. |
| maybeAddForeignParameters(); |
| |
| // Process all the non-self parameters. |
| for (unsigned i = 0; i != numNonSelfParams; ++i) { |
| auto ty = params[i].getParameterType(); |
| auto eltPattern = origType.getFunctionParamType(i); |
| auto flags = params[i].getParameterFlags(); |
| |
| visit(flags.getValueOwnership(), /*forSelf=*/false, eltPattern, ty, |
| flags.isNoDerivative()); |
| } |
| |
| // Process the self parameter. Note that we implicitly drop self |
| // if this is a static foreign-self import. |
| if (hasSelf && !Foreign.Self.isImportAsMember()) { |
| auto selfParam = params[numNonSelfParams]; |
| auto ty = selfParam.getParameterType(); |
| auto eltPattern = origType.getFunctionParamType(numNonSelfParams); |
| auto flags = selfParam.getParameterFlags(); |
| |
| visit(flags.getValueOwnership(), /*forSelf=*/true, |
| eltPattern, ty); |
| } |
| |
| TopLevelOrigType = AbstractionPattern::getInvalid(); |
| ForeignSelf = None; |
| } |
| |
| void visit(ValueOwnership ownership, bool forSelf, |
| AbstractionPattern origType, CanType substType, |
| bool isNonDifferentiable = false) { |
| assert(!isa<InOutType>(substType)); |
| |
| // Tuples get handled specially, in some cases: |
| CanTupleType substTupleTy = dyn_cast<TupleType>(substType); |
| if (substTupleTy && !origType.isTypeParameter()) { |
| assert(origType.getNumTupleElements() == substTupleTy->getNumElements()); |
| switch (ownership) { |
| case ValueOwnership::Default: |
| case ValueOwnership::Owned: |
| case ValueOwnership::Shared: |
| // Expand the tuple. |
| for (auto i : indices(substTupleTy.getElementTypes())) { |
| auto &elt = substTupleTy->getElement(i); |
| auto ownership = elt.getParameterFlags().getValueOwnership(); |
| assert(ownership == ValueOwnership::Default); |
| assert(!elt.isVararg()); |
| visit(ownership, forSelf, |
| origType.getTupleElementType(i), |
| CanType(elt.getRawType())); |
| } |
| return; |
| case ValueOwnership::InOut: |
| // handled below |
| break; |
| } |
| } |
| |
| unsigned origParamIndex = NextOrigParamIndex++; |
| |
| auto substInterfaceType = |
| Subst.getSubstitutedInterfaceType(origType, substType); |
| |
| auto &substTLConv = TC.getTypeLowering(origType, substInterfaceType, |
| TypeExpansionContext::minimal()); |
| auto &substTL = TC.getTypeLowering(origType, substInterfaceType, expansion); |
| |
| ParameterConvention convention; |
| if (ownership == ValueOwnership::InOut) { |
| convention = ParameterConvention::Indirect_Inout; |
| } else if (isFormallyPassedIndirectly(origType, substType, substTLConv)) { |
| convention = Convs.getIndirect(ownership, forSelf, origParamIndex, |
| origType, substTLConv); |
| assert(isIndirectFormalParameter(convention)); |
| } else if (substTL.isTrivial()) { |
| convention = ParameterConvention::Direct_Unowned; |
| } else { |
| convention = Convs.getDirect(ownership, forSelf, origParamIndex, origType, |
| substTLConv); |
| assert(!isIndirectFormalParameter(convention)); |
| } |
| |
| SILParameterInfo param(substTL.getLoweredType().getASTType(), convention); |
| if (isNonDifferentiable) |
| param = param.getWithDifferentiability( |
| SILParameterDifferentiability::NotDifferentiable); |
| Inputs.push_back(param); |
| |
| maybeAddForeignParameters(); |
| } |
| |
| /// Given that we've just reached an argument index for the |
| /// first time, add any foreign parameters. |
| void maybeAddForeignParameters() { |
| while (maybeAddForeignAsyncParameter() || |
| maybeAddForeignErrorParameter() || |
| maybeAddForeignSelfParameter()) { |
| // Continue to see, just in case there are more parameters to add. |
| } |
| } |
| |
| bool maybeAddForeignAsyncParameter() { |
| if (!Foreign.Async |
| || NextOrigParamIndex != Foreign.Async->completionHandlerParamIndex()) |
| return false; |
| |
| auto nativeCHTy = Foreign.Async->completionHandlerType(); |
| |
| // Use the abstraction pattern we're lowering against in order to lower |
| // the completion handler type, so we can preserve C/ObjC distinctions that |
| // normally get abstracted away by the importer. |
| auto completionHandlerNativeOrigTy = TopLevelOrigType |
| .getObjCMethodAsyncCompletionHandlerType(nativeCHTy); |
| |
| // Bridge the Swift completion handler type back to its |
| // foreign representation. |
| auto foreignCHTy = TC.getLoweredBridgedType(completionHandlerNativeOrigTy, |
| nativeCHTy, |
| Bridgeability::Full, |
| SILFunctionTypeRepresentation::ObjCMethod, |
| TypeConverter::ForArgument) |
| ->getCanonicalType(); |
| |
| auto completionHandlerOrigTy = TopLevelOrigType |
| .getObjCMethodAsyncCompletionHandlerType(foreignCHTy); |
| auto completionHandlerTy = TC.getLoweredType(completionHandlerOrigTy, |
| foreignCHTy, expansion) |
| .getASTType(); |
| Inputs.push_back(SILParameterInfo(completionHandlerTy, |
| ParameterConvention::Direct_Unowned)); |
| ++NextOrigParamIndex; |
| return true; |
| } |
| |
| bool maybeAddForeignErrorParameter() { |
| // A foreign async convention absorbs any error parameter, making it into |
| // an argument to the callback. |
| if (Foreign.Async) |
| return false; |
| |
| if (!Foreign.Error || |
| NextOrigParamIndex != Foreign.Error->getErrorParameterIndex()) |
| return false; |
| |
| auto foreignErrorTy = TC.getLoweredRValueType( |
| expansion, Foreign.Error->getErrorParameterType()); |
| |
| // Assume the error parameter doesn't have interesting lowering. |
| Inputs.push_back(SILParameterInfo(foreignErrorTy, |
| ParameterConvention::Direct_Unowned)); |
| ++NextOrigParamIndex; |
| return true; |
| } |
| |
| bool maybeAddForeignSelfParameter() { |
| if (!Foreign.Self.isInstance() || |
| NextOrigParamIndex != Foreign.Self.getSelfIndex()) |
| return false; |
| |
| if (ForeignSelf) { |
| // This is a "self", but it's not a Swift self, we handle it differently. |
| visit(ForeignSelf->SubstSelfParam.getValueOwnership(), |
| /*forSelf=*/false, |
| ForeignSelf->OrigSelfParam, |
| ForeignSelf->SubstSelfParam.getParameterType()); |
| } |
| return true; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| static bool isPseudogeneric(SILDeclRef c) { |
| // FIXME: should this be integrated in with the Sema check that prevents |
| // illegal use of type arguments in pseudo-generic method bodies? |
| |
| // The implicitly-generated native initializer thunks for imported |
| // initializers are never pseudo-generic, because they may need |
| // to use their type arguments to bridge their value arguments. |
| if (!c.isForeign && |
| (c.kind == SILDeclRef::Kind::Allocator || |
| c.kind == SILDeclRef::Kind::Initializer) && |
| c.getDecl()->hasClangNode()) |
| return false; |
| |
| // Otherwise, we have to look at the entity's context. |
| DeclContext *dc; |
| if (c.hasDecl()) { |
| dc = c.getDecl()->getDeclContext(); |
| } else if (auto closure = c.getAbstractClosureExpr()) { |
| dc = closure->getParent(); |
| } else { |
| return false; |
| } |
| dc = dc->getInnermostTypeContext(); |
| if (!dc) return false; |
| |
| auto classDecl = dc->getSelfClassDecl(); |
| return (classDecl && classDecl->usesObjCGenericsModel()); |
| } |
| |
| /// Update the result type given the foreign error convention that we will be |
| /// using. |
| void updateResultTypeForForeignInfo( |
| const ForeignInfo &foreignInfo, CanGenericSignature genericSig, |
| AbstractionPattern &origResultType, CanType &substFormalResultType) { |
| // If there's no error or async convention, the return type is unchanged. |
| if (!foreignInfo.Async && !foreignInfo.Error) { |
| return; |
| } |
| |
| // A foreign async convention means our lowered return type is Void, since |
| // the imported semantic return and/or error type map to the completion |
| // callback's argument(s). |
| auto &C = substFormalResultType->getASTContext(); |
| if (auto async = foreignInfo.Async) { |
| substFormalResultType = TupleType::getEmpty(C); |
| origResultType = AbstractionPattern(genericSig, substFormalResultType); |
| return; |
| } |
| |
| // Otherwise, adjust the return type to match the foreign error convention. |
| auto convention = *foreignInfo.Error; |
| switch (convention.getKind()) { |
| // These conventions replace the result type. |
| case ForeignErrorConvention::ZeroResult: |
| case ForeignErrorConvention::NonZeroResult: |
| assert(substFormalResultType->isVoid()); |
| substFormalResultType = convention.getResultType(); |
| origResultType = AbstractionPattern(genericSig, substFormalResultType); |
| return; |
| |
| // These conventions wrap the result type in a level of optionality. |
| case ForeignErrorConvention::NilResult: |
| assert(!substFormalResultType->getOptionalObjectType()); |
| substFormalResultType = |
| OptionalType::get(substFormalResultType)->getCanonicalType(); |
| origResultType = |
| AbstractionPattern::getOptional(origResultType); |
| return; |
| |
| // These conventions don't require changes to the formal error type. |
| case ForeignErrorConvention::ZeroPreservedResult: |
| case ForeignErrorConvention::NonNilError: |
| return; |
| } |
| llvm_unreachable("unhandled kind"); |
| } |
| |
| /// Lower any/all capture context parameters. |
| /// |
| /// *NOTE* Currently default arg generators can not capture anything. |
| /// If we ever add that ability, it will be a different capture list |
| /// from the function to which the argument is attached. |
| static void |
| lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function, |
| CanGenericSignature genericSig, |
| TypeExpansionContext expansion, |
| SmallVectorImpl<SILParameterInfo> &inputs) { |
| |
| // NB: The generic signature may be elided from the lowered function type |
| // if the function is in a fully-specialized context, but we still need to |
| // canonicalize references to the generic parameters that may appear in |
| // non-canonical types in that context. We need the original generic |
| // signature from the AST for that. |
| auto origGenericSig = function.getAnyFunctionRef()->getGenericSignature(); |
| auto loweredCaptures = TC.getLoweredLocalCaptures(function); |
| |
| for (auto capture : loweredCaptures.getCaptures()) { |
| if (capture.isDynamicSelfMetadata()) { |
| ParameterConvention convention = ParameterConvention::Direct_Unowned; |
| auto dynamicSelfInterfaceType = |
| loweredCaptures.getDynamicSelfType()->mapTypeOutOfContext(); |
| |
| auto selfMetatype = MetatypeType::get(dynamicSelfInterfaceType, |
| MetatypeRepresentation::Thick); |
| |
| auto canSelfMetatype = selfMetatype->getCanonicalType(origGenericSig); |
| SILParameterInfo param(canSelfMetatype, convention); |
| inputs.push_back(param); |
| |
| continue; |
| } |
| |
| if (capture.isOpaqueValue()) { |
| OpaqueValueExpr *opaqueValue = capture.getOpaqueValue(); |
| auto canType = opaqueValue->getType()->mapTypeOutOfContext() |
| ->getCanonicalType(origGenericSig); |
| auto &loweredTL = |
| TC.getTypeLowering(AbstractionPattern(genericSig, canType), |
| canType, expansion); |
| auto loweredTy = loweredTL.getLoweredType(); |
| |
| ParameterConvention convention; |
| if (loweredTL.isAddressOnly()) { |
| convention = ParameterConvention::Indirect_In; |
| } else { |
| convention = ParameterConvention::Direct_Owned; |
| } |
| SILParameterInfo param(loweredTy.getASTType(), convention); |
| inputs.push_back(param); |
| |
| continue; |
| } |
| |
| auto *VD = capture.getDecl(); |
| auto type = VD->getInterfaceType(); |
| auto canType = type->getCanonicalType(origGenericSig); |
| |
| auto &loweredTL = |
| TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType, |
| expansion); |
| auto loweredTy = loweredTL.getLoweredType(); |
| switch (TC.getDeclCaptureKind(capture, expansion)) { |
| case CaptureKind::Constant: { |
| // Constants are captured by value. |
| ParameterConvention convention; |
| assert (!loweredTL.isAddressOnly()); |
| if (loweredTL.isTrivial()) { |
| convention = ParameterConvention::Direct_Unowned; |
| } else { |
| convention = ParameterConvention::Direct_Guaranteed; |
| } |
| SILParameterInfo param(loweredTy.getASTType(), convention); |
| inputs.push_back(param); |
| break; |
| } |
| case CaptureKind::Box: { |
| // The type in the box is lowered in the minimal context. |
| auto minimalLoweredTy = |
| TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType, |
| TypeExpansionContext::minimal()) |
| .getLoweredType(); |
| // Lvalues are captured as a box that owns the captured value. |
| auto boxTy = TC.getInterfaceBoxTypeForCapture( |
| VD, minimalLoweredTy.getASTType(), |
| /*mutable*/ true); |
| auto convention = ParameterConvention::Direct_Guaranteed; |
| auto param = SILParameterInfo(boxTy, convention); |
| inputs.push_back(param); |
| break; |
| } |
| case CaptureKind::StorageAddress: { |
| // Non-escaping lvalues are captured as the address of the value. |
| SILType ty = loweredTy.getAddressType(); |
| auto param = |
| SILParameterInfo(ty.getASTType(), |
| ParameterConvention::Indirect_InoutAliasable); |
| inputs.push_back(param); |
| break; |
| } |
| case CaptureKind::Immutable: { |
| // 'let' constants that are address-only are captured as the address of |
| // the value and will be consumed by the closure. |
| SILType ty = loweredTy.getAddressType(); |
| auto param = |
| SILParameterInfo(ty.getASTType(), |
| ParameterConvention::Indirect_In_Guaranteed); |
| inputs.push_back(param); |
| break; |
| } |
| } |
| } |
| } |
| |
| static AccessorDecl *getAsCoroutineAccessor(Optional<SILDeclRef> constant) { |
| if (!constant || !constant->hasDecl()) |
| return nullptr;; |
| |
| auto accessor = dyn_cast<AccessorDecl>(constant->getDecl()); |
| if (!accessor || !accessor->isCoroutine()) |
| return nullptr; |
| |
| return accessor; |
| } |
| |
| static void destructureYieldsForReadAccessor(TypeConverter &TC, |
| TypeExpansionContext expansion, |
| AbstractionPattern origType, |
| CanType valueType, |
| SmallVectorImpl<SILYieldInfo> &yields, |
| SubstFunctionTypeCollector &subst) { |
| // Recursively destructure tuples. |
| if (origType.isTuple()) { |
| auto valueTupleType = cast<TupleType>(valueType); |
| for (auto i : indices(valueTupleType.getElementTypes())) { |
| auto origEltType = origType.getTupleElementType(i); |
| auto valueEltType = valueTupleType.getElementType(i); |
| destructureYieldsForReadAccessor(TC, expansion, origEltType, valueEltType, |
| yields, subst); |
| } |
| return; |
| } |
| |
| auto valueInterfaceType = |
| subst.getSubstitutedInterfaceType(origType, valueType); |
| |
| auto &tlConv = |
| TC.getTypeLowering(origType, valueInterfaceType, |
| TypeExpansionContext::minimal()); |
| auto &tl = |
| TC.getTypeLowering(origType, valueInterfaceType, expansion); |
| auto convention = [&] { |
| if (isFormallyPassedIndirectly(TC, origType, valueInterfaceType, tlConv)) |
| return ParameterConvention::Indirect_In_Guaranteed; |
| if (tlConv.isTrivial()) |
| return ParameterConvention::Direct_Unowned; |
| return ParameterConvention::Direct_Guaranteed; |
| }(); |
| |
| yields.push_back(SILYieldInfo(tl.getLoweredType().getASTType(), |
| convention)); |
| } |
| |
| static void destructureYieldsForCoroutine(TypeConverter &TC, |
| TypeExpansionContext expansion, |
| Optional<SILDeclRef> origConstant, |
| Optional<SILDeclRef> constant, |
| Optional<SubstitutionMap> reqtSubs, |
| SmallVectorImpl<SILYieldInfo> &yields, |
| SILCoroutineKind &coroutineKind, |
| SubstFunctionTypeCollector &subst) { |
| assert(coroutineKind == SILCoroutineKind::None); |
| assert(yields.empty()); |
| |
| auto accessor = getAsCoroutineAccessor(constant); |
| if (!accessor) |
| return; |
| |
| auto origAccessor = cast<AccessorDecl>(origConstant->getDecl()); |
| |
| // Coroutine accessors are implicitly yield-once coroutines, despite |
| // their function type. |
| coroutineKind = SILCoroutineKind::YieldOnce; |
| |
| // Coroutine accessors are always native, so fetch the native |
| // abstraction pattern. |
| auto origStorage = origAccessor->getStorage(); |
| auto origType = TC.getAbstractionPattern(origStorage, /*nonobjc*/ true) |
| .getReferenceStorageReferentType(); |
| |
| auto storage = accessor->getStorage(); |
| auto valueType = storage->getValueInterfaceType(); |
| if (reqtSubs) { |
| valueType = valueType.subst(*reqtSubs); |
| } |
| |
| auto canValueType = valueType->getCanonicalType( |
| accessor->getGenericSignature()); |
| |
| // 'modify' yields an inout of the target type. |
| if (accessor->getAccessorKind() == AccessorKind::Modify) { |
| auto valueInterfaceType = subst.getSubstitutedInterfaceType(origType, |
| canValueType); |
| auto loweredValueTy = |
| TC.getLoweredType(origType, valueInterfaceType, expansion); |
| yields.push_back(SILYieldInfo(loweredValueTy.getASTType(), |
| ParameterConvention::Indirect_Inout)); |
| return; |
| } |
| |
| // 'read' yields a borrowed value of the target type, destructuring |
| // tuples as necessary. |
| assert(accessor->getAccessorKind() == AccessorKind::Read); |
| destructureYieldsForReadAccessor(TC, expansion, origType, canValueType, |
| yields, subst); |
| } |
| |
| /// Create the appropriate SIL function type for the given formal type |
| /// and conventions. |
| /// |
| /// The lowering of function types is generally sensitive to the |
| /// declared abstraction pattern. We want to be able to take |
| /// advantage of declared type information in order to, say, pass |
| /// arguments separately and directly; but we also want to be able to |
| /// call functions from generic code without completely embarrassing |
| /// performance. Therefore, different abstraction patterns induce |
| /// different argument-passing conventions, and we must introduce |
| /// implicit reabstracting conversions where necessary to map one |
| /// convention to another. |
| /// |
| /// However, we actually can't reabstract arbitrary thin function |
| /// values while still leaving them thin, at least without costly |
| /// page-mapping tricks. Therefore, the representation must remain |
| /// consistent across all abstraction patterns. |
| /// |
| /// We could reabstract block functions in theory, but (1) we don't |
| /// really need to and (2) doing so would be problematic because |
| /// stuffing something in an Optional currently forces it to be |
| /// reabstracted to the most general type, which means that we'd |
| /// expect the wrong abstraction conventions on bridged block function |
| /// types. |
| /// |
| /// Therefore, we only honor abstraction patterns on thick or |
| /// polymorphic functions. |
| /// |
| /// FIXME: we shouldn't just drop the original abstraction pattern |
| /// when we can't reabstract. Instead, we should introduce |
| /// dynamic-indirect argument-passing conventions and map opaque |
| /// archetypes to that, then respect those conventions in IRGen by |
| /// using runtime call construction. |
| /// |
| /// \param conventions - conventions as expressed for the original type |
| static CanSILFunctionType getSILFunctionType( |
| TypeConverter &TC, TypeExpansionContext expansionContext, |
| AbstractionPattern origType, CanAnyFunctionType substFnInterfaceType, |
| SILExtInfoBuilder extInfoBuilder, const Conventions &conventions, |
| const ForeignInfo &foreignInfo, Optional<SILDeclRef> origConstant, |
| Optional<SILDeclRef> constant, Optional<SubstitutionMap> reqtSubs, |
| ProtocolConformanceRef witnessMethodConformance) { |
| // Find the generic parameters. |
| CanGenericSignature genericSig = |
| substFnInterfaceType.getOptGenericSignature(); |
| |
| Optional<TypeConverter::GenericContextRAII> contextRAII; |
| if (genericSig) contextRAII.emplace(TC, genericSig); |
| |
| // Per above, only fully honor opaqueness in the abstraction pattern |
| // for thick or polymorphic functions. We don't need to worry about |
| // non-opaque patterns because the type-checker forbids non-thick |
| // function types from having generic parameters or results. |
| if (origType.isTypeParameter() && |
| substFnInterfaceType->getExtInfo().getSILRepresentation() |
| != SILFunctionType::Representation::Thick && |
| isa<FunctionType>(substFnInterfaceType)) { |
| origType = AbstractionPattern(genericSig, |
| substFnInterfaceType); |
| } |
| |
| Optional<SILResultInfo> errorResult; |
| assert( |
| (!foreignInfo.Error || substFnInterfaceType->getExtInfo().isThrowing()) |
| && "foreignError was set but function type does not throw?"); |
| assert( |
| (!foreignInfo.Async || substFnInterfaceType->getExtInfo().isAsync()) |
| && "foreignAsync was set but function type is not async?"); |
| |
| // Map 'async' to the appropriate `@async` modifier. |
| bool isAsync = false; |
| if (substFnInterfaceType->getExtInfo().isAsync() && !foreignInfo.Async) { |
| assert(!origType.isForeign() |
| && "using native Swift async for foreign type!"); |
| isAsync = true; |
| } |
| |
| // Map 'throws' to the appropriate error convention. |
| if (substFnInterfaceType->getExtInfo().isThrowing() |
| && !foreignInfo.Error |
| && !foreignInfo.Async) { |
| assert(!origType.isForeign() |
| && "using native Swift error convention for foreign type!"); |
| SILType exnType = SILType::getExceptionType(TC.Context); |
| assert(exnType.isObject()); |
| errorResult = SILResultInfo(exnType.getASTType(), |
| ResultConvention::Owned); |
| } |
| |
| // Lower the result type. |
| AbstractionPattern origResultType = origType.getFunctionResultType(); |
| CanType substFormalResultType = substFnInterfaceType.getResult(); |
| |
| // If we have a foreign error and/or async convention, adjust the |
| // lowered result type. |
| updateResultTypeForForeignInfo(foreignInfo, genericSig, origResultType, |
| substFormalResultType); |
| |
| bool shouldBuildSubstFunctionType = [&]{ |
| if (!TC.Context.LangOpts.EnableSubstSILFunctionTypesForFunctionValues) |
| return false; |
| |
| // We always use substituted function types for coroutines that are |
| // being lowered in the context of another coroutine, which is to say, |
| // for class override thunks. This is required to make the yields |
| // match in abstraction to the base method's yields, which is necessary |
| // to make the extracted continuation-function signatures match. |
| if (constant != origConstant && getAsCoroutineAccessor(constant)) |
| return true; |
| |
| // We don't currently use substituted function types for generic function |
| // type lowering, though we should for generic methods on classes and |
| // protocols. |
| if (genericSig) |
| return false; |
| |
| // We only currently use substituted function types for function values, |
| // which will have standard thin or thick representation. (Per the previous |
| // comment, it would be useful to do so for generic methods on classes and |
| // protocols too.) |
| auto rep = extInfoBuilder.getRepresentation(); |
| return (rep == SILFunctionTypeRepresentation::Thick || |
| rep == SILFunctionTypeRepresentation::Thin); |
| }(); |
| |
| SubstFunctionTypeCollector subst(TC, expansionContext, genericSig, |
| shouldBuildSubstFunctionType); |
| |
| // Destructure the input tuple type. |
| SmallVector<SILParameterInfo, 8> inputs; |
| { |
| DestructureInputs destructurer(expansionContext, TC, conventions, |
| foreignInfo, inputs, subst); |
| destructurer.destructure(origType, substFnInterfaceType.getParams(), |
| extInfoBuilder); |
| } |
| |
| // Destructure the coroutine yields. |
| SILCoroutineKind coroutineKind = SILCoroutineKind::None; |
| SmallVector<SILYieldInfo, 8> yields; |
| destructureYieldsForCoroutine(TC, expansionContext, origConstant, constant, |
| reqtSubs, yields, coroutineKind, subst); |
| |
| // Destructure the result tuple type. |
| SmallVector<SILResultInfo, 8> results; |
| { |
| DestructureResults destructurer(expansionContext, TC, conventions, |
| results, subst); |
| destructurer.destructure(origResultType, substFormalResultType); |
| } |
| |
| // Lower the capture context parameters, if any. |
| if (constant && constant->getAnyFunctionRef()) { |
| auto expansion = TypeExpansionContext::maximal( |
| expansionContext.getContext(), expansionContext.isWholeModuleContext()); |
| if (constant->isSerialized()) |
| expansion = TypeExpansionContext::minimal(); |
| lowerCaptureContextParameters(TC, *constant, genericSig, expansion, inputs); |
| } |
| |
| auto calleeConvention = ParameterConvention::Direct_Unowned; |
| if (extInfoBuilder.hasContext()) |
| calleeConvention = conventions.getCallee(); |
| |
| bool pseudogeneric = genericSig && constant |
| ? isPseudogeneric(*constant) |
| : false; |
| |
| auto silRep = extInfoBuilder.getRepresentation(); |
| const clang::Type *clangType = extInfoBuilder.getClangTypeInfo().getType(); |
| if (shouldStoreClangType(silRep) && !clangType) { |
| // If we have invalid code in the source like |
| // do { let x = 0; let _ : @convention(c) () -> Int = { x } } |
| // we will fail to convert the corresponding SIL function type, as it will |
| // have a sil_box_type { Int } parameter reflecting the capture. So we |
| // convert the AST type instead. |
| // N.B. The `do` is necessary; the code compiles at global scope. |
| SmallVector<AnyFunctionType::Param, 4> params; |
| for (auto ty : substFnInterfaceType.getParams()) |
| params.push_back(ty); |
| clangType = TC.Context.getClangFunctionType( |
| params, substFnInterfaceType.getResult(), |
| convertRepresentation(silRep).getValue()); |
| } |
| auto silExtInfo = extInfoBuilder.withClangFunctionType(clangType) |
| .withIsPseudogeneric(pseudogeneric) |
| .withAsync(isAsync) |
| .build(); |
| |
| // Build the substituted generic signature we extracted. |
| SubstitutionMap substitutions; |
| if (subst.Enabled) { |
| if (!subst.substGenericParams.empty()) { |
| auto subSig = GenericSignature::get(subst.substGenericParams, |
| subst.substRequirements) |
| .getCanonicalSignature(); |
| substitutions = SubstitutionMap::get(subSig, |
| llvm::makeArrayRef(subst.substReplacements), |
| llvm::makeArrayRef(subst.substConformances)); |
| } |
| } |
| |
| return SILFunctionType::get(genericSig, silExtInfo, coroutineKind, |
| calleeConvention, inputs, yields, |
| results, errorResult, |
| substitutions, SubstitutionMap(), |
| TC.Context, witnessMethodConformance); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Deallocator SILFunctionTypes |
| //===----------------------------------------------------------------------===// |
| |
| namespace { |
| |
| // The convention for general deallocators. |
| struct DeallocatorConventions : Conventions { |
| DeallocatorConventions() : Conventions(ConventionsKind::Deallocator) {} |
| |
| ParameterConvention getIndirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const override { |
| llvm_unreachable("Deallocators do not have indirect parameters"); |
| } |
| |
| ParameterConvention getDirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const override { |
| llvm_unreachable("Deallocators do not have non-self direct parameters"); |
| } |
| |
| ParameterConvention getCallee() const override { |
| llvm_unreachable("Deallocators do not have callees"); |
| } |
| |
| ResultConvention getResult(const TypeLowering &tl) const override { |
| // TODO: Put an unreachable here? |
| return ResultConvention::Owned; |
| } |
| |
| ParameterConvention |
| getDirectSelfParameter(const AbstractionPattern &type) const override { |
| // TODO: Investigate whether or not it is |
| return ParameterConvention::Direct_Owned; |
| } |
| |
| ParameterConvention |
| getIndirectSelfParameter(const AbstractionPattern &type) const override { |
| llvm_unreachable("Deallocators do not have indirect self parameters"); |
| } |
| |
| static bool classof(const Conventions *C) { |
| return C->getKind() == ConventionsKind::Deallocator; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| //===----------------------------------------------------------------------===// |
| // Default Convention FunctionTypes |
| //===----------------------------------------------------------------------===// |
| |
| namespace { |
| |
| enum class NormalParameterConvention { Owned, Guaranteed }; |
| |
| /// The default Swift conventions. |
| class DefaultConventions : public Conventions { |
| NormalParameterConvention normalParameterConvention; |
| |
| public: |
| DefaultConventions(NormalParameterConvention normalParameterConvention) |
| : Conventions(ConventionsKind::Default), |
| normalParameterConvention(normalParameterConvention) {} |
| |
| bool isNormalParameterConventionGuaranteed() const { |
| return normalParameterConvention == NormalParameterConvention::Guaranteed; |
| } |
| |
| ParameterConvention getIndirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const override { |
| if (isNormalParameterConventionGuaranteed()) { |
| return ParameterConvention::Indirect_In_Guaranteed; |
| } |
| return ParameterConvention::Indirect_In; |
| } |
| |
| ParameterConvention getDirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const override { |
| if (isNormalParameterConventionGuaranteed()) |
| return ParameterConvention::Direct_Guaranteed; |
| return ParameterConvention::Direct_Owned; |
| } |
| |
| ParameterConvention getCallee() const override { |
| return DefaultThickCalleeConvention; |
| } |
| |
| ResultConvention getResult(const TypeLowering &tl) const override { |
| return ResultConvention::Owned; |
| } |
| |
| ParameterConvention |
| getDirectSelfParameter(const AbstractionPattern &type) const override { |
| return ParameterConvention::Direct_Guaranteed; |
| } |
| |
| ParameterConvention |
| getIndirectSelfParameter(const AbstractionPattern &type) const override { |
| return ParameterConvention::Indirect_In_Guaranteed; |
| } |
| |
| static bool classof(const Conventions *C) { |
| return C->getKind() == ConventionsKind::Default; |
| } |
| }; |
| |
| /// The default conventions for Swift initializing constructors. |
| /// |
| /// Initializing constructors take all parameters (including) self at +1. This |
| /// is because: |
| /// |
| /// 1. We are likely to be initializing fields of self implying that the |
| /// parameters are likely to be forwarded into memory without further |
| /// copies. |
| /// 2. Initializers must take 'self' at +1, since they will return it back |
| /// at +1, and may chain onto Objective-C initializers that replace the |
| /// instance. |
| struct DefaultInitializerConventions : DefaultConventions { |
| DefaultInitializerConventions() |
| : DefaultConventions(NormalParameterConvention::Owned) {} |
| |
| /// Initializers must take 'self' at +1, since they will return it back at +1, |
| /// and may chain onto Objective-C initializers that replace the instance. |
| ParameterConvention |
| getDirectSelfParameter(const AbstractionPattern &type) const override { |
| return ParameterConvention::Direct_Owned; |
| } |
| |
| ParameterConvention |
| getIndirectSelfParameter(const AbstractionPattern &type) const override { |
| return ParameterConvention::Indirect_In; |
| } |
| }; |
| |
| /// The convention used for allocating inits. Allocating inits take their normal |
| /// parameters at +1 and do not have a self parameter. |
| struct DefaultAllocatorConventions : DefaultConventions { |
| DefaultAllocatorConventions() |
| : DefaultConventions(NormalParameterConvention::Owned) {} |
| |
| ParameterConvention |
| getDirectSelfParameter(const AbstractionPattern &type) const override { |
| llvm_unreachable("Allocating inits do not have self parameters"); |
| } |
| |
| ParameterConvention |
| getIndirectSelfParameter(const AbstractionPattern &type) const override { |
| llvm_unreachable("Allocating inits do not have self parameters"); |
| } |
| }; |
| |
| /// The default conventions for Swift setter acccessors. |
| /// |
| /// These take self at +0, but all other parameters at +1. This is because we |
| /// assume that setter parameters are likely to be values to be forwarded into |
| /// memory. Thus by passing in the +1 value, we avoid a potential copy in that |
| /// case. |
| struct DefaultSetterConventions : DefaultConventions { |
| DefaultSetterConventions() |
| : DefaultConventions(NormalParameterConvention::Owned) {} |
| }; |
| |
| /// The default conventions for ObjC blocks. |
| struct DefaultBlockConventions : Conventions { |
| DefaultBlockConventions() : Conventions(ConventionsKind::DefaultBlock) {} |
| |
| ParameterConvention getIndirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const override { |
| llvm_unreachable("indirect block parameters unsupported"); |
| } |
| |
| ParameterConvention getDirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const override { |
| return ParameterConvention::Direct_Unowned; |
| } |
| |
| ParameterConvention getCallee() const override { |
| return ParameterConvention::Direct_Unowned; |
| } |
| |
| ResultConvention getResult(const TypeLowering &substTL) const override { |
| return ResultConvention::Autoreleased; |
| } |
| |
| ParameterConvention |
| getDirectSelfParameter(const AbstractionPattern &type) const override { |
| llvm_unreachable("objc blocks do not have a self parameter"); |
| } |
| |
| ParameterConvention |
| getIndirectSelfParameter(const AbstractionPattern &type) const override { |
| llvm_unreachable("objc blocks do not have a self parameter"); |
| } |
| |
| static bool classof(const Conventions *C) { |
| return C->getKind() == ConventionsKind::DefaultBlock; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| static CanSILFunctionType getSILFunctionTypeForAbstractCFunction( |
| TypeConverter &TC, AbstractionPattern origType, |
| CanAnyFunctionType substType, SILExtInfoBuilder extInfoBuilder, |
| Optional<SILDeclRef> constant); |
| |
| static CanSILFunctionType getNativeSILFunctionType( |
| TypeConverter &TC, TypeExpansionContext context, |
| AbstractionPattern origType, CanAnyFunctionType substInterfaceType, |
| SILExtInfoBuilder extInfoBuilder, Optional<SILDeclRef> origConstant, |
| Optional<SILDeclRef> constant, Optional<SubstitutionMap> reqtSubs, |
| ProtocolConformanceRef witnessMethodConformance) { |
| assert(bool(origConstant) == bool(constant)); |
| auto getSILFunctionTypeForConventions = |
| [&](const Conventions &convs) -> CanSILFunctionType { |
| return getSILFunctionType(TC, context, origType, substInterfaceType, |
| extInfoBuilder, convs, ForeignInfo(), |
| origConstant, constant, reqtSubs, |
| witnessMethodConformance); |
| }; |
| switch (extInfoBuilder.getRepresentation()) { |
| case SILFunctionType::Representation::Block: |
| case SILFunctionType::Representation::CFunctionPointer: |
| return getSILFunctionTypeForAbstractCFunction( |
| TC, origType, substInterfaceType, extInfoBuilder, constant); |
| |
| case SILFunctionType::Representation::Thin: |
| case SILFunctionType::Representation::ObjCMethod: |
| case SILFunctionType::Representation::Thick: |
| case SILFunctionType::Representation::Method: |
| case SILFunctionType::Representation::Closure: |
| case SILFunctionType::Representation::WitnessMethod: { |
| switch (constant ? constant->kind : SILDeclRef::Kind::Func) { |
| case SILDeclRef::Kind::Initializer: |
| case SILDeclRef::Kind::EnumElement: |
| return getSILFunctionTypeForConventions(DefaultInitializerConventions()); |
| case SILDeclRef::Kind::Allocator: |
| return getSILFunctionTypeForConventions(DefaultAllocatorConventions()); |
| case SILDeclRef::Kind::Func: { |
| // If we have a setter, use the special setter convention. This ensures |
| // that we take normal parameters at +1. |
| if (constant && constant->isSetter()) { |
| return getSILFunctionTypeForConventions(DefaultSetterConventions()); |
| } |
| return getSILFunctionTypeForConventions( |
| DefaultConventions(NormalParameterConvention::Guaranteed)); |
| } |
| case SILDeclRef::Kind::Destroyer: |
| case SILDeclRef::Kind::GlobalAccessor: |
| case SILDeclRef::Kind::DefaultArgGenerator: |
| case SILDeclRef::Kind::StoredPropertyInitializer: |
| case SILDeclRef::Kind::PropertyWrapperBackingInitializer: |
| case SILDeclRef::Kind::IVarInitializer: |
| case SILDeclRef::Kind::IVarDestroyer: |
| return getSILFunctionTypeForConventions( |
| DefaultConventions(NormalParameterConvention::Guaranteed)); |
| case SILDeclRef::Kind::Deallocator: |
| return getSILFunctionTypeForConventions(DeallocatorConventions()); |
| } |
| } |
| } |
| |
| llvm_unreachable("Unhandled SILDeclRefKind in switch."); |
| } |
| |
| CanSILFunctionType swift::getNativeSILFunctionType( |
| TypeConverter &TC, TypeExpansionContext context, |
| AbstractionPattern origType, CanAnyFunctionType substType, |
| SILExtInfo silExtInfo, Optional<SILDeclRef> origConstant, |
| Optional<SILDeclRef> substConstant, Optional<SubstitutionMap> reqtSubs, |
| ProtocolConformanceRef witnessMethodConformance) { |
| |
| return ::getNativeSILFunctionType( |
| TC, context, origType, substType, silExtInfo.intoBuilder(), origConstant, |
| substConstant, reqtSubs, witnessMethodConformance); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Foreign SILFunctionTypes |
| //===----------------------------------------------------------------------===// |
| |
| static bool isCFTypedef(const TypeLowering &tl, clang::QualType type) { |
| // If we imported a C pointer type as a non-trivial type, it was |
| // a foreign class type. |
| return !tl.isTrivial() && type->isPointerType(); |
| } |
| |
| /// Given nothing but a formal C parameter type that's passed |
| /// indirectly, deduce the convention for it. |
| /// |
| /// Generally, whether the parameter is +1 is handled before this. |
| static ParameterConvention getIndirectCParameterConvention(clang::QualType type) { |
| // Non-trivial C++ types would be Indirect_Inout (at least in Itanium). |
| // A trivial const * parameter in C should be considered @in. |
| return ParameterConvention::Indirect_In; |
| } |
| |
| /// Given a C parameter declaration whose type is passed indirectly, |
| /// deduce the convention for it. |
| /// |
| /// Generally, whether the parameter is +1 is handled before this. |
| static ParameterConvention |
| getIndirectCParameterConvention(const clang::ParmVarDecl *param) { |
| return getIndirectCParameterConvention(param->getType()); |
| } |
| |
| /// Given nothing but a formal C parameter type that's passed |
| /// directly, deduce the convention for it. |
| /// |
| /// Generally, whether the parameter is +1 is handled before this. |
| static ParameterConvention getDirectCParameterConvention(clang::QualType type) { |
| return ParameterConvention::Direct_Unowned; |
| } |
| |
| /// Given a C parameter declaration whose type is passed directly, |
| /// deduce the convention for it. |
| static ParameterConvention |
| getDirectCParameterConvention(const clang::ParmVarDecl *param) { |
| if (param->hasAttr<clang::NSConsumedAttr>() || |
| param->hasAttr<clang::CFConsumedAttr>()) |
| return ParameterConvention::Direct_Owned; |
| return getDirectCParameterConvention(param->getType()); |
| } |
| |
| // FIXME: that should be Direct_Guaranteed |
| const auto ObjCSelfConvention = ParameterConvention::Direct_Unowned; |
| |
| namespace { |
| |
| class ObjCMethodConventions : public Conventions { |
| const clang::ObjCMethodDecl *Method; |
| |
| public: |
| const clang::ObjCMethodDecl *getMethod() const { return Method; } |
| |
| ObjCMethodConventions(const clang::ObjCMethodDecl *method) |
| : Conventions(ConventionsKind::ObjCMethod), Method(method) {} |
| |
| ParameterConvention getIndirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const override { |
| return getIndirectCParameterConvention(Method->param_begin()[index]); |
| } |
| |
| ParameterConvention getDirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const override { |
| return getDirectCParameterConvention(Method->param_begin()[index]); |
| } |
| |
| ParameterConvention getCallee() const override { |
| // Always thin. |
| return ParameterConvention::Direct_Unowned; |
| } |
| |
| /// Given that a method returns a CF type, infer its method |
| /// family. Unfortunately, Clang's getMethodFamily() never |
| /// considers a method to be in a special family if its result |
| /// doesn't satisfy isObjCRetainable(). |
| clang::ObjCMethodFamily getMethodFamilyForCFResult() const { |
| // Trust an explicit attribute. |
| if (auto attr = Method->getAttr<clang::ObjCMethodFamilyAttr>()) { |
| switch (attr->getFamily()) { |
| case clang::ObjCMethodFamilyAttr::OMF_None: |
| return clang::OMF_None; |
| case clang::ObjCMethodFamilyAttr::OMF_alloc: |
| return clang::OMF_alloc; |
| case clang::ObjCMethodFamilyAttr::OMF_copy: |
| return clang::OMF_copy; |
| case clang::ObjCMethodFamilyAttr::OMF_init: |
| return clang::OMF_init; |
| case clang::ObjCMethodFamilyAttr::OMF_mutableCopy: |
| return clang::OMF_mutableCopy; |
| case clang::ObjCMethodFamilyAttr::OMF_new: |
| return clang::OMF_new; |
| } |
| llvm_unreachable("bad attribute value"); |
| } |
| |
| return Method->getSelector().getMethodFamily(); |
| } |
| |
| bool isImplicitPlusOneCFResult() const { |
| switch (getMethodFamilyForCFResult()) { |
| case clang::OMF_None: |
| case clang::OMF_dealloc: |
| case clang::OMF_finalize: |
| case clang::OMF_retain: |
| case clang::OMF_release: |
| case clang::OMF_autorelease: |
| case clang::OMF_retainCount: |
| case clang::OMF_self: |
| case clang::OMF_initialize: |
| case clang::OMF_performSelector: |
| return false; |
| |
| case clang::OMF_alloc: |
| case clang::OMF_new: |
| case clang::OMF_mutableCopy: |
| case clang::OMF_copy: |
| return true; |
| |
| case clang::OMF_init: |
| return Method->isInstanceMethod(); |
| } |
| llvm_unreachable("bad method family"); |
| } |
| |
| ResultConvention getResult(const TypeLowering &tl) const override { |
| // If we imported the result as something trivial, we need to |
| // use one of the unowned conventions. |
| if (tl.isTrivial()) { |
| if (Method->hasAttr<clang::ObjCReturnsInnerPointerAttr>()) |
| return ResultConvention::UnownedInnerPointer; |
| |
| auto type = tl.getLoweredType(); |
| if (type.unwrapOptionalType().getStructOrBoundGenericStruct() |
| == type.getASTContext().getUnmanagedDecl()) |
| return ResultConvention::UnownedInnerPointer; |
| return ResultConvention::Unowned; |
| } |
| |
| // Otherwise, the return type had better be a retainable object pointer. |
| auto resultType = Method->getReturnType(); |
| assert(resultType->isObjCRetainableType() || isCFTypedef(tl, resultType)); |
| |
| // If it's retainable for the purposes of ObjC ARC, we can trust |
| // the presence of ns_returns_retained, because Clang will add |
| // that implicitly based on the method family. |
| if (resultType->isObjCRetainableType()) { |
| if (Method->hasAttr<clang::NSReturnsRetainedAttr>()) |
| return ResultConvention::Owned; |
| return ResultConvention::Autoreleased; |
| } |
| |
| // Otherwise, it's a CF return type, which unfortunately means |
| // we can't just trust getMethodFamily(). We should really just |
| // change that, but that's an annoying change to make to Clang |
| // right now. |
| assert(isCFTypedef(tl, resultType)); |
| |
| // Trust the explicit attributes. |
| if (Method->hasAttr<clang::CFReturnsRetainedAttr>()) |
| return ResultConvention::Owned; |
| if (Method->hasAttr<clang::CFReturnsNotRetainedAttr>()) |
| return ResultConvention::Autoreleased; |
| |
| // Otherwise, infer based on the method family. |
| if (isImplicitPlusOneCFResult()) |
| return ResultConvention::Owned; |
| return ResultConvention::Autoreleased; |
| } |
| |
| ParameterConvention |
| getDirectSelfParameter(const AbstractionPattern &type) const override { |
| if (Method->hasAttr<clang::NSConsumesSelfAttr>()) |
| return ParameterConvention::Direct_Owned; |
| |
| // The caller is supposed to take responsibility for ensuring |
| // that 'self' survives a method call. |
| return ObjCSelfConvention; |
| } |
| |
| ParameterConvention |
| getIndirectSelfParameter(const AbstractionPattern &type) const override { |
| llvm_unreachable("objc methods do not support indirect self parameters"); |
| } |
| |
| static bool classof(const Conventions *C) { |
| return C->getKind() == ConventionsKind::ObjCMethod; |
| } |
| }; |
| |
| /// Conventions based on a C function type. |
| class CFunctionTypeConventions : public Conventions { |
| const clang::FunctionType *FnType; |
| |
| clang::QualType getParamType(unsigned i) const { |
| return FnType->castAs<clang::FunctionProtoType>()->getParamType(i); |
| } |
| |
| protected: |
| /// Protected constructor for subclasses to override the kind passed to the |
| /// super class. |
| CFunctionTypeConventions(ConventionsKind kind, |
| const clang::FunctionType *type) |
| : Conventions(kind), FnType(type) {} |
| |
| public: |
| CFunctionTypeConventions(const clang::FunctionType *type) |
| : Conventions(ConventionsKind::CFunctionType), FnType(type) {} |
| |
| ParameterConvention getIndirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const override { |
| return getIndirectCParameterConvention(getParamType(index)); |
| } |
| |
| ParameterConvention getDirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const override { |
| if (cast<clang::FunctionProtoType>(FnType)->isParamConsumed(index)) |
| return ParameterConvention::Direct_Owned; |
| return getDirectCParameterConvention(getParamType(index)); |
| } |
| |
| ParameterConvention getCallee() const override { |
| // FIXME: blocks should be Direct_Guaranteed. |
| return ParameterConvention::Direct_Unowned; |
| } |
| |
| ResultConvention getResult(const TypeLowering &tl) const override { |
| if (tl.isTrivial()) |
| return ResultConvention::Unowned; |
| if (FnType->getExtInfo().getProducesResult()) |
| return ResultConvention::Owned; |
| return ResultConvention::Autoreleased; |
| } |
| |
| ParameterConvention |
| getDirectSelfParameter(const AbstractionPattern &type) const override { |
| llvm_unreachable("c function types do not have a self parameter"); |
| } |
| |
| ParameterConvention |
| getIndirectSelfParameter(const AbstractionPattern &type) const override { |
| llvm_unreachable("c function types do not have a self parameter"); |
| } |
| |
| static bool classof(const Conventions *C) { |
| return C->getKind() == ConventionsKind::CFunctionType; |
| } |
| }; |
| |
| /// Conventions based on C function declarations. |
| class CFunctionConventions : public CFunctionTypeConventions { |
| using super = CFunctionTypeConventions; |
| const clang::FunctionDecl *TheDecl; |
| public: |
| CFunctionConventions(const clang::FunctionDecl *decl) |
| : CFunctionTypeConventions(ConventionsKind::CFunction, |
| decl->getType()->castAs<clang::FunctionType>()), |
| TheDecl(decl) {} |
| |
| ParameterConvention getDirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const override { |
| if (auto param = TheDecl->getParamDecl(index)) |
| if (param->hasAttr<clang::CFConsumedAttr>()) |
| return ParameterConvention::Direct_Owned; |
| return super::getDirectParameter(index, type, substTL); |
| } |
| |
| ResultConvention getResult(const TypeLowering &tl) const override { |
| if (isCFTypedef(tl, TheDecl->getReturnType())) { |
| // The CF attributes aren't represented in the type, so we need |
| // to check them here. |
| if (TheDecl->hasAttr<clang::CFReturnsRetainedAttr>()) { |
| return ResultConvention::Owned; |
| } else if (TheDecl->hasAttr<clang::CFReturnsNotRetainedAttr>()) { |
| // Probably not actually autoreleased. |
| return ResultConvention::Autoreleased; |
| |
| // The CF Create/Copy rule only applies to functions that return |
| // a CF-runtime type; it does not apply to methods, and it does |
| // not apply to functions returning ObjC types. |
| } else if (clang::ento::coreFoundation::followsCreateRule(TheDecl)) { |
| return ResultConvention::Owned; |
| } else { |
| return ResultConvention::Autoreleased; |
| } |
| } |
| |
| // Otherwise, fall back on the ARC annotations, which are part |
| // of the type. |
| return super::getResult(tl); |
| } |
| |
| static bool classof(const Conventions *C) { |
| return C->getKind() == ConventionsKind::CFunction; |
| } |
| }; |
| |
| /// Conventions based on C++ method declarations. |
| class CXXMethodConventions : public CFunctionTypeConventions { |
| using super = CFunctionTypeConventions; |
| const clang::CXXMethodDecl *TheDecl; |
| |
| public: |
| CXXMethodConventions(const clang::CXXMethodDecl *decl) |
| : CFunctionTypeConventions( |
| ConventionsKind::CXXMethod, |
| decl->getType()->castAs<clang::FunctionType>()), |
| TheDecl(decl) {} |
| ParameterConvention |
| getIndirectSelfParameter(const AbstractionPattern &type) const override { |
| if (TheDecl->isConst()) |
| return ParameterConvention::Indirect_In_Guaranteed; |
| return ParameterConvention::Indirect_Inout; |
| } |
| ResultConvention getResult(const TypeLowering &resultTL) const override { |
| if (isa<clang::CXXConstructorDecl>(TheDecl)) { |
| // Represent the `this` pointer as an indirectly returned result. |
| // This gets us most of the way towards representing the ABI of a |
| // constructor correctly, but it's not guaranteed to be entirely correct. |
| // C++ constructor ABIs are complicated and can require passing additional |
| // "implicit" arguments that depend not only on the signature of the |
| // constructor but on the class on which it's defined (e.g. whether that |
| // class has a virtual base class). |
| // Effectively, we're making an assumption here that there are no implicit |
| // arguments and that the return type of the constructor ABI is void (and |
| // indeed we have no way to represent anything else here). If this assumed |
| // ABI doesn't match the actual ABI, we insert a thunk in IRGen. On some |
| // ABIs (e.g. Itanium x64), we get lucky and the ABI for a complete |
| // constructor call always matches the ABI we assume here. Even if the |
| // actual ABI doesn't match the assumed ABI, we try to get as close as |
| // possible to make it easy for LLVM to optimize away the thunk. |
| return ResultConvention::Indirect; |
| } |
| return CFunctionTypeConventions::getResult(resultTL); |
| } |
| static bool classof(const Conventions *C) { |
| return C->getKind() == ConventionsKind::CXXMethod; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| /// Given that we have an imported Clang declaration, deduce the |
| /// ownership conventions for calling it and build the SILFunctionType. |
| static CanSILFunctionType getSILFunctionTypeForClangDecl( |
| TypeConverter &TC, const clang::Decl *clangDecl, |
| CanAnyFunctionType origType, CanAnyFunctionType substInterfaceType, |
| SILExtInfoBuilder extInfoBuilder, const ForeignInfo &foreignInfo, |
| Optional<SILDeclRef> constant) { |
| if (auto method = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) { |
| auto origPattern = |
| AbstractionPattern::getObjCMethod(origType, method, |
| foreignInfo.Error, |
| foreignInfo.Async); |
| return getSILFunctionType( |
| TC, TypeExpansionContext::minimal(), origPattern, substInterfaceType, |
| extInfoBuilder, ObjCMethodConventions(method), foreignInfo, constant, |
| constant, None, ProtocolConformanceRef()); |
| } |
| |
| if (auto method = dyn_cast<clang::CXXMethodDecl>(clangDecl)) { |
| AbstractionPattern origPattern = method->isOverloadedOperator() ? |
| AbstractionPattern::getCXXOperatorMethod(origType, method): |
| AbstractionPattern::getCXXMethod(origType, method); |
| auto conventions = CXXMethodConventions(method); |
| return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, |
| substInterfaceType, extInfoBuilder, conventions, |
| foreignInfo, constant, constant, None, |
| ProtocolConformanceRef()); |
| } |
| |
| if (auto func = dyn_cast<clang::FunctionDecl>(clangDecl)) { |
| auto clangType = func->getType().getTypePtr(); |
| AbstractionPattern origPattern = |
| foreignInfo.Self.isImportAsMember() |
| ? AbstractionPattern::getCFunctionAsMethod(origType, clangType, |
| foreignInfo.Self) |
| : AbstractionPattern(origType, clangType); |
| return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, |
| substInterfaceType, extInfoBuilder, |
| CFunctionConventions(func), foreignInfo, constant, |
| constant, None, ProtocolConformanceRef()); |
| } |
| |
| llvm_unreachable("call to unknown kind of C function"); |
| } |
| |
| static CanSILFunctionType getSILFunctionTypeForAbstractCFunction( |
| TypeConverter &TC, AbstractionPattern origType, |
| CanAnyFunctionType substType, SILExtInfoBuilder extInfoBuilder, |
| Optional<SILDeclRef> constant) { |
| if (origType.isClangType()) { |
| auto clangType = origType.getClangType(); |
| const clang::FunctionType *fnType; |
| if (auto blockPtr = clangType->getAs<clang::BlockPointerType>()) { |
| fnType = blockPtr->getPointeeType()->castAs<clang::FunctionType>(); |
| } else if (auto ptr = clangType->getAs<clang::PointerType>()) { |
| fnType = ptr->getPointeeType()->getAs<clang::FunctionType>(); |
| } else if (auto ref = clangType->getAs<clang::ReferenceType>()) { |
| fnType = ref->getPointeeType()->getAs<clang::FunctionType>(); |
| } else if (auto fn = clangType->getAs<clang::FunctionType>()) { |
| fnType = fn; |
| } else { |
| llvm_unreachable("unexpected type imported as a function type"); |
| } |
| if (fnType) { |
| return getSILFunctionType( |
| TC, TypeExpansionContext::minimal(), origType, substType, |
| extInfoBuilder, CFunctionTypeConventions(fnType), ForeignInfo(), |
| constant, constant, None, ProtocolConformanceRef()); |
| } |
| } |
| |
| // TODO: Ought to support captures in block funcs. |
| return getSILFunctionType(TC, TypeExpansionContext::minimal(), origType, |
| substType, extInfoBuilder, |
| DefaultBlockConventions(), ForeignInfo(), constant, |
| constant, None, ProtocolConformanceRef()); |
| } |
| |
| /// Try to find a clang method declaration for the given function. |
| static const clang::Decl *findClangMethod(ValueDecl *method) { |
| if (auto *methodFn = dyn_cast<FuncDecl>(method)) { |
| if (auto *decl = methodFn->getClangDecl()) |
| return decl; |
| |
| if (auto overridden = methodFn->getOverriddenDecl()) |
| return findClangMethod(overridden); |
| } |
| |
| if (auto *constructor = dyn_cast<ConstructorDecl>(method)) { |
| if (auto *decl = constructor->getClangDecl()) |
| return decl; |
| } |
| |
| return nullptr; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Selector Family SILFunctionTypes |
| //===----------------------------------------------------------------------===// |
| |
| /// Derive the ObjC selector family from an identifier. |
| /// |
| /// Note that this will never derive the Init family, which is too dangerous |
| /// to leave to chance. Swift functions starting with "init" are always |
| /// emitted as if they are part of the "none" family. |
| static ObjCSelectorFamily getObjCSelectorFamily(ObjCSelector name) { |
| auto result = name.getSelectorFamily(); |
| |
| if (result == ObjCSelectorFamily::Init) |
| return ObjCSelectorFamily::None; |
| |
| return result; |
| } |
| |
| /// Get the ObjC selector family a foreign SILDeclRef belongs to. |
| static ObjCSelectorFamily getObjCSelectorFamily(SILDeclRef c) { |
| assert(c.isForeign); |
| switch (c.kind) { |
| case SILDeclRef::Kind::Func: { |
| if (!c.hasDecl()) |
| return ObjCSelectorFamily::None; |
| |
| auto *FD = cast<FuncDecl>(c.getDecl()); |
| if (auto accessor = dyn_cast<AccessorDecl>(FD)) { |
| switch (accessor->getAccessorKind()) { |
| case AccessorKind::Get: |
| case AccessorKind::Set: |
| break; |
| #define OBJC_ACCESSOR(ID, KEYWORD) |
| #define ACCESSOR(ID) \ |
| case AccessorKind::ID: |
| #include "swift/AST/AccessorKinds.def" |
| llvm_unreachable("Unexpected AccessorKind of foreign FuncDecl"); |
| } |
| } |
| |
| return getObjCSelectorFamily(FD->getObjCSelector()); |
| } |
| case SILDeclRef::Kind::Initializer: |
| case SILDeclRef::Kind::IVarInitializer: |
| return ObjCSelectorFamily::Init; |
| |
| /// Currently IRGen wraps alloc/init methods into Swift constructors |
| /// with Swift conventions. |
| case SILDeclRef::Kind::Allocator: |
| /// These constants don't correspond to method families we care about yet. |
| case SILDeclRef::Kind::Destroyer: |
| case SILDeclRef::Kind::Deallocator: |
| case SILDeclRef::Kind::IVarDestroyer: |
| return ObjCSelectorFamily::None; |
| |
| case SILDeclRef::Kind::EnumElement: |
| case SILDeclRef::Kind::GlobalAccessor: |
| case SILDeclRef::Kind::DefaultArgGenerator: |
| case SILDeclRef::Kind::StoredPropertyInitializer: |
| case SILDeclRef::Kind::PropertyWrapperBackingInitializer: |
| llvm_unreachable("Unexpected Kind of foreign SILDeclRef"); |
| } |
| |
| llvm_unreachable("Unhandled SILDeclRefKind in switch."); |
| } |
| |
| namespace { |
| |
| class ObjCSelectorFamilyConventions : public Conventions { |
| ObjCSelectorFamily Family; |
| |
| public: |
| ObjCSelectorFamilyConventions(ObjCSelectorFamily family) |
| : Conventions(ConventionsKind::ObjCSelectorFamily), Family(family) {} |
| |
| ParameterConvention getIndirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const override { |
| return ParameterConvention::Indirect_In; |
| } |
| |
| ParameterConvention getDirectParameter(unsigned index, |
| const AbstractionPattern &type, |
| const TypeLowering &substTL) const override { |
| return ParameterConvention::Direct_Unowned; |
| } |
| |
| ParameterConvention getCallee() const override { |
| // Always thin. |
| return ParameterConvention::Direct_Unowned; |
| } |
| |
| ResultConvention getResult(const TypeLowering &tl) const override { |
| switch (Family) { |
| case ObjCSelectorFamily::Alloc: |
| case ObjCSelectorFamily::Copy: |
| case ObjCSelectorFamily::Init: |
| case ObjCSelectorFamily::MutableCopy: |
| case ObjCSelectorFamily::New: |
| return ResultConvention::Owned; |
| |
| case ObjCSelectorFamily::None: |
| // Defaults below. |
| break; |
| } |
| |
| // Get the underlying AST type, potentially stripping off one level of |
| // optionality while we do it. |
| CanType type = tl.getLoweredType().unwrapOptionalType().getASTType(); |
| if (type->hasRetainablePointerRepresentation() |
| || (type->getSwiftNewtypeUnderlyingType() && !tl.isTrivial())) |
| return ResultConvention::Autoreleased; |
| |
| return ResultConvention::Unowned; |
| } |
| |
| ParameterConvention |
| getDirectSelfParameter(const AbstractionPattern &type) const override { |
| if (Family == ObjCSelectorFamily::Init) |
| return ParameterConvention::Direct_Owned; |
| return ObjCSelfConvention; |
| } |
| |
| ParameterConvention |
| getIndirectSelfParameter(const AbstractionPattern &type) const override { |
| llvm_unreachable("selector family objc function types do not support " |
| "indirect self parameters"); |
| } |
| |
| static bool classof(const Conventions *C) { |
| return C->getKind() == ConventionsKind::ObjCSelectorFamily; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| static CanSILFunctionType getSILFunctionTypeForObjCSelectorFamily( |
| TypeConverter &TC, ObjCSelectorFamily family, CanAnyFunctionType origType, |
| CanAnyFunctionType substInterfaceType, SILExtInfoBuilder extInfoBuilder, |
| const ForeignInfo &foreignInfo, Optional<SILDeclRef> constant) { |
| return getSILFunctionType( |
| TC, TypeExpansionContext::minimal(), AbstractionPattern(origType), |
| substInterfaceType, extInfoBuilder, ObjCSelectorFamilyConventions(family), |
| foreignInfo, constant, constant, |
| /*requirement subs*/ None, ProtocolConformanceRef()); |
| } |
| |
| static bool isImporterGeneratedAccessor(const clang::Decl *clangDecl, |
| SILDeclRef constant) { |
| // Must be an accessor. |
| auto accessor = dyn_cast<AccessorDecl>(constant.getDecl()); |
| if (!accessor) |
| return false; |
| |
| // Must be a type member. |
| if (constant.getParameterListCount() != 2) |
| return false; |
| |
| // Must be imported from a function. |
| if (!isa<clang::FunctionDecl>(clangDecl)) |
| return false; |
| |
| return true; |
| } |
| |
| static CanSILFunctionType getUncachedSILFunctionTypeForConstant( |
| TypeConverter &TC, TypeExpansionContext context, SILDeclRef constant, |
| TypeConverter::LoweredFormalTypes bridgedTypes) { |
| auto silRep = TC.getDeclRefRepresentation(constant); |
| assert(silRep != SILFunctionTypeRepresentation::Thick && |
| silRep != SILFunctionTypeRepresentation::Block); |
| |
| auto origLoweredInterfaceType = bridgedTypes.Uncurried; |
| auto extInfo = origLoweredInterfaceType->getExtInfo(); |
| |
| auto extInfoBuilder = |
| SILExtInfo(extInfo, false).intoBuilder().withRepresentation(silRep); |
| |
| if (shouldStoreClangType(silRep)) { |
| const clang::Type *clangType = nullptr; |
| if (bridgedTypes.Pattern.isClangType()) { |
| clangType = bridgedTypes.Pattern.getClangType(); |
| } |
| if (clangType) { |
| // According to [NOTE: ClangTypeInfo-contents], we need to wrap a function |
| // type in an additional clang::PointerType. |
| if (clangType->isFunctionType()) { |
| clangType = |
| static_cast<ClangImporter *>(TC.Context.getClangModuleLoader()) |
| ->getClangASTContext() |
| .getPointerType(clang::QualType(clangType, 0)) |
| .getTypePtr(); |
| } |
| extInfoBuilder = extInfoBuilder.withClangFunctionType(clangType); |
| } |
| } |
| |
| if (!constant.isForeign) { |
| ProtocolConformanceRef witnessMethodConformance; |
| |
| if (silRep == SILFunctionTypeRepresentation::WitnessMethod) { |
| auto proto = constant.getDecl()->getDeclContext()->getSelfProtocolDecl(); |
| witnessMethodConformance = ProtocolConformanceRef(proto); |
| } |
| |
| return ::getNativeSILFunctionType( |
| TC, context, AbstractionPattern(origLoweredInterfaceType), |
| origLoweredInterfaceType, extInfoBuilder, constant, constant, None, |
| witnessMethodConformance); |
| } |
| |
| ForeignInfo foreignInfo; |
| |
| // If we have a clang decl associated with the Swift decl, derive its |
| // ownership conventions. |
| if (constant.hasDecl()) { |
| auto decl = constant.getDecl(); |
| if (auto funcDecl = dyn_cast<AbstractFunctionDecl>(decl)) { |
| foreignInfo = ForeignInfo{ |
| funcDecl->getImportAsMemberStatus(), |
| funcDecl->getForeignErrorConvention(), |
| funcDecl->getForeignAsyncConvention(), |
| }; |
| } |
| |
| if (auto clangDecl = findClangMethod(decl)) { |
| // The importer generates accessors that are not actually |
| // import-as-member but do involve the same gymnastics with the |
| // formal type. That's all that SILFunctionType cares about, so |
| // pretend that it's import-as-member. |
| if (!foreignInfo.Self.isImportAsMember() && |
| isImporterGeneratedAccessor(clangDecl, constant)) { |
| unsigned selfIndex = cast<AccessorDecl>(decl)->isSetter() ? 1 : 0; |
| foreignInfo.Self.setSelfIndex(selfIndex); |
| } |
| |
| return getSILFunctionTypeForClangDecl( |
| TC, clangDecl, origLoweredInterfaceType, origLoweredInterfaceType, |
| extInfoBuilder, foreignInfo, constant); |
| } |
| } |
| |
| // If the decl belongs to an ObjC method family, use that family's |
| // ownership conventions. |
| return getSILFunctionTypeForObjCSelectorFamily( |
| TC, getObjCSelectorFamily(constant), origLoweredInterfaceType, |
| origLoweredInterfaceType, extInfoBuilder, foreignInfo, constant); |
| } |
| |
| CanSILFunctionType TypeConverter::getUncachedSILFunctionTypeForConstant( |
| TypeExpansionContext context, SILDeclRef constant, |
| CanAnyFunctionType origInterfaceType) { |
| auto bridgedTypes = getLoweredFormalTypes(constant, origInterfaceType); |
| return ::getUncachedSILFunctionTypeForConstant(*this, context, constant, |
| bridgedTypes); |
| } |
| |
| static bool isClassOrProtocolMethod(ValueDecl *vd) { |
| if (!vd->getDeclContext()) |
| return false; |
| Type contextType = vd->getDeclContext()->getDeclaredInterfaceType(); |
| if (!contextType) |
| return false; |
| return contextType->getClassOrBoundGenericClass() |
| || contextType->isClassExistentialType(); |
| } |
| |
| SILFunctionTypeRepresentation |
| TypeConverter::getDeclRefRepresentation(SILDeclRef c) { |
| // If this is a foreign thunk, it always has the foreign calling convention. |
| if (c.isForeign) { |
| if (!c.hasDecl() || |
| c.getDecl()->isImportAsMember()) |
| return SILFunctionTypeRepresentation::CFunctionPointer; |
| |
| if (isClassOrProtocolMethod(c.getDecl()) || |
| c.kind == SILDeclRef::Kind::IVarInitializer || |
| c.kind == SILDeclRef::Kind::IVarDestroyer) |
| return SILFunctionTypeRepresentation::ObjCMethod; |
| |
| return SILFunctionTypeRepresentation::CFunctionPointer; |
| } |
| |
| // Anonymous functions currently always have Freestanding CC. |
| if (!c.hasDecl()) |
| return SILFunctionTypeRepresentation::Thin; |
| |
| // FIXME: Assert that there is a native entry point |
| // available. There's no great way to do this. |
| |
| // Protocol witnesses are called using the witness calling convention. |
| if (auto proto = dyn_cast<ProtocolDecl>(c.getDecl()->getDeclContext())) { |
| // Use the regular method convention for foreign-to-native thunks. |
| if (c.isForeignToNativeThunk()) |
| return SILFunctionTypeRepresentation::Method; |
| assert(!c.isNativeToForeignThunk() && "shouldn't be possible"); |
| return getProtocolWitnessRepresentation(proto); |
| } |
| |
| switch (c.kind) { |
| case SILDeclRef::Kind::GlobalAccessor: |
| case SILDeclRef::Kind::DefaultArgGenerator: |
| case SILDeclRef::Kind::StoredPropertyInitializer: |
| case SILDeclRef::Kind::PropertyWrapperBackingInitializer: |
| return SILFunctionTypeRepresentation::Thin; |
| |
| case SILDeclRef::Kind::Func: |
| if (c.getDecl()->getDeclContext()->isTypeContext()) |
| return SILFunctionTypeRepresentation::Method; |
| return SILFunctionTypeRepresentation::Thin; |
| |
| case SILDeclRef::Kind::Destroyer: |
| case SILDeclRef::Kind::Deallocator: |
| case SILDeclRef::Kind::Allocator: |
| case SILDeclRef::Kind::Initializer: |
| case SILDeclRef::Kind::EnumElement: |
| case SILDeclRef::Kind::IVarInitializer: |
| case SILDeclRef::Kind::IVarDestroyer: |
| return SILFunctionTypeRepresentation::Method; |
| } |
| |
| llvm_unreachable("Unhandled SILDeclRefKind in switch."); |
| } |
| |
| // Provide the ability to turn off the type converter cache to ease debugging. |
| static llvm::cl::opt<bool> |
| DisableConstantInfoCache("sil-disable-typelowering-constantinfo-cache", |
| llvm::cl::init(false)); |
| |
| const SILConstantInfo & |
| TypeConverter::getConstantInfo(TypeExpansionContext expansion, |
| SILDeclRef constant) { |
| if (!DisableConstantInfoCache) { |
| auto found = ConstantTypes.find(std::make_pair(expansion, constant)); |
| if (found != ConstantTypes.end()) |
| return *found->second; |
| } |
| |
| // First, get a function type for the constant. This creates the |
| // right type for a getter or setter. |
| auto formalInterfaceType = makeConstantInterfaceType(constant); |
| |
| // The lowered type is the formal type, but uncurried and with |
| // parameters automatically turned into their bridged equivalents. |
| auto bridgedTypes = getLoweredFormalTypes(constant, formalInterfaceType); |
| |
| CanAnyFunctionType loweredInterfaceType = bridgedTypes.Uncurried; |
| |
| // The SIL type encodes conventions according to the original type. |
| CanSILFunctionType silFnType = ::getUncachedSILFunctionTypeForConstant( |
| *this, expansion, constant, bridgedTypes); |
| |
| // If the constant refers to a derivative function, get the SIL type of the |
| // original function and use it to compute the derivative SIL type. |
| // |
| // This is necessary because the "lowered AST derivative function type" (bc) |
| // may differ from the "derivative type of the lowered original function type" |
| // (ad): |
| // |
| // ┌────────────────────┐ lowering ┌────────────────────┐ |
| // │ AST orig. fn type │ ───────(a)──────► │ SIL orig. fn type │ |
| // └────────────────────┘ └────────────────────┘ |
| // │ │ |
| // (b, Sema) getAutoDiffDerivativeFunctionType (d, here) |
| // │ │ |
| // ▼ ▼ |
| // ┌────────────────────┐ lowering ┌────────────────────┐ |
| // │ AST deriv. fn type │ ───────(c)──────► │ SIL deriv. fn type │ |
| // └────────────────────┘ └────────────────────┘ |
| // |
| // (ad) does not always commute with (bc): |
| // - (bc) is the result of computing the AST derivative type (Sema), then |
| // lowering it via SILGen. This is the default lowering behavior, but may |
| // break SIL typing invariants because expected lowered derivative types are |
| // computed from lowered original function types. |
| // - (ad) is the result of lowering the original function type, then computing |
| // its derivative type. This is the expected lowered derivative type, |
| // preserving SIL typing invariants. |
| // |
| // Always use (ad) to compute lowered derivative function types. |
| if (auto *derivativeId = constant.getDerivativeFunctionIdentifier()) { |
| // Get lowered original function type. |
| auto origFnConstantInfo = getConstantInfo( |
| TypeExpansionContext::minimal(), constant.asAutoDiffOriginalFunction()); |
| // Use it to compute lowered derivative function type. |
| auto *loweredParamIndices = autodiff::getLoweredParameterIndices( |
| derivativeId->getParameterIndices(), formalInterfaceType); |
| auto numResults = |
| origFnConstantInfo.SILFnType->getNumResults() + |
| origFnConstantInfo.SILFnType->getNumIndirectMutatingParameters(); |
| auto *loweredResultIndices = IndexSubset::getDefault( |
| M.getASTContext(), numResults, /*includeAll*/ true); |
| silFnType = origFnConstantInfo.SILFnType->getAutoDiffDerivativeFunctionType( |
| loweredParamIndices, loweredResultIndices, derivativeId->getKind(), |
| *this, LookUpConformanceInModule(&M)); |
| } |
| |
| LLVM_DEBUG(llvm::dbgs() << "lowering type for constant "; |
| constant.print(llvm::dbgs()); |
| llvm::dbgs() << "\n formal type: "; |
| formalInterfaceType.print(llvm::dbgs()); |
| llvm::dbgs() << "\n lowered AST type: "; |
| loweredInterfaceType.print(llvm::dbgs()); |
| llvm::dbgs() << "\n SIL type: "; |
| silFnType.print(llvm::dbgs()); |
| llvm::dbgs() << "\n Expansion context: " |
| << expansion.shouldLookThroughOpaqueTypeArchetypes(); |
| llvm::dbgs() << "\n"); |
| |
| auto resultBuf = Context.Allocate(sizeof(SILConstantInfo), |
| alignof(SILConstantInfo)); |
| |
| auto result = ::new (resultBuf) SILConstantInfo{formalInterfaceType, |
| bridgedTypes.Pattern, |
| loweredInterfaceType, |
| silFnType}; |
| if (DisableConstantInfoCache) |
| return *result; |
| |
| auto inserted = |
| ConstantTypes.insert({std::make_pair(expansion, constant), result}); |
| assert(inserted.second); |
| (void)inserted; |
| return *result; |
| } |
| |
| /// Returns the SILParameterInfo for the given declaration's `self` parameter. |
| /// `constant` must refer to a method. |
| SILParameterInfo |
| TypeConverter::getConstantSelfParameter(TypeExpansionContext context, |
| SILDeclRef constant) { |
| auto ty = getConstantFunctionType(context, constant); |
| |
| // In most cases the "self" parameter is lowered as the back parameter. |
| // The exception is C functions imported as methods. |
| if (!constant.isForeign) |
| return ty->getParameters().back(); |
| if (!constant.hasDecl()) |
| return ty->getParameters().back(); |
| auto fn = dyn_cast<AbstractFunctionDecl>(constant.getDecl()); |
| if (!fn) |
| return ty->getParameters().back(); |
| if (fn->isImportAsStaticMember()) |
| return SILParameterInfo(); |
| if (fn->isImportAsInstanceMember()) |
| return ty->getParameters()[fn->getSelfIndex()]; |
| return ty->getParameters().back(); |
| } |
| |
| // This check duplicates TypeConverter::checkForABIDifferences(), |
| // but on AST types. The issue is we only want to introduce a new |
| // vtable thunk if the AST type changes, but an abstraction change |
| // is OK; we don't want a new entry if an @in parameter became |
| // @guaranteed or whatever. |
| static bool checkASTTypeForABIDifferences(CanType type1, |
| CanType type2) { |
| return !type1->matches(type2, TypeMatchFlags::AllowABICompatible); |
| } |
| |
| // FIXME: This makes me very upset. Can we do without this? |
| static CanType copyOptionalityFromDerivedToBase(TypeConverter &tc, |
| CanType derived, |
| CanType base) { |
| // Unwrap optionals, but remember that we did. |
| bool derivedWasOptional = false; |
| if (auto object = derived.getOptionalObjectType()) { |
| derivedWasOptional = true; |
| derived = object; |
| } |
| if (auto object = base.getOptionalObjectType()) { |
| base = object; |
| } |
| |
| // T? +> S = (T +> S)? |
| // T? +> S? = (T +> S)? |
| if (derivedWasOptional) { |
| base = copyOptionalityFromDerivedToBase(tc, derived, base); |
| |
| auto optDecl = tc.Context.getOptionalDecl(); |
| return CanType(BoundGenericEnumType::get(optDecl, Type(), base)); |
| } |
| |
| // (T1, T2, ...) +> (S1, S2, ...) = (T1 +> S1, T2 +> S2, ...) |
| if (auto derivedTuple = dyn_cast<TupleType>(derived)) { |
| if (auto baseTuple = dyn_cast<TupleType>(base)) { |
| assert(derivedTuple->getNumElements() == baseTuple->getNumElements()); |
| SmallVector<TupleTypeElt, 4> elements; |
| for (unsigned i = 0, e = derivedTuple->getNumElements(); i < e; i++) { |
| elements.push_back( |
| baseTuple->getElement(i).getWithType( |
| copyOptionalityFromDerivedToBase( |
| tc, |
| derivedTuple.getElementType(i), |
| baseTuple.getElementType(i)))); |
| } |
| return CanType(TupleType::get(elements, tc.Context)); |
| } |
| } |
| |
| // (T1 -> T2) +> (S1 -> S2) = (T1 +> S1) -> (T2 +> S2) |
| if (auto derivedFunc = dyn_cast<AnyFunctionType>(derived)) { |
| if (auto baseFunc = dyn_cast<AnyFunctionType>(base)) { |
| SmallVector<FunctionType::Param, 8> params; |
| |
| auto derivedParams = derivedFunc.getParams(); |
| auto baseParams = baseFunc.getParams(); |
| assert(derivedParams.size() == baseParams.size()); |
| for (unsigned i = 0, e = derivedParams.size(); i < e; ++i) { |
| assert(derivedParams[i].getParameterFlags() == |
| baseParams[i].getParameterFlags()); |
| |
| params.emplace_back( |
| copyOptionalityFromDerivedToBase( |
| tc, |
| derivedParams[i].getPlainType(), |
| baseParams[i].getPlainType()), |
| Identifier(), |
| baseParams[i].getParameterFlags()); |
| } |
| |
| auto result = copyOptionalityFromDerivedToBase(tc, |
| derivedFunc.getResult(), |
| baseFunc.getResult()); |
| return CanAnyFunctionType::get(baseFunc.getOptGenericSignature(), |
| llvm::makeArrayRef(params), result, |
| baseFunc->getExtInfo()); |
| } |
| } |
| |
| return base; |
| } |
| |
| /// Returns the ConstantInfo corresponding to the VTable thunk for overriding. |
| /// Will be the same as getConstantInfo if the declaration does not override. |
| const SILConstantInfo & |
| TypeConverter::getConstantOverrideInfo(TypeExpansionContext context, |
| SILDeclRef derived, SILDeclRef base) { |
| // Foreign overrides currently don't need reabstraction. |
| if (derived.isForeign) |
| return getConstantInfo(context, derived); |
| |
| auto found = ConstantOverrideTypes.find({derived, base}); |
| if (found != ConstantOverrideTypes.end()) |
| return *found->second; |
| |
| assert(base.requiresNewVTableEntry() && "base must not be an override"); |
| |
| // Figure out the generic signature for the class method call. This is the |
| // signature of the derived class, with requirements transplanted from |
| // the base method. The derived method is allowed to have fewer |
| // requirements, in which case the thunk will translate the calling |
| // convention appropriately before calling the derived method. |
| bool hasGenericRequirementDifference = false; |
| |
| auto derivedSig = derived.getDecl()->getAsGenericContext() |
| ->getGenericSignature(); |
| auto genericSig = Context.getOverrideGenericSignature(base.getDecl(), |
| derived.getDecl()); |
| if (genericSig) { |
| hasGenericRequirementDifference = |
| !genericSig->requirementsNotSatisfiedBy(derivedSig).empty(); |
| } |
| |
| auto baseInfo = getConstantInfo(context, base); |
| auto derivedInfo = getConstantInfo(context, derived); |
| |
| auto params = derivedInfo.FormalType.getParams(); |
| assert(params.size() == 1); |
| auto selfInterfaceTy = params[0].getPlainType()->getMetatypeInstanceType(); |
| |
| auto overrideInterfaceTy = |
| cast<AnyFunctionType>( |
| selfInterfaceTy->adjustSuperclassMemberDeclType( |
| base.getDecl(), derived.getDecl(), baseInfo.FormalType) |
| ->getCanonicalType()); |
| |
| // Build the formal AST function type for the class method call. |
| auto basePattern = AbstractionPattern(baseInfo.LoweredType); |
| |
| if (!hasGenericRequirementDifference && |
| !checkASTTypeForABIDifferences(derivedInfo.FormalType, |
| overrideInterfaceTy)) { |
| |
| // The derived method is ABI-compatible with the base method. Let's |
| // just use the derived method's formal type. |
| basePattern = AbstractionPattern( |
| copyOptionalityFromDerivedToBase( |
| *this, |
| derivedInfo.LoweredType, |
| baseInfo.LoweredType)); |
| overrideInterfaceTy = derivedInfo.FormalType; |
| } |
| |
| if (genericSig && !genericSig->areAllParamsConcrete()) { |
| overrideInterfaceTy = |
| cast<AnyFunctionType>( |
| GenericFunctionType::get(genericSig, |
| overrideInterfaceTy->getParams(), |
| overrideInterfaceTy->getResult(), |
| overrideInterfaceTy->getExtInfo()) |
| ->getCanonicalType()); |
| } |
| |
| // Build the lowered AST function type for the class method call. |
| auto bridgedTypes = getLoweredFormalTypes(derived, overrideInterfaceTy); |
| |
| // Build the SILFunctionType for the class method call. |
| CanSILFunctionType fnTy = getNativeSILFunctionType( |
| *this, context, basePattern, bridgedTypes.Uncurried, |
| derivedInfo.SILFnType->getExtInfo(), base, derived, |
| /*reqt subs*/ None, ProtocolConformanceRef()); |
| |
| // Build the SILConstantInfo and cache it. |
| auto resultBuf = Context.Allocate(sizeof(SILConstantInfo), |
| alignof(SILConstantInfo)); |
| auto result = ::new (resultBuf) SILConstantInfo{ |
| overrideInterfaceTy, |
| basePattern, |
| bridgedTypes.Uncurried, |
| fnTy}; |
| |
| auto inserted = ConstantOverrideTypes.insert({{derived, base}, result}); |
| assert(inserted.second); |
| (void)inserted; |
| return *result; |
| } |
| |
| namespace { |
| |
| /// Given a lowered SIL type, apply a substitution to it to produce another |
| /// lowered SIL type which uses the same abstraction conventions. |
| class SILTypeSubstituter : |
| public CanTypeVisitor<SILTypeSubstituter, CanType> { |
| TypeConverter &TC; |
| TypeSubstitutionFn Subst; |
| LookupConformanceFn Conformances; |
| // The signature for the original type. |
| // |
| // Replacement types are lowered with respect to the current |
| // context signature. |
| CanGenericSignature Sig; |
| |
| TypeExpansionContext typeExpansionContext; |
| |
| bool shouldSubstituteOpaqueArchetypes; |
| |
| public: |
| SILTypeSubstituter(TypeConverter &TC, |
| TypeExpansionContext context, |
| TypeSubstitutionFn Subst, |
| LookupConformanceFn Conformances, |
| CanGenericSignature Sig, |
| bool shouldSubstituteOpaqueArchetypes) |
| : TC(TC), |
| Subst(Subst), |
| Conformances(Conformances), |
| Sig(Sig), |
| typeExpansionContext(context), |
| shouldSubstituteOpaqueArchetypes(shouldSubstituteOpaqueArchetypes) |
| {} |
| |
| // SIL type lowering only does special things to tuples and functions. |
| |
| // When a function appears inside of another type, we only perform |
| // substitutions if it is not polymorphic. |
| CanSILFunctionType visitSILFunctionType(CanSILFunctionType origType) { |
| return substSILFunctionType(origType, false); |
| } |
| |
| SubstitutionMap substSubstitutions(SubstitutionMap subs) { |
| // Substitute the substitutions. |
| SubstOptions options = None; |
| if (shouldSubstituteOpaqueArchetypes) |
| options |= SubstFlags::SubstituteOpaqueArchetypes; |
| |
| // Expand substituted type according to the expansion context. |
| auto newSubs = subs.subst(Subst, Conformances, options); |
| |
| // If we need to look through opaque types in this context, re-substitute |
| // according to the expansion context. |
| newSubs = substOpaqueTypes(newSubs); |
| |
| return newSubs; |
| } |
| |
| SubstitutionMap substOpaqueTypes(SubstitutionMap subs) { |
| if (!typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) |
| return subs; |
| |
| return subs.subst([&](SubstitutableType *s) -> Type { |
| return substOpaqueTypesWithUnderlyingTypes(s->getCanonicalType(), |
| typeExpansionContext); |
| }, [&](CanType dependentType, |
| Type conformingReplacementType, |
| ProtocolDecl *conformedProtocol) -> ProtocolConformanceRef { |
| return substOpaqueTypesWithUnderlyingTypes( |
| ProtocolConformanceRef(conformedProtocol), |
| conformingReplacementType->getCanonicalType(), |
| typeExpansionContext); |
| }, SubstFlags::SubstituteOpaqueArchetypes); |
| } |
| |
| // Substitute a function type. |
| CanSILFunctionType substSILFunctionType(CanSILFunctionType origType, |
| bool isGenericApplication) { |
| assert((!isGenericApplication || origType->isPolymorphic()) && |
| "generic application without invocation signature or with " |
| "existing arguments"); |
| assert((!isGenericApplication || !shouldSubstituteOpaqueArchetypes) && |
| "generic application while substituting opaque archetypes"); |
| |
| // The general substitution rule is that we should only substitute |
| // into the free components of the type, i.e. the components that |
| // aren't inside a generic signature. That rule would say: |
| // |
| // - If there are invocation substitutions, just substitute those; |
| // the other components are necessarily inside the invocation |
| // generic signature. |
| // |
| // - Otherwise, if there's an invocation generic signature, |
| // substitute nothing. If we are applying generic arguments, |
| // add the appropriate invocation substitutions. |
| // |
| // - Otherwise, if there are pattern substitutions, just substitute |
| // those; the other components are inside the patttern generic |
| // signature. |
| // |
| // - Otherwise, substitute the basic components. |
| // |
| // There are two caveats here. The first is that we haven't yet |
| // written all the code that would be necessary in order to handle |
| // invocation substitutions everywhere, and so we never build those. |
| // Instead, we substitute into the pattern substitutions if present, |
| // or the components if not, and build a type with no invocation |
| // signature. As a special case, when substituting a coroutine type, |
| // we build pattern substitutions instead of substituting the |
| // component types in order to preserve the original yield structure, |
| // which factors into the continuation function ABI. |
| // |
| // The second is that this function is also used when substituting |
| // opaque archetypes. In this case, we may need to substitute |
| // into component types even within generic signatures. This is |
| // safe because the substitutions used in this case don't change |
| // generics, they just narrowly look through certain opaque archetypes. |
| // If substitutions are present, we still don't substitute into |
| // the basic components, in order to maintain the information about |
| // what was abstracted there. |
| |
| auto patternSubs = origType->getPatternSubstitutions(); |
| |
| // If we have an invocation signatture, we generally shouldn't |
| // substitute into the pattern substitutions and component types. |
| if (auto sig = origType->getInvocationGenericSignature()) { |
| // Substitute the invocation substitutions if present. |
| if (auto invocationSubs = origType->getInvocationSubstitutions()) { |
| assert(!isGenericApplication); |
| invocationSubs = substSubstitutions(invocationSubs); |
| auto substType = |
| origType->withInvocationSubstitutions(invocationSubs); |
| |
| // Also do opaque-type substitutions on the pattern substitutions |
| // if requested and applicable. |
| if (patternSubs) { |
| patternSubs = substOpaqueTypes(patternSubs); |
| substType = substType->withPatternSubstitutions(patternSubs); |
| } |
| |
| return substType; |
| } |
| |
| // Otherwise, we shouldn't substitute any components except |
| // when substituting opaque archetypes. |
| |
| // If we're doing a generic application, and there are pattern |
| // substitutions, substitute into the pattern substitutions; or if |
| // it's a coroutine, build pattern substitutions; or else, fall |
| // through to substitute the component types as discussed above. |
| if (isGenericApplication) { |
| if (patternSubs || origType->isCoroutine()) { |
| CanSILFunctionType substType = origType; |
| if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) { |
| substType = |
| origType->substituteOpaqueArchetypes(TC, typeExpansionContext); |
| } |
| |
| SubstitutionMap subs; |
| if (patternSubs) { |
| subs = substSubstitutions(patternSubs); |
| } else { |
| subs = SubstitutionMap::get(sig, Subst, Conformances); |
| } |
| auto witnessConformance = substWitnessConformance(origType); |
| substType = substType->withPatternSpecialization(nullptr, subs, |
| witnessConformance); |
| if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) { |
| substType = |
| substType->substituteOpaqueArchetypes(TC, typeExpansionContext); |
| } |
| return substType; |
| } |
| // else fall down to component substitution |
| |
| // If we're substituting opaque archetypes, and there are pattern |
| // substitutions present, just substitute those and preserve the |
| // basic structure in the component types. Otherwise, fall through |
| // to substitute the component types. |
| } else if (shouldSubstituteOpaqueArchetypes) { |
| if (patternSubs) { |
| patternSubs = substOpaqueTypes(patternSubs); |
| auto witnessConformance = substWitnessConformance(origType); |
| return origType->withPatternSpecialization(sig, patternSubs, |
| witnessConformance); |
| } |
| // else fall down to component substitution |
| |
| // Otherwise, don't try to substitute bound components. |
| } else { |
| auto substType = origType; |
| if (patternSubs) { |
| patternSubs = substOpaqueTypes(patternSubs); |
| auto witnessConformance = substWitnessConformance(origType); |
| substType = substType->withPatternSpecialization(sig, patternSubs, |
| witnessConformance); |
| } |
| return substType; |
| } |
| |
| // Otherwise, if there are pattern substitutions, just substitute |
| // into those and don't touch the component types. |
| } else if (patternSubs) { |
| patternSubs = substSubstitutions(patternSubs); |
| auto witnessConformance = substWitnessConformance(origType); |
| return origType->withPatternSpecialization(nullptr, patternSubs, |
| witnessConformance); |
| } |
| |
| // Otherwise, we need to substitute component types. |
| |
| SmallVector<SILResultInfo, 8> substResults; |
| substResults.reserve(origType->getNumResults()); |
| for (auto origResult : origType->getResults()) { |
| substResults.push_back(substInterface(origResult)); |
| } |
| |
| auto substErrorResult = origType->getOptionalErrorResult(); |
| assert(!substErrorResult || |
| (!substErrorResult->getInterfaceType()->hasTypeParameter() && |
| !substErrorResult->getInterfaceType()->hasArchetype())); |
| |
| SmallVector<SILParameterInfo, 8> substParams; |
| substParams.reserve(origType->getParameters().size()); |
| for (auto &origParam : origType->getParameters()) { |
| substParams.push_back(substInterface(origParam)); |
| } |
| |
| SmallVector<SILYieldInfo, 8> substYields; |
| substYields.reserve(origType->getYields().size()); |
| for (auto &origYield : origType->getYields()) { |
| substYields.push_back(substInterface(origYield)); |
| } |
| |
| auto witnessMethodConformance = substWitnessConformance(origType); |
| |
| // The substituted type is no longer generic, so it'd never be |
| // pseudogeneric. |
| auto extInfo = origType->getExtInfo(); |
| if (!shouldSubstituteOpaqueArchetypes) |
| extInfo = extInfo.intoBuilder().withIsPseudogeneric(false).build(); |
| |
| auto genericSig = shouldSubstituteOpaqueArchetypes |
| ? origType->getInvocationGenericSignature() |
| : nullptr; |
| |
| return SILFunctionType::get(genericSig, extInfo, |
| origType->getCoroutineKind(), |
| origType->getCalleeConvention(), substParams, |
| substYields, substResults, substErrorResult, |
| SubstitutionMap(), SubstitutionMap(), |
| TC.Context, witnessMethodConformance); |
| } |
| |
| ProtocolConformanceRef substWitnessConformance(CanSILFunctionType origType) { |
| auto conformance = origType->getWitnessMethodConformanceOrInvalid(); |
| if (!conformance) return conformance; |
| |
| assert(origType->getExtInfo().hasSelfParam()); |
| auto selfType = origType->getSelfParameter().getInterfaceType(); |
| |
| // The Self type can be nested in a few layers of metatypes (etc.). |
| while (auto metatypeType = dyn_cast<MetatypeType>(selfType)) { |
| auto next = metatypeType.getInstanceType(); |
| if (next == selfType) |
| break; |
| selfType = next; |
| } |
| |
| auto substConformance = |
| conformance.subst(selfType, Subst, Conformances); |
| |
| // Substitute the underlying conformance of opaque type archetypes if we |
| // should look through opaque archetypes. |
| if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) { |
| SubstOptions substOptions(None); |
| auto substType = selfType.subst(Subst, Conformances, substOptions) |
| ->getCanonicalType(); |
| if (substType->hasOpaqueArchetype()) { |
| substConformance = substOpaqueTypesWithUnderlyingTypes( |
| substConformance, substType, typeExpansionContext); |
| } |
| } |
| |
| return substConformance; |
| } |
| |
| SILType subst(SILType type) { |
| return SILType::getPrimitiveType(visit(type.getASTType()), |
| type.getCategory()); |
| } |
| |
| SILResultInfo substInterface(SILResultInfo orig) { |
| return SILResultInfo(visit(orig.getInterfaceType()), orig.getConvention()); |
| } |
| |
| SILYieldInfo substInterface(SILYieldInfo orig) { |
| return SILYieldInfo(visit(orig.getInterfaceType()), orig.getConvention()); |
| } |
| |
| SILParameterInfo substInterface(SILParameterInfo orig) { |
| return SILParameterInfo(visit(orig.getInterfaceType()), |
| orig.getConvention(), orig.getDifferentiability()); |
| } |
| |
| /// Tuples need to have their component types substituted by these |
| /// same rules. |
| CanType visitTupleType(CanTupleType origType) { |
| // Fast-path the empty tuple. |
| if (origType->getNumElements() == 0) return origType; |
| |
| SmallVector<TupleTypeElt, 8> substElts; |
| substElts.reserve(origType->getNumElements()); |
| for (auto &origElt : origType->getElements()) { |
| auto substEltType = visit(CanType(origElt.getType())); |
| substElts.push_back(origElt.getWithType(substEltType)); |
| } |
| return CanType(TupleType::get(substElts, TC.Context)); |
| } |
| // Block storage types need to substitute their capture type by these same |
| // rules. |
| CanType visitSILBlockStorageType(CanSILBlockStorageType origType) { |
| auto substCaptureType = visit(origType->getCaptureType()); |
| return SILBlockStorageType::get(substCaptureType); |
| } |
| |
| /// Optionals need to have their object types substituted by these rules. |
| CanType visitBoundGenericEnumType(CanBoundGenericEnumType origType) { |
| // Only use a special rule if it's Optional. |
| if (!origType->getDecl()->isOptionalDecl()) { |
| return visitType(origType); |
| } |
| |
| CanType origObjectType = origType.getGenericArgs()[0]; |
| CanType substObjectType = visit(origObjectType); |
| return CanType(BoundGenericType::get(origType->getDecl(), Type(), |
| substObjectType)); |
| } |
| |
| /// Any other type would be a valid type in the AST. Just apply the |
| /// substitution on the AST level and then lower that. |
| CanType visitType(CanType origType) { |
| assert(!isa<AnyFunctionType>(origType)); |
| assert(!isa<LValueType>(origType) && !isa<InOutType>(origType)); |
| |
| SubstOptions substOptions(None); |
| if (shouldSubstituteOpaqueArchetypes) |
| substOptions = SubstFlags::SubstituteOpaqueArchetypes | |
| SubstFlags::AllowLoweredTypes; |
| auto substType = |
| origType.subst(Subst, Conformances, substOptions)->getCanonicalType(); |
| |
| // If the substitution didn't change anything, we know that the |
| // original type was a lowered type, so we're good. |
| if (origType == substType) { |
| return origType; |
| } |
| |
| AbstractionPattern abstraction(Sig, origType); |
| return TC.getLoweredRValueType(typeExpansionContext, abstraction, |
| substType); |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| SILType SILType::subst(TypeConverter &tc, TypeSubstitutionFn subs, |
| LookupConformanceFn conformances, |
| CanGenericSignature genericSig, |
| bool shouldSubstituteOpaqueArchetypes) const { |
| if (!hasArchetype() && !hasTypeParameter() && |
| (!shouldSubstituteOpaqueArchetypes || |
| !getASTType()->hasOpaqueArchetype())) |
| return *this; |
| |
| SILTypeSubstituter STST(tc, TypeExpansionContext::minimal(), subs, |
| conformances, genericSig, |
| shouldSubstituteOpaqueArchetypes); |
| return STST.subst(*this); |
| } |
| |
| SILType SILType::subst(SILModule &M, TypeSubstitutionFn subs, |
| LookupConformanceFn conformances, |
| CanGenericSignature genericSig, |
| bool shouldSubstituteOpaqueArchetypes) const { |
| return subst(M.Types, subs, conformances, genericSig, |
| shouldSubstituteOpaqueArchetypes); |
| } |
| |
| SILType SILType::subst(TypeConverter &tc, SubstitutionMap subs) const { |
| auto sig = subs.getGenericSignature(); |
| return subst(tc, QuerySubstitutionMap{subs}, |
| LookUpConformanceInSubstitutionMap(subs), |
| sig.getCanonicalSignature()); |
| } |
| SILType SILType::subst(SILModule &M, SubstitutionMap subs) const{ |
| return subst(M.Types, subs); |
| } |
| |
| SILType SILType::subst(SILModule &M, SubstitutionMap subs, |
| TypeExpansionContext context) const { |
| if (!hasArchetype() && !hasTypeParameter() && |
| !getASTType()->hasOpaqueArchetype()) |
| return *this; |
| |
| // Pass the TypeSubstitutionFn and LookupConformanceFn as arguments so that |
| // the llvm::function_ref value's scope spans the STST.subst call since |
| // SILTypeSubstituter captures these functions. |
| auto result = [&](TypeSubstitutionFn subsFn, |
| LookupConformanceFn conformancesFn) -> SILType { |
| SILTypeSubstituter STST(M.Types, context, subsFn, conformancesFn, |
| subs.getGenericSignature().getCanonicalSignature(), |
| false); |
| return STST.subst(*this); |
| }(QuerySubstitutionMap{subs}, LookUpConformanceInSubstitutionMap(subs)); |
| return result; |
| } |
| |
| /// Apply a substitution to this polymorphic SILFunctionType so that |
| /// it has the form of the normal SILFunctionType for the substituted |
| /// type, except using the original conventions. |
| CanSILFunctionType |
| SILFunctionType::substGenericArgs(SILModule &silModule, SubstitutionMap subs, |
| TypeExpansionContext context) { |
| if (!isPolymorphic()) { |
| return CanSILFunctionType(this); |
| } |
| |
| if (subs.empty()) { |
| return CanSILFunctionType(this); |
| } |
| |
| return substGenericArgs(silModule, |
| QuerySubstitutionMap{subs}, |
| LookUpConformanceInSubstitutionMap(subs), |
| context); |
| } |
| |
| CanSILFunctionType |
| SILFunctionType::substGenericArgs(SILModule &silModule, |
| TypeSubstitutionFn subs, |
| LookupConformanceFn conformances, |
| TypeExpansionContext context) { |
| if (!isPolymorphic()) return CanSILFunctionType(this); |
| SILTypeSubstituter substituter(silModule.Types, context, subs, conformances, |
| getSubstGenericSignature(), |
| /*shouldSubstituteOpaqueTypes*/ false); |
| return substituter.substSILFunctionType(CanSILFunctionType(this), true); |
| } |
| |
| CanSILFunctionType |
| SILFunctionType::substituteOpaqueArchetypes(TypeConverter &TC, |
| TypeExpansionContext context) { |
| if (!hasOpaqueArchetype() || |
| !context.shouldLookThroughOpaqueTypeArchetypes()) |
| return CanSILFunctionType(this); |
| |
| ReplaceOpaqueTypesWithUnderlyingTypes replacer( |
| context.getContext(), context.getResilienceExpansion(), |
| context.isWholeModuleContext()); |
| |
| SILTypeSubstituter substituter(TC, context, replacer, replacer, |
| getSubstGenericSignature(), |
| /*shouldSubstituteOpaqueTypes*/ true); |
| auto resTy = |
| substituter.substSILFunctionType(CanSILFunctionType(this), false); |
| |
| return resTy; |
| } |
| |
| /// Fast path for bridging types in a function type without uncurrying. |
| CanAnyFunctionType TypeConverter::getBridgedFunctionType( |
| AbstractionPattern pattern, CanAnyFunctionType t, Bridgeability bridging, |
| SILFunctionTypeRepresentation rep) { |
| // Pull out the generic signature. |
| CanGenericSignature genericSig = t.getOptGenericSignature(); |
| |
| switch (getSILFunctionLanguage(rep)) { |
| case SILFunctionLanguage::Swift: { |
| // No bridging needed for native functions. |
| return t; |
| } |
| case SILFunctionLanguage::C: { |
| SmallVector<AnyFunctionType::Param, 8> params; |
| getBridgedParams(rep, pattern, t->getParams(), params, bridging); |
| |
| bool suppressOptional = pattern.hasForeignErrorStrippingResultOptionality(); |
| auto result = getBridgedResultType(rep, |
| pattern.getFunctionResultType(), |
| t.getResult(), |
| bridging, |
| suppressOptional); |
| |
| return CanAnyFunctionType::get(genericSig, llvm::makeArrayRef(params), |
| result, t->getExtInfo()); |
| } |
| } |
| llvm_unreachable("bad calling convention"); |
| } |
| |
| static AbstractFunctionDecl *getBridgedFunction(SILDeclRef declRef) { |
| switch (declRef.kind) { |
| case SILDeclRef::Kind::Func: |
| case SILDeclRef::Kind::Allocator: |
| case SILDeclRef::Kind::Initializer: |
| return (declRef.hasDecl() |
| ? cast<AbstractFunctionDecl>(declRef.getDecl()) |
| : nullptr); |
| |
| case SILDeclRef::Kind::EnumElement: |
| case SILDeclRef::Kind::Destroyer: |
| case SILDeclRef::Kind::Deallocator: |
| case SILDeclRef::Kind::GlobalAccessor: |
| case SILDeclRef::Kind::DefaultArgGenerator: |
| case SILDeclRef::Kind::StoredPropertyInitializer: |
| case SILDeclRef::Kind::PropertyWrapperBackingInitializer: |
| case SILDeclRef::Kind::IVarInitializer: |
| case SILDeclRef::Kind::IVarDestroyer: |
| return nullptr; |
| } |
| llvm_unreachable("bad SILDeclRef kind"); |
| } |
| |
| static AbstractionPattern |
| getAbstractionPatternForConstant(ASTContext &ctx, SILDeclRef constant, |
| CanAnyFunctionType fnType, |
| unsigned numParameterLists) { |
| if (!constant.isForeign) |
| return AbstractionPattern(fnType); |
| |
| auto bridgedFn = getBridgedFunction(constant); |
| if (!bridgedFn) |
| return AbstractionPattern(fnType); |
| const clang::Decl *clangDecl = bridgedFn->getClangDecl(); |
| if (!clangDecl) |
| return AbstractionPattern(fnType); |
| |
| // Don't implicitly turn non-optional results to optional if |
| // we're going to apply a foreign error convention that checks |
| // for nil results. |
| if (auto method = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) { |
| assert(numParameterLists == 2 && "getting curried ObjC method type?"); |
| return AbstractionPattern::getCurriedObjCMethod(fnType, method, |
| bridgedFn->getForeignErrorConvention(), |
| bridgedFn->getForeignAsyncConvention()); |
| } else if (auto value = dyn_cast<clang::ValueDecl>(clangDecl)) { |
| if (numParameterLists == 1) { |
| // C function imported as a function. |
| return AbstractionPattern(fnType, value->getType().getTypePtr()); |
| } else { |
| assert(numParameterLists == 2); |
| if (auto method = dyn_cast<clang::CXXMethodDecl>(clangDecl)) { |
| // C++ method. |
| return method->isOverloadedOperator() |
| ? AbstractionPattern::getCurriedCXXOperatorMethod(fnType, |
| bridgedFn) |
| : AbstractionPattern::getCurriedCXXMethod(fnType, bridgedFn); |
| } else { |
| // C function imported as a method. |
| return AbstractionPattern::getCurriedCFunctionAsMethod(fnType, |
| bridgedFn); |
| } |
| } |
| } |
| |
| return AbstractionPattern(fnType); |
| } |
| |
| TypeConverter::LoweredFormalTypes |
| TypeConverter::getLoweredFormalTypes(SILDeclRef constant, |
| CanAnyFunctionType fnType) { |
| // We always use full bridging when importing a constant because we can |
| // directly bridge its arguments and results when calling it. |
| auto bridging = Bridgeability::Full; |
| |
| unsigned numParameterLists = constant.getParameterListCount(); |
| |
| // Form an abstraction pattern for bridging purposes. |
| AbstractionPattern bridgingFnPattern = |
| getAbstractionPatternForConstant(Context, constant, fnType, |
| numParameterLists); |
| |
| auto extInfo = fnType->getExtInfo(); |
| SILFunctionTypeRepresentation rep = getDeclRefRepresentation(constant); |
| assert(rep != SILFunctionType::Representation::Block && |
| "objc blocks cannot be curried"); |
| |
| // Fast path: no uncurrying required. |
| if (numParameterLists == 1) { |
| auto bridgedFnType = |
| getBridgedFunctionType(bridgingFnPattern, fnType, bridging, rep); |
| bridgingFnPattern.rewriteType(bridgingFnPattern.getGenericSignature(), |
| bridgedFnType); |
| return { bridgingFnPattern, bridgedFnType }; |
| } |
| |
| // The dependent generic signature. |
| CanGenericSignature genericSig = fnType.getOptGenericSignature(); |
| |
| // The 'self' parameter. |
| assert(fnType.getParams().size() == 1); |
| AnyFunctionType::Param selfParam = fnType.getParams()[0]; |
| |
| // The formal method parameters. |
| // If we actually partially-apply this, assume we'll need a thick function. |
| fnType = cast<FunctionType>(fnType.getResult()); |
| auto innerExtInfo = |
| fnType->getExtInfo().withRepresentation(FunctionTypeRepresentation::Swift); |
| auto methodParams = fnType->getParams(); |
| |
| auto resultType = fnType.getResult(); |
| bool suppressOptionalResult = |
| bridgingFnPattern.hasForeignErrorStrippingResultOptionality(); |
| |
| // Bridge input and result types. |
| SmallVector<AnyFunctionType::Param, 8> bridgedParams; |
| CanType bridgedResultType; |
| |
| switch (rep) { |
| case SILFunctionTypeRepresentation::Thin: |
| case SILFunctionTypeRepresentation::Thick: |
| case SILFunctionTypeRepresentation::Method: |
| case SILFunctionTypeRepresentation::Closure: |
| case SILFunctionTypeRepresentation::WitnessMethod: |
| // Native functions don't need bridging. |
| bridgedParams.append(methodParams.begin(), methodParams.end()); |
| bridgedResultType = resultType; |
| break; |
| |
| case SILFunctionTypeRepresentation::ObjCMethod: |
| case SILFunctionTypeRepresentation::CFunctionPointer: { |
| if (rep == SILFunctionTypeRepresentation::ObjCMethod) { |
| // The "self" parameter should not get bridged unless it's a metatype. |
| if (selfParam.getPlainType()->is<AnyMetatypeType>()) { |
| auto selfPattern = bridgingFnPattern.getFunctionParamType(0); |
| selfParam = getBridgedParam(rep, selfPattern, selfParam, bridging); |
| } |
| } |
| |
| auto partialFnPattern = bridgingFnPattern.getFunctionResultType(); |
| for (unsigned i : indices(methodParams)) { |
| // C++ operators that are implemented as non-static member functions get |
| // imported into Swift as static methods that have an additional |
| // parameter for the left-hand-side operand instead of the receiver |
| // object. These are inout parameters and don't get bridged. |
| // TODO: Undo this if we stop using inout. |
| if (auto method = dyn_cast_or_null<clang::CXXMethodDecl>( |
| constant.getDecl()->getClangDecl())) { |
| if (i==0 && method->isOverloadedOperator()) { |
| bridgedParams.push_back(methodParams[0]); |
| continue; |
| } |
| } |
| |
| auto paramPattern = partialFnPattern.getFunctionParamType(i); |
| auto bridgedParam = |
| getBridgedParam(rep, paramPattern, methodParams[i], bridging); |
| bridgedParams.push_back(bridgedParam); |
| } |
| |
| bridgedResultType = |
| getBridgedResultType(rep, |
| partialFnPattern.getFunctionResultType(), |
| resultType, bridging, suppressOptionalResult); |
| break; |
| } |
| |
| case SILFunctionTypeRepresentation::Block: |
| llvm_unreachable("Cannot uncurry native representation"); |
| } |
| |
| // Build the curried function type. |
| auto inner = |
| CanFunctionType::get(llvm::makeArrayRef(bridgedParams), |
| bridgedResultType, innerExtInfo); |
| |
| auto curried = |
| CanAnyFunctionType::get(genericSig, {selfParam}, inner, extInfo); |
| |
| // Replace the type in the abstraction pattern with the curried type. |
| bridgingFnPattern.rewriteType(genericSig, curried); |
| |
| // Build the uncurried function type. |
| if (innerExtInfo.isThrowing()) |
| extInfo = extInfo.withThrows(true); |
| if (innerExtInfo.isAsync()) |
| extInfo = extInfo.withAsync(true); |
| |
| // If this is a C++ constructor, don't add the metatype "self" parameter |
| // because we'll never use it and it will cause problems in IRGen. |
| if (constant.getDecl()->getClangDecl() && |
| isa<clang::CXXConstructorDecl>(constant.getDecl()->getClangDecl())) { |
| // But, make sure it is actually a metatype that we're not adding. If |
| // changes to the self parameter are made in the future, this logic may |
| // need to be updated. |
| assert(selfParam.getParameterType()->is<MetatypeType>()); |
| } else { |
| bridgedParams.push_back(selfParam); |
| } |
| |
| auto uncurried = |
| CanAnyFunctionType::get(genericSig, |
| llvm::makeArrayRef(bridgedParams), |
| bridgedResultType, |
| extInfo); |
| |
| return { bridgingFnPattern, uncurried }; |
| } |
| |
| // TODO: We should compare generic signatures. Class and witness methods |
| // allow variance in "self"-fulfilled parameters; other functions must |
| // match exactly. |
| // TODO: More sophisticated param and return ABI compatibility rules could |
| // diverge. |
| static bool areABICompatibleParamsOrReturns(SILType a, SILType b, |
| SILFunction *inFunction) { |
| // Address parameters are all ABI-compatible, though the referenced |
| // values may not be. Assume whoever's doing this knows what they're |
| // doing. |
| if (a.isAddress() && b.isAddress()) |
| return true; |
| |
| // Addresses aren't compatible with values. |
| // TODO: An exception for pointerish types? |
| if (a.isAddress() || b.isAddress()) |
| return false; |
| |
| // Tuples are ABI compatible if their elements are. |
| // TODO: Should destructure recursively. |
| SmallVector<CanType, 1> aElements, bElements; |
| if (auto tup = a.getAs<TupleType>()) { |
| auto types = tup.getElementTypes(); |
| aElements.append(types.begin(), types.end()); |
| } else { |
| aElements.push_back(a.getASTType()); |
| } |
| if (auto tup = b.getAs<TupleType>()) { |
| auto types = tup.getElementTypes(); |
| bElements.append(types.begin(), types.end()); |
| } else { |
| bElements.push_back(b.getASTType()); |
| } |
| |
| if (aElements.size() != bElements.size()) |
| return false; |
| |
| for (unsigned i : indices(aElements)) { |
| auto aa = SILType::getPrimitiveObjectType(aElements[i]); |
| auto bb = SILType::getPrimitiveObjectType(bElements[i]); |
| // Equivalent types are always ABI-compatible. |
| if (aa == bb) |
| continue; |
| |
| // Opaque types are compatible with their substitution. |
| if (inFunction) { |
| auto opaqueTypesSubsituted = aa; |
| auto *dc = inFunction->getDeclContext(); |
| auto *currentModule = inFunction->getModule().getSwiftModule(); |
| if (!dc || !dc->isChildContextOf(currentModule)) |
| dc = currentModule; |
| ReplaceOpaqueTypesWithUnderlyingTypes replacer( |
| dc, inFunction->getResilienceExpansion(), |
| inFunction->getModule().isWholeModule()); |
| if (aa.getASTType()->hasOpaqueArchetype()) |
| opaqueTypesSubsituted = aa.subst(inFunction->getModule(), replacer, |
| replacer, CanGenericSignature(), true); |
| |
| auto opaqueTypesSubsituted2 = bb; |
| if (bb.getASTType()->hasOpaqueArchetype()) |
| opaqueTypesSubsituted2 = |
| bb.subst(inFunction->getModule(), replacer, replacer, |
| CanGenericSignature(), true); |
| if (opaqueTypesSubsituted == opaqueTypesSubsituted2) |
| continue; |
| } |
| |
| // FIXME: If one or both types are dependent, we can't accurately assess |
| // whether they're ABI-compatible without a generic context. We can |
| // do a better job here when dependent types are related to their |
| // generic signatures. |
| if (aa.hasTypeParameter() || bb.hasTypeParameter()) |
| continue; |
| |
| // Bridgeable object types are interchangeable. |
| if (aa.isBridgeableObjectType() && bb.isBridgeableObjectType()) |
| continue; |
| |
| // Optional and IUO are interchangeable if their elements are. |
| auto aObject = aa.getOptionalObjectType(); |
| auto bObject = bb.getOptionalObjectType(); |
| if (aObject && bObject && |
| areABICompatibleParamsOrReturns(aObject, bObject, inFunction)) |
| continue; |
| // Optional objects are ABI-interchangeable with non-optionals; |
| // None is represented by a null pointer. |
| if (aObject && aObject.isBridgeableObjectType() && |
| bb.isBridgeableObjectType()) |
| continue; |
| if (bObject && bObject.isBridgeableObjectType() && |
| aa.isBridgeableObjectType()) |
| continue; |
| |
| // Optional thick metatypes are ABI-interchangeable with non-optionals |
| // too. |
| if (aObject) |
| if (auto aObjMeta = aObject.getAs<MetatypeType>()) |
| if (auto bMeta = bb.getAs<MetatypeType>()) |
| if (aObjMeta->getRepresentation() == bMeta->getRepresentation() && |
| bMeta->getRepresentation() != MetatypeRepresentation::Thin) |
| continue; |
| if (bObject) |
| if (auto aMeta = aa.getAs<MetatypeType>()) |
| if (auto bObjMeta = bObject.getAs<MetatypeType>()) |
| if (aMeta->getRepresentation() == bObjMeta->getRepresentation() && |
| aMeta->getRepresentation() != MetatypeRepresentation::Thin) |
| continue; |
| |
| // Function types are interchangeable if they're also ABI-compatible. |
| if (auto aFunc = aa.getAs<SILFunctionType>()) { |
| if (auto bFunc = bb.getAs<SILFunctionType>()) { |
| // *NOTE* We swallow the specific error here for now. We will still get |
| // that the function types are incompatible though, just not more |
| // specific information. |
| return aFunc->isABICompatibleWith(bFunc, *inFunction).isCompatible(); |
| } |
| } |
| |
| // Metatypes are interchangeable with metatypes with the same |
| // representation. |
| if (auto aMeta = aa.getAs<MetatypeType>()) { |
| if (auto bMeta = bb.getAs<MetatypeType>()) { |
| if (aMeta->getRepresentation() == bMeta->getRepresentation()) |
| continue; |
| } |
| } |
| // Other types must match exactly. |
| return false; |
| } |
| |
| return true; |
| } |
| |
| namespace { |
| using ABICompatibilityCheckResult = |
| SILFunctionType::ABICompatibilityCheckResult; |
| } // end anonymous namespace |
| |
| ABICompatibilityCheckResult |
| SILFunctionType::isABICompatibleWith(CanSILFunctionType other, |
| SILFunction &context) const { |
| // The calling convention and function representation can't be changed. |
| if (getRepresentation() != other->getRepresentation()) |
| return ABICompatibilityCheckResult::DifferentFunctionRepresentations; |
| |
| // Check the results. |
| if (getNumResults() != other->getNumResults()) |
| return ABICompatibilityCheckResult::DifferentNumberOfResults; |
| |
| for (unsigned i : indices(getResults())) { |
| auto result1 = getResults()[i]; |
| auto result2 = other->getResults()[i]; |
| |
| if (result1.getConvention() != result2.getConvention()) |
| return ABICompatibilityCheckResult::DifferentReturnValueConventions; |
| |
| if (!areABICompatibleParamsOrReturns( |
| result1.getSILStorageType(context.getModule(), this, |
| context.getTypeExpansionContext()), |
| result2.getSILStorageType(context.getModule(), other, |
| context.getTypeExpansionContext()), |
| &context)) { |
| return ABICompatibilityCheckResult::ABIIncompatibleReturnValues; |
| } |
| } |
| |
| // Our error result conventions are designed to be ABI compatible |
| // with functions lacking error results. Just make sure that the |
| // actual conventions match up. |
| if (hasErrorResult() && other->hasErrorResult()) { |
| auto error1 = getErrorResult(); |
| auto error2 = other->getErrorResult(); |
| if (error1.getConvention() != error2.getConvention()) |
| return ABICompatibilityCheckResult::DifferentErrorResultConventions; |
| |
| if (!areABICompatibleParamsOrReturns( |
| error1.getSILStorageType(context.getModule(), this, |
| context.getTypeExpansionContext()), |
| error2.getSILStorageType(context.getModule(), other, |
| context.getTypeExpansionContext()), |
| &context)) |
| return ABICompatibilityCheckResult::ABIIncompatibleErrorResults; |
| } |
| |
| // Check the parameters. |
| // TODO: Could allow known-empty types to be inserted or removed, but SIL |
| // doesn't know what empty types are yet. |
| if (getParameters().size() != other->getParameters().size()) |
| return ABICompatibilityCheckResult::DifferentNumberOfParameters; |
| |
| for (unsigned i : indices(getParameters())) { |
| auto param1 = getParameters()[i]; |
| auto param2 = other->getParameters()[i]; |
| |
| if (param1.getConvention() != param2.getConvention()) |
| return {ABICompatibilityCheckResult::DifferingParameterConvention, i}; |
| if (!areABICompatibleParamsOrReturns( |
| param1.getSILStorageType(context.getModule(), this, |
| context.getTypeExpansionContext()), |
| param2.getSILStorageType(context.getModule(), other, |
| context.getTypeExpansionContext()), |
| &context)) |
| return {ABICompatibilityCheckResult::ABIIncompatibleParameterType, i}; |
| } |
| |
| // This needs to be checked last because the result implies everying else has |
| // already been checked and this is the only difference. |
| if (isNoEscape() != other->isNoEscape() && |
| (getRepresentation() == SILFunctionType::Representation::Thick)) |
| return ABICompatibilityCheckResult::ABIEscapeToNoEscapeConversion; |
| |
| return ABICompatibilityCheckResult::None; |
| } |
| |
| StringRef SILFunctionType::ABICompatibilityCheckResult::getMessage() const { |
| switch (kind) { |
| case innerty::None: |
| return "None"; |
| case innerty::DifferentFunctionRepresentations: |
| return "Different function representations"; |
| case innerty::DifferentNumberOfResults: |
| return "Different number of results"; |
| case innerty::DifferentReturnValueConventions: |
| return "Different return value conventions"; |
| case innerty::ABIIncompatibleReturnValues: |
| return "ABI incompatible return values"; |
| case innerty::DifferentErrorResultConventions: |
| return "Different error result conventions"; |
| case innerty::ABIIncompatibleErrorResults: |
| return "ABI incompatible error results"; |
| case innerty::DifferentNumberOfParameters: |
| return "Different number of parameters"; |
| |
| // These two have to do with specific parameters, so keep the error message |
| // non-plural. |
| case innerty::DifferingParameterConvention: |
| return "Differing parameter convention"; |
| case innerty::ABIIncompatibleParameterType: |
| return "ABI incompatible parameter type."; |
| case innerty::ABIEscapeToNoEscapeConversion: |
| return "Escape to no escape conversion"; |
| } |
| llvm_unreachable("Covered switch isn't completely covered?!"); |
| } |
| |
| TypeExpansionContext::TypeExpansionContext(const SILFunction &f) |
| : expansion(f.getResilienceExpansion()), |
| inContext(f.getModule().getAssociatedContext()), |
| isContextWholeModule(f.getModule().isWholeModule()) {} |
| |
| CanSILFunctionType SILFunction::getLoweredFunctionTypeInContext( |
| TypeExpansionContext context) const { |
| auto origFunTy = getLoweredFunctionType(); |
| auto &M = getModule(); |
| auto funTy = M.Types.getLoweredType(origFunTy , context); |
| return cast<SILFunctionType>(funTy.getASTType()); |
| } |