[Property delegates] Implicit initialization for properties with delegates.

When a property delegate type has a default initializer, use that to
implicitly initialize properties that use that delegate and do not have
their own initializers. For example, this would allow (e.g.), delegate
types like the DelayedImmutable and DelayedMutable examples to drop
the explicit initialization, e.g.,

```
  @DelayedMutable var foo: Int
```

would be implicitly initialized via

```
  $foo = DelayedMutable()
```

This is a simplistic implementation that does not yet propertly handle
definite initialization.

Fixes rdar://problem/50266039.
This commit is contained in:
Doug Gregor
2019-05-01 23:17:16 -07:00
parent 830eebb9a4
commit f34aa79df1
6 changed files with 152 additions and 22 deletions

View File

@@ -1520,6 +1520,23 @@ static VarDecl *synthesizePropertyDelegateStorageDelegateProperty(
return property;
}
static void typeCheckSynthesizedDelegateInitializer(
PatternBindingDecl *pbd, VarDecl *backingVar, PatternBindingDecl *parentPBD,
Expr *&initializer) {
DeclContext *dc = pbd->getDeclContext();
ASTContext &ctx = dc->getASTContext();
// Type-check the initialization.
auto &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());
tc.typeCheckExpression(initializer, dc);
if (auto initializerContext =
dyn_cast_or_null<Initializer>(
pbd->getPatternEntryForVarDecl(backingVar).getInitContext())) {
tc.contextualizeInitializer(initializerContext, initializer);
}
tc.checkPropertyDelegateErrorHandling(pbd, initializer);
}
llvm::Expected<PropertyDelegateBackingPropertyInfo>
PropertyDelegateBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
VarDecl *var) const {
@@ -1589,14 +1606,6 @@ PropertyDelegateBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
tc.typeCheckPatternBinding(parentPBD, patternNumber);
}
Expr *originalInitialValue = nullptr;
if (Expr *init = parentPBD->getInit(patternNumber)) {
pbd->setInit(0, init);
pbd->setInitializerChecked(0);
originalInitialValue = findOriginalPropertyDelegateInitialValue(var, init);
}
// Mark the backing property as 'final'. There's no sensible way to override.
if (dc->getSelfClassDecl())
makeFinal(ctx, backingVar);
@@ -1616,6 +1625,23 @@ PropertyDelegateBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
std::min(defaultAccess, var->getSetterFormalAccess());
backingVar->overwriteSetterAccess(setterAccess);
Expr *originalInitialValue = nullptr;
if (Expr *init = parentPBD->getInit(patternNumber)) {
pbd->setInit(0, init);
pbd->setInitializerChecked(0);
originalInitialValue = findOriginalPropertyDelegateInitialValue(var, init);
} else if (!parentPBD->isInitialized(patternNumber) &&
delegateInfo.defaultInit) {
// FIXME: Record this expression somewhere so that DI can perform the
// initialization itself.
auto typeExpr = TypeExpr::createImplicit(storageType, ctx);
Expr *initializer = CallExpr::createImplicit(ctx, typeExpr, {}, { });
typeCheckSynthesizedDelegateInitializer(pbd, backingVar, parentPBD,
initializer);
pbd->setInit(0, initializer);
pbd->setInitializerChecked(0);
}
// If there is a storage delegate property (delegateVar) in the delegate,
// synthesize a computed property for '$foo'.
VarDecl *storageVar = nullptr;
@@ -1640,16 +1666,9 @@ PropertyDelegateBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
Expr *initializer =
CallExpr::createImplicit(ctx, typeExpr, {origValue},
{ctx.Id_initialValue});
typeCheckSynthesizedDelegateInitializer(pbd, backingVar, parentPBD,
initializer);
// Type-check the initialization.
auto &tc = *static_cast<TypeChecker *>(ctx.getLazyResolver());
tc.typeCheckExpression(initializer, dc);
if (auto initializerContext =
dyn_cast_or_null<Initializer>(
pbd->getPatternEntryForVarDecl(backingVar).getInitContext())) {
tc.contextualizeInitializer(initializerContext, initializer);
}
tc.checkPropertyDelegateErrorHandling(parentPBD, initializer);
return PropertyDelegateBackingPropertyInfo(
backingVar, storageVar, originalInitialValue, initializer, origValue);
}