Skip to content

Commit 78e8a36

Browse files
committed
[Property delegates] Diagnose too-restrictive 'value' and 'init(initialValue:)' .
The 'value' property and 'init(initialValue:)' initializer cannot have more restrictive access than the property delegate itself. Diagnose this.
1 parent 9017c7e commit 78e8a36

File tree

3 files changed

+44
-4
lines changed

3 files changed

+44
-4
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4326,6 +4326,11 @@ ERROR(property_with_delegate_conflict_attribute,none,
43264326
"property %0 with a delegate cannot also be "
43274327
"%select{lazy|@NSCopying|@NSManaged|weak|unowned|unmanaged}1",
43284328
(DeclName, int))
4329+
ERROR(property_delegate_type_requirement_not_accessible,none,
4330+
"%select{private|fileprivate|internal|public|open}0 %1 %2 cannot have "
4331+
"more restrictive access than its enclosing property delegate type %3 "
4332+
"(which is %select{private|fileprivate|internal|public|open}4)",
4333+
(AccessLevel, DescriptiveDeclKind, DeclName, Type, AccessLevel))
43294334

43304335
#ifndef DIAG_NO_UNDEF
43314336
# if defined(DIAG)

lib/Sema/TypeCheckPropertyDelegates.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ PropertyDelegateTypeInfoRequest::evaluate(
219219
nominal->lookupQualified(nominal, ctx.Id_value, NL_QualifiedDefault, decls);
220220
for (const auto &foundDecl : decls) {
221221
auto foundVar = dyn_cast<VarDecl>(foundDecl);
222-
if (!foundVar || foundVar->isStatic())
222+
if (!foundVar || foundVar->isStatic() ||
223+
foundVar->getDeclContext() != nominal)
223224
continue;
224225

225226
unwrapVars.push_back(foundVar);
@@ -247,6 +248,16 @@ PropertyDelegateTypeInfoRequest::evaluate(
247248
return PropertyDelegateTypeInfo();
248249
}
249250

251+
// The 'value' property must be as accessible as the nominal type.
252+
if (result.unwrapProperty->getFormalAccess() < nominal->getFormalAccess()) {
253+
auto var = result.unwrapProperty;
254+
var->diagnose(diag::property_delegate_type_requirement_not_accessible,
255+
var->getFormalAccess(), var->getDescriptiveKind(),
256+
var->getFullName(), nominal->getDeclaredType(),
257+
nominal->getFormalAccess());
258+
return PropertyDelegateTypeInfo();
259+
}
260+
250261
// Determine whether we have an init(initialValue:), and diagnose
251262
// ambiguities.
252263
{
@@ -257,7 +268,7 @@ PropertyDelegateTypeInfoRequest::evaluate(
257268
nominal->lookupQualified(nominal, initName, NL_QualifiedDefault, decls);
258269
for (const auto &decl : decls) {
259270
auto init = dyn_cast<ConstructorDecl>(decl);
260-
if (!init)
271+
if (!init || init->getDeclContext() != nominal)
261272
continue;
262273

263274
initialValueInitializers.push_back(init);
@@ -267,9 +278,19 @@ PropertyDelegateTypeInfoRequest::evaluate(
267278
case 0:
268279
break;
269280

270-
case 1:
271-
result.initialValueInit = initialValueInitializers.front();
281+
case 1: {
282+
// 'init(initialValue:)' must be as accessible as the nominal type.
283+
auto init = initialValueInitializers.front();
284+
if (init->getFormalAccess() < nominal->getFormalAccess()) {
285+
init->diagnose(diag::property_delegate_type_requirement_not_accessible,
286+
init->getFormalAccess(), init->getDescriptiveKind(),
287+
init->getFullName(), nominal->getDeclaredType(),
288+
nominal->getFormalAccess());
289+
} else {
290+
result.initialValueInit = init;
291+
}
272292
break;
293+
}
273294

274295
default:
275296
// Diagnose ambiguous init(initialValue:) initializers.

test/decl/var/property_delegates.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,20 @@ struct BadCombinations {
430430
unowned var z: C by Wrapper // expected-error{{property 'z' with a delegate cannot also be unowned}}
431431
}
432432

433+
@propertyDelegate
434+
struct NonVisibleValueDelegate<Value> {
435+
private var value: Value // expected-error{{private property 'value' cannot have more restrictive access than its enclosing property delegate type 'NonVisibleValueDelegate' (which is internal)}}
436+
}
437+
438+
@propertyDelegate
439+
struct NonVisibleInitDelegate<Value> {
440+
var value: Value
441+
442+
private init(initialValue: Value) { // expected-error{{private initializer 'init(initialValue:)' cannot have more restrictive access than its enclosing property delegate type 'NonVisibleInitDelegate' (which is internal)}}
443+
self.value = initialValue
444+
}
445+
}
446+
433447
// ---------------------------------------------------------------------------
434448
// Explicitly-specified accessors
435449
// ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)