diff --git a/lib/AST/ModuleNameLookup.cpp b/lib/AST/ModuleNameLookup.cpp index 894e91f063ce4..a836dd000ecdf 100644 --- a/lib/AST/ModuleNameLookup.cpp +++ b/lib/AST/ModuleNameLookup.cpp @@ -78,7 +78,7 @@ class LookupByName : public ModuleNameLookup { lookupKind(lookupKind) {} private: - /// Returns whether it's okay to stop recursively searching imports, given  + /// Returns whether it's okay to stop recursively searching imports, given /// that we found something non-overloadable. static bool canReturnEarly() { return true; diff --git a/lib/IRGen/GenPack.cpp b/lib/IRGen/GenPack.cpp index c48e5902803af..31cf1208597aa 100644 --- a/lib/IRGen/GenPack.cpp +++ b/lib/IRGen/GenPack.cpp @@ -1349,3 +1349,63 @@ irgen::emitDynamicTupleTypeLabels(IRGenFunction &IGF, return labelString; } + +StackAddress +irgen::emitDynamicFunctionParameterFlags(IRGenFunction &IGF, + AnyFunctionType::CanParamArrayRef params, + CanPackType packType, + llvm::Value *shapeExpression) { + auto array = + IGF.emitDynamicAlloca(IGF.IGM.Int32Ty, shapeExpression, + Alignment(4), /*allowTaskAlloc=*/true); + + unsigned numExpansions = 0; + + auto visitFn = [&](CanType eltTy, + unsigned scalarIndex, + llvm::Value *dynamicIndex, + llvm::Value *dynamicLength) { + if (scalarIndex != 0 || dynamicIndex == nullptr) { + auto *constant = llvm::ConstantInt::get(IGF.IGM.SizeTy, scalarIndex); + accumulateSum(IGF, dynamicIndex, constant); + } + + auto elt = params[scalarIndex + numExpansions]; + auto flags = getABIParameterFlags(elt.getParameterFlags()); + auto flagsVal = llvm::ConstantInt::get( + IGF.IGM.Int32Ty, flags.getIntValue()); + + assert(eltTy == elt.getPlainType()); + + // If we're looking at a pack expansion, insert the appropriate + // number of flags fields. + if (auto expansionTy = dyn_cast(eltTy)) { + emitPackExpansionPack(IGF, array.getAddress(), expansionTy, + dynamicIndex, dynamicLength, + [&](llvm::Value *) -> llvm::Value * { + return flagsVal; + }); + + // We consumed an expansion. + numExpansions += 1; + + return; + } + + // The destination address, where we put the current element's flags field. + Address eltAddr( + IGF.Builder.CreateInBoundsGEP(array.getAddress().getElementType(), + array.getAddressPointer(), + dynamicIndex), + array.getAddress().getElementType(), + array.getAlignment()); + + // Otherwise, we have a single scalar element, which deposits a single + // flags field. + IGF.Builder.CreateStore(flagsVal, eltAddr); + }; + + (void) visitPackExplosion(IGF, packType, visitFn); + + return array; +} \ No newline at end of file diff --git a/lib/IRGen/GenPack.h b/lib/IRGen/GenPack.h index 912d0960bfb54..504e3c77d4eda 100644 --- a/lib/IRGen/GenPack.h +++ b/lib/IRGen/GenPack.h @@ -120,6 +120,12 @@ emitDynamicTupleTypeLabels(IRGenFunction &IGF, CanPackType packType, llvm::Value *shapeExpression); +StackAddress +emitDynamicFunctionParameterFlags(IRGenFunction &IGF, + AnyFunctionType::CanParamArrayRef params, + CanPackType packType, + llvm::Value *shapeExpression); + } // end namespace irgen } // end namespace swift diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index e226401fc7251..805a1399b1d99 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -1364,6 +1364,342 @@ static void destroyGenericArgumentsArray(IRGenFunction &IGF, IGF.IGM.getPointerSize() * args.size()); } +static llvm::Value *getFunctionParameterRef(IRGenFunction &IGF, + AnyFunctionType::CanParam param) { + auto type = param.getPlainType()->getCanonicalType(); + return IGF.emitAbstractTypeMetadataRef(type); +} + +/// Mapping type-level parameter flags to ABI parameter flags. +ParameterFlags irgen::getABIParameterFlags(ParameterTypeFlags flags) { + return ParameterFlags() + .withValueOwnership(flags.getValueOwnership()) + .withVariadic(flags.isVariadic()) + .withAutoClosure(flags.isAutoClosure()) + .withNoDerivative(flags.isNoDerivative()) + .withIsolated(flags.isIsolated()); +} + +static FunctionTypeFlags getFunctionTypeFlags(CanFunctionType type) { + bool hasParameterFlags = false; + for (auto param : type.getParams()) { + if (!getABIParameterFlags(param.getParameterFlags()).isNone()) { + hasParameterFlags = true; + break; + } + } + + // Map the convention to a runtime metadata value. + FunctionMetadataConvention metadataConvention; + bool isEscaping = false; + switch (type->getRepresentation()) { + case FunctionTypeRepresentation::Swift: + metadataConvention = FunctionMetadataConvention::Swift; + isEscaping = !type->isNoEscape(); + break; + case FunctionTypeRepresentation::Thin: + metadataConvention = FunctionMetadataConvention::Thin; + break; + case FunctionTypeRepresentation::Block: + metadataConvention = FunctionMetadataConvention::Block; + break; + case FunctionTypeRepresentation::CFunctionPointer: + metadataConvention = FunctionMetadataConvention::CFunctionPointer; + break; + } + + return FunctionTypeFlags() + .withConvention(metadataConvention) + .withAsync(type->isAsync()) + .withConcurrent(type->isSendable()) + .withThrows(type->isThrowing()) + .withParameterFlags(hasParameterFlags) + .withEscaping(isEscaping) + .withDifferentiable(type->isDifferentiable()) + .withGlobalActor(!type->getGlobalActor().isNull()); +} + +namespace { +struct FunctionTypeMetadataParamInfo { + StackAddress parameters; + StackAddress paramFlags; + unsigned numParams; +}; +} + +static FunctionTypeMetadataParamInfo +emitFunctionTypeMetadataParams(IRGenFunction &IGF, + AnyFunctionType::CanParamArrayRef params, + FunctionTypeFlags flags, + DynamicMetadataRequest request, + SmallVectorImpl &arguments) { + FunctionTypeMetadataParamInfo info; + info.numParams = params.size(); + + ConstantInitBuilder paramFlags(IGF.IGM); + auto flagsArr = paramFlags.beginArray(); + + if (!params.empty()) { + auto arrayTy = + llvm::ArrayType::get(IGF.IGM.TypeMetadataPtrTy, info.numParams); + info.parameters = StackAddress(IGF.createAlloca( + arrayTy, IGF.IGM.getTypeMetadataAlignment(), "function-parameters")); + + IGF.Builder.CreateLifetimeStart(info.parameters.getAddress(), + IGF.IGM.getPointerSize() * info.numParams); + + for (unsigned i : indices(params)) { + auto param = params[i]; + auto paramFlags = getABIParameterFlags(param.getParameterFlags()); + + auto argPtr = IGF.Builder.CreateStructGEP(info.parameters.getAddress(), i, + IGF.IGM.getPointerSize()); + auto *typeRef = getFunctionParameterRef(IGF, param); + IGF.Builder.CreateStore(typeRef, argPtr); + if (i == 0) + arguments.push_back(argPtr.getAddress()); + + flagsArr.addInt32(paramFlags.getIntValue()); + } + } else { + auto parametersPtr = + llvm::ConstantPointerNull::get( + IGF.IGM.TypeMetadataPtrTy->getPointerTo()); + arguments.push_back(parametersPtr); + } + + auto *Int32Ptr = IGF.IGM.Int32Ty->getPointerTo(); + if (flags.hasParameterFlags()) { + auto *flagsVar = flagsArr.finishAndCreateGlobal( + "parameter-flags", IGF.IGM.getPointerAlignment(), + /* constant */ true); + arguments.push_back(IGF.Builder.CreateBitCast(flagsVar, Int32Ptr)); + } else { + flagsArr.abandon(); + arguments.push_back(llvm::ConstantPointerNull::get(Int32Ptr)); + } + + return info; +} + +static FunctionTypeMetadataParamInfo +emitDynamicFunctionTypeMetadataParams(IRGenFunction &IGF, + AnyFunctionType::CanParamArrayRef params, + FunctionTypeFlags flags, + CanPackType packType, + DynamicMetadataRequest request, + SmallVectorImpl &arguments) { + assert(!params.empty()); + + FunctionTypeMetadataParamInfo info; + + llvm::Value *shape; + std::tie(info.parameters, shape) = emitTypeMetadataPack( + IGF, packType, MetadataState::Abstract); + + arguments.push_back(info.parameters.getAddress().getAddress()); + + if (flags.hasParameterFlags()) { + info.paramFlags = emitDynamicFunctionParameterFlags( + IGF, params, packType, shape); + + arguments.push_back(info.paramFlags.getAddress().getAddress()); + } else { + arguments.push_back(llvm::ConstantPointerNull::get( + IGF.IGM.Int32Ty->getPointerTo())); + } + + return info; +} + +static void cleanupFunctionTypeMetadataParams(IRGenFunction &IGF, + FunctionTypeMetadataParamInfo info) { + if (info.parameters.isValid()) { + if (info.parameters.getExtraInfo()) { + IGF.emitDeallocateDynamicAlloca(info.parameters); + } else { + IGF.Builder.CreateLifetimeEnd(info.parameters.getAddress(), + IGF.IGM.getPointerSize() * info.numParams); + } + } +} + +static CanPackType getInducedPackType(AnyFunctionType::CanParamArrayRef params, + ASTContext &ctx) { + SmallVector elts; + for (auto param : params) + elts.push_back(param.getPlainType()); + + return CanPackType::get(ctx, elts); +} + +static MetadataResponse emitFunctionTypeMetadataRef(IRGenFunction &IGF, + CanFunctionType type, + DynamicMetadataRequest request) { + auto result = + IGF.emitAbstractTypeMetadataRef(type->getResult()->getCanonicalType()); + + auto params = type.getParams(); + bool hasPackExpansion = type->containsPackExpansionParam(); + + auto flags = getFunctionTypeFlags(type); + llvm::Value *flagsVal = nullptr; + llvm::Value *shapeExpression = nullptr; + CanPackType packType; + + if (!hasPackExpansion) { + flags = flags.withNumParameters(params.size()); + flagsVal = llvm::ConstantInt::get(IGF.IGM.SizeTy, + flags.getIntValue()); + } else { + packType = getInducedPackType(type.getParams(), type->getASTContext()); + auto *shapeExpression = IGF.emitPackShapeExpression(packType); + + flagsVal = llvm::ConstantInt::get(IGF.IGM.SizeTy, + flags.getIntValue()); + flagsVal = IGF.Builder.CreateOr(flagsVal, shapeExpression); + } + + auto constructSimpleCall = + [&](llvm::SmallVectorImpl &arguments) + -> FunctionPointer { + assert(!flags.hasParameterFlags()); + assert(!shapeExpression); + + arguments.push_back(flagsVal); + + for (auto param : params) { + arguments.push_back(getFunctionParameterRef(IGF, param)); + } + + arguments.push_back(result); + + switch (params.size()) { + case 0: + return IGF.IGM.getGetFunctionMetadata0FunctionPointer(); + + case 1: + return IGF.IGM.getGetFunctionMetadata1FunctionPointer(); + + case 2: + return IGF.IGM.getGetFunctionMetadata2FunctionPointer(); + + case 3: + return IGF.IGM.getGetFunctionMetadata3FunctionPointer(); + + default: + llvm_unreachable("supports only 1/2/3 parameter functions"); + } + }; + + switch (params.size()) { + case 0: + case 1: + case 2: + case 3: { + if (!flags.hasParameterFlags() && !type->isDifferentiable() && + !type->getGlobalActor() && !hasPackExpansion) { + llvm::SmallVector arguments; + auto metadataFn = constructSimpleCall(arguments); + auto *call = IGF.Builder.CreateCall(metadataFn, arguments); + call->setDoesNotThrow(); + return MetadataResponse::forComplete(call); + } + + // If function type has parameter flags or is differentiable or has a + // global actor, emit the most general function to retrieve them. + LLVM_FALLTHROUGH; + } + + default: + assert((!params.empty() || type->isDifferentiable() || + type->getGlobalActor()) && + "0 parameter case should be specialized unless it is a " + "differentiable function or has a global actor"); + + llvm::SmallVector arguments; + + arguments.push_back(flagsVal); + + llvm::Value *diffKindVal = nullptr; + + { + FunctionMetadataDifferentiabilityKind metadataDifferentiabilityKind; + switch (type->getDifferentiabilityKind()) { + case DifferentiabilityKind::NonDifferentiable: + metadataDifferentiabilityKind = + FunctionMetadataDifferentiabilityKind::NonDifferentiable; + break; + case DifferentiabilityKind::Normal: + metadataDifferentiabilityKind = + FunctionMetadataDifferentiabilityKind::Normal; + break; + case DifferentiabilityKind::Linear: + metadataDifferentiabilityKind = + FunctionMetadataDifferentiabilityKind::Linear; + break; + case DifferentiabilityKind::Forward: + metadataDifferentiabilityKind = + FunctionMetadataDifferentiabilityKind::Forward; + break; + case DifferentiabilityKind::Reverse: + metadataDifferentiabilityKind = + FunctionMetadataDifferentiabilityKind::Reverse; + break; + } + + if (type->isDifferentiable()) { + assert(metadataDifferentiabilityKind.isDifferentiable()); + diffKindVal = llvm::ConstantInt::get( + IGF.IGM.SizeTy, metadataDifferentiabilityKind.getIntValue()); + } else if (type->getGlobalActor()) { + diffKindVal = llvm::ConstantInt::get( + IGF.IGM.SizeTy, + FunctionMetadataDifferentiabilityKind::NonDifferentiable); + } + } + + if (diffKindVal) { + arguments.push_back(diffKindVal); + } + + FunctionTypeMetadataParamInfo info; + if (!hasPackExpansion) { + assert(!shapeExpression); + info = emitFunctionTypeMetadataParams(IGF, params, flags, request, + arguments); + } else { + info = emitDynamicFunctionTypeMetadataParams(IGF, params, flags, packType, + request, arguments); + } + + arguments.push_back(result); + + if (Type globalActor = type->getGlobalActor()) { + arguments.push_back( + IGF.emitAbstractTypeMetadataRef(globalActor->getCanonicalType())); + } + + auto getMetadataFn = + type->getGlobalActor() + ? (IGF.IGM.isConcurrencyAvailable() + ? IGF.IGM + .getGetFunctionMetadataGlobalActorFunctionPointer() + : IGF.IGM + .getGetFunctionMetadataGlobalActorBackDeployFunctionPointer()) + : type->isDifferentiable() + ? IGF.IGM.getGetFunctionMetadataDifferentiableFunctionPointer() + : IGF.IGM.getGetFunctionMetadataFunctionPointer(); + + auto call = IGF.Builder.CreateCall(getMetadataFn, arguments); + call->setDoesNotThrow(); + + cleanupFunctionTypeMetadataParams(IGF, info); + + return MetadataResponse::forComplete(call); + } +} + namespace { /// A visitor class for emitting a reference to a metatype object. /// This implements a "raw" access, useful for implementing cache @@ -1516,256 +1852,14 @@ namespace { return MetadataResponse::getUndef(IGF); } - llvm::Value *getFunctionParameterRef(AnyFunctionType::CanParam ¶m) { - auto type = param.getPlainType()->getCanonicalType(); - return IGF.emitAbstractTypeMetadataRef(type); - } - MetadataResponse visitFunctionType(CanFunctionType type, DynamicMetadataRequest request) { if (auto metatype = tryGetLocal(type, request)) return metatype; - auto result = - IGF.emitAbstractTypeMetadataRef(type->getResult()->getCanonicalType()); - - auto params = type.getParams(); - auto numParams = params.size(); - - // Retrieve the ABI parameter flags from the type-level parameter - // flags. - auto getABIParameterFlags = [](ParameterTypeFlags flags) { - return ParameterFlags() - .withValueOwnership(flags.getValueOwnership()) - .withVariadic(flags.isVariadic()) - .withAutoClosure(flags.isAutoClosure()) - .withNoDerivative(flags.isNoDerivative()) - .withIsolated(flags.isIsolated()); - }; - - bool hasParameterFlags = false; - for (auto param : params) { - if (!getABIParameterFlags(param.getParameterFlags()).isNone()) { - hasParameterFlags = true; - break; - } - } - - // Map the convention to a runtime metadata value. - FunctionMetadataConvention metadataConvention; - bool isEscaping = false; - switch (type->getRepresentation()) { - case FunctionTypeRepresentation::Swift: - metadataConvention = FunctionMetadataConvention::Swift; - isEscaping = !type->isNoEscape(); - break; - case FunctionTypeRepresentation::Thin: - metadataConvention = FunctionMetadataConvention::Thin; - break; - case FunctionTypeRepresentation::Block: - metadataConvention = FunctionMetadataConvention::Block; - break; - case FunctionTypeRepresentation::CFunctionPointer: - metadataConvention = FunctionMetadataConvention::CFunctionPointer; - break; - } - - FunctionMetadataDifferentiabilityKind metadataDifferentiabilityKind; - switch (type->getDifferentiabilityKind()) { - case DifferentiabilityKind::NonDifferentiable: - metadataDifferentiabilityKind = - FunctionMetadataDifferentiabilityKind::NonDifferentiable; - break; - case DifferentiabilityKind::Normal: - metadataDifferentiabilityKind = - FunctionMetadataDifferentiabilityKind::Normal; - break; - case DifferentiabilityKind::Linear: - metadataDifferentiabilityKind = - FunctionMetadataDifferentiabilityKind::Linear; - break; - case DifferentiabilityKind::Forward: - metadataDifferentiabilityKind = - FunctionMetadataDifferentiabilityKind::Forward; - break; - case DifferentiabilityKind::Reverse: - metadataDifferentiabilityKind = - FunctionMetadataDifferentiabilityKind::Reverse; - break; - } - - auto flags = FunctionTypeFlags() - .withNumParameters(numParams) - .withConvention(metadataConvention) - .withAsync(type->isAsync()) - .withConcurrent(type->isSendable()) - .withThrows(type->isThrowing()) - .withParameterFlags(hasParameterFlags) - .withEscaping(isEscaping) - .withDifferentiable(type->isDifferentiable()) - .withGlobalActor(!type->getGlobalActor().isNull()); - - auto flagsVal = llvm::ConstantInt::get(IGF.IGM.SizeTy, - flags.getIntValue()); - llvm::Value *diffKindVal = nullptr; - if (type->isDifferentiable()) { - assert(metadataDifferentiabilityKind.isDifferentiable()); - diffKindVal = llvm::ConstantInt::get( - IGF.IGM.SizeTy, metadataDifferentiabilityKind.getIntValue()); - } else if (type->getGlobalActor()) { - diffKindVal = llvm::ConstantInt::get( - IGF.IGM.SizeTy, - FunctionMetadataDifferentiabilityKind::NonDifferentiable); - } - - auto collectParameters = - [&](llvm::function_ref - processor) { - for (auto index : indices(params)) { - auto param = params[index]; - auto flags = param.getParameterFlags(); - - auto parameterFlags = getABIParameterFlags(flags); - processor(index, getFunctionParameterRef(param), parameterFlags); - } - }; - - auto constructSimpleCall = - [&](llvm::SmallVectorImpl &arguments) - -> FunctionPointer { - arguments.push_back(flagsVal); - - collectParameters([&](unsigned i, llvm::Value *typeRef, - ParameterFlags flags) { - arguments.push_back(typeRef); - if (hasParameterFlags) - arguments.push_back( - llvm::ConstantInt::get(IGF.IGM.Int32Ty, flags.getIntValue())); - }); - - arguments.push_back(result); - - switch (params.size()) { - case 0: - return IGF.IGM.getGetFunctionMetadata0FunctionPointer(); - - case 1: - return IGF.IGM.getGetFunctionMetadata1FunctionPointer(); - - case 2: - return IGF.IGM.getGetFunctionMetadata2FunctionPointer(); - - case 3: - return IGF.IGM.getGetFunctionMetadata3FunctionPointer(); - - default: - llvm_unreachable("supports only 1/2/3 parameter functions"); - } - }; - - switch (numParams) { - case 0: - case 1: - case 2: - case 3: { - if (!hasParameterFlags && !type->isDifferentiable() && - !type->getGlobalActor()) { - llvm::SmallVector arguments; - auto metadataFn = constructSimpleCall(arguments); - auto *call = IGF.Builder.CreateCall(metadataFn, arguments); - call->setDoesNotThrow(); - return setLocal(CanType(type), MetadataResponse::forComplete(call)); - } - - // If function type has parameter flags or is differentiable or has a - // global actor, emit the most general function to retrieve them. - LLVM_FALLTHROUGH; - } - - default: - assert((!params.empty() || type->isDifferentiable() || - type->getGlobalActor()) && - "0 parameter case should be specialized unless it is a " - "differentiable function or has a global actor"); - - auto *const Int32Ptr = IGF.IGM.Int32Ty->getPointerTo(); - llvm::SmallVector arguments; - - arguments.push_back(flagsVal); - - if (diffKindVal) { - arguments.push_back(diffKindVal); - } + auto response = emitFunctionTypeMetadataRef(IGF, type, request); - ConstantInitBuilder paramFlags(IGF.IGM); - auto flagsArr = paramFlags.beginArray(); - - Address parameters; - if (!params.empty()) { - auto arrayTy = - llvm::ArrayType::get(IGF.IGM.TypeMetadataPtrTy, numParams); - parameters = IGF.createAlloca( - arrayTy, IGF.IGM.getTypeMetadataAlignment(), "function-parameters"); - - IGF.Builder.CreateLifetimeStart(parameters, - IGF.IGM.getPointerSize() * numParams); - - collectParameters([&](unsigned i, llvm::Value *typeRef, - ParameterFlags flags) { - auto argPtr = IGF.Builder.CreateStructGEP(parameters, i, - IGF.IGM.getPointerSize()); - IGF.Builder.CreateStore(typeRef, argPtr); - if (i == 0) - arguments.push_back(argPtr.getAddress()); - - if (hasParameterFlags) - flagsArr.addInt32(flags.getIntValue()); - }); - } else { - auto parametersPtr = - llvm::ConstantPointerNull::get( - IGF.IGM.TypeMetadataPtrTy->getPointerTo()); - arguments.push_back(parametersPtr); - } - - if (hasParameterFlags) { - auto *flagsVar = flagsArr.finishAndCreateGlobal( - "parameter-flags", IGF.IGM.getPointerAlignment(), - /* constant */ true); - arguments.push_back(IGF.Builder.CreateBitCast(flagsVar, Int32Ptr)); - } else { - flagsArr.abandon(); - arguments.push_back(llvm::ConstantPointerNull::get(Int32Ptr)); - } - - arguments.push_back(result); - - if (Type globalActor = type->getGlobalActor()) { - arguments.push_back( - IGF.emitAbstractTypeMetadataRef(globalActor->getCanonicalType())); - } - - auto getMetadataFn = - type->getGlobalActor() - ? (IGF.IGM.isConcurrencyAvailable() - ? IGF.IGM - .getGetFunctionMetadataGlobalActorFunctionPointer() - : IGF.IGM - .getGetFunctionMetadataGlobalActorBackDeployFunctionPointer()) - : type->isDifferentiable() - ? IGF.IGM.getGetFunctionMetadataDifferentiableFunctionPointer() - : IGF.IGM.getGetFunctionMetadataFunctionPointer(); - - auto call = IGF.Builder.CreateCall(getMetadataFn, arguments); - call->setDoesNotThrow(); - - if (parameters.isValid()) - IGF.Builder.CreateLifetimeEnd(parameters, - IGF.IGM.getPointerSize() * numParams); - - return setLocal(type, MetadataResponse::forComplete(call)); - } + return setLocal(type, response); } MetadataResponse visitMetatypeType(CanMetatypeType type, diff --git a/lib/IRGen/MetadataRequest.h b/lib/IRGen/MetadataRequest.h index d8e08b78f50e2..f752e399c74ed 100644 --- a/lib/IRGen/MetadataRequest.h +++ b/lib/IRGen/MetadataRequest.h @@ -709,6 +709,8 @@ MetadataResponse emitCheckTypeMetadataState(IRGenFunction &IGF, OperationCost getCheckTypeMetadataStateCost(DynamicMetadataRequest request, MetadataResponse response); +ParameterFlags getABIParameterFlags(ParameterTypeFlags flags); + } // end namespace irgen } // end namespace swift diff --git a/test/Interpreter/variadic_generic_func_types.swift b/test/Interpreter/variadic_generic_func_types.swift new file mode 100644 index 0000000000000..3c7614ba87cd6 --- /dev/null +++ b/test/Interpreter/variadic_generic_func_types.swift @@ -0,0 +1,42 @@ +// RUN: %target-run-simple-swift + +// REQUIRES: executable_test + +import StdlibUnittest + +var funcs = TestSuite("VariadicGenericFuncTypes") + +func makeFunctionType1(_: repeat (each T).Type) -> Any.Type { + return ((repeat each T) -> ()).self +} + +func makeFunctionType2(_: repeat (each T).Type) -> Any.Type { + return ((Character, repeat each T, Bool) -> ()).self +} + +func makeFunctionType3(_: repeat (each T).Type) -> Any.Type { + return ((inout Character, repeat each T, inout Bool) -> ()).self +} + +funcs.test("makeFunctionType1") { + expectEqual("() -> ()", _typeName(makeFunctionType1())) + expectEqual("(Swift.Int) -> ()", _typeName(makeFunctionType1(Int.self))) + expectEqual("(Swift.Int, Swift.String) -> ()", _typeName(makeFunctionType1(Int.self, String.self))) + expectEqual("(Swift.Int, Swift.Float, Swift.String) -> ()", _typeName(makeFunctionType1(Int.self, Float.self, String.self))) +} + +funcs.test("makeFunctionType2") { + expectEqual("(Swift.Character, Swift.Bool) -> ()", _typeName(makeFunctionType2())) + expectEqual("(Swift.Character, Swift.Int, Swift.Bool) -> ()", _typeName(makeFunctionType2(Int.self))) + expectEqual("(Swift.Character, Swift.Int, Swift.String, Swift.Bool) -> ()", _typeName(makeFunctionType2(Int.self, String.self))) + expectEqual("(Swift.Character, Swift.Int, Swift.Float, Swift.String, Swift.Bool) -> ()", _typeName(makeFunctionType2(Int.self, Float.self, String.self))) +} + +funcs.test("makeFunctionType3") { + expectEqual("(inout Swift.Character, inout Swift.Bool) -> ()", _typeName(makeFunctionType3())) + expectEqual("(inout Swift.Character, Swift.Int, inout Swift.Bool) -> ()", _typeName(makeFunctionType3(Int.self))) + expectEqual("(inout Swift.Character, Swift.Int, Swift.String, inout Swift.Bool) -> ()", _typeName(makeFunctionType3(Int.self, String.self))) + expectEqual("(inout Swift.Character, Swift.Int, Swift.Float, Swift.String, inout Swift.Bool) -> ()", _typeName(makeFunctionType3(Int.self, Float.self, String.self))) +} + +runAllTests()