Skip to content

Commit 116dea2

Browse files
committed
[AST/TypeChecker] TypeWrappers: Add @typeWrapperIgnored attribute
`@typeWrapperIgnored` attribute could be used on stored properties of a type wrapped type to exclude them from type wrapper transform.
1 parent 86c7f9f commit 116dea2

File tree

6 files changed

+99
-0
lines changed

6 files changed

+99
-0
lines changed

include/swift/AST/Attr.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,11 @@ DECL_ATTR(_documentation, Documentation,
778778
APIBreakingToAdd | APIStableToRemove | ABIStableToAdd | ABIStableToRemove,
779779
136)
780780

781+
SIMPLE_DECL_ATTR(typeWrapperIgnored, TypeWrapperIgnored,
782+
OnVar |
783+
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
784+
137)
785+
781786
// If you're adding a new underscored attribute here, please document it in
782787
// docs/ReferenceGuides/UnderscoredAttributes.md.
783788

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6560,5 +6560,14 @@ ERROR(type_wrapper_type_requirement_not_accessible,none,
65606560
"(which is %select{private|fileprivate|internal|public|open}4)",
65616561
(AccessLevel, DescriptiveDeclKind, DeclName, Type, AccessLevel))
65626562

6563+
ERROR(type_wrapper_ignored_on_local_properties,none,
6564+
"%0 must not be used on local properties", (DeclAttribute))
6565+
ERROR(type_wrapper_ignored_on_computed_properties,none,
6566+
"%0 must not be used on computed properties", (DeclAttribute))
6567+
ERROR(type_wrapper_ignored_on_static_properties,none,
6568+
"%0 must not be used on static properties", (DeclAttribute))
6569+
ERROR(type_wrapper_ignored_on_lazy_properties,none,
6570+
"%0 must not be used on lazy properties", (DeclAttribute))
6571+
65636572
#define UNDEFINE_DIAGNOSTIC_MACROS
65646573
#include "DefineDiagnosticMacros.h"

lib/Sema/TypeCheckAttr.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
294294
void visitCustomAttr(CustomAttr *attr);
295295
void visitPropertyWrapperAttr(PropertyWrapperAttr *attr);
296296
void visitTypeWrapperAttr(TypeWrapperAttr *attr);
297+
void visitTypeWrapperIgnoredAttr(TypeWrapperIgnoredAttr *attr);
297298
void visitResultBuilderAttr(ResultBuilderAttr *attr);
298299

299300
void visitImplementationOnlyAttr(ImplementationOnlyAttr *attr);
@@ -3796,6 +3797,46 @@ void AttributeChecker::visitTypeWrapperAttr(TypeWrapperAttr *attr) {
37963797
}
37973798
}
37983799

3800+
void AttributeChecker::visitTypeWrapperIgnoredAttr(TypeWrapperIgnoredAttr *attr) {
3801+
auto *var = cast<VarDecl>(D);
3802+
3803+
// @typeWrapperIgnored applies only to properties that type wrapper can manage.
3804+
if (var->getDeclContext()->isLocalContext()) {
3805+
diagnoseAndRemoveAttr(attr, diag::type_wrapper_ignored_on_local_properties, attr);
3806+
return;
3807+
}
3808+
3809+
if (var->isLet()) {
3810+
diagnoseAndRemoveAttr(attr, diag::attr_only_one_decl_kind, attr, "var");
3811+
return;
3812+
}
3813+
3814+
if (var->getAttrs().hasAttribute<LazyAttr>()) {
3815+
diagnoseAndRemoveAttr(attr, diag::type_wrapper_ignored_on_lazy_properties, attr);
3816+
return;
3817+
}
3818+
3819+
if (var->isStatic()) {
3820+
diagnoseAndRemoveAttr(attr, diag::type_wrapper_ignored_on_static_properties, attr);
3821+
return;
3822+
}
3823+
3824+
// computed properties
3825+
{
3826+
SmallVector<AccessorKind, 4> accessors{AccessorKind::Get, AccessorKind::Set,
3827+
AccessorKind::Modify,
3828+
AccessorKind::MutableAddress};
3829+
3830+
if (llvm::any_of(accessors, [&var](const auto &accessor) {
3831+
return var->getParsedAccessor(accessor);
3832+
})) {
3833+
diagnoseAndRemoveAttr(
3834+
attr, diag::type_wrapper_ignored_on_computed_properties, attr);
3835+
return;
3836+
}
3837+
}
3838+
}
3839+
37993840
void AttributeChecker::visitResultBuilderAttr(ResultBuilderAttr *attr) {
38003841
auto *nominal = dyn_cast<NominalTypeDecl>(D);
38013842
auto &ctx = D->getASTContext();

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,6 +1587,7 @@ namespace {
15871587
UNINTERESTING_ATTR(Custom)
15881588
UNINTERESTING_ATTR(PropertyWrapper)
15891589
UNINTERESTING_ATTR(TypeWrapper)
1590+
UNINTERESTING_ATTR(TypeWrapperIgnored)
15901591
UNINTERESTING_ATTR(DisfavoredOverload)
15911592
UNINTERESTING_ATTR(ResultBuilder)
15921593
UNINTERESTING_ATTR(ProjectedValueProperty)

test/IDE/complete_decl_attribute.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ actor MyGlobalActor {
172172
// ON_GLOBALVAR-DAG: Keyword/None: noDerivative[#Var Attribute#]; name=noDerivative
173173
// ON_GLOBALVAR-DAG: Keyword/None: exclusivity[#Var Attribute#]; name=exclusivity
174174
// ON_GLOBALVAR-DAG: Keyword/None: preconcurrency[#Var Attribute#]; name=preconcurrency
175+
// ON_GLOBALVAR-DAG: Keyword/None: typeWrapperIgnored[#Var Attribute#]; name=typeWrapperIgnored
175176
// ON_GLOBALVAR-NOT: Keyword
176177
// ON_GLOBALVAR-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct
177178
// ON_GLOBALVAR-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: MyPropertyWrapper[#MyPropertyWrapper#]; name=MyPropertyWrapper
@@ -209,6 +210,7 @@ struct _S {
209210
// ON_PROPERTY-DAG: Keyword/None: noDerivative[#Var Attribute#]; name=noDerivative
210211
// ON_PROPERTY-DAG: Keyword/None: exclusivity[#Var Attribute#]; name=exclusivity
211212
// ON_PROPERTY-DAG: Keyword/None: preconcurrency[#Var Attribute#]; name=preconcurrency
213+
// ON_PROPERTY-DAG: Keyword/None: typeWrapperIgnored[#Var Attribute#]; name=typeWrapperIgnored
212214
// ON_PROPERTY-NOT: Keyword
213215
// ON_PROPERTY-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct
214216
// ON_PROPERTY-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: MyPropertyWrapper[#MyPropertyWrapper#]; name=MyPropertyWrapper
@@ -309,6 +311,7 @@ struct _S {
309311
// ON_MEMBER_LAST-DAG: Keyword/None: exclusivity[#Declaration Attribute#]; name=exclusivity
310312
// ON_MEMBER_LAST-DAG: Keyword/None: preconcurrency[#Declaration Attribute#]; name=preconcurrency
311313
// ON_MEMBER_LAST-DAG: Keyword/None: typeWrapper[#Declaration Attribute#]; name=typeWrapper
314+
// ON_MEMBER_LAST-DAG: Keyword/None: typeWrapperIgnored[#Declaration Attribute#]; name=typeWrapperIgnored
312315
// ON_MEMBER_LAST-NOT: Keyword
313316
// ON_MEMBER_LAST-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct
314317
// ON_MEMBER_LAST-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: MyPropertyWrapper[#MyPropertyWrapper#]; name=MyPropertyWrapper
@@ -379,6 +382,7 @@ func dummy2() {}
379382
// KEYWORD_LAST-DAG: Keyword/None: exclusivity[#Declaration Attribute#]; name=exclusivity
380383
// KEYWORD_LAST-DAG: Keyword/None: preconcurrency[#Declaration Attribute#]; name=preconcurrency
381384
// KEYWORD_LAST-DAG: Keyword/None: typeWrapper[#Declaration Attribute#]; name=typeWrapper
385+
// KEYWORD_LAST-DAG: Keyword/None: typeWrapperIgnored[#Declaration Attribute#]; name=typeWrapperIgnored
382386
// KEYWORD_LAST-NOT: Keyword
383387
// KEYWORD_LAST-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct
384388
// KEYWORD_LAST-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: MyPropertyWrapper[#MyPropertyWrapper#]; name=MyPropertyWrapper

test/type/type_wrapper.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,3 +398,42 @@ func testActors() async {
398398
person.name = "NoName" // expected-error {{actor-isolated property 'name' can not be mutated from a non-isolated context}}
399399
person.age = 0 // expected-error {{actor-isolated property 'age' can not be mutated from a non-isolated context}}
400400
}
401+
402+
func testIgnoredAttr() {
403+
@NoopWrapper
404+
struct X {
405+
@typeWrapperIgnored static var staticVar: Int = 0 // expected-error {{@typeWrapperIgnored must not be used on static properties}}
406+
407+
@typeWrapperIgnored lazy var lazyVar: Int = { // expected-error {{@typeWrapperIgnored must not be used on lazy properties}}
408+
42
409+
}()
410+
411+
@typeWrapperIgnored var x: Int // Ok
412+
413+
var y: Int {
414+
@typeWrapperIgnored get { // expected-error {{@typeWrapperIgnored may only be used on 'var' declarations}}
415+
42
416+
}
417+
418+
@typeWrapperIgnored set { // expected-error {{@typeWrapperIgnored may only be used on 'var' declarations}}
419+
}
420+
}
421+
422+
@typeWrapperIgnored var computed: Int { // expected-error {{@typeWrapperIgnored must not be used on computed properties}}
423+
get { 42 }
424+
set {}
425+
}
426+
427+
@typeWrapperIgnored let z: Int = 0 // expected-error {{@typeWrapperIgnored may only be used on 'var' declarations}}
428+
429+
func test_param(@typeWrapperIgnored x: Int) {} // expected-error {{@typeWrapperIgnored may only be used on 'var' declarations}}
430+
431+
func test_local() {
432+
@typeWrapperIgnored var x: Int = 42 // expected-error {{@typeWrapperIgnored must not be used on local properties}}
433+
// expected-warning@-1 {{variable 'x' was never used; consider replacing with '_' or removing it}}
434+
435+
@typeWrapperIgnored let y: String // expected-error {{@typeWrapperIgnored must not be used on local properties}}
436+
// expected-warning@-1 {{immutable value 'y' was never used; consider replacing with '_' or removing it}}
437+
}
438+
}
439+
}

0 commit comments

Comments
 (0)