@@ -325,20 +325,40 @@ ManagedValue
325
325
SILGenFunction::emitOptionalSome (SILLocation loc, SILType optTy,
326
326
ValueProducerRef produceValue,
327
327
SGFContext C) {
328
- // If the conversion is a bridging conversion from an optional type,
329
- // do a bridging conversion from the non-optional type instead.
330
- // TODO: should this be a general thing for all conversions?
328
+ // If we're emitting into a conversion, try to peephole the
329
+ // injection into it.
331
330
if (auto optInit = C.getAsConversion ()) {
332
331
const auto &optConversion = optInit->getConversion ();
333
- if (optConversion.isBridging ()) {
334
- auto sourceValueType =
335
- optConversion.getBridgingSourceType ().getOptionalObjectType ();
336
- assert (sourceValueType);
337
- if (auto valueConversion =
338
- optConversion.adjustForInitialOptionalConversions (sourceValueType)){
339
- return optInit->emitWithAdjustedConversion (*this , loc, *valueConversion,
340
- produceValue);
341
- }
332
+
333
+ auto adjustment = optConversion.adjustForInitialOptionalInjection ();
334
+
335
+ // If the adjustment gives us a conversion that produces an optional
336
+ // value, that completely takes over emission. This generally happens
337
+ // only because of bridging.
338
+ if (adjustment.isInjection ()) {
339
+ return optInit->emitWithAdjustedConversion (*this , loc,
340
+ adjustment.getInjectionConversion (),
341
+ produceValue);
342
+
343
+ // If the adjustment gives us a conversion that produces a non-optional
344
+ // value, we need to produce the value under that conversion and then
345
+ // inject that into an optional. We can do that by recursing. This
346
+ // will terminate because the recursive call to emitOptionalSome gets
347
+ // passed a strictly "smaller" context: the parent context of the
348
+ // converting context we were passed.
349
+ } else if (adjustment.isValue ()) {
350
+ auto produceConvertedValue = [&](SILGenFunction &SGF,
351
+ SILLocation loc,
352
+ SGFContext C) {
353
+ return SGF.emitConvertedRValue (loc, adjustment.getValueConversion (),
354
+ C, produceValue);
355
+ };
356
+ auto result = emitOptionalSome (loc, optConversion.getLoweredResultType (),
357
+ produceConvertedValue,
358
+ optInit->getFinalContext ());
359
+ optInit->initWithConvertedValue (*this , loc, result);
360
+ optInit->finishInitialization (*this );
361
+ return ManagedValue::forInContext ();
342
362
}
343
363
}
344
364
@@ -1141,20 +1161,6 @@ void ConvertingInitialization::
1141
1161
});
1142
1162
}
1143
1163
1144
- namespace {
1145
- struct CombinedConversions {
1146
- std::optional<Conversion> first;
1147
- std::optional<Conversion> second;
1148
-
1149
- explicit CombinedConversions () {}
1150
- explicit CombinedConversions (const Conversion &first)
1151
- : first(first) {}
1152
- explicit CombinedConversions (const Conversion &first,
1153
- const Conversion &second)
1154
- : first(first), second(second) {}
1155
- };
1156
- }
1157
-
1158
1164
static std::optional<CombinedConversions>
1159
1165
combineConversions (SILGenFunction &SGF, const Conversion &outer,
1160
1166
const Conversion &inner);
@@ -1258,6 +1264,7 @@ ManagedValue Conversion::emit(SILGenFunction &SGF, SILLocation loc,
1258
1264
ManagedValue value, SGFContext C) const {
1259
1265
switch (getKind ()) {
1260
1266
case AnyErasure:
1267
+ case BridgingSubtype:
1261
1268
case Subtype:
1262
1269
return SGF.emitTransformedValue (loc, value, getBridgingSourceType (),
1263
1270
getBridgingResultType (), C);
@@ -1312,6 +1319,48 @@ ManagedValue Conversion::emit(SILGenFunction &SGF, SILLocation loc,
1312
1319
llvm_unreachable (" bad kind" );
1313
1320
}
1314
1321
1322
+ OptionalInjectionConversion
1323
+ Conversion::adjustForInitialOptionalInjection () const {
1324
+ switch (getKind ()) {
1325
+ case Reabstract:
1326
+ return OptionalInjectionConversion::forValue (
1327
+ getReabstract (
1328
+ getReabstractionInputOrigType ().getOptionalObjectType (),
1329
+ getReabstractionInputSubstType ().getOptionalObjectType (),
1330
+ getReabstractionInputLoweredType ().getOptionalObjectType (),
1331
+ getReabstractionOutputOrigType ().getOptionalObjectType (),
1332
+ getReabstractionOutputSubstType ().getOptionalObjectType (),
1333
+ getReabstractionOutputLoweredType ().getOptionalObjectType ())
1334
+ );
1335
+
1336
+ case Subtype:
1337
+ return OptionalInjectionConversion::forValue (
1338
+ getSubtype (
1339
+ getBridgingSourceType ().getOptionalObjectType (),
1340
+ getBridgingResultType ().getOptionalObjectType (),
1341
+ getBridgingLoweredResultType ().getOptionalObjectType ())
1342
+ );
1343
+
1344
+ // TODO: can these actually happen?
1345
+ case ForceOptional:
1346
+ case ForceAndBridgeToObjC:
1347
+ case BridgingSubtype:
1348
+ return OptionalInjectionConversion ();
1349
+
1350
+ case AnyErasure:
1351
+ case BridgeToObjC:
1352
+ case BridgeFromObjC:
1353
+ case BridgeResultFromObjC:
1354
+ return OptionalInjectionConversion::forInjection (
1355
+ getBridging (getKind (), getBridgingSourceType ().getOptionalObjectType (),
1356
+ getBridgingResultType (),
1357
+ getBridgingLoweredResultType (),
1358
+ isBridgingExplicit ())
1359
+ );
1360
+ }
1361
+ llvm_unreachable (" bad kind" );
1362
+ }
1363
+
1315
1364
std::optional<Conversion>
1316
1365
Conversion::adjustForInitialOptionalConversions (CanType newSourceType) const {
1317
1366
switch (getKind ()) {
@@ -1323,6 +1372,7 @@ Conversion::adjustForInitialOptionalConversions(CanType newSourceType) const {
1323
1372
case ForceAndBridgeToObjC:
1324
1373
return std::nullopt;
1325
1374
1375
+ case BridgingSubtype:
1326
1376
case Subtype:
1327
1377
case AnyErasure:
1328
1378
case BridgeToObjC:
@@ -1344,6 +1394,7 @@ std::optional<Conversion> Conversion::adjustForInitialForceValue() const {
1344
1394
case BridgeResultFromObjC:
1345
1395
case ForceOptional:
1346
1396
case ForceAndBridgeToObjC:
1397
+ case BridgingSubtype:
1347
1398
case Subtype:
1348
1399
return std::nullopt;
1349
1400
@@ -1397,6 +1448,8 @@ void Conversion::print(llvm::raw_ostream &out) const {
1397
1448
return printReabstraction (*this , out, " Reabstract" );
1398
1449
case AnyErasure:
1399
1450
return printBridging (*this , out, " AnyErasure" );
1451
+ case BridgingSubtype:
1452
+ return printBridging (*this , out, " BridgingSubtype" );
1400
1453
case Subtype:
1401
1454
return printBridging (*this , out, " Subtype" );
1402
1455
case ForceOptional:
@@ -1749,7 +1802,8 @@ combineBridging(SILGenFunction &SGF,
1749
1802
sourceType, resultType, loweredResultTy));
1750
1803
} else {
1751
1804
return applyPeephole (
1752
- Conversion::getSubtype (sourceType, resultType, loweredResultTy));
1805
+ Conversion::getBridging (Conversion::BridgingSubtype,
1806
+ sourceType, resultType, loweredResultTy));
1753
1807
}
1754
1808
}
1755
1809
@@ -1777,7 +1831,8 @@ combineBridging(SILGenFunction &SGF,
1777
1831
// Look for a subtype relationship between the source and destination.
1778
1832
if (areRelatedTypesForBridgingPeephole (sourceType, resultType)) {
1779
1833
return applyPeephole (
1780
- Conversion::getSubtype (sourceType, resultType, loweredResultTy));
1834
+ Conversion::getBridging (Conversion::BridgingSubtype,
1835
+ sourceType, resultType, loweredResultTy));
1781
1836
}
1782
1837
1783
1838
// If the inner conversion is a result conversion that removes
@@ -1792,7 +1847,8 @@ combineBridging(SILGenFunction &SGF,
1792
1847
sourceType = sourceValueType;
1793
1848
loweredSourceTy = loweredSourceTy.getOptionalObjectType ();
1794
1849
return applyPeephole (
1795
- Conversion::getSubtype (sourceValueType, resultType, loweredResultTy));
1850
+ Conversion::getBridging (Conversion::BridgingSubtype,
1851
+ sourceValueType, resultType, loweredResultTy));
1796
1852
}
1797
1853
}
1798
1854
}
@@ -1824,6 +1880,7 @@ combineConversions(SILGenFunction &SGF, const Conversion &outer,
1824
1880
return std::nullopt;
1825
1881
1826
1882
case Conversion::AnyErasure:
1883
+ case Conversion::BridgingSubtype:
1827
1884
case Conversion::BridgeFromObjC:
1828
1885
case Conversion::BridgeResultFromObjC:
1829
1886
// TODO: maybe peephole bridging through a Swift type?
0 commit comments