Skip to content

Commit ae5f66a

Browse files
committed
Record throwing property accesses as potential throw sites
1 parent 956c330 commit ae5f66a

File tree

4 files changed

+91
-23
lines changed

4 files changed

+91
-23
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,6 +1455,9 @@ struct PotentialThrowSite {
14551455
/// A non-exhaustive do...catch, which rethrows whatever is thrown from
14561456
/// inside it's `do` block.
14571457
NonExhaustiveDoCatch,
1458+
1459+
/// A property access that can throw an error.
1460+
PropertyAccess,
14581461
} kind;
14591462

14601463
/// The type that describes the potential throw site, such as the type of the
@@ -2070,6 +2073,9 @@ struct DeclReferenceType {
20702073
/// (e.g.) applying the base of a member access. This is the type of the
20712074
/// expression used to form the declaration reference.
20722075
Type adjustedReferenceType;
2076+
2077+
/// The type that could be thrown by accessing this declaration.
2078+
Type thrownErrorTypeOnAccess;
20732079
};
20742080

20752081
/// Describes a system of constraints on type variables, the

lib/Sema/ConstraintSystem.cpp

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,7 @@ Type ConstraintSystem::getCaughtErrorType(CatchNode catchNode) {
456456

457457
case PotentialThrowSite::ExplicitThrow:
458458
case PotentialThrowSite::NonExhaustiveDoCatch:
459+
case PotentialThrowSite::PropertyAccess:
459460
thrownErrorType = type;
460461
break;
461462
}
@@ -1809,7 +1810,7 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
18091810

18101811
// The reference implicitly binds 'self'.
18111812
return {origOpenedType, openedType,
1812-
origOpenedType->getResult(), openedType->getResult()};
1813+
origOpenedType->getResult(), openedType->getResult(), Type()};
18131814
}
18141815

18151816
// Unqualified reference to a local or global function.
@@ -1854,7 +1855,7 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
18541855
// If we opened up any type variables, record the replacements.
18551856
recordOpenedTypes(locator, replacements);
18561857

1857-
return { origOpenedType, openedType, origOpenedType, openedType };
1858+
return { origOpenedType, openedType, origOpenedType, openedType, Type() };
18581859
}
18591860

18601861
// Unqualified reference to a type.
@@ -1876,11 +1877,11 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
18761877

18771878
// Module types are not wrapped in metatypes.
18781879
if (type->is<ModuleType>())
1879-
return { type, type, type, type };
1880+
return { type, type, type, type, Type() };
18801881

18811882
// If it's a value reference, refer to the metatype.
18821883
type = MetatypeType::get(type);
1883-
return { type, type, type, type };
1884+
return { type, type, type, type, Type() };
18841885
}
18851886

18861887
// Unqualified reference to a macro.
@@ -1898,7 +1899,7 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
18981899

18991900
// FIXME: Should we use replaceParamErrorTypeByPlaceholder() here?
19001901

1901-
return { openedType, openedType, openedType, openedType };
1902+
return { openedType, openedType, openedType, openedType, Type() };
19021903
}
19031904

19041905
// Only remaining case: unqualified reference to a property.
@@ -1911,9 +1912,15 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value,
19111912
getUnopenedTypeOfReference(varDecl, Type(), useDC, /*base=*/nullptr,
19121913
wantInterfaceType);
19131914

1915+
Type thrownErrorType;
1916+
if (auto accessor = varDecl->getEffectfulGetAccessor()) {
1917+
thrownErrorType =
1918+
accessor->getEffectiveThrownErrorType().value_or(Type());
1919+
}
1920+
19141921
assert(!valueType->hasUnboundGenericType() &&
19151922
!valueType->hasTypeParameter());
1916-
return { valueType, valueType, valueType, valueType };
1923+
return { valueType, valueType, valueType, valueType, thrownErrorType };
19171924
}
19181925

19191926
/// Bind type variables for archetypes that are determined from
@@ -2640,13 +2647,13 @@ ConstraintSystem::getTypeOfMemberReference(
26402647
memberTy = MetatypeType::get(memberTy);
26412648

26422649
auto openedType = FunctionType::get({baseObjParam}, memberTy);
2643-
return { openedType, openedType, memberTy, memberTy };
2650+
return { openedType, openedType, memberTy, memberTy, Type() };
26442651
}
26452652

26462653
if (isa<AbstractFunctionDecl>(value) || isa<EnumElementDecl>(value)) {
26472654
if (value->getInterfaceType()->is<ErrorType>()) {
26482655
auto genericErrorTy = ErrorType::get(getASTContext());
2649-
return { genericErrorTy, genericErrorTy, genericErrorTy, genericErrorTy };
2656+
return { genericErrorTy, genericErrorTy, genericErrorTy, genericErrorTy, Type() };
26502657
}
26512658
}
26522659

@@ -2665,6 +2672,7 @@ ConstraintSystem::getTypeOfMemberReference(
26652672
if (genericSig)
26662673
openGenericParameters(outerDC, genericSig, replacements, locator);
26672674

2675+
Type thrownErrorType;
26682676
if (isa<AbstractFunctionDecl>(value) || isa<EnumElementDecl>(value)) {
26692677
// This is the easy case.
26702678
openedType = value->getInterfaceType()->castTo<AnyFunctionType>();
@@ -2674,20 +2682,14 @@ ConstraintSystem::getTypeOfMemberReference(
26742682
[&](Type type) { return openType(type, replacements, locator); });
26752683
}
26762684
} else {
2677-
// Figure out the effect information for the reference.
2678-
FunctionType::ExtInfo info;
2685+
// If the storage has a throwing getter, save the thrown error type..
26792686
auto storage = cast<AbstractStorageDecl>(value);
2680-
2681-
// If the storage has a throwing getter, record that in the type.
2682-
if (auto effectfulGetter = storage->getEffectfulGetAccessor()) {
2683-
if (effectfulGetter->hasThrows()) {
2684-
Type thrownErrorType = effectfulGetter->getThrownInterfaceType();
2685-
info = info.withThrows(true, thrownErrorType);
2686-
}
2687+
if (auto accessor = storage->getEffectfulGetAccessor()) {
2688+
thrownErrorType = accessor->getEffectiveThrownErrorType().value_or(Type());
26872689
}
26882690

26892691
// For a property, build a type (Self) -> PropType.
2690-
// For a subscript, build a type (Self) -> (Indices...) -> ElementType.
2692+
// For a subscript, build a type (Self) -> (Indices...) throws(?) -> ElementType.
26912693
//
26922694
// If the access is mutating, wrap the storage type in an lvalue type.
26932695
Type refType;
@@ -2700,6 +2702,14 @@ ConstraintSystem::getTypeOfMemberReference(
27002702
auto indices = subscript->getInterfaceType()
27012703
->castTo<AnyFunctionType>()->getParams();
27022704

2705+
// Transfer the thrown error type into the subscript reference type,
2706+
// which will be used in the application.
2707+
FunctionType::ExtInfo info;
2708+
if (thrownErrorType) {
2709+
info = info.withThrows(true, thrownErrorType);
2710+
thrownErrorType = Type();
2711+
}
2712+
27032713
refType = FunctionType::get(indices, elementTy, info);
27042714
} else {
27052715
// Delay the adjustment for preconcurrency until after we've formed
@@ -2728,9 +2738,13 @@ ConstraintSystem::getTypeOfMemberReference(
27282738
if (genericSig) {
27292739
selfTy = openType(selfTy, replacements, locator);
27302740
refType = openType(refType, replacements, locator);
2741+
2742+
if (thrownErrorType)
2743+
thrownErrorType = openType(thrownErrorType, replacements, locator);
27312744
}
27322745
FunctionType::Param selfParam(selfTy, Identifier(), selfFlags);
27332746

2747+
FunctionType::ExtInfo info;
27342748
openedType = FunctionType::get({selfParam}, refType, info);
27352749
}
27362750
assert(!openedType->hasTypeParameter());
@@ -2863,7 +2877,7 @@ ConstraintSystem::getTypeOfMemberReference(
28632877
// If we opened up any type variables, record the replacements.
28642878
recordOpenedTypes(locator, replacements);
28652879

2866-
return { origOpenedType, openedType, origType, type };
2880+
return { origOpenedType, openedType, origType, type, thrownErrorType };
28672881
}
28682882

28692883
Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator,
@@ -3090,7 +3104,7 @@ static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics(
30903104
// FIXME: Verify ExtInfo state is correct, not working by accident.
30913105
FunctionType::ExtInfo info;
30923106
auto refType = FunctionType::get({inputArg}, output, info);
3093-
return {refType, refType, refType, refType};
3107+
return {refType, refType, refType, refType, Type()};
30943108
}
30953109
case DeclTypeCheckingSemantics::WithoutActuallyEscaping: {
30963110
// Proceed with a "WithoutActuallyEscaping" operation. The body closure
@@ -3125,7 +3139,7 @@ static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics(
31253139
.withAsync(true)
31263140
.withThrows(true, /*FIXME:*/Type())
31273141
.build());
3128-
return {refType, refType, refType, refType};
3142+
return {refType, refType, refType, refType, Type()};
31293143
}
31303144
case DeclTypeCheckingSemantics::OpenExistential: {
31313145
// The body closure receives a freshly-opened archetype constrained by the
@@ -3158,7 +3172,7 @@ static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics(
31583172
.withThrows(true, /*FIXME:*/Type())
31593173
.withAsync(true)
31603174
.build());
3161-
return {refType, refType, refType, refType};
3175+
return {refType, refType, refType, refType, Type()};
31623176
}
31633177
}
31643178

@@ -3751,6 +3765,7 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
37513765
Type adjustedOpenedType;
37523766
Type refType;
37533767
Type adjustedRefType;
3768+
Type thrownErrorTypeOnAccess;
37543769

37553770
switch (auto kind = choice.getKind()) {
37563771
case OverloadChoiceKind::Decl:
@@ -3784,7 +3799,7 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
37843799
adjustedOpenedType = declRefType.adjustedOpenedType;
37853800
refType = declRefType.referenceType;
37863801
adjustedRefType = declRefType.adjustedReferenceType;
3787-
3802+
thrownErrorTypeOnAccess = declRefType.thrownErrorTypeOnAccess;
37883803
break;
37893804
}
37903805

@@ -3951,6 +3966,13 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
39513966
}
39523967
}
39533968

3969+
// If accessing this declaration could throw an error, record this as a
3970+
// potential throw site.
3971+
if (thrownErrorTypeOnAccess) {
3972+
recordPotentialThrowSite(
3973+
PotentialThrowSite::PropertyAccess, thrownErrorTypeOnAccess, locator);
3974+
}
3975+
39543976
// Note that we have resolved this overload.
39553977
auto overload = SelectedOverload{
39563978
choice, openedType, adjustedOpenedType, refType, adjustedRefType,

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,6 +1670,9 @@ void ConstraintSystem::print(raw_ostream &out) const {
16701670
case PotentialThrowSite::NonExhaustiveDoCatch:
16711671
out << " - non-exhaustive do..catch @ ";
16721672
break;
1673+
case PotentialThrowSite::PropertyAccess:
1674+
out << " - property access @ ";
1675+
break;
16731676
}
16741677

16751678
throwSite.second.locator->dump(&getASTContext().SourceMgr, out);

test/stmt/typed_throws.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,24 @@ struct ThrowingMembers {
196196
subscript(i: Int) -> Int {
197197
get throws(MyError) { i }
198198
}
199+
200+
var intOrThrows: Int {
201+
get throws(MyError) { 5 }
202+
}
199203
}
200204

201205
struct ThrowingStaticSubscript {
202206
static subscript(i: Int) -> Int {
203207
get throws(MyError) { i }
204208
}
209+
210+
static var intOrThrows: Int {
211+
get throws(MyError) { 5 }
212+
}
213+
}
214+
215+
var globalIntOrThrows: Int {
216+
get throws(MyError) { 5 }
205217
}
206218

207219
func testDoCatchInClosure(cond: Bool, x: ThrowingMembers) {
@@ -262,4 +274,29 @@ func testDoCatchInClosure(cond: Bool, x: ThrowingMembers) {
262274
let _: MyError = error
263275
}
264276
}
277+
278+
// Property accesses as potential throw sites
279+
apply {
280+
do {
281+
_ = try x.intOrThrows
282+
} catch {
283+
let _: MyError = error
284+
}
285+
}
286+
287+
apply {
288+
do {
289+
_ = try ThrowingStaticSubscript.intOrThrows
290+
} catch {
291+
let _: MyError = error
292+
}
293+
}
294+
295+
apply {
296+
do {
297+
_ = try globalIntOrThrows
298+
} catch {
299+
let _: MyError = error
300+
}
301+
}
265302
}

0 commit comments

Comments
 (0)