Skip to content

Check default init before synthesizing wrapper backing properties. #26352

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5821,7 +5821,8 @@ Expr *swift::findOriginalPropertyWrapperInitialValue(VarDecl *var,
return nullptr;

// If there is no '=' on the pattern, there was no initial value.
if (PBD->getPatternList()[0].getEqualLoc().isInvalid())
if (PBD->getPatternList()[0].getEqualLoc().isInvalid()
&& !PBD->isDefaultInitializable())
return nullptr;

ASTContext &ctx = var->getASTContext();
Expand Down
19 changes: 18 additions & 1 deletion lib/Sema/CodeSynthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,18 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
// Take the initializer from the original property.
auto parentPBD = var->getParentPatternBinding();
unsigned patternNumber = parentPBD->getPatternEntryIndexForVarDecl(var);

// Force the default initializer to come into existence, if there is one,
// and the wrapper doesn't provide its own.
if (!parentPBD->isInitialized(patternNumber)
&& parentPBD->isDefaultInitializable(patternNumber)
&& !wrapperInfo.defaultInit) {
auto &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());
auto ty = parentPBD->getPattern(patternNumber)->getType();
if (auto defaultInit = tc.buildDefaultInitializer(ty))
parentPBD->setInit(patternNumber, defaultInit);
}

if (parentPBD->isInitialized(patternNumber) &&
!parentPBD->isInitializerChecked(patternNumber)) {
auto &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());
Expand Down Expand Up @@ -2558,7 +2570,12 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
return;

// Whether we have explicit initialization.
bool isExplicitlyInitialized = var->isParentInitialized();
bool isExplicitlyInitialized = false;
if (auto pbd = var->getParentPatternBinding()) {
auto &entry = pbd->getPatternEntryForVarDecl(var);
isExplicitlyInitialized =
entry.isInitialized() && entry.getEqualLoc().isValid();
}

// Whether we can default-initialize this property.
auto binding = var->getParentPatternBinding();
Expand Down
10 changes: 5 additions & 5 deletions lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,10 +642,10 @@ TypeChecker::handleSILGenericParams(GenericParamList *genericParams,
}

/// Build a default initializer for the given type.
static Expr *buildDefaultInitializer(TypeChecker &tc, Type type) {
Expr *TypeChecker::buildDefaultInitializer(Type type) {
// Default-initialize optional types and weak values to 'nil'.
if (type->getReferenceStorageReferent()->getOptionalObjectType())
return new (tc.Context) NilLiteralExpr(SourceLoc(), /*Implicit=*/true);
return new (Context) NilLiteralExpr(SourceLoc(), /*Implicit=*/true);

// Build tuple literals for tuple types.
if (auto tupleType = type->getAs<TupleType>()) {
Expand All @@ -654,14 +654,14 @@ static Expr *buildDefaultInitializer(TypeChecker &tc, Type type) {
if (elt.isVararg())
return nullptr;

auto eltInit = buildDefaultInitializer(tc, elt.getType());
auto eltInit = buildDefaultInitializer(elt.getType());
if (!eltInit)
return nullptr;

inits.push_back(eltInit);
}

return TupleExpr::createImplicit(tc.Context, inits, { });
return TupleExpr::createImplicit(Context, inits, { });
}

// We don't default-initialize anything else.
Expand Down Expand Up @@ -2629,7 +2629,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
PBD->getPattern(i)->hasStorage() &&
!PBD->getPattern(i)->getType()->hasError()) {
auto type = PBD->getPattern(i)->getType();
if (auto defaultInit = buildDefaultInitializer(TC, type)) {
if (auto defaultInit = TC.buildDefaultInitializer(type)) {
// If we got a default initializer, install it and re-type-check it
// to make sure it is properly coerced to the pattern type.
PBD->setInit(i, defaultInit);
Expand Down
12 changes: 10 additions & 2 deletions lib/Sema/TypeCheckPropertyWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,10 +666,14 @@ Expr *swift::buildPropertyWrapperInitialValueCall(
= var->getAttachedPropertyWrapperTypeInfo(i).wrappedValueInit) {
argName = init->getFullName().getArgumentNames()[0];
}

auto endLoc = initializer->getEndLoc();
if (endLoc.isInvalid() && startLoc.isValid())
endLoc = wrapperAttrs[i]->getTypeLoc().getSourceRange().End;

initializer = CallExpr::create(
ctx, typeExpr, startLoc, {initializer}, {argName},
{initializer->getStartLoc()}, initializer->getEndLoc(),
{initializer->getStartLoc()}, endLoc,
nullptr, /*implicit=*/true);
continue;
}
Expand All @@ -694,10 +698,14 @@ Expr *swift::buildPropertyWrapperInitialValueCall(
elementNames.push_back(Identifier());
elementLocs.push_back(SourceLoc());
}

auto endLoc = attr->getArg()->getEndLoc();
if (endLoc.isInvalid() && startLoc.isValid())
endLoc = wrapperAttrs[i]->getTypeLoc().getSourceRange().End;

initializer = CallExpr::create(
ctx, typeExpr, startLoc, elements, elementNames, elementLocs,
attr->getArg()->getEndLoc(), nullptr, /*implicit=*/true);
endLoc, nullptr, /*implicit=*/true);
}

return initializer;
Expand Down
2 changes: 2 additions & 0 deletions lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -1799,6 +1799,8 @@ class TypeChecker final : public LazyResolver {
FragileFunctionKind Kind,
bool TreatUsableFromInlineAsPublic);

Expr *buildDefaultInitializer(Type type);

private:
bool diagnoseInlinableDeclRefAccess(SourceLoc loc, const ValueDecl *D,
const DeclContext *DC,
Expand Down
20 changes: 19 additions & 1 deletion test/SILOptimizer/di_property_wrappers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,24 @@ func testOptIntStruct() {
print("\n## OptIntStruct")

let use = OptIntStruct()
// CHECK-NEXT: .. init Optional(42)
// CHECK-NEXT: .. init nil
// CHECK-NEXT: .. set Optional(42)
}

// rdar://problem/53504653

struct DefaultNilOptIntStruct {
@Wrapper var wrapped: Int?

init() {
}
}
func testDefaultNilOptIntStruct() {
// CHECK: ## DefaultNilOptIntStruct
print("\n## DefaultNilOptIntStruct")

let use = DefaultNilOptIntStruct()
// CHECK-NEXT: .. init nil
}

testIntStruct()
Expand All @@ -369,3 +386,4 @@ testRefStruct()
testGenericClass()
testDefaultInit()
testOptIntStruct()
testDefaultNilOptIntStruct()