From 754c7feb2669bf93ec80a9d30ed4c38b9c279a55 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 26 Feb 2017 00:11:59 -0800 Subject: [PATCH 1/4] IRGen: Use SubstitutionMap in one spot Eventually I'd like SubstitutionLists to be opaque, and not ArrayRefs. --- lib/IRGen/IRGenSIL.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 0687e7b20b409..6ac7b44f5e256 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -1887,14 +1887,11 @@ static llvm::Value *emitWitnessTableForLoweredCallee(IRGenSILFunction &IGF, // // We recover the witness table from the substitution that was used to // produce the substituted callee type. - // - // There can be multiple substitutions, but the first one is the Self type. - assert(subs.size() >= 1); - assert(subs[0].getConformances().size() == 1); - - auto conformance = subs[0].getConformances()[0]; - assert(conformance.getRequirement() == proto); (void) proto; - auto substSelfType = subs[0].getReplacement()->getCanonicalType(); + auto subMap = origCalleeType->getGenericSignature() + ->getSubstitutionMap(subs); + auto origSelfType = proto->getSelfInterfaceType()->getCanonicalType(); + auto substSelfType = origSelfType.subst(subMap)->getCanonicalType(); + auto conformance = *subMap.lookupConformance(origSelfType, proto); llvm::Value *argMetadata = IGF.emitTypeMetadataRef(substSelfType); wtable = emitWitnessTableRef(IGF, substSelfType, &argMetadata, From 0af2845c6ddfb2e3e2afa5569cec278dd4bdf9e6 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 24 Feb 2017 15:15:21 -0800 Subject: [PATCH 2/4] SILGen: Emission of materializeForSet for generic subscripts First, use the correct generic environment to compute the substituted storage type. Substitutions derived from 'self' are not enough, because we also want the archetypes of the generic subscript's innermost generic parameters. Also, use the method and witness_method calling conventions for the materializeForSet callback, depending on if we have a protocol witness or concrete implementation. Since the materializeForSet callback is called with a more abstract type at the call site than the actual function type of the callback, we used to rely on these two SIL types being ABI compatible: @convention(thin) () @convention(thin) (..., Foo.Type) -> () The IRGen lowering is roughly the following -- the call site passes two unused parameters, but that's fine: (..., Self.Type*, Self.Type*, Self.P*) (..., Foo.Type*) However if the callback has its own generic parameters because the subscript is generic, we might have SIL types like so, @convention(thin) () @convention(thin) (..., Foo.Type) -> () And the IRGen lowering is the following: (..., Self.Type*, Self.Type*, Self.P*, V.Type*) (..., Foo.Type*, V.Type*) The parameters no longer line up, because the caller still passes the two discarded arguments, and type metadata for V cannot be derived from the Self metadata so must be passed separately. The witness_method calling convention is designed to solve this problem; it puts the Self metadata and protocol conformance last, so if you have these SIL types: @convention(witness_method) () @convention(witness_method) (..., swiftself Foo.Type) -> () The IRGen lowering is the following: (..., Self.Type*, V.Type*, Self.Type*, Self.P*) (..., Foo.Type*, V.Type*, Self.Type*, unused i8*) However, the problem is now that witness_method and thin functions are not ABI compatible, because thin functions don't have a distinguished 'self', which is passed differently in LLVM's swiftcc calling convention: @convention(witness_method) () @convention(thin) (..., Foo.Type) -> () So instead of using 'thin' representation for the concrete callback case, use 'method', which is essentially the same as 'thin' except if the last parameter is pointer-size, it is passed as the 'self' value. This makes everything work out. --- include/swift/SIL/TypeLowering.h | 3 +- lib/SIL/SILVerifier.cpp | 16 +- lib/SIL/TypeLowering.cpp | 8 +- lib/SILGen/SILGenLValue.cpp | 8 +- lib/SILGen/SILGenMaterializeForSet.cpp | 156 +++++++++++++++++- test/SILGen/accessors.swift | 6 +- test/SILGen/addressors.swift | 4 +- test/SILGen/constrained_extensions.swift | 4 +- test/SILGen/lifetime.swift | 2 +- test/SILGen/materializeForSet.swift | 65 ++++++-- test/SILGen/properties.swift | 2 +- .../devirt_materializeForSet.swift | 2 +- 12 files changed, 236 insertions(+), 40 deletions(-) diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index 6c2f7845458a0..e97e6cf35f7a6 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -622,7 +622,8 @@ class TypeConverter { CanSILFunctionType getMaterializeForSetCallbackType(AbstractStorageDecl *storage, CanGenericSignature genericSig, - Type selfType); + Type selfType, + SILFunctionTypeRepresentation rep); /// Return the SILFunctionType for a native function value of the /// given type. diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index dfd06f9532a29..4ec33cf5778f9 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -2876,8 +2876,12 @@ class SILVerifier : public SILVerifierBase { requireObjectType(BuiltinRawPointerType, CI, "thin_function_to_pointer result"); - require(opTI->getRepresentation() == SILFunctionType::Representation::Thin, - "thin_function_to_pointer only works on thin functions"); + auto rep = opTI->getRepresentation(); + require(rep == SILFunctionTypeRepresentation::Thin || + rep == SILFunctionTypeRepresentation::Method || + rep == SILFunctionTypeRepresentation::WitnessMethod, + "thin_function_to_pointer only works on thin, method or " + "witness_method functions"); } void checkPointerToThinFunctionInst(PointerToThinFunctionInst *CI) { @@ -2886,8 +2890,12 @@ class SILVerifier : public SILVerifierBase { requireObjectType(BuiltinRawPointerType, CI->getOperand(), "pointer_to_thin_function operand"); - require(resultTI->getRepresentation() == SILFunctionType::Representation::Thin, - "pointer_to_thin_function only works on thin functions"); + auto rep = resultTI->getRepresentation(); + require(rep == SILFunctionTypeRepresentation::Thin || + rep == SILFunctionTypeRepresentation::Method || + rep == SILFunctionTypeRepresentation::WitnessMethod, + "pointer_to_thin_function only works on thin, method or " + "witness_method functions"); } void checkCondFailInst(CondFailInst *CFI) { diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index 01dd21ba1a232..1bda39f4a6e22 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -2130,7 +2130,8 @@ TypeConverter::getProtocolDispatchStrategy(ProtocolDecl *P) { CanSILFunctionType TypeConverter:: getMaterializeForSetCallbackType(AbstractStorageDecl *storage, CanGenericSignature genericSig, - Type selfType) { + Type selfType, + SILFunctionTypeRepresentation rep) { auto &ctx = M.getASTContext(); // Get lowered formal types for callback parameters. @@ -2168,9 +2169,8 @@ getMaterializeForSetCallbackType(AbstractStorageDecl *storage, { canSelfMetatypeType, ParameterConvention::Direct_Unowned }, }; ArrayRef results = {}; - auto extInfo = - SILFunctionType::ExtInfo() - .withRepresentation(SILFunctionTypeRepresentation::Thin); + + auto extInfo = SILFunctionType::ExtInfo().withRepresentation(rep); if (genericSig && genericSig->areAllParamsConcrete()) genericSig = nullptr; diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 8c3e03ffe413e..c48011c3ae9c5 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -879,8 +879,14 @@ namespace { rawPointerTy, ValueOwnershipKind::Trivial); // Cast the callback to the correct polymorphic function type. + SILFunctionTypeRepresentation rep; + if (isa(decl->getDeclContext())) + rep = SILFunctionTypeRepresentation::WitnessMethod; + else + rep = SILFunctionTypeRepresentation::Method; + auto origCallbackFnType = gen.SGM.Types.getMaterializeForSetCallbackType( - decl, materialized.genericSig, materialized.origSelfType); + decl, materialized.genericSig, materialized.origSelfType, rep); auto origCallbackType = SILType::getPrimitiveObjectType(origCallbackFnType); callback = gen.B.createPointerToThinFunction(loc, callback, origCallbackType); diff --git a/lib/SILGen/SILGenMaterializeForSet.cpp b/lib/SILGen/SILGenMaterializeForSet.cpp index d8e7c8e2ec2be..7c84478c60da9 100644 --- a/lib/SILGen/SILGenMaterializeForSet.cpp +++ b/lib/SILGen/SILGenMaterializeForSet.cpp @@ -12,6 +12,136 @@ // // Emission of materializeForSet. // +// There are two cases where materializeForSet is used for inout access: +// +// === Storage is virtually dispatched on a base class === +// +// For example, suppose we have this setup, where a computed property in a +// base class is overridden with a computed property in the derived class: +// +// class Base { var x: T } +// class Derived : Base { override var x: Int { ... } } +// func operate(b: Base) { +// b.x += 1 +// } +// +// As far as caller is concerned, the callback is invoked with the following +// SIL type: +// +// (RawPointer, @inout UnsafeValueBuffer, @inout Base, @thick Base.Type) -> () +// +// The caller will pass the first four formal parameters, followed by the +// type metadata for 'T'. +// +// However if the dynamic type of the parameter 'b' is actually 'Derived', +// then the actual callback has this SIL type: +// +// (RawPointer, @inout UnsafeValueBuffer, @inout Derived, @thick Derived.Type) -> () +// +// This is a fully concrete function type, with no additional generic metadata. +// +// These two callbacks are be ABI-compatible though, because IRGen makes three +// guarantees: +// +// 1) Passing extra arguments (in this case, the type metadata for 'T') is a +// no-op. +// +// 2) IRGen knows to recover the type metadata for 'T' from the +// '@thick Base.Type' parameter, instead of passing it separately. +// +// 3) The metatype for 'Derived' must be layout-compatible with 'Base'; +// since the generic parameter 'T' is made concrete, we expect to find the +// type metadata for 'Int' at the same offset within 'Derived.Type' as the +// generic parameter 'T' in 'Base.Type'. +// +// === Storage is virtually dispatched on a protocol === +// +// For example, +// +// protocol BoxLike { associatedtype Element; var x: Element { get set } } +// func operate(b: B) where B.Element == Int { +// b.x += 1 +// } +// +// As far as the caller is concerned, the callback is invoked with following +// SIL type: +// +// (RawPointer, @inout UnsafeValueBuffer, @inout Self, @thick Self.Type) -> () +// +// At the IRGen level, a call of a SIL function with the above type will pass +// the four formal parameters, followed by the type metadata for 'Self', and +// then followed by the protocol witness table for 'Self : BoxLike'. +// +// As in the class case, the callback won't have the same identical SIL type, +// because it might have a different representation of 'Self'. +// +// So we must consider two separate cases: +// +// 1) The witness is a method of the concrete conforming type, eg, +// +// struct Box : BoxLike { var x: T } +// +// Here, the actual callback will have the following type: +// +// (RawPointer, @inout UnsafeValueBuffer, @inout Box, @thick Box.Type) -> () +// +// As with the class case, IRGen can already do the right thing -- the type +// metadata for 'T' is recovered from the '@thick Box.Type' parameter, +// and the type metadata for 'Self' as well as the conformance +// 'Self : BoxLike' are ignored. +// +// 2) The witness is a protocol extension method, possibly of some other protocol, eg, +// +// protocol SomeOtherProtocol { } +// extension SomeOtherProtocol { var x: Element { ... } } +// struct FunnyBox : BoxLike, SomeOtherProtocol { typealias Element = T } +// +// Here, the actual callback will have the following type: +// +// (RawPointer, @inout UnsafeValueBuffer, @inout Self, @thick Self.Type) -> () +// +// Here, the actual callback expects to receive the four formal parameters, +// followed by the type metadata for 'Self', followed by the witness table +// for the conformance 'Self : SomeOtherProtocol'. Note that the +// conformance cannot be recovered from the thick metatype. +// +// This is *not* ABI-compatible with the type used at the call site, +// because the caller is passing in the conformance of 'Self : BoxLike' +// (the requirement's signature) but the callee is expecting +// 'Self : SomeOtherProtocol' (the witness signature). +// +// For this reason the materializeForSet method in the protocol extension +// of 'SomeOtherProtocol' cannot witness the materializeForSet requirement +// of 'BoxLike'. So instead, the protocol witness thunk for +// materializeForSet cannot delegate to the materializeForSet witness at +// all; it's entirely open-coded, with its own callback that has the right +// calling convention. +// +// === Storage has its own generic parameters === +// +// One final special case is where the storage has its own generic parameters; +// that is, a generic subscript. +// +// Suppose we have the following protocol: +// +// protocol GenericSubscript { subscript(t: T) -> U { get set } } +// +// At the call site, the callback is invoked with the following signature: +// +// (RawPointer, @inout UnsafeValueBuffer, @inout Self, @thick Self.Type) -> () +// +// If the witness is a member of a concrete type 'AnyDictionary', the actual +// callback will have the following signature: +// +// (RawPointer, @inout UnsafeValueBuffer, @inout AnyDictionary, @thick SelfAnyDictionary.Type) -> () +// +// This is not ABI-compatible with the type at the call site, because the type +// metadata for 'T' and 'U' trails the type metadata for 'Self' and the protocol +// witness table for the conformance 'Self : GenericSubscript'. +// +// So again, protocol witness thunks for materializeForSet of a generic +// subscript must be open-coded. +// //===----------------------------------------------------------------------===// #include "SILGen.h" @@ -124,12 +254,15 @@ struct MaterializeForSetEmitter { SILType WitnessStorageType; + SILFunctionTypeRepresentation CallbackRepresentation; + private: MaterializeForSetEmitter(SILGenModule &SGM, SILLinkage linkage, FuncDecl *witness, SubstitutionList subs, GenericEnvironment *genericEnv, - Type selfInterfaceType, Type selfType) + Type selfInterfaceType, Type selfType, + SILFunctionTypeRepresentation callbackRepresentation) : SGM(SGM), Linkage(linkage), RequirementStorage(nullptr), @@ -142,7 +275,8 @@ struct MaterializeForSetEmitter { SelfInterfaceType(selfInterfaceType->getCanonicalType()), SubstSelfType(selfType->getCanonicalType()), TheAccessSemantics(AccessSemantics::Ordinary), - IsSuper(false) { + IsSuper(false), + CallbackRepresentation(callbackRepresentation) { // Determine the formal type of the 'self' parameter. if (WitnessStorage->isStatic()) { @@ -179,7 +313,8 @@ struct MaterializeForSetEmitter { FuncDecl *requirement, FuncDecl *witness, SubstitutionList witnessSubs) { MaterializeForSetEmitter emitter(SGM, linkage, witness, witnessSubs, - genericEnv, selfInterfaceType, selfType); + genericEnv, selfInterfaceType, selfType, + SILFunctionTypeRepresentation::WitnessMethod); emitter.RequirementStorage = requirement->getAccessorStorageDecl(); // Determine the desired abstraction pattern of the storage type @@ -209,7 +344,8 @@ struct MaterializeForSetEmitter { MaterializeForSetEmitter emitter(SGM, constant.getLinkage(ForDefinition), witness, witnessSubs, witness->getGenericEnvironment(), - selfInterfaceType, selfType); + selfInterfaceType, selfType, + SILFunctionTypeRepresentation::Method); emitter.RequirementStorage = emitter.WitnessStorage; emitter.RequirementStoragePattern = emitter.WitnessStoragePattern; @@ -374,9 +510,12 @@ struct MaterializeForSetEmitter { /// Given part of the witness's interface type, produce its /// substitution according to the witness substitutions. CanType getSubstWitnessInterfaceType(CanType type) { - auto subs = SubstSelfType->getRValueInstanceType() - ->getMemberSubstitutionMap(SGM.SwiftModule, WitnessStorage); - return type.subst(subs)->getCanonicalType(); + if (auto *witnessSig = Witness->getGenericSignature()) { + auto subMap = witnessSig->getSubstitutionMap(WitnessSubs); + return type.subst(subMap, SubstFlags::UseErrorType)->getCanonicalType(); + } + + return type; } }; @@ -537,7 +676,8 @@ SILFunction *MaterializeForSetEmitter::createCallback(SILFunction &F, auto callbackType = SGM.Types.getMaterializeForSetCallbackType(WitnessStorage, GenericSig, - SelfInterfaceType); + SelfInterfaceType, + CallbackRepresentation); auto *genericEnv = GenericEnv; if (GenericEnv && GenericEnv->getGenericSignature()->areAllParamsConcrete()) diff --git a/test/SILGen/accessors.swift b/test/SILGen/accessors.swift index 1f740977bf9bc..3f124b0040519 100644 --- a/test/SILGen/accessors.swift +++ b/test/SILGen/accessors.swift @@ -65,7 +65,7 @@ func test0(_ ref: A) { // CHECK-NEXT: switch_enum [[OPT_CALLBACK]] : $Optional, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]] // CHECK: [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : $Builtin.RawPointer): -// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout A, @thick A.Type) -> () +// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout A, @thick A.Type) -> () // CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $A // SEMANTIC SIL TODO: This is an issue caused by the callback for materializeForSet in the class case taking the value as @inout when it should really take it as @guaranteed. // CHECK-NEXT: store [[BORROWED_ARG_LHS]] to [init] [[TEMP2]] : $*A @@ -128,7 +128,7 @@ func test1(_ ref: B) { // CHECK-NEXT: switch_enum [[OPT_CALLBACK]] : $Optional, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]] // // CHECK: [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : $Builtin.RawPointer): -// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout B, @thick B.Type) -> () +// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout B, @thick B.Type) -> () // CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $B // CHECK-NEXT: store [[BORROWED_ARG_RHS]] to [init] [[TEMP2]] : $*B // CHECK-NEXT: [[T0:%.*]] = metatype $@thick B.Type @@ -154,7 +154,7 @@ func test1(_ ref: B) { // CHECK-NEXT: switch_enum [[OPT_CALLBACK]] : $Optional, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]] // // CHECK: [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : $Builtin.RawPointer): -// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout B, @thick B.Type) -> () +// CHECK-NEXT: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout B, @thick B.Type) -> () // CHECK-NEXT: [[TEMP2:%.*]] = alloc_stack $B // CHECK-NEXT: store [[BORROWED_ARG_LHS]] to [init] [[TEMP2]] : $*B // CHECK-NEXT: [[T0:%.*]] = metatype $@thick B.Type diff --git a/test/SILGen/addressors.swift b/test/SILGen/addressors.swift index 2bd836c9a703d..fe274de285e58 100644 --- a/test/SILGen/addressors.swift +++ b/test/SILGen/addressors.swift @@ -332,7 +332,7 @@ class G { // CHECK: strong_release [[OWNER]] : $Builtin.NativeObject // materializeForSet callback for G.value -// CHECK-LABEL: sil hidden [transparent] @_T010addressors1GC5values5Int32VfmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout G, @thick G.Type) -> () { +// CHECK-LABEL: sil hidden [transparent] @_T010addressors1GC5values5Int32VfmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout G, @thick G.Type) -> () { // CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $*G, [[SELFTYPE:%3]] : $@thick G.Type): // CHECK: [[T0:%.*]] = project_value_buffer $Builtin.NativeObject in [[STORAGE]] : $*Builtin.UnsafeValueBuffer // CHECK: [[OWNER:%.*]] = load [[T0]] @@ -452,7 +452,7 @@ class I { // CHECK: strong_unpin [[OWNER]] : $Optional // materializeForSet callback for I.value -// CHECK-LABEL: sil hidden [transparent] @_T010addressors1IC5values5Int32VfmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout I, @thick I.Type) -> () { +// CHECK-LABEL: sil hidden [transparent] @_T010addressors1IC5values5Int32VfmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout I, @thick I.Type) -> () { // CHECK: bb0([[BUFFER:%0]] : $Builtin.RawPointer, [[STORAGE:%1]] : $*Builtin.UnsafeValueBuffer, [[SELF:%2]] : $*I, [[SELFTYPE:%3]] : $@thick I.Type): // CHECK: [[T0:%.*]] = project_value_buffer $Optional in [[STORAGE]] : $*Builtin.UnsafeValueBuffer // CHECK: [[OWNER:%.*]] = load [[T0]] diff --git a/test/SILGen/constrained_extensions.swift b/test/SILGen/constrained_extensions.swift index ea7ee1bcf1e6d..e6820ca965b96 100644 --- a/test/SILGen/constrained_extensions.swift +++ b/test/SILGen/constrained_extensions.swift @@ -10,7 +10,7 @@ extension Array where Element == Int { // CHECK-LABEL: sil @_T0Sa22constrained_extensionsSiRszlE16instancePropertySifg : $@convention(method) (@guaranteed Array) -> Int // CHECK-LABEL: sil @_T0Sa22constrained_extensionsSiRszlE16instancePropertySifs : $@convention(method) (Int, @inout Array) -> () - // CHECK-LABEL: sil [transparent] [fragile] @_T0Sa22constrained_extensionsSiRszlE16instancePropertySifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Array, @thick Array.Type) -> () + // CHECK-LABEL: sil [transparent] [fragile] @_T0Sa22constrained_extensionsSiRszlE16instancePropertySifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Array, @thick Array.Type) -> () // CHECK-LABEL: sil [transparent] [fragile] @_T0Sa22constrained_extensionsSiRszlE16instancePropertySifm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Array) -> (Builtin.RawPointer, Optional) public var instanceProperty: Element { @@ -71,7 +71,7 @@ extension Dictionary where Key == Int { // CHECK-LABEL: sil @_T0s10DictionaryV22constrained_extensionsSiRszr0_lE16instancePropertyq_fg : $@convention(method) (@guaranteed Dictionary) -> @out Value // CHECK-LABEL: sil @_T0s10DictionaryV22constrained_extensionsSiRszr0_lE16instancePropertyq_fs : $@convention(method) (@in Value, @inout Dictionary) -> () - // CHECK-LABEL: sil [transparent] [fragile] @_T0s10DictionaryV22constrained_extensionsSiRszr0_lE16instancePropertyq_fmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Dictionary, @thick Dictionary.Type) -> () + // CHECK-LABEL: sil [transparent] [fragile] @_T0s10DictionaryV22constrained_extensionsSiRszr0_lE16instancePropertyq_fmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Dictionary, @thick Dictionary.Type) -> () // CHECK-LABEL: sil [transparent] [fragile] @_T0s10DictionaryV22constrained_extensionsSiRszr0_lE16instancePropertyq_fm : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Dictionary) -> (Builtin.RawPointer, Optional) public var instanceProperty: Value { get { diff --git a/test/SILGen/lifetime.swift b/test/SILGen/lifetime.swift index 39a4ab5433d99..47cad67e75332 100644 --- a/test/SILGen/lifetime.swift +++ b/test/SILGen/lifetime.swift @@ -380,7 +380,7 @@ func logical_lvalue_lifetime(_ r: RefWithProp, _ i: Int, _ v: Val) { // CHECK: [[ADDR:%.*]] = pointer_to_address [[PTR]] // CHECK: [[MARKED_ADDR:%.*]] = mark_dependence [[ADDR]] : $*Aleph on [[R2]] // CHECK: {{.*}}([[CALLBACK_ADDR:%.*]] : - // CHECK: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout RefWithProp, @thick RefWithProp.Type) -> () + // CHECK: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout RefWithProp, @thick RefWithProp.Type) -> () // CHECK: [[TEMP:%.*]] = alloc_stack $RefWithProp // CHECK: store [[R2]] to [init] [[TEMP]] // CHECK: apply [[CALLBACK]]({{.*}}, [[STORAGE]], [[TEMP]], {{%.*}}) diff --git a/test/SILGen/materializeForSet.swift b/test/SILGen/materializeForSet.swift index c39fe7eecb644..7f3d867e6d3d2 100644 --- a/test/SILGen/materializeForSet.swift +++ b/test/SILGen/materializeForSet.swift @@ -6,7 +6,7 @@ class Base { // The ordering here is unfortunate: we generate the property // getters and setters after we've processed the decl. - // CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet4BaseC8computedSifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Base, @thick Base.Type) -> () { + // CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet4BaseC8computedSifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Base, @thick Base.Type) -> () { // CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*Base, [[SELFTYPE:%.*]] : $@thick Base.Type): // CHECK: [[T0:%.*]] = load_borrow [[SELF]] // CHECK: [[T1:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int @@ -21,7 +21,7 @@ class Base { // CHECK: [[T1:%.*]] = apply [[T0]]([[SELF]]) // CHECK: store [[T1]] to [trivial] [[ADDR]] : $*Int // CHECK: [[BUFFER:%.*]] = address_to_pointer [[ADDR]] -// CHECK: [[T0:%.*]] = function_ref @_T017materializeForSet4BaseC8computedSifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Base, @thick Base.Type) -> () +// CHECK: [[T0:%.*]] = function_ref @_T017materializeForSet4BaseC8computedSifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Base, @thick Base.Type) -> () // CHECK: [[T2:%.*]] = thin_function_to_pointer [[T0]] // CHECK: [[T3:%.*]] = enum $Optional, #Optional.some!enumelt.1, [[T2]] : $Builtin.RawPointer // CHECK: [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[T3]] : $Optional) @@ -69,7 +69,7 @@ protocol Abstractable { extension Derived : Abstractable {} -// CHECK: sil hidden [transparent] @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14storedFunction6ResultQzycfmytfU_TW : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Derived, @thick Derived.Type) -> () +// CHECK: sil hidden [transparent] @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14storedFunction6ResultQzycfmytfU_TW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Derived, @thick Derived.Type) -> () // CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*Derived, %3 : $@thick Derived.Type): // CHECK-NEXT: [[T0:%.*]] = load_borrow %2 : $*Derived // CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base @@ -167,8 +167,8 @@ extension Derived : Abstractable {} // CHECK-NEXT: destroy_addr [[OUT]] : $*@callee_owned () -> Int // CHECK-NEXT: store [[NEWVALUE]] to [init] [[RESULT_ADDR]] : $*@callee_owned () -> @out Int // CHECK-NEXT: [[ADDR:%.*]] = address_to_pointer [[RESULT_ADDR]] : $*@callee_owned () -> @out Int to $Builtin.RawPointer -// CHECK: [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14staticFunction6ResultQzycfmZytfU_TW : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout @thick Derived.Type, @thick Derived.Type.Type) -> () -// CHECK-NEXT: [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]] : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout @thick Derived.Type, @thick Derived.Type.Type) -> () to $Builtin.RawPointer +// CHECK: [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet7DerivedCAA12AbstractableAaaDP14staticFunction6ResultQzycfmZytfU_TW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout @thick Derived.Type, @thick Derived.Type.Type) -> () +// CHECK-NEXT: [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]] : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout @thick Derived.Type, @thick Derived.Type.Type) -> () to $Builtin.RawPointer // CHECK-NEXT: [[CALLBACK:%.*]] = enum $Optional, #Optional.some!enumelt.1, [[CALLBACK_ADDR]] : $Builtin.RawPointer // CHECK-NEXT: [[RESULT:%.*]] = tuple ([[ADDR]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional) // CHECK-NEXT: dealloc_stack [[OUT]] : $*@callee_owned () -> Int @@ -213,7 +213,7 @@ class HasDidSet : Base { // CHECK: [[T1:%.*]] = apply [[T0]]([[SELF]]) // CHECK: store [[T1]] to [trivial] [[T2]] : $*Int // CHECK: [[BUFFER:%.*]] = address_to_pointer [[T2]] -// CHECK: [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet06HasDidC0C6storedSifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasDidSet, @thick HasDidSet.Type) -> () +// CHECK: [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet06HasDidC0C6storedSifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasDidSet, @thick HasDidSet.Type) -> () // CHECK: [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]] // CHECK: [[CALLBACK:%.*]] = enum $Optional, #Optional.some!enumelt.1, [[CALLBACK_ADDR]] // CHECK: [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional) @@ -232,7 +232,7 @@ class HasDidSet : Base { // CHECK: [[T1:%.*]] = apply [[T0]]([[SELF]]) // CHECK: store [[T1]] to [trivial] [[T2]] : $*Int // CHECK: [[BUFFER:%.*]] = address_to_pointer [[T2]] -// CHECK: [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet06HasDidC0C8computedSifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasDidSet, @thick HasDidSet.Type) -> () +// CHECK: [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet06HasDidC0C8computedSifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasDidSet, @thick HasDidSet.Type) -> () // CHECK: [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]] // CHECK: [[CALLBACK:%.*]] = enum $Optional, #Optional.some!enumelt.1, [[CALLBACK_ADDR]] // CHECK: [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional) @@ -245,7 +245,7 @@ class HasStoredDidSet { didSet {} } -// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet012HasStoredDidC0C6storedSifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasStoredDidSet, @thick HasStoredDidSet.Type) -> () { +// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet012HasStoredDidC0C6storedSifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasStoredDidSet, @thick HasStoredDidSet.Type) -> () { // CHECK: bb0([[BUFFER:%.*]] : $Builtin.RawPointer, [[STORAGE:%.*]] : $*Builtin.UnsafeValueBuffer, [[SELF:%.*]] : $*HasStoredDidSet, [[METATYPE:%.*]] : $@thick HasStoredDidSet.Type): // CHECK: [[SELF_VALUE:%.*]] = load_borrow [[SELF]] : $*HasStoredDidSet // CHECK: [[BUFFER_ADDR:%.*]] = pointer_to_address [[BUFFER]] : $Builtin.RawPointer to [strict] $*Int @@ -262,7 +262,7 @@ class HasStoredDidSet { // CHECK: [[T1:%.*]] = apply [[T0]]([[SELF]]) // CHECK: store [[T1]] to [trivial] [[T2]] : $*Int // CHECK: [[BUFFER:%.*]] = address_to_pointer [[T2]] -// CHECK: [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet012HasStoredDidC0C6storedSifmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasStoredDidSet, @thick HasStoredDidSet.Type) -> () +// CHECK: [[CALLBACK_FN:%.*]] = function_ref @_T017materializeForSet012HasStoredDidC0C6storedSifmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasStoredDidSet, @thick HasStoredDidSet.Type) -> () // CHECK: [[CALLBACK_ADDR:%.*]] = thin_function_to_pointer [[CALLBACK_FN]] // CHECK: [[CALLBACK:%.*]] = enum $Optional, #Optional.some!enumelt.1, [[CALLBACK_ADDR]] // CHECK: [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, [[CALLBACK]] : $Optional) @@ -280,7 +280,7 @@ class HasWeak { // CHECK: [[T1:%.*]] = load_weak [[T0]] : $*@sil_weak Optional // CHECK: store [[T1]] to [init] [[T2]] : $*Optional // CHECK: [[BUFFER:%.*]] = address_to_pointer [[T2]] -// CHECK: [[T0:%.*]] = function_ref @_T017materializeForSet7HasWeakC7weakvarACSgXwfmytfU_ : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasWeak, @thick HasWeak.Type) -> () +// CHECK: [[T0:%.*]] = function_ref @_T017materializeForSet7HasWeakC7weakvarACSgXwfmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout HasWeak, @thick HasWeak.Type) -> () // CHECK: [[T4:%.*]] = tuple ([[BUFFER]] : $Builtin.RawPointer, {{.*}} : $Optional) // CHECK: return [[T4]] : $(Builtin.RawPointer, Optional) // CHECK: } @@ -359,6 +359,47 @@ struct Foo: AddressOnlySubscript { func increment(_ x: inout Int) { x += 1 } +// Generic subscripts. + +protocol GenericSubscriptProtocol { + subscript(_: T) -> T { get set } +} + +struct GenericSubscriptWitness : GenericSubscriptProtocol { + subscript(_: T) -> T { get { } set { } } +} + +// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet23GenericSubscriptWitnessV9subscriptxxclufmytfU_ : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericSubscriptWitness, @thick GenericSubscriptWitness.Type) -> () { +// CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*GenericSubscriptWitness, %3 : $@thick GenericSubscriptWitness.Type): +// CHECK: [[BUFFER:%.*]] = project_value_buffer $T in %1 : $*Builtin.UnsafeValueBuffer +// CHECK-NEXT: [[INDICES:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*T +// CHECK: [[SETTER:%.*]] = function_ref @_T017materializeForSet23GenericSubscriptWitnessV9subscriptxxclufs : $@convention(method) <τ_0_0> (@in τ_0_0, @in τ_0_0, @inout GenericSubscriptWitness) -> () +// CHECK-NEXT: apply [[SETTER]]([[INDICES]], [[BUFFER]], %2) : $@convention(method) <τ_0_0> (@in τ_0_0, @in τ_0_0, @inout GenericSubscriptWitness) -> () +// CHECK-NEXT: dealloc_value_buffer $*T in %1 : $*Builtin.UnsafeValueBuffer +// CHECK-NEXT: [[RESULT:%.*]] = tuple () +// CHECK-NEXT: return [[RESULT]] : $() + +// CHECK-LABEL sil hidden [transparent] [thunk] @_T017materializeForSet23GenericSubscriptWitnessVAA0dE8ProtocolAaaDP9subscriptqd__qd__clufmTW : $@convention(witness_method) <τ_0_0> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @in τ_0_0, @inout GenericSubscriptWitness) -> (Builtin.RawPointer, Optional) { +// CHECK: bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*T, %3 : $*GenericSubscriptWitness): +// CHECK-NEXT: [[BUFFER:%.*]] = alloc_value_buffer $T in %1 : $*Builtin.UnsafeValueBuffer +// CHECK-NEXT: copy_addr %2 to [initialization] [[BUFFER]] : $*T +// CHECK-NEXT: [[VALUE:%.*]] = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*T +// CHECK-NEXT: [[SELF:%.*]] = load [trivial] %3 : $*GenericSubscriptWitness +// CHECK: [[GETTER:%.*]] = function_ref @_T017materializeForSet23GenericSubscriptWitnessV9subscriptxxclufg : $@convention(method) <τ_0_0> (@in τ_0_0, GenericSubscriptWitness) -> @out τ_0_0 +// CHECK-NEXT: apply [[GETTER]]([[VALUE]], %2, [[SELF]]) : $@convention(method) <τ_0_0> (@in τ_0_0, GenericSubscriptWitness) -> @out τ_0_0 +// CHECK-NEXT: [[VALUE_PTR:%.*]] = address_to_pointer [[VALUE]] : $*T to $Builtin.RawPointer +// CHECK: [[CALLBACK:%.*]] = function_ref @_T017materializeForSet23GenericSubscriptWitnessV9subscriptxxclufmytfU_ +// CHECK-NEXT: [[CALLBACK_PTR:%.*]] = thin_function_to_pointer [[CALLBACK]] : $@convention(method) <τ_0_0> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenericSubscriptWitness, @thick GenericSubscriptWitness.Type) -> () to $Builtin.RawPointer +// CHECK-NEXT: [[CALLBACK_OPTIONAL:%.*]] = enum $Optional, #Optional.some!enumelt.1, [[CALLBACK_PTR]] : $Builtin.RawPointer +// CHECK-NEXT: [[RESULT:%.*]] = tuple ([[VALUE_PTR]] : $Builtin.RawPointer, [[CALLBACK_OPTIONAL]] : $Optional) +// CHECK-NEXT: return [[RESULT]] : $(Builtin.RawPointer, Optional) + +extension GenericSubscriptProtocol { + subscript(t: T) -> T { get { } set { } } +} + +struct GenericSubscriptDefaultWitness : GenericSubscriptProtocol { } + // Test for materializeForSet vs static properties of structs. protocol Beverage { @@ -439,7 +480,7 @@ extension Panda { struct TuxedoPanda : Panda { } -// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet11TuxedoPandaVAA0E0AaaDP1xxxcfmytfU_TW : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout TuxedoPanda, @thick TuxedoPanda.Type) -> () +// CHECK-LABEL: sil hidden [transparent] @_T017materializeForSet11TuxedoPandaVAA0E0AaaDP1xxxcfmytfU_TW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout TuxedoPanda, @thick TuxedoPanda.Type) -> () // FIXME: Useless re-abstractions @@ -470,7 +511,7 @@ struct TuxedoPanda : Panda { } // The callback: - // CHECK: function_ref @_T017materializeForSet11TuxedoPandaVAA0E0AaaDP1xxxcfmytfU_TW : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout TuxedoPanda, @thick TuxedoPanda.Type) -> () + // CHECK: function_ref @_T017materializeForSet11TuxedoPandaVAA0E0AaaDP1xxxcfmytfU_TW : $@convention(witness_method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout TuxedoPanda, @thick TuxedoPanda.Type) -> () // CHECK: } diff --git a/test/SILGen/properties.swift b/test/SILGen/properties.swift index e54101b7651dd..3e66fde089830 100644 --- a/test/SILGen/properties.swift +++ b/test/SILGen/properties.swift @@ -227,7 +227,7 @@ func logical_struct_in_reftype_set(_ value: inout Val, z1: Int) { // -- writeback to val.ref.val_prop // CHECK: switch_enum [[OPT_CALLBACK]] : $Optional, case #Optional.some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.none!enumelt: [[CONT:bb[0-9]+]] // CHECK: [[WRITEBACK]]([[CALLBACK_ADDR:%.*]] : $Builtin.RawPointer): - // CHECK: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Ref, @thick Ref.Type) -> () + // CHECK: [[CALLBACK:%.*]] = pointer_to_thin_function [[CALLBACK_ADDR]] : $Builtin.RawPointer to $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Ref, @thick Ref.Type) -> () // CHECK: [[REF_MAT:%.*]] = alloc_stack $Ref // CHECK: store [[VAL_REF]] to [init] [[REF_MAT]] // CHECK: [[T0:%.*]] = metatype $@thick Ref.Type diff --git a/test/SILOptimizer/devirt_materializeForSet.swift b/test/SILOptimizer/devirt_materializeForSet.swift index e84bc406bc1aa..77b805bffd044 100644 --- a/test/SILOptimizer/devirt_materializeForSet.swift +++ b/test/SILOptimizer/devirt_materializeForSet.swift @@ -5,7 +5,7 @@ // CHECK-LABEL: sil [transparent] [fragile] [thunk] @_T024devirt_materializeForSet7BaseFooCAA0F0AaaDP3barSSfmTW // CHECK: checked_cast_br [exact] %{{.*}} : $BaseFoo to $ChildFoo -// CHECK: thin_function_to_pointer %{{.*}} : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout ChildFoo, @thick ChildFoo.Type) -> () to $Builtin.RawPointer +// CHECK: thin_function_to_pointer %{{.*}} : $@convention(method) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout ChildFoo, @thick ChildFoo.Type) -> () to $Builtin.RawPointer // CHECK: enum $Optional, #Optional.some!enumelt.1, %{{.*}} : $Builtin.RawPointer // CHECK: tuple (%{{.*}} : $Builtin.RawPointer, %{{.*}} : $Optional) From 8b0094fe42d1081c3cc43a952f788a1d345d64ec Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 24 Feb 2017 23:00:27 -0800 Subject: [PATCH 3/4] Add executable test for generic subscripts --- test/Interpreter/generic_subscript.swift | 132 +++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 test/Interpreter/generic_subscript.swift diff --git a/test/Interpreter/generic_subscript.swift b/test/Interpreter/generic_subscript.swift new file mode 100644 index 0000000000000..468765d6e3e8f --- /dev/null +++ b/test/Interpreter/generic_subscript.swift @@ -0,0 +1,132 @@ +//===--- FunctionConversion.swift -----------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// RUN: %target-run-simple-swift +// REQUIRES: executable_test +// + +import StdlibUnittest + + +var GenericSubscriptTestSuite = TestSuite("GenericSubscript") + +struct S : P { + typealias Element = T + var t: T + + subscript(a: (T) -> U, b: (U) -> T) -> U { + get { + print(T.self) + print(U.self) + + return a(t) + } + set { + print(T.self) + print(U.self) + + t = b(newValue) + } + } +} + +protocol P { + associatedtype Element + subscript(a: (Element) -> U, b: (U) -> Element) -> U { get set } +} + +func increment(p: inout T) where T.Element == String { + p[{Int($0)!}, {String($0)}] += 1 +} + +GenericSubscriptTestSuite.test("Basic") { + var s = S(t: "0") + increment(p: &s) + expectEqual(s.t, "1") +} + +protocol AnySubscript { + subscript(k: AnyHashable) -> Any? { get set } +} + +struct AnyDictionary : AnySubscript { + var dict: [AnyHashable : Any] = [:] + + subscript(k: AnyHashable) -> Any? { + get { + return dict[k] + } + set { + dict[k] = newValue + } + } +} + +extension AnySubscript { + subscript(k k: K) -> V? { + get { + return self[k] as! V? + } + set { + self[k] = newValue + } + } +} + +GenericSubscriptTestSuite.test("ProtocolExtensionConcrete") { + var dict = AnyDictionary() + + func doIt(dict: inout AnyDictionary) { + dict["a" ] = 0 + dict[k: "a"]! += 1 + } + + doIt(dict: &dict) + + expectEqual(dict["a"]! as! Int, 1) + expectEqual(dict[k: "a"]!, 1) +} + +GenericSubscriptTestSuite.test("ProtocolExtensionAbstract") { + var dict = AnyDictionary() + + func doIt(dict: inout T) { + dict["a" ] = 0 + dict[k: "a"]! += 1 + } + + doIt(dict: &dict) + + expectEqual(dict["a"]! as! Int, 1) + expectEqual(dict[k: "a"]!, 1) +} + +protocol GenericSubscript : AnySubscript { + subscript(k k: K) -> V? { get set } +} + +extension AnyDictionary : GenericSubscript { } + +GenericSubscriptTestSuite.test("ProtocolExtensionWitness") { + var dict = AnyDictionary() + + func doIt(dict: inout T) { + dict["a" ] = 0 + dict[k: "a"]! += 1 + } + + doIt(dict: &dict) + + expectEqual(dict["a"]! as! Int, 1) + expectEqual(dict[k: "a"]!, 1) +} + +runAllTests() From fa8f2ce503f114987e80f81846b0bc2f5286f28d Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 24 Feb 2017 23:05:49 -0800 Subject: [PATCH 4/4] Add CHANGELOG.md entries for SE-0110 and SE-0148 --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 196afd7ff270c..e5ddaa96c3bfa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG | Contents | | :--------------------- | +| [Swift 4.0](#swift-40) | | [Swift 3.1](#swift-31) | | [Swift 3.0](#swift-30) | | [Swift 2.2](#swift-22) | @@ -17,6 +18,28 @@ CHANGELOG +Swift 4.0 +--------- + +* [SE-0148][]: + + Subscript declarations can now be defined to have generic parameter lists. + Example: + + ``` + extension JSON { + subscript(key: String) -> T? + where T : JSONConvertible { + // ... + } + } + ``` + +* [SE-0110][]: + + In Swift 4 mode, Swift's type system properly distinguishes between functions that + take one tuple argument, and functions that take multiple arguments. + * More types of C macros which define integer constants are supported by the importer. Specifically the `+, -, *, /, ^, >>, ==, <, <=, >, >=` operators are now recognized, and the previously-supported `<<, &&, ||, &, |`