Skip to content

Commit 044204a

Browse files
committed
Sema: Don't synthesize null bodies for invalid accessors
We don't want hasBody() == true and getBody() == nullptr.
1 parent 55a6693 commit 044204a

File tree

7 files changed

+83
-19
lines changed

7 files changed

+83
-19
lines changed

lib/AST/ASTContext.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3407,8 +3407,6 @@ ProtocolType::ProtocolType(ProtocolDecl *TheDecl, Type Parent,
34073407
: NominalType(TypeKind::Protocol, &Ctx, TheDecl, Parent, properties) { }
34083408

34093409
LValueType *LValueType::get(Type objectTy) {
3410-
assert(!objectTy->hasError() &&
3411-
"cannot have ErrorType wrapped inside LValueType");
34123410
assert(!objectTy->is<LValueType>() && !objectTy->is<InOutType>() &&
34133411
"cannot have 'inout' or @lvalue wrapped inside an @lvalue");
34143412

lib/Parse/ParseRequests.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ BraceStmt *ParseAbstractFunctionBodyRequest::evaluate(
7070

7171
std::tie(body, isTypeChecked) = (afd->Synthesizer.Fn)(
7272
afd, afd->Synthesizer.Context);
73+
assert(body && "cannot synthesize a null body");
7374
afd->setBodyKind(isTypeChecked ? BodyKind::TypeChecked : BodyKind::Parsed);
7475
return body;
7576
}

lib/Sema/MiscDiagnostics.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2140,6 +2140,12 @@ class VarDeclUsageChecker : public ASTWalker {
21402140
}
21412141
}
21422142

2143+
// Don't walk into implicit accessors, since eg. an observer's setter
2144+
// references the variable, but we don't want to consider it as a real
2145+
// "use".
2146+
if (isa<AccessorDecl>(D) && D->isImplicit())
2147+
return false;
2148+
21432149
if (auto *afd = dyn_cast<AbstractFunctionDecl>(D)) {
21442150
// If this is a nested function with a capture list, mark any captured
21452151
// variables.

lib/Sema/TypeCheckStorage.cpp

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -659,15 +659,24 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
659659
// Otherwise do a self-reference, which is dynamically bogus but
660660
// should be statically valid. This should only happen in invalid cases.
661661
} else {
662-
assert(storage->isInvalid());
663662
semantics = AccessSemantics::Ordinary;
664663
selfAccessKind = SelfAccessorKind::Peer;
665664
}
666665
break;
667666

668667
case TargetImpl::Wrapper: {
669668
auto var = cast<VarDecl>(accessor->getStorage());
670-
storage = var->getPropertyWrapperBackingProperty();
669+
auto *backing = var->getPropertyWrapperBackingProperty();
670+
671+
// Error recovery.
672+
if (!backing) {
673+
auto type = storage->getValueInterfaceType();
674+
if (isLValue)
675+
type = LValueType::get(type);
676+
return new (ctx) ErrorExpr(SourceRange(), type);
677+
}
678+
679+
storage = backing;
671680

672681
// If the outermost property wrapper uses the enclosing self pattern,
673682
// record that.
@@ -691,7 +700,18 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
691700
case TargetImpl::WrapperStorage: {
692701
auto var =
693702
cast<VarDecl>(accessor->getStorage())->getOriginalWrappedProperty();
694-
storage = var->getPropertyWrapperBackingProperty();
703+
auto *backing = var->getPropertyWrapperBackingProperty();
704+
705+
// Error recovery.
706+
if (!backing) {
707+
auto type = storage->getValueInterfaceType();
708+
if (isLValue)
709+
type = LValueType::get(type);
710+
return new (ctx) ErrorExpr(SourceRange(), type);
711+
}
712+
713+
storage = backing;
714+
695715
enclosingSelfAccess =
696716
getEnclosingSelfPropertyWrapperAccess(var, /*forProjected=*/true);
697717
if (!enclosingSelfAccess) {
@@ -976,12 +996,21 @@ void createPropertyStoreOrCallSuperclassSetter(AccessorDecl *accessor,
976996
value = synthesizeCopyWithZoneCall(value, property, ctx);
977997
}
978998

999+
// Error recovery.
1000+
if (value->getType()->hasError())
1001+
return;
1002+
9791003
Expr *dest = buildStorageReference(accessor, storage, target,
9801004
/*isLValue=*/true, ctx);
9811005

9821006
// A lazy property setter will store a value of type T into underlying storage
9831007
// of type T?.
9841008
auto destType = dest->getType()->getWithoutSpecifierType();
1009+
1010+
// Error recovery.
1011+
if (destType->hasError())
1012+
return;
1013+
9851014
if (!destType->isEqual(value->getType())) {
9861015
assert(destType->getOptionalObjectType()->isEqual(value->getType()));
9871016
value = new (ctx) InjectIntoOptionalExpr(value, destType);
@@ -1172,17 +1201,25 @@ synthesizeLazyGetterBody(AccessorDecl *Get, VarDecl *VD, VarDecl *Storage,
11721201
// Take the initializer from the PatternBindingDecl for VD.
11731202
// TODO: This doesn't work with complicated patterns like:
11741203
// lazy var (a,b) = foo()
1175-
auto *InitValue = VD->getParentInitializer();
11761204
auto PBD = VD->getParentPatternBinding();
11771205
unsigned entryIndex = PBD->getPatternEntryIndexForVarDecl(VD);
1178-
PBD->setInitializerSubsumed(entryIndex);
11791206

1180-
if (!PBD->isInitializerChecked(entryIndex))
1181-
TC.typeCheckPatternBinding(PBD, entryIndex);
1207+
Expr *InitValue;
1208+
if (PBD->getPatternList()[entryIndex].getInit()) {
1209+
PBD->setInitializerSubsumed(entryIndex);
1210+
1211+
if (!PBD->isInitializerChecked(entryIndex))
1212+
TC.typeCheckPatternBinding(PBD, entryIndex);
1213+
1214+
InitValue = PBD->getPatternList()[entryIndex].getInit();
1215+
} else {
1216+
InitValue = new (Ctx) ErrorExpr(SourceRange(), Tmp2VD->getType());
1217+
}
11821218

11831219
// Recontextualize any closure declcontexts nested in the initializer to
11841220
// realize that they are in the getter function.
11851221
Get->getImplicitSelfDecl()->setDeclContext(Get);
1222+
11861223
InitValue->walk(RecontextualizeClosures(Get));
11871224

11881225
// Wrap the initializer in a LazyInitializerExpr to avoid walking it twice.
@@ -1226,6 +1263,12 @@ synthesizePropertyWrapperGetterBody(AccessorDecl *getter, ASTContext &ctx) {
12261263
return synthesizeTrivialGetterBody(getter, TargetImpl::Wrapper, ctx);
12271264
}
12281265

1266+
static std::pair<BraceStmt *, bool>
1267+
synthesizeInvalidAccessor(AccessorDecl *accessor, ASTContext &ctx) {
1268+
auto loc = accessor->getLoc();
1269+
return { BraceStmt::create(ctx, loc, ArrayRef<ASTNode>(), loc, true), true };
1270+
}
1271+
12291272
static std::pair<BraceStmt *, bool>
12301273
synthesizeGetterBody(AccessorDecl *getter, ASTContext &ctx) {
12311274
auto storage = getter->getStorage();
@@ -1257,7 +1300,7 @@ synthesizeGetterBody(AccessorDecl *getter, ASTContext &ctx) {
12571300
return synthesizeTrivialGetterBody(getter, ctx);
12581301

12591302
case ReadImplKind::Get:
1260-
llvm_unreachable("synthesizing getter that already exists?");
1303+
return synthesizeInvalidAccessor(getter, ctx);
12611304

12621305
case ReadImplKind::Inherited:
12631306
return synthesizeInheritedGetterBody(getter, ctx);
@@ -1490,7 +1533,7 @@ synthesizeSetterBody(AccessorDecl *setter, ASTContext &ctx) {
14901533
return synthesizeInheritedWithObserversSetterBody(setter, ctx);
14911534

14921535
case WriteImplKind::Set:
1493-
llvm_unreachable("synthesizing setter for unknown reason?");
1536+
return synthesizeInvalidAccessor(setter, ctx);
14941537

14951538
case WriteImplKind::MutableAddress:
14961539
return synthesizeMutableAddressSetterBody(setter, ctx);
@@ -1547,17 +1590,14 @@ synthesizeModifyCoroutineBody(AccessorDecl *modify, ASTContext &ctx) {
15471590
return synthesizeCoroutineAccessorBody(modify, ctx);
15481591
}
15491592

1550-
std::pair<BraceStmt *, bool>
1593+
static std::pair<BraceStmt *, bool>
15511594
synthesizeAccessorBody(AbstractFunctionDecl *fn, void *) {
15521595
auto *accessor = cast<AccessorDecl>(fn);
15531596
auto &ctx = accessor->getASTContext();
15541597

15551598
if (ctx.Stats)
15561599
ctx.Stats->getFrontendCounters().NumAccessorBodiesSynthesized++;
15571600

1558-
if (accessor->isInvalid() || ctx.hadError())
1559-
return { nullptr, true };
1560-
15611601
switch (accessor->getAccessorKind()) {
15621602
case AccessorKind::Get:
15631603
return synthesizeGetterBody(accessor, ctx);

test/attr/attr_objc.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -849,17 +849,21 @@ class infer_instanceVar1 {
849849
var observingAccessorsVar1: Int {
850850
// CHECK: @_hasStorage @objc var observingAccessorsVar1: Int {
851851
willSet {}
852-
// CHECK-NEXT: {{^}} @objc get
852+
// CHECK-NEXT: {{^}} @objc get {
853+
// CHECK-NEXT: return
854+
// CHECK-NEXT: }
853855
didSet {}
854-
// CHECK-NEXT: {{^}} @objc set
856+
// CHECK-NEXT: {{^}} @objc set {
855857
}
856858

857859
@objc var observingAccessorsVar1_: Int {
858860
// CHECK: {{^}} @objc @_hasStorage var observingAccessorsVar1_: Int {
859861
willSet {}
860-
// CHECK-NEXT: {{^}} @objc get
862+
// CHECK-NEXT: {{^}} @objc get {
863+
// CHECK-NEXT: return
864+
// CHECK-NEXT: }
861865
didSet {}
862-
// CHECK-NEXT: {{^}} @objc set
866+
// CHECK-NEXT: {{^}} @objc set {
863867
}
864868

865869

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
public struct SomeStruct {
2+
var x: InvalidType
3+
}
4+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: not %target-swift-frontend -emit-silgen %S/Inputs/library.swift -primary-file %S/main.swift
2+
3+
public func f(x: SomeStruct) {}
4+
5+
public protocol P {
6+
@_borrowed var x: Int { get set }
7+
}
8+
9+
public struct HasAccessors : P {
10+
public var x: Int = 123
11+
}

0 commit comments

Comments
 (0)