@@ -1625,7 +1625,7 @@ synthesizeLazyGetterBody(AccessorDecl *Get, VarDecl *VD, VarDecl *Storage,
1625
1625
auto *InitValue = VD->getParentInitializer ();
1626
1626
auto PBD = VD->getParentPatternBinding ();
1627
1627
unsigned entryIndex = PBD->getPatternEntryIndexForVarDecl (VD);
1628
- assert ( PBD->isInitializerSubsumed (entryIndex) );
1628
+ PBD->setInitializerSubsumed (entryIndex);
1629
1629
1630
1630
if (!PBD->isInitializerChecked (entryIndex))
1631
1631
TC.typeCheckPatternBinding (PBD, entryIndex);
@@ -2025,31 +2025,19 @@ void swift::triggerAccessorSynthesis(TypeChecker &TC,
2025
2025
});
2026
2026
}
2027
2027
2028
- static StorageImplInfo getProtocolStorageImpl (AbstractStorageDecl *storage) {
2029
- auto protocol = cast<ProtocolDecl>(storage->getDeclContext ());
2030
- if (protocol->isObjC ()) {
2031
- return StorageImplInfo::getComputed (storage->supportsMutation ());
2032
- } else {
2033
- return StorageImplInfo::getOpaque (storage->supportsMutation (),
2034
- storage->getOpaqueReadOwnership ());
2035
- }
2036
- }
2037
-
2038
2028
// / Given a storage declaration in a protocol, set it up with the right
2039
2029
// / StorageImpl and add the right set of opaque accessors.
2040
- static void finishProtocolStorageImplInfo (AbstractStorageDecl *storage) {
2030
+ static void finishProtocolStorageImplInfo (AbstractStorageDecl *storage,
2031
+ StorageImplInfo &info) {
2041
2032
if (auto *var = dyn_cast<VarDecl>(storage)) {
2042
- if (var->hasStorage ()) {
2043
- auto &ctx = var->getASTContext ();
2033
+ if (info.hasStorage ()) {
2044
2034
// Protocols cannot have stored properties.
2045
2035
if (var->isLet ()) {
2046
- ctx.Diags .diagnose (var->getLoc (),
2047
- diag::protocol_property_must_be_computed_var)
2036
+ var->diagnose (diag::protocol_property_must_be_computed_var)
2048
2037
.fixItReplace (var->getParentPatternBinding ()->getLoc (), " var" )
2049
2038
.fixItInsertAfter (var->getTypeLoc ().getLoc (), " { get }" );
2050
2039
} else {
2051
- auto diag = ctx.Diags .diagnose (var->getLoc (),
2052
- diag::protocol_property_must_be_computed);
2040
+ auto diag = var->diagnose (diag::protocol_property_must_be_computed);
2053
2041
auto braces = var->getBracesRange ();
2054
2042
2055
2043
if (braces.isValid ())
@@ -2060,15 +2048,59 @@ static void finishProtocolStorageImplInfo(AbstractStorageDecl *storage) {
2060
2048
}
2061
2049
}
2062
2050
2063
- storage->setImplInfo (getProtocolStorageImpl (storage));
2051
+ auto protocol = cast<ProtocolDecl>(storage->getDeclContext ());
2052
+ if (protocol->isObjC ()) {
2053
+ info = StorageImplInfo::getComputed (info.supportsMutation ());
2054
+ } else {
2055
+ info = StorageImplInfo::getOpaque (info.supportsMutation (),
2056
+ storage->getOpaqueReadOwnership ());
2057
+ }
2064
2058
}
2065
2059
2066
- static void finishLazyVariableImplInfo (VarDecl *var) {
2067
- // If there are already accessors, something is invalid; bail out.
2068
- if (!var->getImplInfo ().isSimpleStored ())
2069
- return ;
2060
+ // / This emits a diagnostic with a fixit to remove the attribute.
2061
+ template <typename ...ArgTypes>
2062
+ void diagnoseAndRemoveAttr (Decl *D, DeclAttribute *attr,
2063
+ ArgTypes &&...Args) {
2064
+ auto &ctx = D->getASTContext ();
2065
+ ctx.Diags .diagnose (attr->getLocation (), std::forward<ArgTypes>(Args)...)
2066
+ .fixItRemove (attr->getRangeWithAt ());
2067
+ }
2068
+
2069
+ static void finishLazyVariableImplInfo (VarDecl *var,
2070
+ StorageImplInfo &info) {
2071
+ auto *attr = var->getAttrs ().getAttribute <LazyAttr>();
2072
+
2073
+ // It cannot currently be used on let's since we don't have a mutability model
2074
+ // that supports it.
2075
+ if (var->isLet ())
2076
+ diagnoseAndRemoveAttr (var, attr, diag::lazy_not_on_let);
2077
+
2078
+ // lazy must have an initializer.
2079
+ if (!var->getParentInitializer ())
2080
+ diagnoseAndRemoveAttr (var, attr, diag::lazy_requires_initializer);
2081
+
2082
+ bool invalid = false ;
2070
2083
2071
- var->setImplInfo (StorageImplInfo::getMutableComputed ());
2084
+ if (isa<ProtocolDecl>(var->getDeclContext ())) {
2085
+ diagnoseAndRemoveAttr (var, attr, diag::lazy_not_in_protocol);
2086
+ invalid = true ;
2087
+ }
2088
+
2089
+ // Lazy properties must be written as stored properties in the source.
2090
+ if (!info.isSimpleStored ()) {
2091
+ diagnoseAndRemoveAttr (var, attr,
2092
+ info.hasStorage ()
2093
+ ? diag::lazy_not_observable
2094
+ : diag::lazy_not_on_computed);
2095
+ invalid = true ;
2096
+ }
2097
+
2098
+ // The pattern binding must only bind a single variable.
2099
+ if (!var->getParentPatternBinding ()->getSingleVar ())
2100
+ diagnoseAndRemoveAttr (var, attr, diag::lazy_requires_single_var);
2101
+
2102
+ if (!invalid)
2103
+ info = StorageImplInfo::getMutableComputed ();
2072
2104
}
2073
2105
2074
2106
// / Determine whether all of the wrapped-value setters for the property
@@ -2090,8 +2122,21 @@ static bool allPropertyWrapperValueSettersAreAccessible(VarDecl *var) {
2090
2122
return true ;
2091
2123
}
2092
2124
2093
- static void finishPropertyWrapperImplInfo (VarDecl *var) {
2125
+ static void finishPropertyWrapperImplInfo (VarDecl *var,
2126
+ StorageImplInfo &info) {
2094
2127
auto parentSF = var->getDeclContext ()->getParentSourceFile ();
2128
+ if (!parentSF)
2129
+ return ;
2130
+
2131
+ // Properties with wrappers must not declare a getter or setter.
2132
+ if (!info.hasStorage () && parentSF->Kind != SourceFileKind::Interface) {
2133
+ auto &ctx = parentSF->getASTContext ();
2134
+ for (auto attr : var->getAttrs ().getAttributes <CustomAttr>())
2135
+ ctx.Diags .diagnose (attr->getLocation (), diag::property_wrapper_computed);
2136
+
2137
+ return ;
2138
+ }
2139
+
2095
2140
bool wrapperSetterIsUsable =
2096
2141
var->getSetter () ||
2097
2142
(parentSF &&
@@ -2100,36 +2145,68 @@ static void finishPropertyWrapperImplInfo(VarDecl *var) {
2100
2145
allPropertyWrapperValueSettersAreAccessible (var));
2101
2146
2102
2147
if (wrapperSetterIsUsable)
2103
- var-> setImplInfo ( StorageImplInfo::getMutableComputed () );
2148
+ info = StorageImplInfo::getMutableComputed ();
2104
2149
else
2105
- var-> setImplInfo ( StorageImplInfo::getImmutableComputed () );
2150
+ info = StorageImplInfo::getImmutableComputed ();
2106
2151
}
2107
2152
2108
- static void finishNSManagedImplInfo (VarDecl *VD) {
2109
- // If it's not still stored, just bail out.
2110
- if (!VD->getImplInfo ().isSimpleStored ())
2111
- return ;
2153
+ static void finishNSManagedImplInfo (VarDecl *var,
2154
+ StorageImplInfo &info) {
2155
+ auto *attr = var->getAttrs ().getAttribute <NSManagedAttr>();
2112
2156
2113
- VD-> setImplInfo ( StorageImplInfo::getMutableComputed ());
2114
- }
2157
+ if (var-> isLet ())
2158
+ diagnoseAndRemoveAttr (var, attr, diag::attr_NSManaged_let_property);
2115
2159
2116
- static void finishStorageImplInfo (AbstractStorageDecl *storage) {
2117
- if (isa<ProtocolDecl>(storage->getDeclContext ())) {
2118
- finishProtocolStorageImplInfo (storage);
2119
- return ;
2160
+ auto diagnoseNotStored = [&](unsigned kind) {
2161
+ diagnoseAndRemoveAttr (var, attr, diag::attr_NSManaged_not_stored, kind);
2162
+ };
2163
+
2164
+ // @NSManaged properties must be written as stored.
2165
+ if (info.isSimpleStored ()) {
2166
+ // @NSManaged properties end up being computed; complain if there is
2167
+ // an initializer.
2168
+ if (var->getParentInitializer ()) {
2169
+ auto &Diags = var->getASTContext ().Diags ;
2170
+ Diags.diagnose (attr->getLocation (), diag::attr_NSManaged_initial_value)
2171
+ .highlight (var->getParentInitializer ()->getSourceRange ());
2172
+ }
2173
+
2174
+ // Otherwise, ok.
2175
+ info = StorageImplInfo::getMutableComputed ();
2176
+
2177
+ } else if (info.getReadImpl () == ReadImplKind::Address ||
2178
+ info.getWriteImpl () == WriteImplKind::MutableAddress) {
2179
+ diagnoseNotStored (/* addressed*/ 2 );
2180
+ } else if (info.getWriteImpl () == WriteImplKind::StoredWithObservers ||
2181
+ info.getWriteImpl () == WriteImplKind::InheritedWithObservers) {
2182
+ diagnoseNotStored (/* observing*/ 1 );
2183
+ } else {
2184
+ diagnoseNotStored (/* computed*/ 0 );
2120
2185
}
2186
+ }
2121
2187
2122
- auto var = dyn_cast<VarDecl>(storage);
2123
- if (var == nullptr )
2124
- return ;
2188
+ static void finishStorageImplInfo (AbstractStorageDecl *storage,
2189
+ StorageImplInfo &info) {
2190
+ if (auto var = dyn_cast<VarDecl>(storage)) {
2191
+ if (!info.hasStorage ()) {
2192
+ if (auto *init = var->getParentInitializer ()) {
2193
+ auto &Diags = var->getASTContext ().Diags ;
2194
+ Diags.diagnose (init->getLoc (), diag::getset_init)
2195
+ .highlight (init->getSourceRange ());
2196
+ }
2197
+ }
2125
2198
2126
- if (var->getAttrs ().hasAttribute <LazyAttr>()) {
2127
- finishLazyVariableImplInfo (var);
2128
- } else if (var->getAttrs ().hasAttribute <NSManagedAttr>()) {
2129
- finishNSManagedImplInfo (var);
2130
- } else if (var->hasAttachedPropertyWrapper ()) {
2131
- finishPropertyWrapperImplInfo (var);
2199
+ if (var->getAttrs ().hasAttribute <LazyAttr>()) {
2200
+ finishLazyVariableImplInfo (var, info);
2201
+ } else if (var->getAttrs ().hasAttribute <NSManagedAttr>()) {
2202
+ finishNSManagedImplInfo (var, info);
2203
+ } else if (var->hasAttachedPropertyWrapper ()) {
2204
+ finishPropertyWrapperImplInfo (var, info);
2205
+ }
2132
2206
}
2207
+
2208
+ if (isa<ProtocolDecl>(storage->getDeclContext ()))
2209
+ finishProtocolStorageImplInfo (storage, info);
2133
2210
}
2134
2211
2135
2212
static bool hasParsedAccessor (AbstractStorageDecl *storage, AccessorKind kind) {
@@ -2284,14 +2361,15 @@ StorageImplInfoRequest::evaluate(Evaluator &evaluator,
2284
2361
readWriteImpl = ReadWriteImplKind::Immutable;
2285
2362
}
2286
2363
2287
- return StorageImplInfo (readImpl, writeImpl, readWriteImpl);
2364
+ StorageImplInfo info (readImpl, writeImpl, readWriteImpl);
2365
+ finishStorageImplInfo (storage, info);
2366
+
2367
+ return info;
2288
2368
}
2289
2369
2290
2370
// / Try to add the appropriate accessors required a storage declaration.
2291
2371
// / This needs to be idempotent.
2292
2372
void swift::maybeAddAccessorsToStorage (AbstractStorageDecl *storage) {
2293
- finishStorageImplInfo (storage);
2294
-
2295
2373
// Implicit properties don't get accessors.
2296
2374
if (storage->isImplicit () &&
2297
2375
!(isa<VarDecl>(storage) &&
0 commit comments