From 706e7baac41b9a95769ff8f4400a123edded2008 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Fri, 20 Dec 2013 02:25:11 +0000 Subject: [PATCH] SILGen: Handle abstraction differences in stored property access. When we produce a physical LValue with an abstraction difference, cap off the LValue with a logical "OrigToSubstComponent", which enacts the abstraction change on load or store, and introduces a writeback for the property when used in an @inout context. Swift SVN r11498 --- lib/SIL/TypeLowering.cpp | 13 +++--- lib/SILGen/LValue.h | 9 ++++ lib/SILGen/SILGenLValue.cpp | 62 +++++++++++++++++++++++-- test/SILGen/property_abstraction.swift | 64 ++++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 10 deletions(-) create mode 100644 test/SILGen/property_abstraction.swift diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index fe3a9252d2f..c5d4cb6752b 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -1319,15 +1319,16 @@ SILType TypeConverter::getSubstitutedStorageType(ValueDecl *value, // same substitutions to value->getType(). // Canonicalize and lower the l-value's object type. - CanType substType = - cast(lvalueType->getCanonicalType()).getObjectType(); - SILType silSubstType = getLoweredType(substType).getAddressType(); + CanType origType = value->getType()->getCanonicalType(); + CanType substType + = cast(lvalueType->getCanonicalType()).getObjectType(); + SILType silSubstType + = getLoweredType(AbstractionPattern(origType), substType).getAddressType(); substType = silSubstType.getSwiftRValueType(); // Fast path: if the unsubstituted type from the variable equals the // substituted type from the l-value, there's nothing to do. - CanType valueType = value->getType()->getCanonicalType(); - if (valueType == substType) + if (origType == substType) return silSubstType; // Type substitution preserves structural type structure, and the @@ -1337,7 +1338,7 @@ SILType TypeConverter::getSubstitutedStorageType(ValueDecl *value, // The only really significant manipulation there is with [weak] and // [unowned]. - if (auto refType = dyn_cast(valueType)) { + if (auto refType = dyn_cast(origType)) { // Strip Optional<> off of [weak] types. if (isa(refType)) substType = cast(substType).getGenericArgs()[0]; diff --git a/lib/SILGen/LValue.h b/lib/SILGen/LValue.h index c5c79342564..e92ad57707e 100644 --- a/lib/SILGen/LValue.h +++ b/lib/SILGen/LValue.h @@ -195,6 +195,15 @@ public: return true; } + /// Is the lvalue's final component physical? + bool isLastComponentPhysical() const { + assert(isValid()); + auto component = begin(), next = begin(), e = end(); + ++next; + for (; next != e; component = next, ++next) { } + return component->isPhysical(); + } + /// Add a new component at the end of the access path of this lvalue. template T &add(A &&...args) { T &component = Path.add(std::forward(args)...); diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 81fa21fd91c..375bf6950c9 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -198,10 +198,6 @@ SILGenFunction::Writeback::Writeback(SILLocation loc, { } -LValue SILGenFunction::emitLValue(Expr *e) { - return SILGenLValue(*this).visit(e); -} - RValue SILGenFunction::emitLValueAsRValue(Expr *e) { LValue lv = emitLValue(e); return RValue(*this, e, emitAddressOfLValue(e, lv)); @@ -448,6 +444,64 @@ namespace { return std::unique_ptr(clone); } }; + + /// Remap an lvalue referencing a generic type to an lvalue of its substituted + /// type in a concrete context. + class OrigToSubstComponent : public LogicalPathComponent { + AbstractionPattern origType; + CanType substType; + + public: + OrigToSubstComponent(SILGenFunction &gen, + AbstractionPattern origType, CanType substType) + : LogicalPathComponent(getUnsubstitutedTypeData(gen, substType)), + origType(origType), substType(substType) + {} + + bool isSettable() const override { + return true; + } + + void set(SILGenFunction &gen, SILLocation loc, + RValueSource &&rvalue, SILValue base) const override { + // Map the value to the original abstraction level. + ManagedValue mv = std::move(rvalue).getAsSingleValue(gen); + mv = gen.emitSubstToOrigValue(loc, mv, origType, substType); + // Store to the base. + mv.assignInto(gen, loc, base); + } + + ManagedValue get(SILGenFunction &gen, SILLocation loc, + SILValue base, SGFContext c) const override { + // Load the original value. + ManagedValue baseVal = gen.emitLoad(loc, base, + gen.getTypeLowering(base.getType()), + SGFContext(), + IsNotTake); + // Map the base value to its substituted representation. + return gen.emitOrigToSubstValue(loc, baseVal, + origType, substType, c); + } + + std::unique_ptr + clone(SILGenFunction &gen, SILLocation loc) const override { + LogicalPathComponent *clone + = new OrigToSubstComponent(gen, origType, substType); + return std::unique_ptr(clone); + } + }; +} + +LValue SILGenFunction::emitLValue(Expr *e) { + LValue r = SILGenLValue(*this).visit(e); + // If the final component is physical with an abstraction change, introduce a + // reabstraction component. + if (r.isLastComponentPhysical()) { + if (r.getOrigFormalType().getAsType() != r.getSubstFormalType()) + r.add(*this, r.getOrigFormalType(), + r.getSubstFormalType()); + } + return r; } LValue SILGenLValue::visitRec(Expr *e) { diff --git a/test/SILGen/property_abstraction.swift b/test/SILGen/property_abstraction.swift new file mode 100644 index 00000000000..c9c3457d8a9 --- /dev/null +++ b/test/SILGen/property_abstraction.swift @@ -0,0 +1,64 @@ +// RUN: %swift -parse-stdlib -emit-silgen %s | FileCheck %s + +struct Int {} + +struct Foo { + var f: T -> U +} + +// CHECK-LABEL: sil @_TF20property_abstraction4getFFT1xGVS_3FooVS_3IntS1___FS1_S1_ : $@thin (@owned Foo) -> @owned @callee_owned (Int) -> Int +// CHECK: [[F_ADDR:%.*]] = struct_element_addr {{%.*}} : $*Foo, #f +// CHECK: [[F_ORIG:%.*]] = load [[F_ADDR]] +// CHECK: [[REABSTRACT_FN:%.*]] = function_ref @_TTRXFo_iV20property_abstraction3Int_iS0__XFo_dS0__dS0__ : $@thin (Int, @owned @callee_owned (@out Int, @in Int) -> ()) -> Int +// CHECK: [[F_SUBST:%.*]] = partial_apply [[REABSTRACT_FN]]([[F_ORIG]]) +// CHECK: return [[F_SUBST]] +func getF(x: Foo) -> Int -> Int { + return x.f +} + +// CHECK-LABEL: sil @_TF20property_abstraction4setFFT1xRGVS_3FooVS_3IntS1__1fFS1_S1__T_ : $@thin (@inout Foo, @owned @callee_owned (Int) -> Int) -> () +// CHECK: [[F_ADDR:%.*]] = struct_element_addr {{%.*}} : $*Foo, #f +// CHECK: [[REABSTRACT_FN:%.*]] = function_ref @_TTRXFo_dV20property_abstraction3Int_dS0__XFo_iS0__iS0__ : $@thin (@out Int, @in Int, @owned @callee_owned (Int) -> Int) -> () +// CHECK: [[F_ORIG:%.*]] = partial_apply [[REABSTRACT_FN]]({{%.*}}) +// CHECK: assign [[F_ORIG]] to [[F_ADDR]] +func setF(x: @inout Foo, f: Int -> Int) { + x.f = f +} + +func inOutFunc(f: @inout (Int -> Int)) { } + +// CHECK-LABEL: sil @_TF20property_abstraction6inOutFFT1xGVS_3FooVS_3IntS1___T_ : $@thin (@owned Foo) -> () { +// CHECK: [[INOUTFUNC:%.*]] = function_ref @_TF20property_abstraction9inOutFuncFT1fRFVS_3IntS0__T_ : $@thin (@inout @callee_owned (Int) -> Int) -> () +// CHECK: [[F_ADDR:%.*]] = struct_element_addr {{%.*}} : $*Foo, #f +// CHECK: [[F_ORIG:%.*]] = load [[F_ADDR]] +// CHECK: [[REABSTRACT_FN:%.*]] = function_ref @_TTRXFo_iV20property_abstraction3Int_iS0__XFo_dS0__dS0__ : $@thin (Int, @owned @callee_owned (@out Int, @in Int) -> ()) -> Int +// CHECK: [[F_SUBST_IN:%.*]] = partial_apply [[REABSTRACT_FN]]([[F_ORIG]]) +// CHECK: [[F_SUBST_MAT:%.*]] = alloc_stack +// CHECK: store [[F_SUBST_IN]] to [[F_SUBST_MAT]] +// CHECK: apply [[INOUTFUNC]]([[F_SUBST_MAT]]#1) +// CHECK: [[F_SUBST_OUT:%.*]] = load [[F_SUBST_MAT]] +// CHECK: [[REABSTRACT_FN:%.*]] = function_ref @_TTRXFo_dV20property_abstraction3Int_dS0__XFo_iS0__iS0__ : $@thin (@out Int, @in Int, @owned @callee_owned (Int) -> Int) -> () +// CHECK: [[F_ORIG:%.*]] = partial_apply [[REABSTRACT_FN]]([[F_SUBST_OUT]]) +// CHECK: assign [[F_ORIG]] to [[F_ADDR]] +func inOutF(x: Foo) { + inOutFunc(&x.f) +} + +/* + TODO +enum Bar { + case F(T -> U) +} + +func getF(x: Bar) -> Int -> Int { + switch x { + case .F(var f): + return f + } +} + +func makeF(f: Int -> Int) -> Bar { + return Bar.F(f) +} + +*/