@@ -2822,12 +2822,78 @@ RValue RValueEmitter::visitDynamicSubscriptExpr(
2822
2822
E->getType ()->getCanonicalType (), C);
2823
2823
}
2824
2824
2825
+ namespace {
2826
+ class CollectValueInitialization : public Initialization {
2827
+ ManagedValue Value;
2828
+
2829
+ public:
2830
+ ManagedValue getValue () const {
2831
+ assert (Value);
2832
+ return Value;
2833
+ }
2834
+
2835
+ void copyOrInitValueInto (SILGenFunction &SGF, SILLocation loc,
2836
+ ManagedValue value, bool isInit) override {
2837
+ if (!isInit) value = value.copy (SGF, loc);
2838
+ Value = value;
2839
+ }
2840
+ };
2841
+ }
2825
2842
2826
2843
RValue RValueEmitter::visitTupleElementExpr (TupleElementExpr *E,
2827
2844
SGFContext C) {
2828
2845
assert (!E->getType ()->is <LValueType>() &&
2829
2846
" RValueEmitter shouldn't be called on lvalues" );
2830
-
2847
+
2848
+ auto tupleType = cast<TupleType>(E->getBase ()->getType ()->getCanonicalType ());
2849
+ auto projectedEltInit = C.getEmitInto ();
2850
+
2851
+ std::optional<CollectValueInitialization> collection;
2852
+
2853
+ // If we have an initialization to emit into, or if we'd need to emit
2854
+ // a tuple that contains pack expansions, make a tuple initialization
2855
+ // of it plus some black holes.
2856
+ if (projectedEltInit || tupleType->containsPackExpansionType ()) {
2857
+ TupleInitialization tupleInit (tupleType);
2858
+
2859
+ auto projectedIndex = E->getFieldNumber ();
2860
+ auto numElts = tupleType->getNumElements ();
2861
+ assert (projectedIndex < numElts);
2862
+
2863
+ tupleInit.SubInitializations .reserve (numElts);
2864
+ for (auto i : range (numElts)) {
2865
+ // Create a black-hole initialization for everything except the
2866
+ // projected index.
2867
+ if (i != projectedIndex) {
2868
+ tupleInit.SubInitializations .emplace_back (new BlackHoleInitialization ());
2869
+
2870
+ // If we have an initialization for the projected initialization,
2871
+ // put it in the right place.
2872
+ } else if (projectedEltInit) {
2873
+ tupleInit.SubInitializations .emplace_back (projectedEltInit,
2874
+ PointerIsNotOwned);
2875
+
2876
+ // Otherwise, create the collection initialization and put it in the
2877
+ // right place.
2878
+ } else {
2879
+ collection.emplace ();
2880
+ tupleInit.SubInitializations .emplace_back (&*collection,
2881
+ PointerIsNotOwned);
2882
+ }
2883
+ }
2884
+
2885
+ // Emit the expression into the initialization.
2886
+ SGF.emitExprInto (E->getBase (), &tupleInit);
2887
+
2888
+ // If we had an initialization to emit into, we've done so.
2889
+ if (projectedEltInit) {
2890
+ return RValue::forInContext ();
2891
+ }
2892
+
2893
+ // Otherwise, pull out the owned value.
2894
+ return RValue (SGF, E, collection->getValue ());
2895
+ }
2896
+
2831
2897
// If our client is ok with a +0 result, then we can compute our base as +0
2832
2898
// and return its element that way. It would not be ok to reuse the Context's
2833
2899
// address buffer though, since our base value will a different type than the
0 commit comments