Skip to content

Commit 5a73b48

Browse files
committed
[Sema] CodeSynthesis: Extract logic to synthesize a parameter for memberwise init
1 parent 8c0f6e1 commit 5a73b48

File tree

1 file changed

+70
-65
lines changed

1 file changed

+70
-65
lines changed

lib/Sema/CodeSynthesis.cpp

Lines changed: 70 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ ArgumentList *swift::buildForwardingArgumentList(ArrayRef<ParamDecl *> params,
128128
}
129129

130130
static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
131-
unsigned paramSize, ASTContext &ctx) {
131+
ASTContext &ctx) {
132132
// First and foremost, if this is a constant don't bother.
133133
if (var->isLet())
134134
return;
@@ -250,6 +250,74 @@ enum class ImplicitConstructorKind {
250250
TypeWrapper,
251251
};
252252

253+
static ParamDecl *createMemberwiseInitParameter(DeclContext *DC,
254+
SourceLoc paramLoc,
255+
VarDecl *var) {
256+
auto &ctx = var->getASTContext();
257+
auto varInterfaceType = var->getValueInterfaceType();
258+
bool isAutoClosure = false;
259+
260+
if (var->getAttrs().hasAttribute<LazyAttr>()) {
261+
// If var is a lazy property, its value is provided for the underlying
262+
// storage. We thus take an optional of the property's type. We only
263+
// need to do this because the implicit initializer is added before all
264+
// the properties are type checked. Perhaps init() synth should be
265+
// moved later.
266+
varInterfaceType = OptionalType::get(varInterfaceType);
267+
} else if (Type backingPropertyType =
268+
var->getPropertyWrapperBackingPropertyType()) {
269+
// For a property that has a wrapper, writing the initializer
270+
// with an '=' implies that the memberwise initializer should also
271+
// accept a value of the original property type. Otherwise, the
272+
// memberwise initializer will be in terms of the backing storage
273+
// type.
274+
if (var->isPropertyMemberwiseInitializedWithWrappedType()) {
275+
varInterfaceType = var->getPropertyWrapperInitValueInterfaceType();
276+
277+
auto initInfo = var->getPropertyWrapperInitializerInfo();
278+
isAutoClosure = initInfo.getWrappedValuePlaceholder()->isAutoClosure();
279+
} else {
280+
varInterfaceType = backingPropertyType;
281+
}
282+
}
283+
284+
Type resultBuilderType = var->getResultBuilderType();
285+
if (resultBuilderType) {
286+
// If the variable's type is structurally a function type, use that
287+
// type. Otherwise, form a non-escaping function type for the function
288+
// parameter.
289+
bool isStructuralFunctionType =
290+
varInterfaceType->lookThroughAllOptionalTypes()->is<AnyFunctionType>();
291+
if (!isStructuralFunctionType) {
292+
auto extInfo = ASTExtInfoBuilder().withNoEscape().build();
293+
varInterfaceType = FunctionType::get({}, varInterfaceType, extInfo);
294+
}
295+
}
296+
297+
// Create the parameter.
298+
auto *arg = new (ctx) ParamDecl(SourceLoc(), paramLoc, var->getName(),
299+
paramLoc, var->getName(), DC);
300+
arg->setSpecifier(ParamSpecifier::Default);
301+
arg->setInterfaceType(varInterfaceType);
302+
arg->setImplicit();
303+
arg->setAutoClosure(isAutoClosure);
304+
305+
// Don't allow the parameter to accept temporary pointer conversions.
306+
arg->setNonEphemeralIfPossible();
307+
308+
// Attach a result builder attribute if needed.
309+
if (resultBuilderType) {
310+
auto typeExpr = TypeExpr::createImplicit(resultBuilderType, ctx);
311+
auto attr =
312+
CustomAttr::create(ctx, SourceLoc(), typeExpr, /*implicit=*/true);
313+
arg->getAttrs().add(attr);
314+
}
315+
316+
maybeAddMemberwiseDefaultArg(arg, var, ctx);
317+
318+
return arg;
319+
}
320+
253321
/// Create an implicit struct or class constructor.
254322
///
255323
/// \param decl The struct or class for which a constructor will be created.
@@ -281,70 +349,7 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
281349

282350
accessLevel = std::min(accessLevel, var->getFormalAccess());
283351

284-
auto varInterfaceType = var->getValueInterfaceType();
285-
bool isAutoClosure = false;
286-
287-
if (var->getAttrs().hasAttribute<LazyAttr>()) {
288-
// If var is a lazy property, its value is provided for the underlying
289-
// storage. We thus take an optional of the property's type. We only
290-
// need to do this because the implicit initializer is added before all
291-
// the properties are type checked. Perhaps init() synth should be
292-
// moved later.
293-
varInterfaceType = OptionalType::get(varInterfaceType);
294-
} else if (Type backingPropertyType =
295-
var->getPropertyWrapperBackingPropertyType()) {
296-
// For a property that has a wrapper, writing the initializer
297-
// with an '=' implies that the memberwise initializer should also
298-
// accept a value of the original property type. Otherwise, the
299-
// memberwise initializer will be in terms of the backing storage
300-
// type.
301-
if (var->isPropertyMemberwiseInitializedWithWrappedType()) {
302-
varInterfaceType = var->getPropertyWrapperInitValueInterfaceType();
303-
304-
auto initInfo = var->getPropertyWrapperInitializerInfo();
305-
isAutoClosure = initInfo.getWrappedValuePlaceholder()->isAutoClosure();
306-
} else {
307-
varInterfaceType = backingPropertyType;
308-
}
309-
}
310-
311-
Type resultBuilderType= var->getResultBuilderType();
312-
if (resultBuilderType) {
313-
// If the variable's type is structurally a function type, use that
314-
// type. Otherwise, form a non-escaping function type for the function
315-
// parameter.
316-
bool isStructuralFunctionType =
317-
varInterfaceType->lookThroughAllOptionalTypes()
318-
->is<AnyFunctionType>();
319-
if (!isStructuralFunctionType) {
320-
auto extInfo = ASTExtInfoBuilder().withNoEscape().build();
321-
varInterfaceType = FunctionType::get({ }, varInterfaceType, extInfo);
322-
}
323-
}
324-
325-
// Create the parameter.
326-
auto *arg = new (ctx)
327-
ParamDecl(SourceLoc(), Loc,
328-
var->getName(), Loc, var->getName(), decl);
329-
arg->setSpecifier(ParamSpecifier::Default);
330-
arg->setInterfaceType(varInterfaceType);
331-
arg->setImplicit();
332-
arg->setAutoClosure(isAutoClosure);
333-
334-
// Don't allow the parameter to accept temporary pointer conversions.
335-
arg->setNonEphemeralIfPossible();
336-
337-
// Attach a result builder attribute if needed.
338-
if (resultBuilderType) {
339-
auto typeExpr = TypeExpr::createImplicit(resultBuilderType, ctx);
340-
auto attr = CustomAttr::create(
341-
ctx, SourceLoc(), typeExpr, /*implicit=*/true);
342-
arg->getAttrs().add(attr);
343-
}
344-
345-
maybeAddMemberwiseDefaultArg(arg, var, params.size(), ctx);
346-
347-
params.push_back(arg);
352+
params.push_back(createMemberwiseInitParameter(decl, Loc, var));
348353
}
349354
} else if (ICK == ImplicitConstructorKind::DefaultDistributedActor) {
350355
auto classDecl = dyn_cast<ClassDecl>(decl);

0 commit comments

Comments
 (0)