Skip to content

Commit 7f83ece

Browse files
authored
Merge pull request #4388 from slavapestov/escaping-fixes-3.0
Sema: Three fixes for the new @escaping attribute (3.0)
2 parents 1641bdc + c1214fe commit 7f83ece

21 files changed

+190
-119
lines changed

lib/Sema/TypeCheckType.cpp

Lines changed: 105 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,38 @@ static bool diagnoseAvailability(Type ty, IdentTypeRepr *IdType, SourceLoc Loc,
14021402
return false;
14031403
}
14041404

1405+
/// Whether the given DC is a noescape-by-default context, i.e. not a property
1406+
/// setter
1407+
static bool isDefaultNoEscapeContext(const DeclContext *DC) {
1408+
auto funcDecl = dyn_cast<FuncDecl>(DC);
1409+
return !funcDecl || !funcDecl->isSetter();
1410+
}
1411+
1412+
// Hack to apply context-specific @escaping to an AST function type.
1413+
static Type adjustFunctionExtInfo(DeclContext *DC,
1414+
Type ty,
1415+
TypeResolutionOptions options) {
1416+
// Remember whether this is a function parameter.
1417+
bool isFunctionParam =
1418+
options.contains(TR_FunctionInput) ||
1419+
options.contains(TR_ImmediateFunctionInput);
1420+
1421+
bool defaultNoEscape = isFunctionParam && isDefaultNoEscapeContext(DC);
1422+
1423+
// Desugar here
1424+
auto *funcTy = ty->castTo<FunctionType>();
1425+
auto extInfo = funcTy->getExtInfo();
1426+
if (defaultNoEscape && !extInfo.isNoEscape()) {
1427+
extInfo = extInfo.withNoEscape();
1428+
1429+
// We lost the sugar to flip the isNoEscape bit
1430+
return FunctionType::get(funcTy->getInput(), funcTy->getResult(), extInfo);
1431+
}
1432+
1433+
// Note: original sugared type
1434+
return ty;
1435+
}
1436+
14051437
/// \brief Returns a valid type or ErrorType in case of an error.
14061438
Type TypeChecker::resolveIdentifierType(
14071439
DeclContext *DC,
@@ -1432,6 +1464,11 @@ Type TypeChecker::resolveIdentifierType(
14321464
return ErrorType::get(Context);
14331465
}
14341466

1467+
// Hack to apply context-specific @escaping to a typealias with an underlying
1468+
// function type.
1469+
if (result->is<FunctionType>())
1470+
result = adjustFunctionExtInfo(DC, result, options);
1471+
14351472
// We allow a type to conform to a protocol that is less available than
14361473
// the type itself. This enables a type to retroactively model or directly
14371474
// conform to a protocol only available on newer OSes and yet still be used on
@@ -1637,29 +1674,20 @@ Type TypeChecker::resolveType(TypeRepr *TyR, DeclContext *DC,
16371674
return result;
16381675
}
16391676

1640-
/// Whether the given DC is a noescape-by-default context, i.e. not a property
1641-
/// setter
1642-
static bool isDefaultNoEscapeContext(const DeclContext *DC) {
1643-
auto funcDecl = dyn_cast<FuncDecl>(DC);
1644-
return !funcDecl || !funcDecl->isSetter();
1645-
}
1646-
16471677
Type TypeResolver::resolveType(TypeRepr *repr, TypeResolutionOptions options) {
16481678
assert(repr && "Cannot validate null TypeReprs!");
16491679

16501680
// If we know the type representation is invalid, just return an
16511681
// error type.
16521682
if (repr->isInvalid()) return ErrorType::get(TC.Context);
16531683

1654-
// Remember whether this is a function parameter.
1655-
bool isFunctionParam =
1656-
options.contains(TR_FunctionInput) ||
1657-
options.contains(TR_ImmediateFunctionInput);
1658-
16591684
// Strip the "is function input" bits unless this is a type that knows about
16601685
// them.
1661-
if (!isa<InOutTypeRepr>(repr) && !isa<TupleTypeRepr>(repr) &&
1662-
!isa<AttributedTypeRepr>(repr)) {
1686+
if (!isa<InOutTypeRepr>(repr) &&
1687+
!isa<TupleTypeRepr>(repr) &&
1688+
!isa<AttributedTypeRepr>(repr) &&
1689+
!isa<FunctionTypeRepr>(repr) &&
1690+
!isa<IdentTypeRepr>(repr)) {
16631691
options -= TR_ImmediateFunctionInput;
16641692
options -= TR_FunctionInput;
16651693
}
@@ -1686,11 +1714,10 @@ Type TypeResolver::resolveType(TypeRepr *repr, TypeResolutionOptions options) {
16861714
case TypeReprKind::Function:
16871715
if (!(options & TR_SILType)) {
16881716
// Default non-escaping for closure parameters
1689-
auto info = AnyFunctionType::ExtInfo().withNoEscape(
1690-
isFunctionParam &&
1691-
isDefaultNoEscapeContext(DC));
1692-
return resolveASTFunctionType(cast<FunctionTypeRepr>(repr), options,
1693-
info);
1717+
auto result = resolveASTFunctionType(cast<FunctionTypeRepr>(repr), options);
1718+
if (result && result->is<FunctionType>())
1719+
return adjustFunctionExtInfo(DC, result, options);
1720+
return result;
16941721
}
16951722
return resolveSILFunctionType(cast<FunctionTypeRepr>(repr), options);
16961723

@@ -1747,8 +1774,6 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
17471774
bool isFunctionParam =
17481775
options.contains(TR_FunctionInput) ||
17491776
options.contains(TR_ImmediateFunctionInput);
1750-
options -= TR_ImmediateFunctionInput;
1751-
options -= TR_FunctionInput;
17521777

17531778
// The type we're working with, in case we want to build it differently
17541779
// based on the attributes we see.
@@ -1772,7 +1797,11 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
17721797
if (base) {
17731798
Optional<MetatypeRepresentation> storedRepr;
17741799
// The instance type is not a SIL type.
1775-
auto instanceOptions = options - TR_SILType;
1800+
auto instanceOptions = options;
1801+
instanceOptions -= TR_SILType;
1802+
instanceOptions -= TR_ImmediateFunctionInput;
1803+
instanceOptions -= TR_FunctionInput;
1804+
17761805
auto instanceTy = resolveType(base, instanceOptions);
17771806
if (!instanceTy || instanceTy->is<ErrorType>())
17781807
return instanceTy;
@@ -1901,10 +1930,6 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
19011930

19021931
ty = resolveSILFunctionType(fnRepr, options, extInfo, calleeConvention);
19031932
if (!ty || ty->is<ErrorType>()) return ty;
1904-
1905-
for (auto i : FunctionAttrs)
1906-
attrs.clearAttribute(i);
1907-
attrs.convention = None;
19081933
} else if (hasFunctionAttr && fnRepr) {
19091934

19101935
FunctionType::Representation rep = FunctionType::Representation::Swift;
@@ -1948,29 +1973,54 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
19481973
.fixItReplace(resultRange, "Never");
19491974
}
19501975

1951-
bool defaultNoEscape = false;
1952-
if (isFunctionParam && !attrs.has(TAK_escaping)) {
1953-
defaultNoEscape = isDefaultNoEscapeContext(DC);
1954-
}
1955-
1956-
if (isFunctionParam && attrs.has(TAK_noescape) &&
1957-
isDefaultNoEscapeContext(DC)) {
1976+
if (attrs.has(TAK_noescape)) {
19581977
// FIXME: diagnostic to tell user this is redundant and drop it
19591978
}
19601979

19611980
// Resolve the function type directly with these attributes.
19621981
FunctionType::ExtInfo extInfo(rep,
19631982
attrs.has(TAK_autoclosure),
1964-
defaultNoEscape | attrs.has(TAK_noescape),
1983+
attrs.has(TAK_noescape),
19651984
fnRepr->throws());
19661985

19671986
ty = resolveASTFunctionType(fnRepr, options, extInfo);
19681987
if (!ty || ty->is<ErrorType>()) return ty;
1988+
}
19691989

1970-
for (auto i : FunctionAttrs)
1971-
attrs.clearAttribute(i);
1972-
attrs.convention = None;
1973-
} else if (hasFunctionAttr) {
1990+
auto instanceOptions = options;
1991+
instanceOptions -= TR_ImmediateFunctionInput;
1992+
instanceOptions -= TR_FunctionInput;
1993+
1994+
// If we didn't build the type differently above, we might have
1995+
// a typealias pointing at a function type with the @escaping
1996+
// attribute. Resolve the type as if it were in non-parameter
1997+
// context, and then set isNoEscape if @escaping is not present.
1998+
if (!ty) ty = resolveType(repr, instanceOptions);
1999+
if (!ty || ty->is<ErrorType>()) return ty;
2000+
2001+
// Handle @escaping
2002+
if (hasFunctionAttr && ty->is<FunctionType>()) {
2003+
if (attrs.has(TAK_escaping)) {
2004+
// The attribute is meaningless except on parameter types.
2005+
if (!isFunctionParam) {
2006+
auto &SM = TC.Context.SourceMgr;
2007+
auto loc = attrs.getLoc(TAK_escaping);
2008+
auto attrRange = SourceRange(
2009+
loc.getAdvancedLoc(-1),
2010+
Lexer::getLocForEndOfToken(SM, loc));
2011+
2012+
TC.diagnose(loc, diag::escaping_function_type)
2013+
.fixItRemove(attrRange);
2014+
}
2015+
2016+
attrs.clearAttribute(TAK_escaping);
2017+
} else {
2018+
// No attribute; set the isNoEscape bit if we're in parameter context.
2019+
ty = adjustFunctionExtInfo(DC, ty, options);
2020+
}
2021+
}
2022+
2023+
if (hasFunctionAttr && !fnRepr) {
19742024
// @autoclosure usually auto-implies @noescape, don't complain about both
19752025
// of them.
19762026
if (attrs.has(TAK_autoclosure))
@@ -1983,11 +2033,11 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
19832033
attrs.clearAttribute(i);
19842034
}
19852035
}
1986-
}
1987-
1988-
// If we didn't build the type differently above, build it normally now.
1989-
if (!ty) ty = resolveType(repr, options);
1990-
if (!ty || ty->is<ErrorType>()) return ty;
2036+
} else if (hasFunctionAttr && fnRepr) {
2037+
for (auto i : FunctionAttrs)
2038+
attrs.clearAttribute(i);
2039+
attrs.convention = None;
2040+
}
19912041

19922042
// In SIL, handle @opened (n), which creates an existential archetype.
19932043
if (attrs.has(TAK_opened)) {
@@ -2036,6 +2086,9 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
20362086
Type TypeResolver::resolveASTFunctionType(FunctionTypeRepr *repr,
20372087
TypeResolutionOptions options,
20382088
FunctionType::ExtInfo extInfo) {
2089+
options -= TR_ImmediateFunctionInput;
2090+
options -= TR_FunctionInput;
2091+
20392092
Type inputTy = resolveType(repr->getArgsTypeRepr(),
20402093
options | TR_ImmediateFunctionInput);
20412094
if (!inputTy || inputTy->is<ErrorType>()) return inputTy;
@@ -2100,6 +2153,9 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr,
21002153
TypeResolutionOptions options,
21012154
SILFunctionType::ExtInfo extInfo,
21022155
ParameterConvention callee) {
2156+
options -= TR_ImmediateFunctionInput;
2157+
options -= TR_FunctionInput;
2158+
21032159
bool hasError = false;
21042160

21052161
SmallVector<SILParameterInfo, 4> params;
@@ -2428,9 +2484,12 @@ Type TypeResolver::resolveTupleType(TupleTypeRepr *repr,
24282484

24292485
// If this is the top level of a function input list, peel off the
24302486
// ImmediateFunctionInput marker and install a FunctionInput one instead.
2431-
auto elementOptions = withoutContext(options);
2432-
if (options & TR_ImmediateFunctionInput)
2433-
elementOptions |= TR_FunctionInput;
2487+
auto elementOptions = options;
2488+
if (!repr->isParenType()) {
2489+
elementOptions = withoutContext(elementOptions);
2490+
if (options & TR_ImmediateFunctionInput)
2491+
elementOptions |= TR_FunctionInput;
2492+
}
24342493

24352494
for (auto tyR : repr->getElements()) {
24362495
NamedTypeRepr *namedTyR = dyn_cast<NamedTypeRepr>(tyR);

lib/Serialization/Serialization.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3097,9 +3097,9 @@ void Serializer::writeType(Type ty) {
30973097
}
30983098

30993099
case TypeKind::Optional: {
3100-
auto sliceTy = cast<OptionalType>(ty.getPointer());
3100+
auto optionalTy = cast<OptionalType>(ty.getPointer());
31013101

3102-
Type base = sliceTy->getBaseType();
3102+
Type base = optionalTy->getBaseType();
31033103

31043104
unsigned abbrCode = DeclTypeAbbrCodes[OptionalTypeLayout::Code];
31053105
OptionalTypeLayout::emitRecord(Out, ScratchRecord, abbrCode,
@@ -3108,13 +3108,13 @@ void Serializer::writeType(Type ty) {
31083108
}
31093109

31103110
case TypeKind::ImplicitlyUnwrappedOptional: {
3111-
auto sliceTy = cast<ImplicitlyUnwrappedOptionalType>(ty.getPointer());
3111+
auto optionalTy = cast<ImplicitlyUnwrappedOptionalType>(ty.getPointer());
31123112

3113-
Type base = sliceTy->getBaseType();
3113+
Type base = optionalTy->getBaseType();
31143114

31153115
unsigned abbrCode = DeclTypeAbbrCodes[ImplicitlyUnwrappedOptionalTypeLayout::Code];
31163116
ImplicitlyUnwrappedOptionalTypeLayout::emitRecord(Out, ScratchRecord, abbrCode,
3117-
addTypeRef(base));
3117+
addTypeRef(base));
31183118
break;
31193119
}
31203120

stdlib/private/StdlibCollectionUnittest/CheckCollectionType.swift.gyb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -511,8 +511,8 @@ internal func _product<C1 : Collection, C2 : Collection>(
511511
wrapValueIntoEquatable: @escaping (
512512
MinimalEquatableValue) -> CollectionWithEquatableElement.Iterator.Element,
513513

514-
extractValueFromEquatable:
515-
((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
514+
extractValueFromEquatable: @escaping (
515+
CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue,
516516

517517
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
518518
outOfBoundsIndexOffset: Int = 1,

stdlib/private/StdlibCollectionUnittest/CheckMutableCollectionType.swift.gyb

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,11 @@ extension TestSuite {
9292

9393
makeCollectionOfEquatable: @escaping ([CollectionWithEquatableElement.Iterator.Element]) -> CollectionWithEquatableElement,
9494
wrapValueIntoEquatable: @escaping (MinimalEquatableValue) -> CollectionWithEquatableElement.Iterator.Element,
95-
extractValueFromEquatable: ((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
95+
extractValueFromEquatable: @escaping ((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
9696

9797
makeCollectionOfComparable: @escaping ([CollectionWithComparableElement.Iterator.Element]) -> CollectionWithComparableElement,
9898
wrapValueIntoComparable: @escaping (MinimalComparableValue) -> CollectionWithComparableElement.Iterator.Element,
99-
extractValueFromComparable: ((CollectionWithComparableElement.Iterator.Element) -> MinimalComparableValue),
99+
extractValueFromComparable: @escaping ((CollectionWithComparableElement.Iterator.Element) -> MinimalComparableValue),
100100

101101
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
102102
outOfBoundsIndexOffset: Int = 1,
@@ -502,8 +502,8 @@ self.test("\(testNamePrefix).sorted/DispatchesThrough_withUnsafeMutableBufferPoi
502502

503503
func checkSort_${'Predicate' if predicate else 'WhereElementIsComparable'}(
504504
sequence: [Int],
505-
equalImpl: ((Int, Int) -> Bool),
506-
lessImpl: ((Int, Int) -> Bool),
505+
equalImpl: @escaping ((Int, Int) -> Bool),
506+
lessImpl: @escaping ((Int, Int) -> Bool),
507507
verifyOrder: Bool
508508
) {
509509
% if predicate:
@@ -683,11 +683,11 @@ self.test("\(testNamePrefix).partition/InvalidOrderings") {
683683

684684
makeCollectionOfEquatable: @escaping ([CollectionWithEquatableElement.Iterator.Element]) -> CollectionWithEquatableElement,
685685
wrapValueIntoEquatable: @escaping (MinimalEquatableValue) -> CollectionWithEquatableElement.Iterator.Element,
686-
extractValueFromEquatable: ((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
686+
extractValueFromEquatable: @escaping ((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
687687

688688
makeCollectionOfComparable: @escaping ([CollectionWithComparableElement.Iterator.Element]) -> CollectionWithComparableElement,
689689
wrapValueIntoComparable: @escaping (MinimalComparableValue) -> CollectionWithComparableElement.Iterator.Element,
690-
extractValueFromComparable: ((CollectionWithComparableElement.Iterator.Element) -> MinimalComparableValue),
690+
extractValueFromComparable: @escaping ((CollectionWithComparableElement.Iterator.Element) -> MinimalComparableValue),
691691

692692
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
693693
outOfBoundsIndexOffset: Int = 1,
@@ -836,11 +836,11 @@ self.test("\(testNamePrefix).partition/DispatchesThrough_withUnsafeMutableBuffer
836836

837837
makeCollectionOfEquatable: @escaping ([CollectionWithEquatableElement.Iterator.Element]) -> CollectionWithEquatableElement,
838838
wrapValueIntoEquatable: @escaping (MinimalEquatableValue) -> CollectionWithEquatableElement.Iterator.Element,
839-
extractValueFromEquatable: ((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
839+
extractValueFromEquatable: @escaping ((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
840840

841841
makeCollectionOfComparable: @escaping ([CollectionWithComparableElement.Iterator.Element]) -> CollectionWithComparableElement,
842842
wrapValueIntoComparable: @escaping (MinimalComparableValue) -> CollectionWithComparableElement.Iterator.Element,
843-
extractValueFromComparable: ((CollectionWithComparableElement.Iterator.Element) -> MinimalComparableValue),
843+
extractValueFromComparable: @escaping ((CollectionWithComparableElement.Iterator.Element) -> MinimalComparableValue),
844844

845845
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
846846
outOfBoundsIndexOffset: Int = 1,
@@ -919,8 +919,8 @@ self.test("\(testNamePrefix).partition/DispatchesThrough_withUnsafeMutableBuffer
919919

920920
func checkSortInPlace_${'Predicate' if predicate else 'WhereElementIsComparable'}(
921921
sequence: [Int],
922-
equalImpl: ((Int, Int) -> Bool),
923-
lessImpl: ((Int, Int) -> Bool),
922+
equalImpl: @escaping ((Int, Int) -> Bool),
923+
lessImpl: @escaping ((Int, Int) -> Bool),
924924
verifyOrder: Bool
925925
) {
926926
% if predicate:

stdlib/private/StdlibCollectionUnittest/CheckRangeReplaceableCollectionType.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ extension TestSuite {
456456

457457
makeCollectionOfEquatable: @escaping ([CollectionWithEquatableElement.Iterator.Element]) -> CollectionWithEquatableElement,
458458
wrapValueIntoEquatable: @escaping (MinimalEquatableValue) -> CollectionWithEquatableElement.Iterator.Element,
459-
extractValueFromEquatable: ((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
459+
extractValueFromEquatable: @escaping ((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
460460

461461
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
462462
outOfBoundsIndexOffset: Int = 1,
@@ -1168,7 +1168,7 @@ self.test("\(testNamePrefix).OperatorPlus") {
11681168

11691169
makeCollectionOfEquatable: @escaping ([CollectionWithEquatableElement.Iterator.Element]) -> CollectionWithEquatableElement,
11701170
wrapValueIntoEquatable: @escaping (MinimalEquatableValue) -> CollectionWithEquatableElement.Iterator.Element,
1171-
extractValueFromEquatable: ((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
1171+
extractValueFromEquatable: @escaping ((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
11721172

11731173
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
11741174
outOfBoundsIndexOffset: Int = 1
@@ -1297,7 +1297,7 @@ self.test("\(testNamePrefix).removeLast(n: Int)/whereIndexIsBidirectional/remove
12971297

12981298
makeCollectionOfEquatable: @escaping ([CollectionWithEquatableElement.Iterator.Element]) -> CollectionWithEquatableElement,
12991299
wrapValueIntoEquatable: @escaping (MinimalEquatableValue) -> CollectionWithEquatableElement.Iterator.Element,
1300-
extractValueFromEquatable: ((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
1300+
extractValueFromEquatable: @escaping ((CollectionWithEquatableElement.Iterator.Element) -> MinimalEquatableValue),
13011301

13021302
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
13031303
outOfBoundsIndexOffset: Int = 1

0 commit comments

Comments
 (0)