Skip to content

Commit a15f423

Browse files
committed
[Property Wrappers] Implement implementation-detail property wrappers for
parameters.
1 parent 669a49a commit a15f423

File tree

11 files changed

+87
-42
lines changed

11 files changed

+87
-42
lines changed

include/swift/AST/AnyFunctionRef.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,9 @@ class AnyFunctionRef {
110110
return TheFunction.get<AbstractClosureExpr *>()->getParameters();
111111
}
112112

113-
bool hasPropertyWrapperParameters() const {
113+
bool hasExternalPropertyWrapperParameters() const {
114114
return llvm::any_of(*getParameters(), [](const ParamDecl *param) {
115-
return param->hasAttachedPropertyWrapper();
115+
return param->hasExternalPropertyWrapper();
116116
});
117117
}
118118

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5013,6 +5013,10 @@ class VarDecl : public AbstractStorageDecl {
50135013
/// Whether this var has an implicit property wrapper attribute.
50145014
bool hasImplicitPropertyWrapper() const;
50155015

5016+
/// Whether this var is a parameter with an attached property wrapper
5017+
/// that has an external effect on the function.
5018+
bool hasExternalPropertyWrapper() const;
5019+
50165020
/// Whether all of the attached property wrappers have an init(wrappedValue:)
50175021
/// initializer.
50185022
bool allAttachedPropertyWrappersHaveWrappedValueInit() const;

lib/AST/Decl.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5903,6 +5903,27 @@ bool VarDecl::hasImplicitPropertyWrapper() const {
59035903
return !isImplicit() && getName().hasDollarPrefix() && isClosureParam;
59045904
}
59055905

5906+
bool VarDecl::hasExternalPropertyWrapper() const {
5907+
if (!hasAttachedPropertyWrapper())
5908+
return false;
5909+
5910+
// This decision needs to be made before closures are type checked (and
5911+
// the wrapper types are potentially inferred) so closure parameters with
5912+
// property wrappers are always "external". This is fine, because the
5913+
// type checker will always inject a thunk with the wrapped or projected type
5914+
// around the closure, so the wrapper will never affect the caller's
5915+
// arguments directly anyway.
5916+
if (isa<AbstractClosureExpr>(getDeclContext()))
5917+
return true;
5918+
5919+
// Wrappers with attribute arguments are always implementation-detail.
5920+
if (getAttachedPropertyWrappers().front()->getArg())
5921+
return false;
5922+
5923+
auto wrapperInfo = getAttachedPropertyWrapperTypeInfo(0);
5924+
return wrapperInfo.projectedValueVar && wrapperInfo.hasProjectedValueInit;
5925+
}
5926+
59065927
/// Whether all of the attached property wrappers have an init(wrappedValue:)
59075928
/// initializer.
59085929
bool VarDecl::allAttachedPropertyWrappersHaveWrappedValueInit() const {
@@ -6303,7 +6324,7 @@ Type ParamDecl::getVarargBaseTy(Type VarArgT) {
63036324

63046325
AnyFunctionType::Param ParamDecl::toFunctionParam(Type type) const {
63056326
if (!type) {
6306-
if (hasAttachedPropertyWrapper() && !hasImplicitPropertyWrapper()) {
6327+
if (hasExternalPropertyWrapper()) {
63076328
type = getPropertyWrapperBackingPropertyType();
63086329
} else {
63096330
type = getInterfaceType();

lib/AST/Type.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -967,7 +967,7 @@ ParameterListInfo::ParameterListInfo(
967967
acceptsUnlabeledTrailingClosures.set(i);
968968
}
969969

970-
if (param->hasAttachedPropertyWrapper()) {
970+
if (param->hasExternalPropertyWrapper()) {
971971
propertyWrappers.set(i);
972972
}
973973
}

lib/SILGen/SILGenFunction.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -512,17 +512,29 @@ void SILGenFunction::emitFunction(FuncDecl *fd) {
512512
emitProlog(captureInfo, fd->getParameters(), fd->getImplicitSelfDecl(), fd,
513513
fd->getResultInterfaceType(), fd->hasThrows(), fd->getThrowsLoc());
514514
prepareEpilog(true, fd->hasThrows(), CleanupLocation(fd));
515-
for (auto *param : *fd->getParameters()) {
516-
param->visitAuxiliaryDecls([&](VarDecl *auxiliaryVar) {
517-
visit(auxiliaryVar);
518-
});
519-
}
520515

521516
if (fd->isAsyncHandler() &&
522517
// If F.isAsync() we are emitting the asyncHandler body and not the
523518
// original asyncHandler.
524519
!F.isAsync()) {
525520
emitAsyncHandler(fd);
521+
} else if (llvm::any_of(*fd->getParameters(),
522+
[](ParamDecl *p){ return p->hasAttachedPropertyWrapper(); })) {
523+
// If any parameters have property wrappers, emit the local auxiliary
524+
// variables before emitting the function body.
525+
LexicalScope BraceScope(*this, CleanupLocation(fd));
526+
for (auto *param : *fd->getParameters()) {
527+
param->visitAuxiliaryDecls([&](VarDecl *auxiliaryVar) {
528+
SILLocation WrapperLoc(auxiliaryVar);
529+
WrapperLoc.markAsPrologue();
530+
if (auto *patternBinding = auxiliaryVar->getParentPatternBinding())
531+
visitPatternBindingDecl(patternBinding);
532+
533+
visit(auxiliaryVar);
534+
});
535+
}
536+
537+
emitStmt(fd->getTypecheckedBody());
526538
} else {
527539
emitStmt(fd->getTypecheckedBody());
528540
}

lib/SILGen/SILGenProlog.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,13 +244,13 @@ struct ArgumentInitHelper {
244244
}
245245

246246
void emitParam(ParamDecl *PD) {
247-
if (auto *backingVar = PD->getPropertyWrapperBackingProperty()) {
247+
if (PD->hasExternalPropertyWrapper()) {
248248
auto initInfo = PD->getPropertyWrapperInitializerInfo();
249249
if (initInfo.hasSynthesizedInitializers()) {
250250
SGF.SGM.emitPropertyWrapperBackingInitializer(PD);
251251
}
252252

253-
PD = cast<ParamDecl>(backingVar);
253+
PD = cast<ParamDecl>(PD->getPropertyWrapperBackingProperty());
254254
}
255255

256256
auto type = PD->getType();

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,7 @@ namespace {
689689
Expr *result = forceUnwrapIfExpected(declRefExpr, choice, locator);
690690

691691
if (auto *fnDecl = dyn_cast<AbstractFunctionDecl>(decl)) {
692-
if (AnyFunctionRef(fnDecl).hasPropertyWrapperParameters() &&
692+
if (AnyFunctionRef(fnDecl).hasExternalPropertyWrapperParameters() &&
693693
(declRefExpr->getFunctionRefKind() == FunctionRefKind::Compound ||
694694
declRefExpr->getFunctionRefKind() == FunctionRefKind::Unapplied)) {
695695
auto &appliedWrappers = solution.appliedPropertyWrappers[locator.getAnchor()];
@@ -7932,7 +7932,7 @@ namespace {
79327932
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
79337933
rewriteFunction(closure);
79347934

7935-
if (AnyFunctionRef(closure).hasPropertyWrapperParameters()) {
7935+
if (AnyFunctionRef(closure).hasExternalPropertyWrapperParameters()) {
79367936
return { false, rewriteClosure(closure) };
79377937
}
79387938

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4058,21 +4058,7 @@ ConstraintSystem::applyPropertyWrapperToParameter(
40584058
anchor = apply->getFn();
40594059
}
40604060

4061-
auto supportsProjectedValueInit = [&](ParamDecl *param) -> bool {
4062-
if (!param->hasAttachedPropertyWrapper())
4063-
return false;
4064-
4065-
if (param->hasImplicitPropertyWrapper())
4066-
return true;
4067-
4068-
if (param->getAttachedPropertyWrappers().front()->getArg())
4069-
return false;
4070-
4071-
auto wrapperInfo = param->getAttachedPropertyWrapperTypeInfo(0);
4072-
return wrapperInfo.projectedValueVar && wrapperInfo.hasProjectedValueInit;
4073-
};
4074-
4075-
if (argLabel.hasDollarPrefix() && (!param || !supportsProjectedValueInit(param))) {
4061+
if (argLabel.hasDollarPrefix() && (!param || !param->hasExternalPropertyWrapper())) {
40764062
if (!shouldAttemptFixes())
40774063
return getTypeMatchFailure(locator);
40784064

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3022,6 +3022,9 @@ void TypeChecker::checkParameterList(ParameterList *params,
30223022
}
30233023
}
30243024

3025+
if (param->hasAttachedPropertyWrapper())
3026+
(void) param->getPropertyWrapperInitializerInfo();
3027+
30253028
auto *SF = param->getDeclContext()->getParentSourceFile();
30263029
param->visitAuxiliaryDecls([&](VarDecl *auxiliaryDecl) {
30273030
if (!isa<ParamDecl>(auxiliaryDecl))

lib/Sema/TypeCheckStorage.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2746,7 +2746,8 @@ PropertyWrapperAuxiliaryVariablesRequest::evaluate(Evaluator &evaluator,
27462746
VarDecl *wrappedValueVar = nullptr;
27472747

27482748
// Create the backing storage property.
2749-
if (auto *param = dyn_cast<ParamDecl>(var)) {
2749+
if (var->hasExternalPropertyWrapper()) {
2750+
auto *param = cast<ParamDecl>(var);
27502751
backingVar = ParamDecl::cloneWithoutType(ctx, param);
27512752
backingVar->setName(name);
27522753
} else {
@@ -2855,6 +2856,24 @@ PropertyWrapperInitializerInfoRequest::evaluate(Evaluator &evaluator,
28552856
var->diagnose(diag::opaque_type_var_no_underlying_type);
28562857
}
28572858
}
2859+
} else if (!var->hasExternalPropertyWrapper()) {
2860+
auto *param = cast<ParamDecl>(var);
2861+
auto *backingVar = var->getPropertyWrapperBackingProperty();
2862+
auto *pbd = createPBD(backingVar);
2863+
2864+
auto *paramRef = new (ctx) DeclRefExpr(var, DeclNameLoc(), /*implicit=*/true);
2865+
initializer = buildPropertyWrapperInitCall(
2866+
var, storageType, paramRef, PropertyWrapperInitKind::WrappedValue);
2867+
TypeChecker::typeCheckExpression(initializer, dc);
2868+
2869+
// Check initializer effects.
2870+
auto *initContext = new (ctx) PropertyWrapperInitializer(
2871+
dc, param, PropertyWrapperInitializer::Kind::ProjectedValue);
2872+
2873+
TypeChecker::checkInitializerEffects(initContext, initializer);
2874+
2875+
pbd->setInit(0, initializer);
2876+
pbd->setInitializerChecked(0);
28582877
}
28592878

28602879
// If there is a projection property (projectedValue) in the wrapper,
@@ -2863,8 +2882,7 @@ PropertyWrapperInitializerInfoRequest::evaluate(Evaluator &evaluator,
28632882
if (auto *projection = var->getPropertyWrapperProjectionVar()) {
28642883
createPBD(projection);
28652884

2866-
auto wrapperInfo = var->getAttachedPropertyWrapperTypeInfo(0);
2867-
if (wrapperInfo.hasProjectedValueInit && isa<ParamDecl>(var)) {
2885+
if (var->hasExternalPropertyWrapper()) {
28682886
// Projected-value initialization is currently only supported for parameters.
28692887
auto *param = dyn_cast<ParamDecl>(var);
28702888
auto *placeholder = PropertyWrapperValuePlaceholderExpr::create(

0 commit comments

Comments
 (0)