@@ -1407,6 +1407,21 @@ namespace {
1407
1407
return false ;
1408
1408
}
1409
1409
1410
+ bool canRewriteSetAsTypeWrapperInit (SILGenFunction &SGF) const {
1411
+ auto *VD = dyn_cast<VarDecl>(Storage);
1412
+ if (!(VD && VD->isAccessedViaTypeWrapper ()))
1413
+ return false ;
1414
+
1415
+ auto *fnDecl = SGF.FunctionDC ->getAsDecl ();
1416
+ // Type wrapper transform applies only to user-defined
1417
+ // designated initializers.
1418
+ if (auto *ctor = dyn_cast_or_null<ConstructorDecl>(fnDecl)) {
1419
+ return !ctor->isImplicit () && ctor->isDesignatedInit ();
1420
+ }
1421
+
1422
+ return false ;
1423
+ }
1424
+
1410
1425
void emitAssignWithSetter (SILGenFunction &SGF, SILLocation loc,
1411
1426
LValue &&dest, ArgumentSource &&value) {
1412
1427
assert (getAccessorDecl ()->isSetter ());
@@ -1470,6 +1485,154 @@ namespace {
1470
1485
assert (!ActorIso && " no support for cross-actor set operations" );
1471
1486
SILDeclRef setter = Accessor;
1472
1487
1488
+ auto getSetterFRef = [&]() -> SILValue {
1489
+ auto setterInfo =
1490
+ SGF.getConstantInfo (SGF.getTypeExpansionContext (), setter);
1491
+ if (setter.hasDecl () && setter.getDecl ()->shouldUseObjCDispatch ()) {
1492
+ // Emit a thunk we might have to bridge arguments.
1493
+ auto foreignSetterThunk = setter.asForeign (false );
1494
+ return SGF
1495
+ .emitDynamicMethodRef (
1496
+ loc, foreignSetterThunk,
1497
+ SGF.SGM .Types
1498
+ .getConstantInfo (SGF.getTypeExpansionContext (),
1499
+ foreignSetterThunk)
1500
+ .SILFnType )
1501
+ .getValue ();
1502
+ }
1503
+
1504
+ return SGF.emitGlobalFunctionRef (loc, setter, setterInfo);
1505
+ };
1506
+
1507
+ auto getSetterType = [&](SILValue setterFRef) {
1508
+ CanSILFunctionType setterTy =
1509
+ setterFRef->getType ().castTo <SILFunctionType>();
1510
+ return setterTy->substGenericArgs (SGF.SGM .M , Substitutions,
1511
+ SGF.getTypeExpansionContext ());
1512
+ };
1513
+
1514
+ auto emitPartialSetterApply =
1515
+ [&](SILValue setterFRef,
1516
+ const SILFunctionConventions &setterConv) -> ManagedValue {
1517
+ // Emit captures for thI e setter
1518
+ SmallVector<SILValue, 4 > capturedArgs;
1519
+ auto captureInfo = SGF.SGM .Types .getLoweredLocalCaptures (setter);
1520
+ if (!captureInfo.getCaptures ().empty ()) {
1521
+ SmallVector<ManagedValue, 4 > captures;
1522
+ SGF.emitCaptures (loc, setter, CaptureEmission::AssignByWrapper,
1523
+ captures);
1524
+
1525
+ for (auto capture : captures)
1526
+ capturedArgs.push_back (capture.forward (SGF));
1527
+ } else {
1528
+ assert (base);
1529
+
1530
+ SILValue capturedBase;
1531
+ unsigned argIdx = setterConv.getNumSILArguments () - 1 ;
1532
+
1533
+ if (setterConv.getSILArgumentConvention (argIdx).isInoutConvention ()) {
1534
+ capturedBase = base.getValue ();
1535
+ } else if (base.getType ().isAddress () &&
1536
+ base.getType ().getObjectType () ==
1537
+ setterConv.getSILArgumentType (
1538
+ argIdx, SGF.getTypeExpansionContext ())) {
1539
+ // If the base is a reference and the setter expects a value, emit a
1540
+ // load. This pattern is emitted for property wrappers with a
1541
+ // nonmutating setter, for example.
1542
+ capturedBase = SGF.B .createTrivialLoadOr (
1543
+ loc, base.getValue (), LoadOwnershipQualifier::Copy);
1544
+ } else {
1545
+ capturedBase = base.copy (SGF, loc).forward (SGF);
1546
+ }
1547
+
1548
+ capturedArgs.push_back (capturedBase);
1549
+ }
1550
+
1551
+ PartialApplyInst *setterPAI = SGF.B .createPartialApply (
1552
+ loc, setterFRef, Substitutions, capturedArgs,
1553
+ ParameterConvention::Direct_Guaranteed);
1554
+ return SGF.emitManagedRValueWithCleanup (setterPAI);
1555
+ };
1556
+
1557
+ auto emitValue =
1558
+ [&](VarDecl *field, Type fieldType, CanSILFunctionType setterTy,
1559
+ const SILFunctionConventions &setterConv) -> ManagedValue {
1560
+ // FIXME: This should use CallEmission instead of doing everything
1561
+ // manually.
1562
+ assert (value.isRValue ());
1563
+ ManagedValue Mval =
1564
+ std::move (value).asKnownRValue (SGF).getAsSingleValue (SGF, loc);
1565
+ auto param = setterTy->getParameters ()[0 ];
1566
+ SILType loweredSubstArgType = Mval.getType ();
1567
+ if (param.isIndirectInOut ()) {
1568
+ loweredSubstArgType = SILType::getPrimitiveAddressType (
1569
+ loweredSubstArgType.getASTType ());
1570
+ }
1571
+ auto loweredSubstParamTy = SILType::getPrimitiveType (
1572
+ param.getArgumentType (SGF.SGM .M , setterTy,
1573
+ SGF.getTypeExpansionContext ()),
1574
+ loweredSubstArgType.getCategory ());
1575
+ // Handle reabstraction differences.
1576
+ if (Mval.getType () != loweredSubstParamTy) {
1577
+ Mval = SGF.emitSubstToOrigValue (
1578
+ loc, Mval, SGF.SGM .Types .getAbstractionPattern (field),
1579
+ fieldType->getCanonicalType ());
1580
+ }
1581
+
1582
+ // If we need the argument in memory, materialize an address.
1583
+ if (setterConv.getSILArgumentConvention (0 ).isIndirectConvention () &&
1584
+ !Mval.getType ().isAddress ()) {
1585
+ Mval = Mval.materialize (SGF, loc);
1586
+ }
1587
+
1588
+ return Mval;
1589
+ };
1590
+
1591
+ if (canRewriteSetAsTypeWrapperInit (SGF)) {
1592
+ auto *ctor = cast<ConstructorDecl>(SGF.FunctionDC ->getAsDecl ());
1593
+ auto *field = cast<VarDecl>(Storage);
1594
+ auto FieldType = field->getValueInterfaceType ();
1595
+ if (!Substitutions.empty ()) {
1596
+ FieldType = FieldType.subst (Substitutions);
1597
+ }
1598
+
1599
+ auto *localVar = ctor->getLocalTypeWrapperStorageVar ();
1600
+
1601
+ // First, we need to find index of the current field in `_storage.
1602
+ auto *tempType = localVar->getInterfaceType ()->castTo <TupleType>();
1603
+ int fieldIdx = tempType->getNamedElementId (field->getName ());
1604
+ assert (fieldIdx >= 0 );
1605
+
1606
+ // Load `_storage.<name>`
1607
+ auto storageBase =
1608
+ SGF.maybeEmitValueOfLocalVarDecl (localVar, AccessKind::Write);
1609
+
1610
+ auto typeData = getLogicalStorageTypeData (
1611
+ SGF.getTypeExpansionContext (), SGF.SGM , getTypeData ().AccessKind ,
1612
+ FieldType->getCanonicalType ());
1613
+
1614
+ TupleElementComponent TEC (fieldIdx, typeData);
1615
+ auto storage = std::move (TEC).project (SGF, loc, storageBase);
1616
+
1617
+ // Partially apply the setter so it could be used by assign_by_wrapper
1618
+
1619
+ auto setterFRef = getSetterFRef ();
1620
+ auto setterTy = getSetterType (setterFRef);
1621
+ SILFunctionConventions setterConv (setterTy, SGF.SGM .M );
1622
+ auto setterFn = emitPartialSetterApply (setterFRef, setterConv);
1623
+
1624
+ // Create the assign_by_wrapper with the initializer and setter.
1625
+
1626
+ auto Mval = emitValue (field, FieldType, setterTy, setterConv);
1627
+
1628
+ // Inject assign_by_wrapper instruction
1629
+
1630
+ SGF.B .createAssignByTypeWrapper (
1631
+ loc, Mval.forward (SGF), storage.forward (SGF), setterFn.getValue (),
1632
+ AssignByWrapperInst::Unknown);
1633
+ return ;
1634
+ }
1635
+
1473
1636
if (canRewriteSetAsPropertyWrapperInit (SGF) &&
1474
1637
!Storage->isStatic () &&
1475
1638
isBackingVarVisible (cast<VarDecl>(Storage),
@@ -1528,95 +1691,14 @@ namespace {
1528
1691
ManagedValue initFn = SGF.emitManagedRValueWithCleanup (initPAI);
1529
1692
1530
1693
// Create the allocating setter function. It captures the base address.
1531
- auto setterInfo =
1532
- SGF.getConstantInfo (SGF.getTypeExpansionContext (), setter);
1533
- SILValue setterFRef;
1534
- if (setter.hasDecl () && setter.getDecl ()->shouldUseObjCDispatch ()) {
1535
- // Emit a thunk we might have to bridge arguments.
1536
- auto foreignSetterThunk = setter.asForeign (false );
1537
- setterFRef =
1538
- SGF.emitDynamicMethodRef (
1539
- loc, foreignSetterThunk,
1540
- SGF.SGM .Types
1541
- .getConstantInfo (SGF.getTypeExpansionContext (), foreignSetterThunk)
1542
- .SILFnType )
1543
- .getValue ();
1544
-
1545
- } else {
1546
- setterFRef = SGF.emitGlobalFunctionRef (loc, setter, setterInfo);
1547
- }
1548
-
1549
- CanSILFunctionType setterTy = setterFRef->getType ().castTo <SILFunctionType>();
1550
- auto substSetterTy = setterTy->substGenericArgs (SGF.SGM .M , Substitutions,
1551
- SGF.getTypeExpansionContext ());
1552
- SILFunctionConventions setterConv (substSetterTy, SGF.SGM .M );
1553
-
1554
- // Emit captures for the setter
1555
- SmallVector<SILValue, 4 > capturedArgs;
1556
- auto captureInfo = SGF.SGM .Types .getLoweredLocalCaptures (setter);
1557
- if (!captureInfo.getCaptures ().empty ()) {
1558
- SmallVector<ManagedValue, 4 > captures;
1559
- SGF.emitCaptures (loc, setter, CaptureEmission::AssignByWrapper, captures);
1560
-
1561
- for (auto capture : captures)
1562
- capturedArgs.push_back (capture.forward (SGF));
1563
- } else {
1564
- assert (base);
1565
-
1566
- SILValue capturedBase;
1567
- unsigned argIdx = setterConv.getNumSILArguments () - 1 ;
1568
-
1569
- if (setterConv.getSILArgumentConvention (argIdx).isInoutConvention ()) {
1570
- capturedBase = base.getValue ();
1571
- } else if (base.getType ().isAddress () &&
1572
- base.getType ().getObjectType () ==
1573
- setterConv.getSILArgumentType (argIdx,
1574
- SGF.getTypeExpansionContext ())) {
1575
- // If the base is a reference and the setter expects a value, emit a
1576
- // load. This pattern is emitted for property wrappers with a
1577
- // nonmutating setter, for example.
1578
- capturedBase = SGF.B .createTrivialLoadOr (
1579
- loc, base.getValue (), LoadOwnershipQualifier::Copy);
1580
- } else {
1581
- capturedBase = base.copy (SGF, loc).forward (SGF);
1582
- }
1694
+ auto setterFRef = getSetterFRef ();
1695
+ auto setterTy = getSetterType (setterFRef);
1696
+ SILFunctionConventions setterConv (setterTy, SGF.SGM .M );
1697
+ auto setterFn = emitPartialSetterApply (setterFRef, setterConv);
1583
1698
1584
- capturedArgs.push_back (capturedBase);
1585
- }
1699
+ // Create the assign_by_wrapper with the initializer and setter.
1586
1700
1587
- PartialApplyInst *setterPAI =
1588
- SGF.B .createPartialApply (loc, setterFRef,
1589
- Substitutions, capturedArgs,
1590
- ParameterConvention::Direct_Guaranteed);
1591
- ManagedValue setterFn = SGF.emitManagedRValueWithCleanup (setterPAI);
1592
-
1593
- // Create the assign_by_wrapper with the allocator and setter.
1594
- // FIXME: This should use CallEmission instead of doing everything manually.
1595
- assert (value.isRValue ());
1596
- ManagedValue Mval = std::move (value).asKnownRValue (SGF).
1597
- getAsSingleValue (SGF, loc);
1598
- auto param = substSetterTy->getParameters ()[0 ];
1599
- SILType loweredSubstArgType = Mval.getType ();
1600
- if (param.isIndirectInOut ()) {
1601
- loweredSubstArgType =
1602
- SILType::getPrimitiveAddressType (loweredSubstArgType.getASTType ());
1603
- }
1604
- auto loweredSubstParamTy = SILType::getPrimitiveType (
1605
- param.getArgumentType (SGF.SGM .M , substSetterTy,
1606
- SGF.getTypeExpansionContext ()),
1607
- loweredSubstArgType.getCategory ());
1608
- // Handle reabstraction differences.
1609
- if (Mval.getType () != loweredSubstParamTy) {
1610
- Mval = SGF.emitSubstToOrigValue (loc, Mval,
1611
- SGF.SGM .Types .getAbstractionPattern (field),
1612
- FieldType->getCanonicalType ());
1613
- }
1614
-
1615
- // If we need the argument in memory, materialize an address.
1616
- if (setterConv.getSILArgumentConvention (0 ).isIndirectConvention () &&
1617
- !Mval.getType ().isAddress ()) {
1618
- Mval = Mval.materialize (SGF, loc);
1619
- }
1701
+ auto Mval = emitValue (field, FieldType, setterTy, setterConv);
1620
1702
1621
1703
SGF.B .createAssignByPropertyWrapper (
1622
1704
loc, Mval.forward (SGF), proj.forward (SGF), initFn.getValue (),
@@ -4717,6 +4799,10 @@ static bool trySetterPeephole(SILGenFunction &SGF, SILLocation loc,
4717
4799
auto &setterComponent = static_cast <GetterSetterComponent&>(component);
4718
4800
if (setterComponent.canRewriteSetAsPropertyWrapperInit (SGF))
4719
4801
return false ;
4802
+
4803
+ if (setterComponent.canRewriteSetAsTypeWrapperInit (SGF))
4804
+ return false ;
4805
+
4720
4806
setterComponent.emitAssignWithSetter (SGF, loc, std::move (dest),
4721
4807
std::move (src));
4722
4808
return true ;;
0 commit comments