Skip to content

Commit 4d5cf77

Browse files
committed
[Sema] TypeWrappers: Synthesize body of a memberwise initializer lazily
Make sure that memberwise initializer body doesn't force other synthesis by emitting it lazily. Resolves: rdar://99884355
1 parent 34fc834 commit 4d5cf77

File tree

5 files changed

+119
-130
lines changed

5 files changed

+119
-130
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3689,22 +3689,6 @@ class SynthesizeTypeWrappedTypeMemberwiseInitializer
36893689
bool isCached() const { return true; }
36903690
};
36913691

3692-
class SynthesizeTypeWrappedTypeMemberwiseInitializerBody
3693-
: public SimpleRequest<SynthesizeTypeWrappedTypeMemberwiseInitializerBody,
3694-
BraceStmt *(ConstructorDecl *),
3695-
RequestFlags::Cached> {
3696-
public:
3697-
using SimpleRequest::SimpleRequest;
3698-
3699-
private:
3700-
friend SimpleRequest;
3701-
3702-
BraceStmt *evaluate(Evaluator &evaluator, ConstructorDecl *) const;
3703-
3704-
public:
3705-
bool isCached() const { return true; }
3706-
};
3707-
37083692
class SynthesizeLocalVariableForTypeWrapperStorage
37093693
: public SimpleRequest<SynthesizeLocalVariableForTypeWrapperStorage,
37103694
VarDecl *(ConstructorDecl *), RequestFlags::Cached> {

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,9 +431,6 @@ SWIFT_REQUEST(TypeChecker, IsPropertyAccessedViaTypeWrapper,
431431
SWIFT_REQUEST(TypeChecker, SynthesizeTypeWrappedTypeMemberwiseInitializer,
432432
ConstructorDecl *(NominalTypeDecl *),
433433
Cached, NoLocationInfo)
434-
SWIFT_REQUEST(TypeChecker, SynthesizeTypeWrappedTypeMemberwiseInitializerBody,
435-
BraceStmt *(ConstructorDecl *),
436-
Cached, NoLocationInfo)
437434
SWIFT_REQUEST(TypeChecker, SynthesizeLocalVariableForTypeWrapperStorage,
438435
VarDecl *(ConstructorDecl *),
439436
Cached, NoLocationInfo)

lib/Sema/CodeSynthesis.cpp

Lines changed: 108 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,113 @@ void swift::addNonIsolatedToSynthesized(
15741574
value->getAttrs().add(new (ctx) NonisolatedAttr(/*isImplicit=*/true));
15751575
}
15761576

1577+
static std::pair<BraceStmt *, /*isTypeChecked=*/bool>
1578+
synthesizeTypeWrappedTypeMemberwiseInitializerBody(AbstractFunctionDecl *decl,
1579+
void *) {
1580+
auto *ctor = cast<ConstructorDecl>(decl);
1581+
auto &ctx = ctor->getASTContext();
1582+
auto *parent = ctor->getDeclContext()->getSelfNominalTypeDecl();
1583+
1584+
// self.$storage = .init(storage: $Storage(...))
1585+
auto *storageType = parent->getTypeWrapperStorageDecl();
1586+
assert(storageType);
1587+
1588+
auto *typeWrapperVar = parent->getTypeWrapperProperty();
1589+
assert(typeWrapperVar);
1590+
1591+
auto *storageVarRef = UnresolvedDotExpr::createImplicit(
1592+
ctx,
1593+
new (ctx) DeclRefExpr({ctor->getImplicitSelfDecl()},
1594+
/*Loc=*/DeclNameLoc(), /*Implicit=*/true),
1595+
typeWrapperVar->getName());
1596+
1597+
// Check whether given parameter requires a direct assignment to
1598+
// intialize the property.
1599+
//
1600+
// If `$Storage` doesn't have a member that corresponds
1601+
// to the current parameter it means that this is a property
1602+
// that not managed by the type wrapper which has to be
1603+
// initialized by direct assignment: `self.<name> = <arg>`
1604+
auto useDirectAssignment = [&](ParamDecl *param) {
1605+
// Properties with property wrappers are always managed by the type wrapper
1606+
if (param->hasAttachedPropertyWrapper())
1607+
return false;
1608+
return storageType->lookupDirect(param->getName()).empty();
1609+
};
1610+
1611+
SmallVector<ASTNode, 2> body;
1612+
1613+
SmallVector<Argument, 4> initArgs;
1614+
{
1615+
for (auto *param : *ctor->getParameters()) {
1616+
VarDecl *arg = param;
1617+
1618+
if (useDirectAssignment(param)) {
1619+
auto *propRef = UnresolvedDotExpr::createImplicit(
1620+
ctx,
1621+
new (ctx) DeclRefExpr({ctor->getImplicitSelfDecl()},
1622+
/*Loc=*/DeclNameLoc(), /*Implicit=*/true),
1623+
arg->getName());
1624+
1625+
body.push_back(new (ctx) AssignExpr(
1626+
propRef, /*EqualLoc=*/SourceLoc(),
1627+
new (ctx) DeclRefExpr({arg}, /*DeclNameLoc=*/DeclNameLoc(),
1628+
/*Implicit=*/true),
1629+
/*Implicit=*/true));
1630+
continue;
1631+
}
1632+
1633+
// type wrappers wrap only backing storage of a wrapped
1634+
// property, so in this case we need to pass `_<name>` to
1635+
// `$Storage` constructor.
1636+
if (param->hasAttachedPropertyWrapper()) {
1637+
arg = param->getPropertyWrapperBackingProperty();
1638+
(void)param->getPropertyWrapperBackingPropertyType();
1639+
}
1640+
1641+
initArgs.push_back({/*labelLoc=*/SourceLoc(), arg->getName(),
1642+
new (ctx) DeclRefExpr(arg, /*Loc=*/DeclNameLoc(),
1643+
/*Implicit=*/true)});
1644+
}
1645+
}
1646+
1647+
auto *storageInit = CallExpr::createImplicit(
1648+
ctx,
1649+
TypeExpr::createImplicitForDecl(
1650+
/*Loc=*/DeclNameLoc(), storageType, ctor,
1651+
ctor->mapTypeIntoContext(storageType->getInterfaceType())),
1652+
ArgumentList::createImplicit(ctx, initArgs));
1653+
1654+
auto *initRef = new (ctx) UnresolvedMemberExpr(
1655+
/*dotLoc=*/SourceLoc(), /*declNameLoc=*/DeclNameLoc(),
1656+
DeclNameRef::createConstructor(), /*implicit=*/true);
1657+
{ initRef->setFunctionRefKind(FunctionRefKind::DoubleApply); }
1658+
1659+
auto *selfTypeRef = TypeExpr::createImplicitForDecl(
1660+
DeclNameLoc(), parent, parent->getDeclContext(),
1661+
ctor->mapTypeIntoContext(parent->getInterfaceType()));
1662+
1663+
auto *selfRef = new (ctx)
1664+
DotSelfExpr(selfTypeRef, /*dot=*/SourceLoc(), /*self=*/SourceLoc());
1665+
selfRef->setImplicit();
1666+
1667+
// .init($Storage(for:storage:))
1668+
Expr *typeWrapperInit = CallExpr::createImplicit(
1669+
ctx, initRef,
1670+
ArgumentList::createImplicit(
1671+
ctx,
1672+
{Argument(/*labelLoc=*/SourceLoc(), ctx.Id_for, selfRef),
1673+
Argument(/*labelLoc=*/SourceLoc(), ctx.Id_storage, storageInit)}));
1674+
1675+
body.push_back(new (ctx) AssignExpr(storageVarRef, /*EqualLoc=*/SourceLoc(),
1676+
typeWrapperInit,
1677+
/*Implicit=*/true));
1678+
1679+
return {BraceStmt::create(ctx, /*lbloc=*/ctor->getLoc(), body,
1680+
/*rbloc=*/ctor->getLoc(), /*implicit=*/true),
1681+
/*isTypeChecked=*/false};
1682+
}
1683+
15771684
ConstructorDecl *SynthesizeTypeWrappedTypeMemberwiseInitializer::evaluate(
15781685
Evaluator &evaluator, NominalTypeDecl *wrappedType) const {
15791686
if (!wrappedType->hasTypeWrapper())
@@ -1585,13 +1692,7 @@ ConstructorDecl *SynthesizeTypeWrappedTypeMemberwiseInitializer::evaluate(
15851692
wrappedType, ImplicitConstructorKind::TypeWrapper, ctx);
15861693
wrappedType->addMember(ctor);
15871694

1588-
auto *body = evaluateOrDefault(
1589-
evaluator, SynthesizeTypeWrappedTypeMemberwiseInitializerBody{ctor},
1590-
nullptr);
1591-
if (!body)
1592-
return nullptr;
1593-
1594-
ctor->setBody(body, AbstractFunctionDecl::BodyKind::Parsed);
1695+
ctor->setBodySynthesizer(synthesizeTypeWrappedTypeMemberwiseInitializerBody);
15951696
return ctor;
15961697
}
15971698

lib/Sema/TypeCheckTypeWrapper.cpp

Lines changed: 0 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -431,110 +431,6 @@ bool IsPropertyAccessedViaTypeWrapper::evaluate(Evaluator &evaluator,
431431
return true;
432432
}
433433

434-
BraceStmt *SynthesizeTypeWrappedTypeMemberwiseInitializerBody::evaluate(
435-
Evaluator &evaluator, ConstructorDecl *ctor) const {
436-
auto &ctx = ctor->getASTContext();
437-
auto *parent = ctor->getDeclContext()->getSelfNominalTypeDecl();
438-
439-
// self.$storage = .init(storage: $Storage(...))
440-
auto *storageType = parent->getTypeWrapperStorageDecl();
441-
assert(storageType);
442-
443-
auto *typeWrapperVar = parent->getTypeWrapperProperty();
444-
assert(typeWrapperVar);
445-
446-
auto *storageVarRef = UnresolvedDotExpr::createImplicit(
447-
ctx,
448-
new (ctx) DeclRefExpr({ctor->getImplicitSelfDecl()},
449-
/*Loc=*/DeclNameLoc(), /*Implicit=*/true),
450-
typeWrapperVar->getName());
451-
452-
// Check whether given parameter requires a direct assignment to
453-
// intialize the property.
454-
//
455-
// If `$Storage` doesn't have a member that corresponds
456-
// to the current parameter it means that this is a property
457-
// that not managed by the type wrapper which has to be
458-
// initialized by direct assignment: `self.<name> = <arg>`
459-
auto useDirectAssignment = [&](ParamDecl *param) {
460-
// Properties with property wrappers are always managed by the type wrapper
461-
if (param->hasAttachedPropertyWrapper())
462-
return false;
463-
return storageType->lookupDirect(param->getName()).empty();
464-
};
465-
466-
SmallVector<ASTNode, 2> body;
467-
468-
SmallVector<Argument, 4> initArgs;
469-
{
470-
for (auto *param : *ctor->getParameters()) {
471-
VarDecl *arg = param;
472-
473-
if (useDirectAssignment(param)) {
474-
auto *propRef = UnresolvedDotExpr::createImplicit(
475-
ctx,
476-
new (ctx) DeclRefExpr({ctor->getImplicitSelfDecl()},
477-
/*Loc=*/DeclNameLoc(), /*Implicit=*/true),
478-
arg->getName());
479-
480-
body.push_back(new (ctx) AssignExpr(
481-
propRef, /*EqualLoc=*/SourceLoc(),
482-
new (ctx) DeclRefExpr({arg}, /*DeclNameLoc=*/DeclNameLoc(),
483-
/*Implicit=*/true),
484-
/*Implicit=*/true));
485-
continue;
486-
}
487-
488-
// type wrappers wrap only backing storage of a wrapped
489-
// property, so in this case we need to pass `_<name>` to
490-
// `$Storage` constructor.
491-
if (param->hasAttachedPropertyWrapper()) {
492-
arg = param->getPropertyWrapperBackingProperty();
493-
(void)param->getPropertyWrapperBackingPropertyType();
494-
}
495-
496-
initArgs.push_back({/*labelLoc=*/SourceLoc(), arg->getName(),
497-
new (ctx) DeclRefExpr(arg, /*Loc=*/DeclNameLoc(),
498-
/*Implicit=*/true)});
499-
}
500-
}
501-
502-
auto *storageInit = CallExpr::createImplicit(
503-
ctx,
504-
TypeExpr::createImplicitForDecl(
505-
/*Loc=*/DeclNameLoc(), storageType, ctor,
506-
ctor->mapTypeIntoContext(storageType->getInterfaceType())),
507-
ArgumentList::createImplicit(ctx, initArgs));
508-
509-
auto *initRef = new (ctx) UnresolvedMemberExpr(
510-
/*dotLoc=*/SourceLoc(), /*declNameLoc=*/DeclNameLoc(),
511-
DeclNameRef::createConstructor(), /*implicit=*/true);
512-
{ initRef->setFunctionRefKind(FunctionRefKind::DoubleApply); }
513-
514-
auto *selfTypeRef = TypeExpr::createImplicitForDecl(
515-
DeclNameLoc(), parent, parent->getDeclContext(),
516-
ctor->mapTypeIntoContext(parent->getInterfaceType()));
517-
518-
auto *selfRef = new (ctx)
519-
DotSelfExpr(selfTypeRef, /*dot=*/SourceLoc(), /*self=*/SourceLoc());
520-
selfRef->setImplicit();
521-
522-
// .init($Storage(for:storage:))
523-
Expr *typeWrapperInit = CallExpr::createImplicit(
524-
ctx, initRef,
525-
ArgumentList::createImplicit(
526-
ctx,
527-
{Argument(/*labelLoc=*/SourceLoc(), ctx.Id_for, selfRef),
528-
Argument(/*labelLoc=*/SourceLoc(), ctx.Id_storage, storageInit)}));
529-
530-
body.push_back(new (ctx) AssignExpr(storageVarRef, /*EqualLoc=*/SourceLoc(),
531-
typeWrapperInit,
532-
/*Implicit=*/true));
533-
534-
return BraceStmt::create(ctx, /*lbloc=*/ctor->getLoc(), body,
535-
/*rbloc=*/ctor->getLoc(), /*implicit=*/true);
536-
}
537-
538434
VarDecl *SynthesizeLocalVariableForTypeWrapperStorage::evaluate(
539435
Evaluator &evaluator, ConstructorDecl *ctor) const {
540436
auto &ctx = ctor->getASTContext();

test/type/type_wrapper.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,5 +595,16 @@ func testWrappedSelfInReferenceOnlySubscript() {
595595
get { fatalError() }
596596
}
597597
}
598+
}
599+
600+
// rdar://99884355 - Missing argument for parameter 'name'
601+
do {
602+
struct Use {
603+
var product = Product(name: "<no name>")
604+
}
598605

606+
@NoopWrapper
607+
struct Product {
608+
var name: String
609+
}
599610
}

0 commit comments

Comments
 (0)