@@ -320,20 +320,40 @@ ManagedValue
320
320
SILGenFunction::emitOptionalSome (SILLocation loc, SILType optTy,
321
321
ValueProducerRef produceValue,
322
322
SGFContext C) {
323
- // If the conversion is a bridging conversion from an optional type,
324
- // do a bridging conversion from the non-optional type instead.
325
- // TODO: should this be a general thing for all conversions?
323
+ // If we're emitting into a conversion, try to peephole the
324
+ // injection into it.
326
325
if (auto optInit = C.getAsConversion ()) {
327
326
const auto &optConversion = optInit->getConversion ();
328
- if (optConversion.isBridging ()) {
329
- auto sourceValueType =
330
- optConversion.getBridgingSourceType ().getOptionalObjectType ();
331
- assert (sourceValueType);
332
- if (auto valueConversion =
333
- optConversion.adjustForInitialOptionalConversions (sourceValueType)){
334
- return optInit->emitWithAdjustedConversion (*this , loc, *valueConversion,
335
- produceValue);
336
- }
327
+
328
+ auto adjustment = optConversion.adjustForInitialOptionalInjection ();
329
+
330
+ // If the adjustment gives us a conversion that produces an optional
331
+ // value, that completely takes over emission. This generally happens
332
+ // only because of bridging.
333
+ if (adjustment.isInjection ()) {
334
+ return optInit->emitWithAdjustedConversion (*this , loc,
335
+ adjustment.getInjectionConversion (),
336
+ produceValue);
337
+
338
+ // If the adjustment gives us a conversion that produces a non-optional
339
+ // value, we need to produce the value under that conversion and then
340
+ // inject that into an optional. We can do that by recursing. This
341
+ // will terminate because the recursive call to emitOptionalSome gets
342
+ // passed a strictly "smaller" context: the parent context of the
343
+ // converting context we were passed.
344
+ } else if (adjustment.isValue ()) {
345
+ auto produceConvertedValue = [&](SILGenFunction &SGF,
346
+ SILLocation loc,
347
+ SGFContext C) {
348
+ return SGF.emitConvertedRValue (loc, adjustment.getValueConversion (),
349
+ C, produceValue);
350
+ };
351
+ auto result = emitOptionalSome (loc, optConversion.getLoweredResultType (),
352
+ produceConvertedValue,
353
+ optInit->getFinalContext ());
354
+ optInit->initWithConvertedValue (*this , loc, result);
355
+ optInit->finishInitialization (*this );
356
+ return ManagedValue::forInContext ();
337
357
}
338
358
}
339
359
@@ -1133,20 +1153,6 @@ void ConvertingInitialization::
1133
1153
});
1134
1154
}
1135
1155
1136
- namespace {
1137
- struct CombinedConversions {
1138
- std::optional<Conversion> first;
1139
- std::optional<Conversion> second;
1140
-
1141
- explicit CombinedConversions () {}
1142
- explicit CombinedConversions (const Conversion &first)
1143
- : first(first) {}
1144
- explicit CombinedConversions (const Conversion &first,
1145
- const Conversion &second)
1146
- : first(first), second(second) {}
1147
- };
1148
- }
1149
-
1150
1156
static std::optional<CombinedConversions>
1151
1157
combineConversions (SILGenFunction &SGF, const Conversion &outer,
1152
1158
const Conversion &inner);
@@ -1250,6 +1256,7 @@ ManagedValue Conversion::emit(SILGenFunction &SGF, SILLocation loc,
1250
1256
ManagedValue value, SGFContext C) const {
1251
1257
switch (getKind ()) {
1252
1258
case AnyErasure:
1259
+ case BridgingSubtype:
1253
1260
case Subtype:
1254
1261
return SGF.emitTransformedValue (loc, value, getBridgingSourceType (),
1255
1262
getBridgingResultType (), C);
@@ -1304,6 +1311,48 @@ ManagedValue Conversion::emit(SILGenFunction &SGF, SILLocation loc,
1304
1311
llvm_unreachable (" bad kind" );
1305
1312
}
1306
1313
1314
+ OptionalInjectionConversion
1315
+ Conversion::adjustForInitialOptionalInjection () const {
1316
+ switch (getKind ()) {
1317
+ case Reabstract:
1318
+ return OptionalInjectionConversion::forValue (
1319
+ getReabstract (
1320
+ getReabstractionInputOrigType ().getOptionalObjectType (),
1321
+ getReabstractionInputSubstType ().getOptionalObjectType (),
1322
+ getReabstractionInputLoweredType ().getOptionalObjectType (),
1323
+ getReabstractionOutputOrigType ().getOptionalObjectType (),
1324
+ getReabstractionOutputSubstType ().getOptionalObjectType (),
1325
+ getReabstractionOutputLoweredType ().getOptionalObjectType ())
1326
+ );
1327
+
1328
+ case Subtype:
1329
+ return OptionalInjectionConversion::forValue (
1330
+ getSubtype (
1331
+ getBridgingSourceType ().getOptionalObjectType (),
1332
+ getBridgingResultType ().getOptionalObjectType (),
1333
+ getBridgingLoweredResultType ().getOptionalObjectType ())
1334
+ );
1335
+
1336
+ // TODO: can these actually happen?
1337
+ case ForceOptional:
1338
+ case ForceAndBridgeToObjC:
1339
+ case BridgingSubtype:
1340
+ return OptionalInjectionConversion ();
1341
+
1342
+ case AnyErasure:
1343
+ case BridgeToObjC:
1344
+ case BridgeFromObjC:
1345
+ case BridgeResultFromObjC:
1346
+ return OptionalInjectionConversion::forInjection (
1347
+ getBridging (getKind (), getBridgingSourceType ().getOptionalObjectType (),
1348
+ getBridgingResultType (),
1349
+ getBridgingLoweredResultType (),
1350
+ isBridgingExplicit ())
1351
+ );
1352
+ }
1353
+ llvm_unreachable (" bad kind" );
1354
+ }
1355
+
1307
1356
std::optional<Conversion>
1308
1357
Conversion::adjustForInitialOptionalConversions (CanType newSourceType) const {
1309
1358
switch (getKind ()) {
@@ -1315,6 +1364,7 @@ Conversion::adjustForInitialOptionalConversions(CanType newSourceType) const {
1315
1364
case ForceAndBridgeToObjC:
1316
1365
return std::nullopt;
1317
1366
1367
+ case BridgingSubtype:
1318
1368
case Subtype:
1319
1369
case AnyErasure:
1320
1370
case BridgeToObjC:
@@ -1336,6 +1386,7 @@ std::optional<Conversion> Conversion::adjustForInitialForceValue() const {
1336
1386
case BridgeResultFromObjC:
1337
1387
case ForceOptional:
1338
1388
case ForceAndBridgeToObjC:
1389
+ case BridgingSubtype:
1339
1390
case Subtype:
1340
1391
return std::nullopt;
1341
1392
@@ -1389,6 +1440,8 @@ void Conversion::print(llvm::raw_ostream &out) const {
1389
1440
return printReabstraction (*this , out, " Reabstract" );
1390
1441
case AnyErasure:
1391
1442
return printBridging (*this , out, " AnyErasure" );
1443
+ case BridgingSubtype:
1444
+ return printBridging (*this , out, " BridgingSubtype" );
1392
1445
case Subtype:
1393
1446
return printBridging (*this , out, " Subtype" );
1394
1447
case ForceOptional:
@@ -1741,7 +1794,8 @@ combineBridging(SILGenFunction &SGF,
1741
1794
sourceType, resultType, loweredResultTy));
1742
1795
} else {
1743
1796
return applyPeephole (
1744
- Conversion::getSubtype (sourceType, resultType, loweredResultTy));
1797
+ Conversion::getBridging (Conversion::BridgingSubtype,
1798
+ sourceType, resultType, loweredResultTy));
1745
1799
}
1746
1800
}
1747
1801
@@ -1769,7 +1823,8 @@ combineBridging(SILGenFunction &SGF,
1769
1823
// Look for a subtype relationship between the source and destination.
1770
1824
if (areRelatedTypesForBridgingPeephole (sourceType, resultType)) {
1771
1825
return applyPeephole (
1772
- Conversion::getSubtype (sourceType, resultType, loweredResultTy));
1826
+ Conversion::getBridging (Conversion::BridgingSubtype,
1827
+ sourceType, resultType, loweredResultTy));
1773
1828
}
1774
1829
1775
1830
// If the inner conversion is a result conversion that removes
@@ -1784,7 +1839,8 @@ combineBridging(SILGenFunction &SGF,
1784
1839
sourceType = sourceValueType;
1785
1840
loweredSourceTy = loweredSourceTy.getOptionalObjectType ();
1786
1841
return applyPeephole (
1787
- Conversion::getSubtype (sourceValueType, resultType, loweredResultTy));
1842
+ Conversion::getBridging (Conversion::BridgingSubtype,
1843
+ sourceValueType, resultType, loweredResultTy));
1788
1844
}
1789
1845
}
1790
1846
}
@@ -1816,6 +1872,7 @@ combineConversions(SILGenFunction &SGF, const Conversion &outer,
1816
1872
return std::nullopt;
1817
1873
1818
1874
case Conversion::AnyErasure:
1875
+ case Conversion::BridgingSubtype:
1819
1876
case Conversion::BridgeFromObjC:
1820
1877
case Conversion::BridgeResultFromObjC:
1821
1878
// TODO: maybe peephole bridging through a Swift type?
0 commit comments