diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index af94e0467ca24..f3b08d07db7d6 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -3958,7 +3958,7 @@ class GenericTypeParamDecl final /// type parameter. /// /// \code - /// struct Vector + /// struct Slab /// \endcode bool isValue() const { return getParamKind() == GenericTypeParamKind::Value; diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 2b77c58419fab..91477d2ca808e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8175,6 +8175,13 @@ ERROR(availability_value_generic_type_only_version_newer, none, ERROR(invalid_value_for_type_same_type,none, "cannot constrain type parameter %0 to be integer %1", (Type, Type)) +//===----------------------------------------------------------------------===// +// MARK: Slab +//===----------------------------------------------------------------------===// + +ERROR(slab_literal_incorrect_count,none, + "expected %0 elements in slab literal, but got %1", (Type, Type)) + //===----------------------------------------------------------------------===// // MARK: @abi Attribute //===----------------------------------------------------------------------===// diff --git a/include/swift/AST/KnownStdlibTypes.def b/include/swift/AST/KnownStdlibTypes.def index d8c772bf9c7da..44c861b34f1a1 100644 --- a/include/swift/AST/KnownStdlibTypes.def +++ b/include/swift/AST/KnownStdlibTypes.def @@ -97,4 +97,6 @@ KNOWN_STDLIB_TYPE_DECL(DecodingError, NominalTypeDecl, 0) KNOWN_STDLIB_TYPE_DECL(Result, NominalTypeDecl, 2) +KNOWN_STDLIB_TYPE_DECL(Slab, NominalTypeDecl, 2) + #undef KNOWN_STDLIB_TYPE_DECL diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index f73bab6650221..680d2c55e3129 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -7246,7 +7246,7 @@ class GenericTypeParamType : public SubstitutableType, /// Returns \c true if this type parameter is declared as a value. /// /// \code - /// struct Vector + /// struct Slab /// \endcode bool isValue() const { return ParamKind == GenericTypeParamKind::Value; diff --git a/include/swift/RemoteInspection/TypeLowering.h b/include/swift/RemoteInspection/TypeLowering.h index fbf5bda7e2ae1..c1f333f182ede 100644 --- a/include/swift/RemoteInspection/TypeLowering.h +++ b/include/swift/RemoteInspection/TypeLowering.h @@ -117,6 +117,7 @@ enum class TypeInfoKind : unsigned { Reference, Invalid, Enum, + Array, }; class TypeInfo { @@ -350,6 +351,24 @@ class ReferenceTypeInfo : public TypeInfo { } }; +/// Array based layouts like Builtin.FixedArray +class ArrayTypeInfo : public TypeInfo { + const TypeInfo *ElementTI; + +public: + explicit ArrayTypeInfo(intptr_t size, const TypeInfo *elementTI); + + bool readExtraInhabitantIndex(remote::MemoryReader &reader, + remote::RemoteAddress address, + int *extraInhabitantIndex) const override; + + BitMask getSpareBits(TypeConverter &TC, bool &hasAddrOnly) const override; + + static bool classof(const TypeInfo *TI) { + return TI->getKind() == TypeInfoKind::Array; + } +}; + /// This class owns the memory for all TypeInfo instances that it vends. class TypeConverter { TypeRefBuilder &Builder; diff --git a/include/swift/RemoteInspection/TypeRef.h b/include/swift/RemoteInspection/TypeRef.h index 75be1c74547e3..593a923d35370 100644 --- a/include/swift/RemoteInspection/TypeRef.h +++ b/include/swift/RemoteInspection/TypeRef.h @@ -1095,6 +1095,68 @@ class SILBoxTypeWithLayoutTypeRef final : public TypeRef { } }; +class IntegerTypeRef final : public TypeRef { + intptr_t Value; + + static TypeRefID Profile(const intptr_t &Value) { + TypeRefID ID; + ID.addInteger((uint64_t)Value); + return ID; + } + +public: + IntegerTypeRef(const intptr_t &Value) + : TypeRef(TypeRefKind::Integer), Value(Value) {} + + template + static const IntegerTypeRef *create(Allocator &A, intptr_t Value) { + FIND_OR_CREATE_TYPEREF(A, IntegerTypeRef, Value); + } + + const intptr_t &getValue() const { + return Value; + } + + static bool classof(const TypeRef *TR) { + return TR->getKind() == TypeRefKind::Integer; + } +}; + +class BuiltinFixedArrayTypeRef final : public TypeRef { + const TypeRef *Size; + const TypeRef *Element; + + static TypeRefID Profile(const TypeRef *Size, const TypeRef *Element) { + TypeRefID ID; + ID.addPointer(Size); + ID.addPointer(Element); + return ID; + } + +public: + BuiltinFixedArrayTypeRef(const TypeRef *Size, const TypeRef *Element) + : TypeRef(TypeRefKind::BuiltinFixedArray), Size(Size), Element(Element) {} + + template + static const BuiltinFixedArrayTypeRef *create(Allocator &A, + const TypeRef *Size, + const TypeRef *Element) { + FIND_OR_CREATE_TYPEREF(A, BuiltinFixedArrayTypeRef, Size, Element); + } + + const TypeRef *getSizeType() const { + return Size; + } + + const TypeRef *getElementType() const { + return Element; + } + + static bool classof(const TypeRef *TR) { + return TR->getKind() == TypeRefKind::BuiltinFixedArray; + } +}; + template class TypeRefVisitor { public: diff --git a/include/swift/RemoteInspection/TypeRefBuilder.h b/include/swift/RemoteInspection/TypeRefBuilder.h index fcc05192631a0..2fa93eda58fda 100644 --- a/include/swift/RemoteInspection/TypeRefBuilder.h +++ b/include/swift/RemoteInspection/TypeRefBuilder.h @@ -929,19 +929,16 @@ class TypeRefBuilder { } const TypeRef *createIntegerType(intptr_t value) { - // FIXME: implement - return nullptr; + return IntegerTypeRef::create(*this, value); } const TypeRef *createNegativeIntegerType(intptr_t value) { - // FIXME: implement - return nullptr; + return IntegerTypeRef::create(*this, value); } const TypeRef *createBuiltinFixedArrayType(const TypeRef *size, const TypeRef *element) { - // FIXME: implement - return nullptr; + return BuiltinFixedArrayTypeRef::create(*this, size, element); } // Construct a bound generic type ref along with the parent type info diff --git a/include/swift/RemoteInspection/TypeRefs.def b/include/swift/RemoteInspection/TypeRefs.def index e95845700b539..e3174bb620350 100644 --- a/include/swift/RemoteInspection/TypeRefs.def +++ b/include/swift/RemoteInspection/TypeRefs.def @@ -37,5 +37,7 @@ TYPEREF(OpaqueArchetype, TypeRef) #include "swift/AST/ReferenceStorage.def" TYPEREF(SILBox, TypeRef) TYPEREF(SILBoxTypeWithLayout, TypeRef) +TYPEREF(Integer, TypeRef) +TYPEREF(BuiltinFixedArray, TypeRef) #undef TYPEREF diff --git a/include/swift/Sema/CSFix.h b/include/swift/Sema/CSFix.h index 9821fcea3312c..b378697d0f372 100644 --- a/include/swift/Sema/CSFix.h +++ b/include/swift/Sema/CSFix.h @@ -483,6 +483,10 @@ enum class FixKind : uint8_t { /// sending result, but is passed a function typed parameter without a sending /// result. AllowSendingMismatch, + + /// Ignore when a 'Slab' literal has mismatched number of elements to the + /// type it's attempting to bind to. + AllowSlabLiteralCountMismatch, }; class ConstraintFix { @@ -3837,6 +3841,30 @@ class IgnoreKeyPathSubscriptIndexMismatch final : public ConstraintFix { } }; +class AllowSlabLiteralCountMismatch final : public ConstraintFix { + Type lhsCount, rhsCount; + + AllowSlabLiteralCountMismatch(ConstraintSystem &cs, Type lhsCount, + Type rhsCount, ConstraintLocator *locator) + : ConstraintFix(cs, FixKind::AllowSlabLiteralCountMismatch, locator), + lhsCount(lhsCount), rhsCount(rhsCount) {} + +public: + std::string getName() const override { + return "allow vector literal count mismatch"; + } + + bool diagnose(const Solution &solution, bool asNote = false) const override; + + static AllowSlabLiteralCountMismatch * + create(ConstraintSystem &cs, Type lhsCount, Type rhsCount, + ConstraintLocator *locator); + + static bool classof(const ConstraintFix *fix) { + return fix->getKind() == FixKind::AllowSlabLiteralCountMismatch; + } +}; + } // end namespace constraints } // end namespace swift diff --git a/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h index 800b27ea5c5c5..3fa7e3c4145c7 100644 --- a/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h +++ b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h @@ -143,6 +143,9 @@ typedef enum swift_layout_kind { // swift_reflection_infoForTypeRef(). SWIFT_CLASS_INSTANCE, SWIFT_CLOSURE_CONTEXT, + + // A contiguous list of N Ts, typically for Builtin.FixedArray. + SWIFT_ARRAY, } swift_layout_kind_t; struct swift_childinfo; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index feb308e35ead2..44d360bb66969 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -1277,6 +1277,7 @@ namespace { break; case GenericTypeParamKind::Value: printField((StringRef)"value", "param_kind"); + printRec(decl->getValueType(), "value_type"); break; } printAttributes(decl); diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index caaaafe36aafc..ad54fc4cf72d7 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -442,7 +442,7 @@ enum class BuiltinThrowsKind : uint8_t { static FuncDecl *getBuiltinGenericFunction( Identifier Id, ArrayRef ArgParamTypes, Type ResType, GenericParamList *GenericParams, GenericSignature Sig, bool Async, - BuiltinThrowsKind Throws, bool SendingResult) { + BuiltinThrowsKind Throws, Type ThrownError, bool SendingResult) { assert(GenericParams && "Missing generic parameters"); auto &Context = ResType->getASTContext(); @@ -471,7 +471,7 @@ static FuncDecl *getBuiltinGenericFunction( Context, StaticSpellingKind::None, Name, /*NameLoc=*/SourceLoc(), Async, - Throws != BuiltinThrowsKind::None, /*thrownType=*/Type(), + Throws != BuiltinThrowsKind::None, ThrownError, GenericParams, paramList, ResType, DC); func->setSendingResult(SendingResult); @@ -696,6 +696,7 @@ namespace { Type InterfaceResult; bool Async = false; BuiltinThrowsKind Throws = BuiltinThrowsKind::None; + Type ThrownError; bool SendingResult = false; // Accumulate params and requirements here, so that we can call @@ -740,6 +741,11 @@ namespace { InterfaceResult = generator.build(*this); } + template + void setThrownError(const G &generator) { + ThrownError = generator.build(*this); + } + template void addConformanceRequirement(const G &generator, KnownProtocolKind kp) { addConformanceRequirement(generator, Context.getProtocol(kp)); @@ -776,7 +782,7 @@ namespace { /*allowInverses=*/false); return getBuiltinGenericFunction(name, InterfaceParams, InterfaceResult, TheGenericParamList, GenericSig, Async, - Throws, SendingResult); + Throws, ThrownError, SendingResult); } // Don't use these generator classes directly; call the make{...} @@ -2231,17 +2237,31 @@ static ValueDecl *getAddressOfRawLayout(ASTContext &ctx, Identifier id) { } static ValueDecl *getEmplace(ASTContext &ctx, Identifier id) { - BuiltinFunctionBuilder builder(ctx, /* genericParamCount */ 1); + BuiltinFunctionBuilder builder(ctx, /* genericParamCount */ 2); - auto T = makeGenericParam(); + // ( + // _: (Builtin.RawPointer) throws(E) -> () + // ) throws(E) -> T + + auto T = makeGenericParam(0); builder.addConformanceRequirement(T, KnownProtocolKind::Escapable); + auto E = makeGenericParam(1); + builder.addConformanceRequirement(E, KnownProtocolKind::Error); + + auto extInfo = ASTExtInfoBuilder() + .withNoEscape() + .withThrows(/* throws */ true, E.build(builder)) + .build(); + auto fnParamTy = FunctionType::get(FunctionType::Param(ctx.TheRawPointerType), ctx.TheEmptyTupleType, - ASTExtInfo().withNoEscape()); + extInfo); builder.addParameter(makeConcrete(fnParamTy), ParamSpecifier::Borrowing); builder.setResult(T); + builder.setThrows(); + builder.setThrownError(E); return builder.build(id); } diff --git a/lib/AST/GenericParamList.cpp b/lib/AST/GenericParamList.cpp index 366fa42d28292..7ca5ffbb42f36 100644 --- a/lib/AST/GenericParamList.cpp +++ b/lib/AST/GenericParamList.cpp @@ -17,6 +17,7 @@ #include "swift/AST/GenericParamList.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/Assertions.h" @@ -78,6 +79,12 @@ GenericParamList::clone(DeclContext *dc) const { dc, param->getName(), GenericTypeParamDecl::InvalidDepth, param->getIndex(), param->getParamKind(), param->getOpaqueTypeRepr()); newParam->setInherited(param->getInherited().getEntries()); + + // Cache the value type computed from the previous param to the new one. + ctx.evaluator.cacheOutput( + GenericTypeParamDeclGetValueTypeRequest{newParam}, + param->getValueType()); + params.push_back(newParam); } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 86a3f59b0b384..a30d09a577838 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -808,8 +808,11 @@ CanType CanType::wrapInOptionalTypeImpl(CanType type) { Type TypeBase::isArrayType() { if (auto boundStruct = getAs()) { - if (boundStruct->getDecl() == getASTContext().getArrayDecl()) + if (isArray()) return boundStruct->getGenericArgs()[0]; + + if (isSlab()) + return boundStruct->getGenericArgs()[1]; } return Type(); } diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 40f7be7116df7..f1c5b272e20c1 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -645,12 +645,13 @@ namespace { return Type(); auto size = type->getSize().getZExtValue(); + // An array of size N is imported as an N-element tuple which // takes very long to compile. We chose 4096 as the upper limit because // we don't want to break arrays of size PATH_MAX. if (size > 4096) return Type(); - + if (size == 1) return elementType; diff --git a/lib/IRGen/GenArray.cpp b/lib/IRGen/GenArray.cpp index b32ae7d62ab25..39190515df1d5 100644 --- a/lib/IRGen/GenArray.cpp +++ b/lib/IRGen/GenArray.cpp @@ -94,16 +94,21 @@ class ArrayTypeInfoBase : public BaseTypeInfo { } body(eltAddrs); - + + // The just ran body may have generated new blocks. Get the current + // insertion block which will become the other incoming block to the phis + // we've generated. + predBB = IGF.Builder.GetInsertBlock(); + for (unsigned i : indices(addrPhis)) { addrPhis[i]->addIncoming(Element.indexArray(IGF, eltAddrs[i], one, getElementSILType(IGF.IGM, T)) .getAddress(), - loopBB); + predBB); } auto nextCount = IGF.Builder.CreateSub(countPhi, one); - countPhi->addIncoming(nextCount, loopBB); + countPhi->addIncoming(nextCount, predBB); auto done = IGF.Builder.CreateICmpEQ(nextCount, zero); IGF.Builder.CreateCondBr(done, endBB, loopBB); @@ -206,10 +211,15 @@ class FixedArrayTypeInfoBase : public ArrayTypeInfoBase { uint64_t paddingBytes = elementTI.getFixedStride().getValue() - elementTI.getFixedSize().getValue(); auto byteTy = llvm::IntegerType::get(LLVMContext, 8); - elementTy = llvm::StructType::get(LLVMContext, - {elementTy, - llvm::ArrayType::get(byteTy, paddingBytes)}, - /*packed*/ true); + auto paddingArrayTy = llvm::ArrayType::get(byteTy, paddingBytes); + + if (elementTI.getFixedSize() == Size(0)) { + elementTy = paddingArrayTy; + } else { + elementTy = llvm::StructType::get(LLVMContext, + {elementTy, paddingArrayTy}, + /*packed*/ true); + } } return llvm::ArrayType::get(elementTy, arraySize); diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index 4ec6aa3a45927..c31d1f78c8088 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -1163,6 +1163,11 @@ class FixedTypeMetadataBuilder : public ReflectionMetadataBuilder { }; void IRGenModule::emitBuiltinTypeMetadataRecord(CanType builtinType) { + // If this builtin is generic, don't emit anything. + if (builtinType->hasTypeParameter()) { + return; + } + FixedTypeMetadataBuilder builder(*this, builtinType); builder.emit(); } diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index 3bfe1b11eebca..4fcd781368173 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -2375,7 +2375,7 @@ const TypeInfo *TypeConverter::convertType(CanType ty) { case TypeKind::SILToken: llvm_unreachable("should not be asking for representation of a SILToken"); case TypeKind::Integer: - llvm_unreachable("implement me"); + llvm_unreachable("should not be asking for the type info an IntegerType"); } } llvm_unreachable("bad type kind"); diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index d974f863d9806..18dc74ca43c48 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -1534,13 +1534,18 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type, for (auto Arg : GenericArgs) { DebugTypeInfo ParamDebugType; if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes && - !AsForwardDeclarations) - // For the DwarfTypes level don't generate just a forward declaration - // for the generic type parameters. - ParamDebugType = DebugTypeInfo::getFromTypeInfo( - Arg, IGM.getTypeInfoForUnlowered(Arg), IGM); - else + !AsForwardDeclarations) { + if (Arg->is()) { + ParamDebugType = DebugTypeInfo(Arg); + } else { + // For the DwarfTypes level don't generate just a forward declaration + // for the generic type parameters. + ParamDebugType = DebugTypeInfo::getFromTypeInfo( + Arg, IGM.getTypeInfoForUnlowered(Arg), IGM); + } + } else { ParamDebugType = DebugTypeInfo::getForwardDecl(Arg); + } TemplateParams.push_back(DBuilder.createTemplateTypeParameter( TheCU, "", getOrCreateType(ParamDebugType), false)); diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index ae09f70426c94..47dc3bac20eb6 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -716,7 +716,7 @@ ParserStatus Parser::parseGenericArguments(SmallVectorImpl &Args, // variadic generic types. if (!startsWithGreater(Tok)) { while (true) { - // Note: This can be a value type, e.g. 'Vector<3, Int>'. + // Note: This can be a value type, e.g. 'Slab<3, Int>'. ParserResult Ty = parseTypeOrValue(diag::expected_type); if (Ty.isNull() || Ty.hasCodeCompletion()) { // Skip until we hit the '>'. diff --git a/lib/SILGen/SILGenBuiltin.cpp b/lib/SILGen/SILGenBuiltin.cpp index 132aa55af27b7..dac0e2fab314a 100644 --- a/lib/SILGen/SILGenBuiltin.cpp +++ b/lib/SILGen/SILGenBuiltin.cpp @@ -2133,12 +2133,36 @@ static ManagedValue emitBuiltinEmplace(SILGenFunction &SGF, SILValue bufferPtr = SGF.B.createAddressToPointer(loc, buffer, SILType::getPrimitiveObjectType(SGF.getASTContext().TheRawPointerType), /*needs stack protection*/ true); - SGF.B.createApply(loc, args[0].getValue(), {}, bufferPtr); - + + auto fnType = args[0].getValue()->getType().castTo(); + + if (fnType->hasErrorResult()) { + auto normalBB = SGF.createBasicBlock(); + auto errorBB = SGF.createBasicBlock(); + + SGF.B.createTryApply(loc, args[0].getValue(), {}, + {SGF.IndirectErrorResult, bufferPtr}, normalBB, errorBB); + + // Error branch + { + SGF.B.emitBlock(errorBB); + + SGF.Cleanups.emitCleanupsForReturn(CleanupLocation(loc), IsForUnwind); + + SGF.B.createThrowAddr(loc); + } + + SGF.B.emitBlock(normalBB); + + normalBB->createPhiArgument(SILType::getEmptyTupleType(Ctx), + OwnershipKind::Owned); + } else { + SGF.B.createApply(loc, args[0].getValue(), {}, bufferPtr); + } + dest->finishInitialization(SGF); if (didEmitInto) { - C.getEmitInto()->finishInitialization(SGF); return ManagedValue::forInContext(); } diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 535263b261953..0bac472577761 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -4598,7 +4598,76 @@ visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E, SGFContext C) { llvm_unreachable("Unhandled MagicIdentifierLiteralExpr in switch."); } +static RValue emitSlabLiteral(SILGenFunction &SGF, CollectionExpr *E, + SGFContext C) { + ArgumentScope scope(SGF, E); + + auto slabType = E->getType()->castTo(); + auto loweredSlabType = SGF.getLoweredType(slabType); + auto elementType = slabType->getGenericArgs()[1]->getCanonicalType(); + auto loweredElementType = SGF.getLoweredType(elementType); + auto &eltTL = SGF.getTypeLowering(AbstractionPattern::getOpaque(), elementType); + + SILValue alloc = SGF.emitTemporaryAllocation(E, loweredSlabType); + SILValue addr = SGF.B.createUncheckedAddrCast(E, alloc, + loweredElementType.getAddressType()); + + // Cleanups for any elements that have been initialized so far. + SmallVector cleanups; + + for (unsigned index : range(E->getNumElements())) { + auto destAddr = addr; + + if (index != 0) { + SILValue indexValue = SGF.B.createIntegerLiteral( + E, SILType::getBuiltinWordType(SGF.getASTContext()), index); + destAddr = SGF.B.createIndexAddr(E, addr, indexValue, + /*needsStackProtection=*/ false); + } + + // Create a dormant cleanup for the value in case we exit before the + // full vector has been constructed. + + CleanupHandle destCleanup = CleanupHandle::invalid(); + if (!eltTL.isTrivial()) { + destCleanup = SGF.enterDestroyCleanup(destAddr); + SGF.Cleanups.setCleanupState(destCleanup, CleanupState::Dormant); + cleanups.push_back(destCleanup); + } + + TemporaryInitialization init(destAddr, destCleanup); + + ArgumentSource(E->getElements()[index]) + .forwardInto(SGF, AbstractionPattern::getOpaque(), &init, eltTL); + } + + // Kill the per-element cleanups. The slab will take ownership of them. + for (auto destCleanup : cleanups) + SGF.Cleanups.setCleanupState(destCleanup, CleanupState::Dead); + + SILValue slabVal; + + // If the slab is naturally address-only, then we can adopt the stack slot + // as the value directly. + if (loweredSlabType.isAddressOnly(SGF.F)) { + slabVal = SGF.B.createUncheckedAddrCast(E, alloc, loweredSlabType); + } else { + // Otherwise, this slab is loadable. Load it. + slabVal = SGF.B.createTrivialLoadOr(E, alloc, LoadOwnershipQualifier::Take); + } + + auto slabMV = SGF.emitManagedRValueWithCleanup(slabVal); + auto slab = RValue(SGF, E, slabMV); + + return scope.popPreservingValue(std::move(slab)); +} + RValue RValueEmitter::visitCollectionExpr(CollectionExpr *E, SGFContext C) { + // Handle 'Slab' literals separately. + if (E->getType()->isSlab()) { + return emitSlabLiteral(SGF, E, C); + } + auto loc = SILLocation(E); ArgumentScope scope(SGF, loc); diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 0adfc3be4da74..7d04c5a2bf184 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -3792,23 +3792,29 @@ namespace { /// "Finish" an array expression by filling in the semantic expression. ArrayExpr *finishArrayExpr(ArrayExpr *expr) { Type arrayTy = cs.getType(expr); + Type elementType; - ProtocolDecl *arrayProto = TypeChecker::getProtocol( - ctx, expr->getLoc(), KnownProtocolKind::ExpressibleByArrayLiteral); - assert(arrayProto && "type-checked array literal w/o protocol?!"); + if (arrayTy->isSlab()) { + // + elementType = arrayTy->castTo()->getGenericArgs()[1]; + } else { + ProtocolDecl *arrayProto = TypeChecker::getProtocol( + ctx, expr->getLoc(), KnownProtocolKind::ExpressibleByArrayLiteral); + assert(arrayProto && "type-checked array literal w/o protocol?!"); - auto conformance = checkConformance(arrayTy, arrayProto); - assert(conformance && "Type does not conform to protocol?"); + auto conformance = checkConformance(arrayTy, arrayProto); + assert(conformance && "Type does not conform to protocol?"); - DeclName name(ctx, DeclBaseName::createConstructor(), - {ctx.Id_arrayLiteral}); - ConcreteDeclRef witness = - conformance.getWitnessByName(arrayTy->getRValueType(), name); - if (!witness || !isa(witness.getDecl())) - return nullptr; - expr->setInitializer(witness); + DeclName name(ctx, DeclBaseName::createConstructor(), + {ctx.Id_arrayLiteral}); + ConcreteDeclRef witness = + conformance.getWitnessByName(arrayTy->getRValueType(), name); + if (!witness || !isa(witness.getDecl())) + return nullptr; + expr->setInitializer(witness); - auto elementType = expr->getElementType(); + elementType = expr->getElementType(); + } for (unsigned i = 0, n = expr->getNumElements(); i != n; ++i) { expr->setElement( @@ -6792,7 +6798,7 @@ Expr *ExprRewriter::buildCollectionUpcastExpr( bridged, locator, 0); // For single-parameter collections, form the upcast. - if (toType->isArrayType() || ConstraintSystem::isSetType(toType)) { + if (toType->isArray() || ConstraintSystem::isSetType(toType)) { return cs.cacheType( new (ctx) CollectionUpcastConversionExpr(expr, toType, {}, conv)); } @@ -6817,7 +6823,7 @@ Expr *ExprRewriter::buildObjCBridgeExpr(Expr *expr, Type toType, // Bridged collection casts always succeed, so we treat them as // collection "upcasts". - if ((fromType->isArrayType() && toType->isArrayType()) + if ((fromType->isArray() && toType->isArray()) || (ConstraintSystem::isDictionaryType(fromType) && ConstraintSystem::isDictionaryType(toType)) || (ConstraintSystem::isSetType(fromType) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index dfb820e9993e1..fb462e8622780 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -9571,3 +9571,8 @@ bool InvalidTypeAsKeyPathSubscriptIndex::diagnoseAsError() { emitDiagnostic(diag::cannot_convert_type_to_keypath_subscript_index, ArgType); return true; } + +bool IncorrectSlabLiteralCount::diagnoseAsError() { + emitDiagnostic(diag::slab_literal_incorrect_count, lhsCount, rhsCount); + return true; +} diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 7544300e20079..03349edd30443 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -3234,6 +3234,24 @@ class InvalidTypeAsKeyPathSubscriptIndex final : public FailureDiagnostic { bool diagnoseAsError() override; }; +/// Diagnose when a slab literal has an incorrect number of elements for the +/// contextual slab type it's initializing. +/// +/// \code +/// let x: Slab<4, Int> = [1, 2] // expected '4' elements but got '2' +/// \endcode +class IncorrectSlabLiteralCount final : public FailureDiagnostic { + Type lhsCount, rhsCount; + +public: + IncorrectSlabLiteralCount(const Solution &solution, Type lhsCount, + Type rhsCount, ConstraintLocator *locator) + : FailureDiagnostic(solution, locator), lhsCount(resolveType(lhsCount)), + rhsCount(resolveType(rhsCount)) {} + + bool diagnoseAsError() override; +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 139358d858ab1..452a95a87f321 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -2722,3 +2722,17 @@ IgnoreKeyPathSubscriptIndexMismatch::create(ConstraintSystem &cs, Type argType, return new (cs.getAllocator()) IgnoreKeyPathSubscriptIndexMismatch(cs, argType, locator); } + +AllowSlabLiteralCountMismatch * +AllowSlabLiteralCountMismatch::create(ConstraintSystem &cs, Type lhsCount, + Type rhsCount, + ConstraintLocator *locator) { + return new (cs.getAllocator()) + AllowSlabLiteralCountMismatch(cs, lhsCount, rhsCount, locator); +} + +bool AllowSlabLiteralCountMismatch::diagnose(const Solution &solution, + bool asNote) const { + IncorrectSlabLiteralCount failure(solution, lhsCount, rhsCount, getLocator()); + return failure.diagnose(asNote); +} diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 81cac0044f9ab..7d2e4bb90a2d8 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -333,7 +333,7 @@ namespace { baseObjTy = baseObjTy->getWithoutSpecifierType(); } - if (baseObjTy->isArrayType()) { + if (auto elementTy = baseObjTy->isArrayType()) { if (auto arraySliceTy = dyn_cast(baseObjTy.getPointer())) { @@ -343,7 +343,7 @@ namespace { if (argList->isUnlabeledUnary() && isa(argList->getExpr(0))) { - outputTy = baseObjTy->getAs()->getGenericArgs()[0]; + outputTy = elementTy; if (isLValueBase) outputTy = LValueType::get(outputTy); diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index cb83e5ac609fd..952a35ae9e967 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -7779,7 +7779,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, // Special implicit nominal conversions. if (!type1->is() && kind >= ConstraintKind::Subtype) { // Array -> Array. - if (desugar1->isArrayType() && desugar2->isArrayType()) { + if (desugar1->isArray() && desugar2->isArray()) { conversionsOrFixes.push_back(ConversionRestrictionKind::ArrayUpcast); // Dictionary -> Dictionary. } else if (isDictionaryType(desugar1) && isDictionaryType(desugar2)) { @@ -8698,6 +8698,51 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( } } } + + auto arrayLiteralProto = + getASTContext().getProtocol(KnownProtocolKind::ExpressibleByArrayLiteral); + auto anchor = loc->getAnchor(); + auto arrayLiteral = getAsExpr(anchor); + + // If we're attempting to bind an array literal to a 'Slab' parameter, + // then check if the counts are equal and solve. + if (kind == ConstraintKind::LiteralConformsTo && + protocol == arrayLiteralProto && + type->isSlab() && + arrayLiteral) { + auto slabTy = type->castTo(); + + // + // Attempt to bind the number of elements in the literal with the + // contextual count. This will diagnose if the literal does not enough + // or too many elements. + auto contextualCount = slabTy->getGenericArgs()[0]; + auto literalCount = IntegerType::get( + std::to_string(arrayLiteral->getNumElements()), + /* isNegative */ false, + slabTy->getASTContext()); + + // If the counts are already equal, '2' == '2', then we're done. + if (contextualCount->isEqual(literalCount)) { + return SolutionKind::Solved; + } + + // If our contextual count is not known, e.g., Slab<_, Int> = [1, 2], + // then just eagerly bind the count to what the literal count is. + if (contextualCount->isTypeVariableOrMember()) { + addConstraint(ConstraintKind::Bind, contextualCount, literalCount, + locator); + return SolutionKind::Solved; + } + + // Otherwise this is an error and the counts aren't equal to each other. + if (!shouldAttemptFixes()) + return SolutionKind::Error; + + auto fix = AllowSlabLiteralCountMismatch::create(*this, contextualCount, + literalCount, loc); + return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; + } } break; default: @@ -15609,6 +15654,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::IgnoreInvalidPlaceholder: case FixKind::IgnoreOutOfPlaceThenStmt: case FixKind::IgnoreMissingEachKeyword: + case FixKind::AllowSlabLiteralCountMismatch: llvm_unreachable("handled elsewhere"); } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 10399eae78625..c6f508a99489b 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1666,6 +1666,20 @@ struct TypeSimplifier { auto *proto = assocType->getProtocol(); auto conformance = CS.lookupConformance(lookupBaseType, proto); if (!conformance) { + // Special case: When building slab literals, we go through the same + // array literal machinery, so there will be a conversion constraint + // for the element to ExpressibleByArrayLiteral.ArrayLiteralType. + if (lookupBaseType->isSlab()) { + auto &ctx = CS.getASTContext(); + auto arrayProto = + ctx.getProtocol(KnownProtocolKind::ExpressibleByArrayLiteral); + auto elementAssocTy = arrayProto->getAssociatedTypeMembers()[0]; + + if (proto == arrayProto && assocType == elementAssocTy) { + return lookupBaseType->isArrayType(); + } + } + // If the base type doesn't conform to the associatedtype's protocol, // there will be a missing conformance fix applied in diagnostic mode, // so the concrete dependent member type is considered a "hole" in diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 74cc96c8ff74f..1bb0dc2400a37 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -560,6 +560,7 @@ static void checkGenericParams(GenericContext *ownerCtx) { return; auto *decl = ownerCtx->getAsDecl(); + auto &ctx = ownerCtx->getASTContext(); bool hasPack = false; for (auto gp : *genericParams) { @@ -567,10 +568,13 @@ static void checkGenericParams(GenericContext *ownerCtx) { // is not enabled. if (gp->isParameterPack()) { // Variadic nominal types require runtime support. - if (isa(decl)) { + // + // Embedded doesn't require runtime support for this feature. + if (isa(decl) && + !ctx.LangOpts.hasFeature(Feature::Embedded)) { TypeChecker::checkAvailability( gp->getSourceRange(), - ownerCtx->getASTContext().getVariadicGenericTypeAvailability(), + ctx.getVariadicGenericTypeAvailability(), diag::availability_variadic_type_only_version_newer, ownerCtx); } @@ -586,10 +590,13 @@ static void checkGenericParams(GenericContext *ownerCtx) { if (gp->isValue()) { // Value generic nominal types require runtime support. - if (isa(decl)) { + // + // Embedded doesn't require runtime support for this feature. + if (isa(decl) && + !ctx.LangOpts.hasFeature(Feature::Embedded)) { TypeChecker::checkAvailability( gp->getSourceRange(), - ownerCtx->getASTContext().getValueGenericTypeAvailability(), + ctx.getValueGenericTypeAvailability(), diag::availability_value_generic_type_only_version_newer, ownerCtx); } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 9822d574fa013..9beb7b102e0f6 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -748,6 +748,9 @@ namespace { if (secondType->is()) return true; + if (secondType->is()) + return true; + return false; } diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index c4f2b65be04c2..97dd61a461219 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -958,6 +958,7 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(sil_block, SIL_OPEN_PACK_ELEMENT); BLOCK_RECORD(sil_block, SIL_PACK_ELEMENT_GET); BLOCK_RECORD(sil_block, SIL_PACK_ELEMENT_SET); + BLOCK_RECORD(sil_block, SIL_TYPE_VALUE); BLOCK_RECORD(sil_block, SIL_DEBUG_SCOPE); BLOCK_RECORD(sil_block, SIL_DEBUG_SCOPE_REF); BLOCK_RECORD(sil_block, SIL_SOURCE_LOC); diff --git a/stdlib/public/RemoteInspection/TypeLowering.cpp b/stdlib/public/RemoteInspection/TypeLowering.cpp index 541c039f6141f..50b2b3e446d15 100644 --- a/stdlib/public/RemoteInspection/TypeLowering.cpp +++ b/stdlib/public/RemoteInspection/TypeLowering.cpp @@ -217,6 +217,13 @@ class PrintTypeInfo { stream << ")"; return; } + + case TypeInfoKind::Array: { + printHeader("array"); + printBasic(TI); + stream << ")"; + return; + } } swift_unreachable("Bad TypeInfo kind"); @@ -475,6 +482,26 @@ BitMask RecordTypeInfo::getSpareBits(TypeConverter &TC, bool &hasAddrOnly) const return mask; } +ArrayTypeInfo::ArrayTypeInfo(intptr_t size, const TypeInfo *elementTI) + : TypeInfo(TypeInfoKind::Array, + /* size */ elementTI->getStride() * size, + /* alignment */ elementTI->getAlignment(), + /* stride */ elementTI->getStride() * size, + /* numExtraInhabitants */ elementTI->getNumExtraInhabitants(), + /* isBitwiseTakable */ elementTI->isBitwiseTakable()), + ElementTI(elementTI) {} + +bool ArrayTypeInfo::readExtraInhabitantIndex( + remote::MemoryReader &reader, remote::RemoteAddress address, + int *extraInhabitantIndex) const { + return ElementTI->readExtraInhabitantIndex(reader, address, + extraInhabitantIndex); +} + +BitMask ArrayTypeInfo::getSpareBits(TypeConverter &TC, bool &hasAddrOnly) const { + return ElementTI->getSpareBits(TC, hasAddrOnly); +} + class UnsupportedEnumTypeInfo: public EnumTypeInfo { public: UnsupportedEnumTypeInfo(unsigned Size, unsigned Alignment, @@ -1786,6 +1813,14 @@ class HasFixedSize bool visitOpaqueArchetypeTypeRef(const OpaqueArchetypeTypeRef *O) { return false; } + + bool visitIntegerTypeRef(const IntegerTypeRef *I) { + return false; + } + + bool visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + return visit(BA->getElementType()); + } }; bool TypeConverter::hasFixedSize(const TypeRef *TR) { @@ -1921,6 +1956,14 @@ class HasSingletonMetatype MetatypeRepresentation visitOpaqueArchetypeTypeRef(const OpaqueArchetypeTypeRef *O) { return MetatypeRepresentation::Unknown; } + + MetatypeRepresentation visitIntegerTypeRef(const IntegerTypeRef *I) { + return MetatypeRepresentation::Unknown; + } + + MetatypeRepresentation visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + return visit(BA->getElementType()); + } }; class EnumTypeInfoBuilder { @@ -2544,6 +2587,18 @@ class LowerType DEBUG_LOG(fprintf(stderr, "Can't lower unresolved opaque archetype TypeRef")); return nullptr; } + + const TypeInfo *visitIntegerTypeRef(const IntegerTypeRef *I) { + DEBUG_LOG(fprintf(stderr, "Can't lower integer TypeRef")); + return nullptr; + } + + const TypeInfo *visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + auto elementTI = visit(BA->getElementType()); + auto size = cast(BA->getSizeType())->getValue(); + + return TC.makeTypeInfo(size, elementTI); + } }; const TypeInfo * diff --git a/stdlib/public/RemoteInspection/TypeRef.cpp b/stdlib/public/RemoteInspection/TypeRef.cpp index e7ebbfd90e2c2..bfa75f1d0f5e0 100644 --- a/stdlib/public/RemoteInspection/TypeRef.cpp +++ b/stdlib/public/RemoteInspection/TypeRef.cpp @@ -395,6 +395,19 @@ class PrintTypeRef : public TypeRefVisitor { printHeader("opaque"); stream << ")"; } + + void visitIntegerTypeRef(const IntegerTypeRef *I) { + printHeader("integer"); + printField("value", std::to_string(I->getValue())); + stream << ")"; + } + + void visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + printHeader("builtin_fixed_array"); + printRec(BA->getSizeType()); + printRec(BA->getElementType()); + stream << ")"; + } }; struct TypeRefIsConcrete @@ -506,6 +519,14 @@ struct TypeRefIsConcrete bool visitSILBoxTypeWithLayoutTypeRef(const SILBoxTypeWithLayoutTypeRef *SB) { return true; } + + bool visitIntegerTypeRef(const IntegerTypeRef *I) { + return true; + } + + bool visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + return visit(BA->getElementType()); + } }; const OpaqueTypeRef * @@ -1049,6 +1070,27 @@ class DemanglingForTypeRef return node; } + + Demangle::NodePointer createInteger(intptr_t value) { + if (value >= 0) { + return Dem.createNode(Node::Kind::Integer, value); + } else { + return Dem.createNode(Node::Kind::NegativeInteger, value); + } + } + + Demangle::NodePointer visitIntegerTypeRef(const IntegerTypeRef *I) { + return createInteger(I->getValue()); + } + + Demangle::NodePointer visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + auto ba = Dem.createNode(Node::Kind::BuiltinFixedArray); + + ba->addChild(visit(BA->getSizeType()), Dem); + ba->addChild(visit(BA->getElementType()), Dem); + + return ba; + } }; Demangle::NodePointer TypeRef::getDemangling(Demangle::Demangler &Dem) const { @@ -1277,6 +1319,14 @@ class ThickenMetatype return O; } + const TypeRef *visitIntegerTypeRef(const IntegerTypeRef *I) { + return I; + } + + const TypeRef *visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + return BuiltinFixedArrayTypeRef::create(Builder, visit(BA->getSizeType()), + visit(BA->getElementType())); + } }; static const TypeRef * @@ -1531,6 +1581,15 @@ class TypeRefSubstitution O->getOrdinal(), newArgLists); } + + const TypeRef *visitIntegerTypeRef(const IntegerTypeRef *I) { + return I; + } + + const TypeRef *visitBuiltinFixedArrayTypeRef(const BuiltinFixedArrayTypeRef *BA) { + return BuiltinFixedArrayTypeRef::create(Builder, visit(BA->getSizeType()), + visit(BA->getElementType())); + } }; const TypeRef *TypeRef::subst(TypeRefBuilder &Builder, diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp index a8873725f13df..64911bd4217cd 100644 --- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp +++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp @@ -529,6 +529,10 @@ swift_layout_kind_t getTypeInfoKind(const TypeInfo &TI) { #include "swift/AST/ReferenceStorage.def" } } + + case TypeInfoKind::Array: { + return SWIFT_ARRAY; + } } swift_unreachable("Unhandled TypeInfoKind in switch"); diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index a03cb87083051..eb9547e7491dd 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -151,6 +151,7 @@ split_embedded_sources( EMBEDDED SetVariant.swift EMBEDDED ShadowProtocols.swift NORMAL Shims.swift + EMBEDDED Slab.swift EMBEDDED Slice.swift EMBEDDED SmallString.swift EMBEDDED Sort.swift @@ -318,6 +319,9 @@ list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "Macros") list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "FreestandingMacros") list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "Extern") list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "BitwiseCopyable") +list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "ValueGenerics") +list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "AddressableParameters") +list(APPEND swift_stdlib_compile_flags "-enable-experimental-feature" "AddressableTypes") if("${SWIFT_NATIVE_SWIFT_TOOLS_PATH}" STREQUAL "") set(swift_bin_dir "${CMAKE_BINARY_DIR}/bin") diff --git a/stdlib/public/core/GroupInfo.json b/stdlib/public/core/GroupInfo.json index 76cc3f7b1b680..93786a2f20c8b 100644 --- a/stdlib/public/core/GroupInfo.json +++ b/stdlib/public/core/GroupInfo.json @@ -256,7 +256,8 @@ "Instant.swift", "EmbeddedRuntime.swift", "EmbeddedStubs.swift", - "EmbeddedPrint.swift" + "EmbeddedPrint.swift", + "Slab.swift" ], "Result": [ "Result.swift" diff --git a/stdlib/public/core/Slab.swift b/stdlib/public/core/Slab.swift new file mode 100644 index 0000000000000..b96f3fe11dc3d --- /dev/null +++ b/stdlib/public/core/Slab.swift @@ -0,0 +1,482 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2024 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 +// +//===----------------------------------------------------------------------===// + +/// A fixed-size array. +@available(SwiftStdlib 6.1, *) +@frozen +public struct Slab: ~Copyable { + @usableFromInline + internal let _storage: Builtin.FixedArray +} + +@available(SwiftStdlib 6.1, *) +extension Slab: Copyable where Element: Copyable {} + +@available(SwiftStdlib 6.1, *) +extension Slab: BitwiseCopyable where Element: BitwiseCopyable {} + +@available(SwiftStdlib 6.1, *) +extension Slab: @unchecked Sendable where Element: Sendable & ~Copyable {} + +//===----------------------------------------------------------------------===// +// Address & Buffer +//===----------------------------------------------------------------------===// + +@available(SwiftStdlib 6.1, *) +extension Slab where Element: ~Copyable { + /// Returns a read-only pointer to the first element in the vector. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + internal var _address: UnsafePointer { + UnsafePointer(Builtin.unprotectedAddressOfBorrow(self)) + } + + /// Returns a buffer pointer over the entire vector. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + internal var _buffer: UnsafeBufferPointer { + UnsafeBufferPointer(start: _address, count: count) + } + + /// Returns a mutable pointer to the first element in the vector. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + internal var _mutableAddress: UnsafeMutablePointer { + mutating get { + UnsafeMutablePointer(Builtin.unprotectedAddressOf(&self)) + } + } + + /// Returns a mutable buffer pointer over the entire vector. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + internal var _mutableBuffer: UnsafeMutableBufferPointer { + mutating get { + UnsafeMutableBufferPointer(start: _mutableAddress, count: count) + } + } + + /// Returns the given raw pointer, which points at an uninitialized vector + /// instance, to a mutable buffer suitable for initialization. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + internal static func _initializationBuffer( + start: Builtin.RawPointer + ) -> UnsafeMutableBufferPointer { + UnsafeMutableBufferPointer( + start: UnsafeMutablePointer(start), + count: count + ) + } +} + +//===----------------------------------------------------------------------===// +// Initialization APIs +//===----------------------------------------------------------------------===// + +@available(SwiftStdlib 6.1, *) +extension Slab where Element: ~Copyable { + /// Initializes every element in this vector running the given closure value + /// that returns the element to emplace at the given index. + /// + /// This will call the closure `Count` times, where `Count` is the static + /// count of the vector, to initialize every element by passing the closure + /// the index of the current element being initialized. The closure is allowed + /// to throw an error at any point during initialization at which point the + /// vector will stop initialization, deinitialize every currently initialized + /// element, and throw the given error back out to the caller. + /// + /// - Parameter body: A closure that returns an owned `Element` to emplace at + /// the passed in index. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + public init(_ body: (Int) throws(E) -> Element) throws(E) { + self = try Builtin.emplace { (rawPtr) throws(E) -> () in + let buffer = Slab._initializationBuffer(start: rawPtr) + + for i in 0 ..< count { + do throws(E) { + try buffer.initializeElement(at: i, to: body(i)) + } catch { + // The closure threw an error. We need to deinitialize every element + // we've initialized up to this point. + for j in 0 ..< i { + buffer.deinitializeElement(at: j) + } + + // Throw the error we were given back out to the caller. + throw error + } + } + } + } + + /// Initializes every element in this vector by running the closure with the + /// passed in first element. + /// + /// This will call the closure 'count' times, where 'count' is the static + /// count of the vector, to initialize every element by passing the closure + /// an immutable borrow reference to the first element given to the + /// initializer. The closure is allowed to throw an error at any point during + /// initialization at which point the vector will stop initialization, + /// deinitialize every currently initialized element, and throw the given + /// error back out to the caller. + /// + /// - Parameter first: The first value to insert into the vector which will be + /// passed to the closure as a borrow. + /// - Parameter next: A closure that passes in an immutable borrow reference + /// of the given first element of the vector which returns + /// an owned `Element` instance to insert into the vector. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + public init( + first: consuming Element, + next: (borrowing Element) throws(E) -> Element + ) throws(E) { + // FIXME: We should be able to mark 'Builtin.emplace' as '@once' or something + // to give the compiler enough information to know we will only run + // it once so it can consume the capture. For now, we use an optional + // and take the underlying value within the closure. + var o: Element? = first + + self = try Builtin.emplace { (rawPtr) throws(E) -> () in + let buffer = Slab._initializationBuffer(start: rawPtr) + + buffer.initializeElement(at: 0, to: o.take()._consumingUncheckedUnwrapped()) + + for i in 1 ..< count { + do throws(E) { + try buffer.initializeElement(at: i, to: next(buffer[i &- 1])) + } catch { + // The closure threw an error. We need to deinitialize every element + // we've initialized up to this point. + for j in 0 ..< i { + buffer.deinitializeElement(at: j) + } + + throw error + } + } + } + } +} + +@available(SwiftStdlib 6.1, *) +extension Slab where Element: Copyable { + /// Initializes every element in this vector to a copy of the given value. + /// + /// - Parameter value: The instance to initialize this vector with. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + public init(repeating value: Element) { + self = Builtin.emplace { + let buffer = Slab._initializationBuffer(start: $0) + + buffer.initialize(repeating: value) + } + } +} + +//===----------------------------------------------------------------------===// +// Collection APIs +//===----------------------------------------------------------------------===// + +@available(SwiftStdlib 6.1, *) +extension Slab where Element: ~Copyable { + /// The type of the container's elements. + @available(SwiftStdlib 6.1, *) + public typealias Element = Element + + /// A type that represents a position in the collection. + /// + /// Valid indices consist of the position of every element and a + /// "past the end" position that's not valid for use as a subscript + /// argument. + @available(SwiftStdlib 6.1, *) + public typealias Index = Int + + /// The number of elements in the collection. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public static var count: Int { + count + } + + /// The number of elements in the collection. + /// + /// - Complexity: O(1) + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public var count: Int { + count + } + + /// The position of the first element in a nonempty collection. + /// + /// If the collection is empty, `startIndex` is equal to `endIndex`. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public var startIndex: Int { + 0 + } + + /// The collection's "past the end" position---that is, the position one + /// greater than the last valid subscript argument. + /// + /// When you need a range that includes the last element of a collection, use + /// the half-open range operator (`..<`) with `endIndex`. The `..<` operator + /// creates a range that doesn't include the upper bound, so it's always + /// safe to use with `endIndex`. For example: + /// + /// let numbers = [10, 20, 30, 40, 50] + /// if let index = numbers.firstIndex(of: 30) { + /// print(numbers[index ..< numbers.endIndex]) + /// } + /// // Prints "[30, 40, 50]" + /// + /// If the collection is empty, `endIndex` is equal to `startIndex`. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public var endIndex: Int { + count + } + + /// The indices that are valid for subscripting the collection, in ascending + /// order. + /// + /// A collection's `indices` property can hold a strong reference to the + /// collection itself, causing the collection to be nonuniquely referenced. + /// If you mutate the collection while iterating over its indices, a strong + /// reference can result in an unexpected copy of the collection. To avoid + /// the unexpected copy, use the `index(after:)` method starting with + /// `startIndex` to produce indices instead. + /// + /// var c = MyFancyCollection([10, 20, 30, 40, 50]) + /// var i = c.startIndex + /// while i != c.endIndex { + /// c[i] /= 5 + /// i = c.index(after: i) + /// } + /// // c == MyFancyCollection([2, 4, 6, 8, 10]) + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public var indices: Range { + Range(_uncheckedBounds: (0, count)) + } + + /// Returns the position immediately after the given index. + /// + /// - Parameter i: A valid index of the collection. `i` must be less than + /// `endIndex`. + /// - Returns: The index immediately after `i`. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public borrowing func index(after i: Int) -> Int { + i &+ 1 + } + + /// Returns the position immediately before the given index. + /// + /// - Parameter i: A valid index of the collection. `i` must be greater than + /// `startIndex`. + /// - Returns: The index value immediately before `i`. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public borrowing func index(before i: Int) -> Int { + i &- 1 + } + + /// Accesses the element at the specified position. + /// + /// The following example accesses an element of an array through its + /// subscript to print its value: + /// + /// var streets = ["Adams", "Bryant", "Channing", "Douglas", "Evarts"] + /// print(streets[1]) + /// // Prints "Bryant" + /// + /// You can subscript a collection with any valid index other than the + /// collection's end index. The end index refers to the position one past + /// the last element of a collection, so it doesn't correspond with an + /// element. + /// + /// - Parameter position: The position of the element to access. `position` + /// must be a valid index of the collection that is not equal to the + /// `endIndex` property. + /// + /// - Complexity: O(1) + @available(SwiftStdlib 6.1, *) + @_addressableSelf + @_alwaysEmitIntoClient + public subscript(_ i: Int) -> Element { + @_transparent + unsafeAddress { + _precondition(indices.contains(i), "Index out of bounds") + + return _address + i + } + + @_transparent + unsafeMutableAddress { + _precondition(indices.contains(i), "Index out of bounds") + + return _mutableAddress + i + } + } +} + +//===----------------------------------------------------------------------===// +// Swap +//===----------------------------------------------------------------------===// + +@available(SwiftStdlib 6.1, *) +extension Slab where Element: ~Copyable { + /// Exchanges the values at the specified indices of the vector. + /// + /// Both parameters must be valid indices of the vector and not + /// equal to `endIndex`. Passing the same index as both `i` and `j` has no + /// effect. + /// + /// - Parameters: + /// - i: The index of the first value to swap. + /// - j: The index of the second value to swap. + /// + /// - Complexity: O(1) + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + public mutating func swapAt( + _ i: Int, + _ j: Int + ) { + guard i != j else { + return + } + + _precondition(indices.contains(i), "Index out of bounds") + _precondition(indices.contains(j), "Index out of bounds") + + let ithElement = _mutableBuffer.moveElement(from: i) + let jthElement = _mutableBuffer.moveElement(from: j) + _mutableBuffer.initializeElement(at: i, to: jthElement) + _mutableBuffer.initializeElement(at: j, to: ithElement) + } +} + +//===----------------------------------------------------------------------===// +// Unsafe APIs +//===----------------------------------------------------------------------===// + +@available(SwiftStdlib 6.1, *) +extension Slab where Element: ~Copyable { + /// Calls a closure with a pointer to the vector's contiguous storage. + /// + /// Often, the optimizer can eliminate bounds checks within a vector + /// algorithm, but when that fails, invoking the same algorithm on the + /// buffer pointer passed into your closure lets you trade safety for speed. + /// + /// The following example shows how you can iterate over the contents of the + /// buffer pointer: + /// + /// // "[1, 2, 3, 4, 5]" + /// let numbers = Slab<5, Int> { + /// $0 + 1 + /// } + /// + /// let sum = numbers.withUnsafeBufferPointer { buffer -> Int in + /// var result = 0 + /// for i in stride(from: buffer.startIndex, to: buffer.endIndex, by: 2) { + /// result += buffer[i] + /// } + /// return result + /// } + /// // 'sum' == 9 + /// + /// The pointer passed as an argument to `body` is valid only during the + /// execution of `withUnsafeBufferPointer(_:)`. Do not store or return the + /// pointer for later use. + /// + /// - Parameter body: A closure with an `UnsafeBufferPointer` parameter that + /// points to the contiguous storage for the vector. If `body` has a return + /// value, that value is also used as the return value for the + /// `withUnsafeBufferPointer(_:)` method. The pointer argument is valid only + /// for the duration of the method's execution. + /// - Returns: The return value, if any, of the `body` closure parameter. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public borrowing func _withUnsafeBufferPointer( + _ body: (UnsafeBufferPointer) throws(E) -> Result + ) throws(E) -> Result { + try body(_buffer) + } + + /// Calls the given closure with a pointer to the vector's mutable contiguous + /// storage. + /// + /// Often, the optimizer can eliminate bounds checks within a vector + /// algorithm, but when that fails, invoking the same algorithm on the + /// buffer pointer passed into your closure lets you trade safety for speed. + /// + /// The following example shows how modifying the contents of the + /// `UnsafeMutableBufferPointer` argument to `body` alters the contents of + /// the vector: + /// + /// // "[1, 2, 3, 4, 5]" + /// var numbers = Slab<5, Int> { + /// $0 + 1 + /// } + /// + /// numbers.withUnsafeMutableBufferPointer { buffer in + /// for i in stride(from: buffer.startIndex, to: buffer.endIndex - 1, by: 2) { + /// buffer.swapAt(i, i + 1) + /// } + /// } + /// + /// print(numbers.description) + /// // Prints "[2, 1, 4, 3, 5]" + /// + /// The pointer passed as an argument to `body` is valid only during the + /// execution of `withUnsafeMutableBufferPointer(_:)`. Do not store or + /// return the pointer for later use. + /// + /// - Warning: Do not rely on anything about the vector that is the target of + /// this method during execution of the `body` closure; it might not + /// appear to have its correct value. Instead, use only the + /// `UnsafeMutableBufferPointer` argument to `body`. + /// + /// - Parameter body: A closure with an `UnsafeMutableBufferPointer` + /// parameter that points to the contiguous storage for the vector. If + /// `body` has a return value, that value is also used as the return value + /// for the `withUnsafeMutableBufferPointer(_:)` method. The pointer + /// argument is valid only for the duration of the method's execution. + /// - Returns: The return value, if any, of the `body` closure parameter. + @available(SwiftStdlib 6.1, *) + @_alwaysEmitIntoClient + @_transparent + public mutating func _withUnsafeMutableBufferPointer( + _ body: (UnsafeMutableBufferPointer) throws(E) -> Result + ) throws(E) -> Result { + try body(_mutableBuffer) + } +} diff --git a/test/DebugInfo/value-generics-embedded.swift b/test/DebugInfo/value-generics-embedded.swift new file mode 100644 index 0000000000000..ed8c48e6bd800 --- /dev/null +++ b/test/DebugInfo/value-generics-embedded.swift @@ -0,0 +1,27 @@ +// RUN: %target-swift-frontend %s -target %target-cpu-apple-macos14 -emit-ir -g -enable-experimental-feature ValueGenerics -enable-experimental-feature Embedded -wmo -disable-availability-checking -o - | %FileCheck %s + +// REQUIRES: OS=macosx + +// REQUIRES: swift_feature_Embedded +// REQUIRES: swift_feature_ValueGenerics + +// CHECK-DAG: !DICompositeType({{.*}}templateParams: ![[SLAB_PARAMS:.*]], {{.*}}identifier: "$es4SlabVy$0_4main8MySpriteVGD" +// CHECK-DAG: ![[SLAB_PARAMS]] = !{![[COUNT_PARAM:.*]], ![[ELEMENT_PARAM:.*]]} +// CHECK-DAG: ![[COUNT_PARAM]] = !DITemplateTypeParameter(type: ![[COUNT_TYPE:.*]]) +// CHECK-DAG: ![[COUNT_TYPE]] = !DICompositeType({{.*}}name: "$e$0_D" +// CHECK-DAG: ![[ELEMENT_PARAM]] = !DITemplateTypeParameter(type: ![[ELEMENT_TYPE:.*]]) +// CHECK-DAG: ![[ELEMENT_TYPE]] = !DICompositeType({{.*}}name: "MySprite", {{.*}}identifier: "$e4main8MySpriteVD" +struct MySprites { + var bricks: Slab<1, MySprite> +} + +struct MySprite { + var x = 42 +} + +nonisolated(unsafe) +var sprites: MySprites? = nil +public func foo() { + let bricks: Slab<1, MySprite> = [MySprite()] + sprites = .init(bricks: bricks) +} diff --git a/test/DebugInfo/value-generics.swift b/test/DebugInfo/value-generics.swift index 0cb8fdfab3802..31071ffcac28c 100644 --- a/test/DebugInfo/value-generics.swift +++ b/test/DebugInfo/value-generics.swift @@ -1,23 +1,28 @@ -// RUN: %target-swift-frontend %s -emit-ir -g -enable-builtin-module -enable-experimental-feature ValueGenerics -disable-experimental-parser-round-trip -disable-availability-checking -o - | %FileCheck %s +// RUN: %target-swift-frontend %s -emit-ir -g -enable-builtin-module -enable-experimental-feature ValueGenerics -disable-availability-checking -o - | %FileCheck %s // REQUIRES: swift_feature_ValueGenerics import Builtin -struct Vector: ~Copyable { +struct Slab: ~Copyable { let storage: Builtin.FixedArray } -extension Vector: Copyable where Element: Copyable {} +extension Slab: Copyable where Element: Copyable {} // CHECK-DAG: !DICompositeType({{.*}}name: "Builtin.FixedArray", {{.*}}identifier: "$sxq_BVD" func genericBA(_: Builtin.FixedArray) {} -// CHECK-DAG: !DICompositeType({{.*}}name: "$s4main6VectorVyxq_GD" -func genericV(_: Vector) {} +// CHECK-DAG: !DICompositeType({{.*}}name: "$s4main4SlabVyxq_GD" +func genericV(_: Slab) {} // CHECK-DAG: !DICompositeType({{.*}}name: "Builtin.FixedArray", {{.*}}identifier: "$s$3_SiBVD" func concreteBA(_: Builtin.FixedArray<4, Int>) {} -// CHECK-DAG: !DICompositeType({{.*}}name: "$s4main6VectorVy$1_SiGD" -func concreteV(_: Vector<2, Int>) {} +// CHECK-DAG: !DICompositeType({{.*}}name: "$s4main4SlabVy$1_SiGD", {{.*}}templateParams: ![[SLAB_PARAMS:.*]]) +// CHECK-DAG: ![[SLAB_PARAMS]] = !{![[COUNT_PARAM:.*]], ![[ELEMENT_PARAM:.*]]} +// CHECK-DAG: ![[COUNT_PARAM]] = !DITemplateTypeParameter(type: ![[COUNT_TYPE:.*]]) +// CHECK-DAG: ![[COUNT_TYPE]] = !DICompositeType({{.*}}name: "$s$1_D" +// CHECK-DAG: ![[ELEMENT_PARAM]] = !DITemplateTypeParameter(type: ![[ELEMENT_TYPE:.*]]) +// CHECK-DAG: ![[ELEMENT_TYPE]] = !DICompositeType({{.*}}name: "$sSiD" +func concreteV(_: Slab<2, Int>) {} diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index f5b079b854d82..11950466b874f 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -481,5 +481,5 @@ $s2hi1SVIetMIy_TC ---> coroutine continuation prototype for @escaping @conventi $s4mainAAyyycAA1CCFTTI ---> identity thunk of main.main(main.C) -> () -> () $s4mainAAyyycAA1CCFTTH ---> hop to main actor thunk of main.main(main.C) -> () -> () -$s4main6VectorVy$1_SiG ---> main.Vector<2, Swift.Int> +$s4main4SlabVy$1_SiG ---> main.Slab<2, Swift.Int> $s$n3_SSBV ---> Builtin.FixedArray<-4, Swift.String> diff --git a/test/IRGen/array_type_layout.swift b/test/IRGen/array_type_layout.swift new file mode 100644 index 0000000000000..6b3434c4f5e93 --- /dev/null +++ b/test/IRGen/array_type_layout.swift @@ -0,0 +1,58 @@ +// RUN: %target-swift-frontend -emit-ir -disable-availability-checking -enable-experimental-feature ValueGenerics %s | %FileCheck %s + +// REQUIRES: swift_feature_ValueGenerics + +struct VerySmallSlab { + var inline: Slab<16, T?> + var count = 0 + + init() { + inline = .init(repeating: nil) + } +} + +//===----------------------------------------------------------------------===// +// VerySmallSlab initializeBufferWithCopyOfBuffer +//===----------------------------------------------------------------------===// + +// CHECK-LABEL: define {{.*}} ptr @"$s17array_type_layout13VerySmallSlabVwCP"(ptr{{.*}} %dest, ptr{{.*}} %src, ptr{{.*}} %"VerySmallSlab") +// CHECK: [[FLAGS:%.*]] = load i32, ptr {{.*}} +// CHECK-NEXT: [[INLINE_BIT:%.*]] = and i32 [[FLAGS]], 131072 +// CHECK-NEXT: [[IS_INLINE:%.*]] = icmp eq i32 [[INLINE_BIT]], 0 +// CHECK-NEXT: br i1 [[IS_INLINE]], label %[[DIRECT_BB:.*]], label %[[INDIRECT_BB:.*]] +// CHECK-EMPTY: +// CHECK-NEXT: [[INDIRECT_BB]]: +// CHECK: br label %[[CONT_BB:.*]] +// CHECK-EMPTY: +// CHECK-NEXT: [[DIRECT_BB]]: +// CHECK: br label %[[LOOP_BB:.*]] +// CHECK-EMPTY: +// CHECK-NEXT: [[LOOP_BB]]: +// CHECK-NEXT: [[COUNT:%.*]] = phi i{{64|32}} [ 16, %[[DIRECT_BB]] ], [ [[SUB:%.*]], %[[PRED_BB:.*]] ] +// CHECK-NEXT: [[DEST:%.*]] = phi ptr [ %dest, %[[DIRECT_BB]] ], [ [[DEST_OFFSET_PTR:%.*]], %[[PRED_BB]] ] +// CHECK-NEXT: [[SRC:%.*]] = phi ptr [ %src, %[[DIRECT_BB]] ], [ [[SRC_OFFSET_PTR:%.*]], %[[PRED_BB]] ] +// CHECK: [[TAG:%.*]] = call i32 %GetEnumTagSinglePayload(ptr{{.*}} [[SRC]], i32 1, ptr %T) +// CHECK-NEXT: [[NIL_CHECK:%.*]] = icmp eq i32 [[TAG]], 0 +// CHECK-NEXT: br i1 [[NIL_CHECK]], label %[[NOT_NIL_BB:.*]], label %[[NIL_BB:.*]] +// CHECK-EMPTY: +// CHECK-NEXT: [[NOT_NIL_BB]]: +// CHECK: {{.*}} = call ptr %InitializeWithCopy(ptr{{.*}} [[DEST]], ptr{{.*}} [[SRC]], ptr %T) + +// CHECK: [[NIL_BB]]: +// CHECK: call void @llvm.memcpy{{.*}}(ptr{{.*}} [[DEST]], ptr{{.*}} [[SRC]], i{{64|32}} {{%.*}}, i1 false) +// CHECK-NEXT: br label %[[PRED_BB]] +// CHECK-EMPTY: +// CHECK-NEXT: [[PRED_BB]]: +// CHECK: [[SUB]] = sub i{{64|32}} [[COUNT]], 1 +// CHECK-NEXT: [[DONE:%.*]] = icmp eq i{{64|32}} [[SUB]], 0 +// CHECK-NEXT: br i1 [[DONE]], label %[[END_LOOP_BB:.*]], label %[[LOOP_BB]] +// CHECK-EMPTY: +// CHECK-NEXT: [[END_LOOP_BB]]: +// CHECK: [[DEST_COUNT_PTR:%.*]] = getelementptr inbounds i8, ptr %dest, i32 {{%.*}} +// CHECK: [[SRC_COUNT_PTR:%.*]] = getelementptr inbounds i8, ptr %src, i32 {{%.*}} +// CHECK-NEXT: call void @llvm.memcpy{{.*}}(ptr{{.*}} [[DEST_COUNT_PTR]], ptr{{.*}} [[SRC_COUNT_PTR]], i{{64 8|32 4}}, i1 false) +// CHECK-NEXT: br label %[[CONT_BB]] +// CHECK-EMPTY: +// CHECK-NEXT: [[CONT_BB]]: +// CHECK-NEXT: [[RETURN_DEST_PTR:%.*]] = phi ptr [ {{%.*}}, %[[INDIRECT_BB]] ], [ %dest, %[[END_LOOP_BB]] ] +// CHECK-NEXT: ret ptr [[RETURN_DEST_PTR]] diff --git a/test/ModuleInterface/value_generics.swift b/test/ModuleInterface/value_generics.swift index 51784a09225b9..5adf8c3c58e58 100644 --- a/test/ModuleInterface/value_generics.swift +++ b/test/ModuleInterface/value_generics.swift @@ -5,8 +5,8 @@ // REQUIRES: swift_feature_ValueGenerics -// CHECK: public struct Vector -public struct Vector { +// CHECK: public struct Slab +public struct Slab { // CHECK-LABEL: public var count: Swift.Int { // CHECK-NEXT: get { // CHECK-NEXT: N @@ -18,11 +18,11 @@ public struct Vector { } } -// CHECK: public func usesGenericVector(_: ValueGeneric.Vector) -public func usesGenericVector(_: Vector) {} +// CHECK: public func usesGenericSlab(_: ValueGeneric.Slab) +public func usesGenericSlab(_: Slab) {} -// CHECK: public func usesConcreteVector(_: ValueGeneric.Vector) -public func usesConcreteVector(_: Vector) {} +// CHECK: public func usesConcreteSlab(_: ValueGeneric.Slab) +public func usesConcreteSlab(_: Slab) {} -// CHECK: public func usesNegativeVector(_: ValueGeneric.Vector) -public func usesNegativeVector(_: Vector) {} +// CHECK: public func usesNegativeSlab(_: ValueGeneric.Slab) +public func usesNegativeSlab(_: Slab) {} diff --git a/test/Reflection/typeref_lowering.swift b/test/Reflection/typeref_lowering.swift index 71dc1be84fe3b..777546ab5f7e3 100644 --- a/test/Reflection/typeref_lowering.swift +++ b/test/Reflection/typeref_lowering.swift @@ -1269,3 +1269,14 @@ BD // CHECK-32: (builtin Builtin.DefaultActorStorage) // CHECK-32-NEXT: (builtin size=48 alignment=8 stride=48 num_extra_inhabitants=0 bitwise_takable=1) + +$1_SiBV +// CHECK-64: (builtin_fixed_array +// CHECK-64-NEXT: (integer value=2) +// CHECK-64-NEXT: (struct Swift.Int)) +// CHECK-64-NEXT: (array size=16 alignment=8 stride=16 num_extra_inhabitants=0 bitwise_takable=1) + +// CHECK-32: (builtin_fixed_array +// CHECK-32-NEXT: (integer value=2) +// CHECK-32-NEXT: (struct Swift.Int)) +// CHECK-32-NEXT: (array size=8 alignment=4 stride=8 num_extra_inhabitants=0 bitwise_takable=1) diff --git a/test/SILGen/slab_literal.swift b/test/SILGen/slab_literal.swift new file mode 100644 index 0000000000000..9f9701e8d510b --- /dev/null +++ b/test/SILGen/slab_literal.swift @@ -0,0 +1,77 @@ +// RUN: %target-swift-emit-silgen %s -disable-availability-checking -enable-experimental-feature ValueGenerics | %FileCheck %s + +// REQUIRES: swift_feature_ValueGenerics + +import Synchronization + +// CHECK-LABEL: sil{{.*}} @$s12slab_literal7trivials4SlabVy$3_SiGyF : $@convention(thin) () -> Slab<4, Int> { +// CHECK: [[SLAB_ALLOC:%.*]] = alloc_stack $Slab<4, Int> +// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[SLAB_ALLOC]] to $*Int +// CHECK-NEXT: [[ELT_0_LITERAL:%.*]] = integer_literal $Builtin.IntLiteral, 1 +// CHECK: [[ELT_0:%.*]] = apply {{%.*}}([[ELT_0_LITERAL]], {{%.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK-NEXT: store [[ELT_0]] to [trivial] [[ELEMENT_PTR]] +// CHECK-NEXT: [[ELT_1_OFFSET:%.*]] = integer_literal $Builtin.Word, 1 +// CHECK-NEXT: [[ELT_1_PTR:%.*]] = index_addr [[ELEMENT_PTR]], [[ELT_1_OFFSET]] +// CHECK-NEXT: [[ELT_1_LITERAL:%.*]] = integer_literal $Builtin.IntLiteral, 2 +// CHECK: [[ELT_1:%.*]] = apply {{%.*}}([[ELT_1_LITERAL]], {{%.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK-NEXT: store [[ELT_1]] to [trivial] [[ELT_1_PTR]] +// CHECK-NEXT: [[ELT_2_OFFSET:%.*]] = integer_literal $Builtin.Word, 2 +// CHECK-NEXT: [[ELT_2_PTR:%.*]] = index_addr [[ELEMENT_PTR]], [[ELT_2_OFFSET]] +// CHECK-NEXT: [[ELT_2_LITERAL:%.*]] = integer_literal $Builtin.IntLiteral, 3 +// CHECK: [[ELT_2:%.*]] = apply {{%.*}}([[ELT_2_LITERAL]], {{%.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK-NEXT: store [[ELT_2]] to [trivial] [[ELT_2_PTR]] +// CHECK-NEXT: [[ELT_3_OFFSET:%.*]] = integer_literal $Builtin.Word, 3 +// CHECK-NEXT: [[ELT_3_PTR:%.*]] = index_addr [[ELEMENT_PTR]], [[ELT_3_OFFSET]] +// CHECK-NEXT: [[ELT_3_LITERAL:%.*]] = integer_literal $Builtin.IntLiteral, 4 +// CHECK: [[ELT_3:%.*]] = apply {{%.*}}([[ELT_3_LITERAL]], {{%.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int +// CHECK-NEXT: store [[ELT_3]] to [trivial] [[ELT_3_PTR]] +// CHECK-NEXT: [[SLAB:%.*]] = load [trivial] [[SLAB_ALLOC]] +// CHECK-NEXT: dealloc_stack [[SLAB_ALLOC]] +// CHECK-NEXT: return [[SLAB]] +// CHECK-LABEL: } // end sil function '$s12slab_literal7trivials4SlabVy$3_SiGyF' +func trivial() -> Slab<4, Int> { + [1, 2, 3, 4] +} + +// CHECK-LABEL: sil{{.*}} @$s12slab_literal10nontrivials4SlabVy$1_SSGyF : $@convention(thin) () -> @owned Slab<2, String> { +// CHECK: [[SLAB_ALLOC:%.*]] = alloc_stack $Slab<2, String> +// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[SLAB_ALLOC]] to $*String +// CHECK-NEXT: [[ELT_0_LITERAL:%.*]] = string_literal utf8 "hello" +// CHECK: [[ELT_0:%.*]] = apply {{%.*}}([[ELT_0_LITERAL]], {{.*}}) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String +// CHECK-NEXT: store [[ELT_0]] to [init] [[ELEMENT_PTR]] +// CHECK-NEXT: [[ELT_1_OFFSET:%.*]] = integer_literal $Builtin.Word, 1 +// CHECK-NEXT: [[ELT_1_PTR:%.*]] = index_addr [[ELEMENT_PTR]], [[ELT_1_OFFSET]] +// CHECK-NEXT: [[ELT_1_LITERAL:%.*]] = string_literal utf8 "world" +// CHECK: [[ELT_1:%.*]] = apply {{%.*}}([[ELT_1_LITERAL]], {{.*}}) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String +// CHECK-NEXT: store [[ELT_1]] to [init] [[ELT_1_PTR]] +// CHECK-NEXT: [[SLAB:%.*]] = load [take] [[SLAB_ALLOC]] +// CHECK-NEXT: dealloc_stack [[SLAB_ALLOC]] +// CHECK-NEXT: return [[SLAB]] +// CHECK-LABEL: } // end sil function '$s12slab_literal10nontrivials4SlabVy$1_SSGyF' +func nontrivial() -> Slab<2, String> { + ["hello", "world"] +} + +// CHECK-LABEL: sil{{.*}} @$s12slab_literal11noncopyables4SlabVy$1_15Synchronization6AtomicVySiGGyF : $@convention(thin) () -> @out Slab<2, Atomic> { +// CHECK: bb0([[SLAB_RETURN:%.*]] : $*Slab<2, Atomic>): +// CHECK-NEXT: [[SLAB_ALLOC:%.*]] = alloc_stack $Slab<2, Atomic> +// CHECK-NEXT: [[ELEMENT_PTR:%.*]] = unchecked_addr_cast [[SLAB_ALLOC]] to $*Atomic +// CHECK: [[ATOMIC_INIT:%.*]] = function_ref @$s15Synchronization6AtomicVyACyxGxcfC +// CHECK-NEXT: [[ELT_0:%.*]] = apply [[ATOMIC_INIT]]([[ELEMENT_PTR]], {{.*}}) : $@convention(method) <τ_0_0 where τ_0_0 : AtomicRepresentable> (@in τ_0_0, @thin Atomic<τ_0_0>.Type) -> @out Atomic<τ_0_0> +// CHECK: [[ELT_1_OFFSET:%.*]] = integer_literal $Builtin.Word, 1 +// CHECK-NEXT: [[ELT_1_PTR:%.*]] = index_addr [[ELEMENT_PTR]], [[ELT_1_OFFSET]] +// CHECK: [[ATOMIC_INIT:%.*]] = function_ref @$s15Synchronization6AtomicVyACyxGxcfC +// CHECK-NEXT: [[ELT_1:%.*]] = apply [[ATOMIC_INIT]]([[ELT_1_PTR]], {{.*}}) : $@convention(method) <τ_0_0 where τ_0_0 : AtomicRepresentable> (@in τ_0_0, @thin Atomic<τ_0_0>.Type) -> @out Atomic<τ_0_0> +// CHECK: [[SLAB_ALLOC_AGAIN:%.*]] = unchecked_addr_cast [[SLAB_ALLOC]] to $*Slab<2, Atomic> +// CHECK-NEXT: [[BOX:%.*]] = alloc_box +// CHECK-NEXT: [[BOX_BORROW:%.*]] = begin_borrow [lexical] [[BOX]] +// CHECK-NEXT: [[BOX_PROJECT:%.*]] = project_box [[BOX_BORROW]] +// CHECK-NEXT: copy_addr [take] [[SLAB_ALLOC_AGAIN]] to [init] [[BOX_PROJECT]] +// CHECK-NEXT: dealloc_stack [[SLAB_ALLOC]] +// CHECK-NEXT: copy_addr [take] [[BOX_PROJECT]] to [init] [[SLAB_RETURN]] +// CHECK-NEXT: end_borrow [[BOX_BORROW]] +// CHECK-NEXT: dealloc_box [[BOX]] +// CHECK-LABEL: } // end sil function '$s12slab_literal11noncopyables4SlabVy$1_15Synchronization6AtomicVySiGGyF' +func noncopyable() -> Slab<2, Atomic> { + [Atomic(0), Atomic(1)] +} diff --git a/test/Sema/slab.swift b/test/Sema/slab.swift new file mode 100644 index 0000000000000..3e94324ad86bd --- /dev/null +++ b/test/Sema/slab.swift @@ -0,0 +1,82 @@ +// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-experimental-feature ValueGenerics + +// REQUIRES: swift_feature_ValueGenerics + +let a: Slab = [1, 2, 3] // Ok, Slab<3, Int> +let b: Slab<_, Int> = [1, 2, 3] // Ok, Slab<3, Int> +let c: Slab<3, _> = [1, 2, 3] // Ok, Slab<3, Int> + +let d: Slab<2, _> = [1, 2, 3] // expected-error {{expected '2' elements in slab literal, but got '3'}} +let e: Slab<2, _> = [1] // expected-error {{expected '2' elements in slab literal, but got '1'}} + +let f: Slab<_, Int> = ["hello"] // expected-error {{cannot convert value of type 'String' to expected element type 'Int'}} + +func takeVectorOf2(_: Slab<2, T>) {} + +takeVectorOf2([1, 2]) // Ok +takeVectorOf2(["hello", "world"]) // Ok + +takeVectorOf2([1]) // expected-error {{expected '2' elements in slab literal, but got '1'}} + +takeVectorOf2([1, 2, 3]) // expected-error {{expected '2' elements in slab literal, but got '3'}} + +takeVectorOf2(["hello"]) // expected-error {{expected '2' elements in slab literal, but got '1'}} + +takeVectorOf2(["hello", "world", "!"]) // expected-error {{expected '2' elements in slab literal, but got '3'}} + +func takeVectorOf2Int(_: Slab<2, Int>) {} + +takeVectorOf2Int([1, 2]) // Ok + +takeVectorOf2Int([1]) // expected-error {{expected '2' elements in slab literal, but got '1'}} + +takeVectorOf2Int([1, 2, 3]) // expected-error {{expected '2' elements in slab literal, but got '3'}} + +takeVectorOf2Int(["hello"]) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Slab<2, Int>'}} + +takeVectorOf2Int(["hello", "world"]) // expected-error {{cannot convert value of type 'String' to expected element type 'Int'}} + // expected-error@-1 {{cannot convert value of type 'String' to expected element type 'Int'}} + +takeVectorOf2Int(["hello", "world", "!"]) // expected-error {{cannot convert value of type '[String]' to expected argument type 'Slab<2, Int>'}} + +struct X { + var sprites: Slab<2, Int> +} + +func foo(x: inout X) { + x.sprites = [1, 2, 3] // expected-error {{cannot assign value of type '[Int]' to type 'Slab<2, Int>'}} +} + +struct MySprites { + var bricks: Slab<40, MySprite> +} + +struct MySprite { + var x = 42 +} + +nonisolated(unsafe) +var sprites: MySprites? = nil + +func foo() { + let bricks: Slab<1, MySprite> = [MySprite()] + + sprites = .init(bricks: bricks) // expected-error {{cannot convert value of type 'Slab<1, MySprite>' to expected argument type 'Slab<40, MySprite>'}} + // expected-note@-1 {{arguments to generic parameter 'count' ('1' and '40') are expected to be equal}} +} + +// Make sure the deserialized integer generic argument gets treated as an integer +// generic argument when we clone the generic param list for extensions. +extension Slab where Element: ~Copyable { + func forEach(_ body: (borrowing Element) -> Void) { + for i in 0 ..< count { + body(self[i]) + } + } + + func enumerated(_ body: (Int, borrowing Element) -> Void) { + for i in 0 ..< count { + body(i, self[i]) + } + } +} diff --git a/test/Sema/typo_correction.swift b/test/Sema/typo_correction.swift index 68c7413bd3ee1..33aafffbf7beb 100644 --- a/test/Sema/typo_correction.swift +++ b/test/Sema/typo_correction.swift @@ -10,7 +10,7 @@ import NoSuchModule // This is close enough to get typo-correction. func test_short_and_close() { - let plop = 4 // expected-note {{'plop' declared here}} + let plop = 4 // expected-note {{did you mean 'plop'?}} let bab = plob + 1 // expected-error@-1 {{cannot find 'plob' in scope}} } diff --git a/test/abi/macOS/arm64/stdlib.swift b/test/abi/macOS/arm64/stdlib.swift index 2dea1c96ddc58..9a5e5e70fb1c0 100644 --- a/test/abi/macOS/arm64/stdlib.swift +++ b/test/abi/macOS/arm64/stdlib.swift @@ -809,3 +809,15 @@ Added: _$ss13_SwiftifyInfoON // Eager-lazy Array bridging Added: _$ss12_ArrayBufferV14associationKeySVvpZMV + +// Slab metadata accessor +Added: _$ss4SlabVMa + +// Slab nominal type descriptor +Added: _$ss4SlabVMn + +// Slab.count property descriptor +Added: _$ss4SlabVsRi__rlE5countSivpZMV + +// Slab._storage _read accessor +Added: _$ss4SlabVsRi__rlE8_storagexq_BVvr diff --git a/test/abi/macOS/x86_64/stdlib.swift b/test/abi/macOS/x86_64/stdlib.swift index d76c741599a8c..9f4543ff116d5 100644 --- a/test/abi/macOS/x86_64/stdlib.swift +++ b/test/abi/macOS/x86_64/stdlib.swift @@ -810,3 +810,15 @@ Added: _$ss13_SwiftifyInfoON // Eager-lazy Array bridging Added: _$ss12_ArrayBufferV14associationKeySVvpZMV + +// Slab metadata accessor +Added: _$ss4SlabVMa + +// Slab nominal type descriptor +Added: _$ss4SlabVMn + +// Slab.count property descriptor +Added: _$ss4SlabVsRi__rlE5countSivpZMV + +// Slab._storage _read accessor +Added: _$ss4SlabVsRi__rlE8_storagexq_BVvr