Skip to content

Commit a6e4203

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 8b44880 commit a6e4203

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
@@ -1588,6 +1588,113 @@ void swift::addNonIsolatedToSynthesized(
15881588
value->getAttrs().add(new (ctx) NonisolatedAttr(/*isImplicit=*/true));
15891589
}
15901590

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

1602-
auto *body = evaluateOrDefault(
1603-
evaluator, SynthesizeTypeWrappedTypeMemberwiseInitializerBody{ctor},
1604-
nullptr);
1605-
if (!body)
1606-
return nullptr;
1607-
1608-
ctor->setBody(body, AbstractFunctionDecl::BodyKind::Parsed);
1709+
ctor->setBodySynthesizer(synthesizeTypeWrappedTypeMemberwiseInitializerBody);
16091710
return ctor;
16101711
}

lib/Sema/TypeCheckTypeWrapper.cpp

Lines changed: 0 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -424,110 +424,6 @@ bool IsPropertyAccessedViaTypeWrapper::evaluate(Evaluator &evaluator,
424424
return true;
425425
}
426426

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