Skip to content

Commit 5a582a6

Browse files
authored
Merge pull request #28988 from slavapestov/enclosing-self-type-check-expression-crash
Sema: Fix crash-on-invalid with 'enclosing self' property wrappers
2 parents 3e7ab04 + 41a00e5 commit 5a582a6

File tree

2 files changed

+76
-24
lines changed

2 files changed

+76
-24
lines changed

lib/Sema/TypeCheckStorage.cpp

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,9 @@ getEnclosingSelfPropertyWrapperAccess(VarDecl *property, bool forProjected) {
596596
return result;
597597
}
598598

599-
/// Build an l-value for the storage of a declaration.
599+
/// Build an l-value for the storage of a declaration. Returns nullptr if there
600+
/// was an error. This should only occur if an invalid declaration was type
601+
/// checked; another diagnostic should have been emitted already.
600602
static Expr *buildStorageReference(AccessorDecl *accessor,
601603
AbstractStorageDecl *storage,
602604
TargetImpl target,
@@ -683,12 +685,8 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
683685
auto *backing = var->getPropertyWrapperBackingProperty();
684686

685687
// Error recovery.
686-
if (!backing) {
687-
auto type = storage->getValueInterfaceType();
688-
if (isLValue)
689-
type = LValueType::get(type);
690-
return new (ctx) ErrorExpr(SourceRange(), type);
691-
}
688+
if (!backing)
689+
return nullptr;
692690

693691
storage = backing;
694692

@@ -730,12 +728,8 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
730728
auto *backing = var->getPropertyWrapperBackingProperty();
731729

732730
// Error recovery.
733-
if (!backing) {
734-
auto type = storage->getValueInterfaceType();
735-
if (isLValue)
736-
type = LValueType::get(type);
737-
return new (ctx) ErrorExpr(SourceRange(), type);
738-
}
731+
if (!backing)
732+
return nullptr;
739733

740734
storage = backing;
741735

@@ -845,7 +839,12 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
845839
ctx, wrapperMetatype, SourceLoc(), args,
846840
subscriptDecl->getFullName().getArgumentNames(), { }, SourceLoc(),
847841
nullptr, subscriptDecl, /*Implicit=*/true);
848-
TypeChecker::typeCheckExpression(lookupExpr, accessor);
842+
843+
// FIXME: Since we're not resolving overloads or anything, we should be
844+
// building fully type-checked AST above; we already have all the
845+
// information that we need.
846+
if (!TypeChecker::typeCheckExpression(lookupExpr, accessor))
847+
return nullptr;
849848

850849
// Make sure we produce an lvalue only when desired.
851850
if (isMemberLValue != lookupExpr->getType()->is<LValueType>()) {
@@ -1043,6 +1042,10 @@ void createPropertyStoreOrCallSuperclassSetter(AccessorDecl *accessor,
10431042
Expr *dest = buildStorageReference(accessor, storage, target,
10441043
/*isLValue=*/true, ctx);
10451044

1045+
// Error recovery.
1046+
if (dest == nullptr)
1047+
return;
1048+
10461049
// A lazy property setter will store a value of type T into underlying storage
10471050
// of type T?.
10481051
auto destType = dest->getType()->getWithoutSpecifierType();
@@ -1052,6 +1055,7 @@ void createPropertyStoreOrCallSuperclassSetter(AccessorDecl *accessor,
10521055
return;
10531056

10541057
if (!destType->isEqual(value->getType())) {
1058+
assert(destType->getOptionalObjectType());
10551059
assert(destType->getOptionalObjectType()->isEqual(value->getType()));
10561060
value = new (ctx) InjectIntoOptionalExpr(value, destType);
10571061
}
@@ -1087,10 +1091,15 @@ synthesizeTrivialGetterBody(AccessorDecl *getter, TargetImpl target,
10871091

10881092
Expr *result =
10891093
createPropertyLoadOrCallSuperclassGetter(getter, storage, target, ctx);
1090-
ASTNode returnStmt = new (ctx) ReturnStmt(SourceLoc(), result,
1091-
/*IsImplicit=*/true);
10921094

1093-
return { BraceStmt::create(ctx, loc, returnStmt, loc, true),
1095+
SmallVector<ASTNode, 2> body;
1096+
if (result != nullptr) {
1097+
ASTNode returnStmt = new (ctx) ReturnStmt(SourceLoc(), result,
1098+
/*IsImplicit=*/true);
1099+
body.push_back(returnStmt);
1100+
}
1101+
1102+
return { BraceStmt::create(ctx, loc, body, loc, true),
10941103
/*isTypeChecked=*/true };
10951104
}
10961105

@@ -1482,7 +1491,13 @@ synthesizeObservedSetterBody(AccessorDecl *Set, TargetImpl target,
14821491
if (VD->getParsedAccessor(AccessorKind::DidSet)) {
14831492
Expr *OldValueExpr
14841493
= buildStorageReference(Set, VD, target, /*isLValue=*/true, Ctx);
1485-
OldValueExpr = new (Ctx) LoadExpr(OldValueExpr, VD->getType());
1494+
1495+
// Error recovery.
1496+
if (OldValueExpr == nullptr) {
1497+
OldValueExpr = new (Ctx) ErrorExpr(SourceRange(), VD->getType());
1498+
} else {
1499+
OldValueExpr = new (Ctx) LoadExpr(OldValueExpr, VD->getType());
1500+
}
14861501

14871502
OldValue = new (Ctx) VarDecl(/*IsStatic*/false, VarDecl::Introducer::Let,
14881503
/*IsCaptureList*/false, SourceLoc(),
@@ -1610,13 +1625,14 @@ synthesizeCoroutineAccessorBody(AccessorDecl *accessor, ASTContext &ctx) {
16101625

16111626
// Build a reference to the storage.
16121627
Expr *ref = buildStorageReference(accessor, storage, target, isLValue, ctx);
1628+
if (ref != nullptr) {
1629+
// Wrap it with an `&` marker if this is a modify.
1630+
ref = maybeWrapInOutExpr(ref, ctx);
16131631

1614-
// Wrap it with an `&` marker if this is a modify.
1615-
ref = maybeWrapInOutExpr(ref, ctx);
1616-
1617-
// Yield it.
1618-
YieldStmt *yield = YieldStmt::create(ctx, loc, loc, ref, loc, true);
1619-
body.push_back(yield);
1632+
// Yield it.
1633+
YieldStmt *yield = YieldStmt::create(ctx, loc, loc, ref, loc, true);
1634+
body.push_back(yield);
1635+
}
16201636

16211637
return { BraceStmt::create(ctx, loc, body, loc, true),
16221638
/*isTypeChecked=*/true };
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %target-swift-frontend -typecheck %s -verify -verify-ignore-unknown
2+
3+
// FIXME: This should produce a diagnostic with a proper
4+
// source location. Right now, we just get three useless errors:
5+
6+
// <unknown>:0: error: type of expression is ambiguous without more context
7+
// <unknown>:0: error: type of expression is ambiguous without more context
8+
// <unknown>:0: error: type of expression is ambiguous without more context
9+
10+
// The actual problem is the type of the subscript declaration is wrong.
11+
12+
public class Store {
13+
@Published public var state: Any
14+
init() {
15+
self.state = 0
16+
}
17+
}
18+
19+
@propertyWrapper public struct Published<Value> {
20+
public init(wrappedValue: Value) {}
21+
public var wrappedValue: Value {
22+
get { fatalError() }
23+
set {}
24+
}
25+
public static subscript(_enclosingInstance object: Any,
26+
wrapped wrappedKeyPath: Any,
27+
storage storageKeyPath: Any)
28+
-> Value {
29+
get { fatalError() }
30+
set {}
31+
}
32+
public struct Publisher {}
33+
public var projectedValue: Publisher {
34+
mutating get { fatalError() }
35+
}
36+
}

0 commit comments

Comments
 (0)