Skip to content

Commit ab14e67

Browse files
committed
Progress towards implementing SE-0049 - Allow autoclosure in parameter types
as well as on parameter decls. Also, tighten up the type checker to look at parameter types instead of decl attributes in some cases (exposing a type checker bug). Still TODO: - Reject autoclosure/noescape on non-parameter types. - Move stdlib and other code to use noescape and autoclosure in the right spot. - Warn about autoclosure/noescape on parameters decls, with a fixit to move it. - Upgrade the warning to an error.
1 parent a961161 commit ab14e67

File tree

11 files changed

+65
-30
lines changed

11 files changed

+65
-30
lines changed

include/swift/AST/Attr.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@
3131
#endif
3232

3333
// Type attributes
34+
TYPE_ATTR(autoclosure)
3435
TYPE_ATTR(convention)
3536
TYPE_ATTR(noreturn)
37+
TYPE_ATTR(noescape)
3638

3739
// SIL-specific attributes
3840
TYPE_ATTR(block_storage)
@@ -46,7 +48,6 @@ TYPE_ATTR(in)
4648
TYPE_ATTR(inout)
4749
TYPE_ATTR(inout_aliasable)
4850
TYPE_ATTR(in_guaranteed)
49-
TYPE_ATTR(noescape)
5051
TYPE_ATTR(owned)
5152
TYPE_ATTR(unowned_inner_pointer)
5253
TYPE_ATTR(guaranteed)

include/swift/AST/Expr.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2972,7 +2972,8 @@ class ClosureExpr : public AbstractClosureExpr {
29722972
/// when a scalar expression is converted to @autoclosure function type.
29732973
/// For example:
29742974
/// \code
2975-
/// @autoclosure var x : () -> Int = 4
2975+
/// func f(x : @autoclosure () -> Int)
2976+
/// f(42) // AutoclosureExpr convert from Int to ()->Int
29762977
/// \endcode
29772978
class AutoClosureExpr : public AbstractClosureExpr {
29782979
BraceStmt *Body;

include/swift/AST/Types.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,13 +2362,10 @@ BEGIN_CAN_TYPE_WRAPPER(AnyFunctionType, Type)
23622362
PROXY_CAN_TYPE_SIMPLE_GETTER(getResult)
23632363
END_CAN_TYPE_WRAPPER(AnyFunctionType, Type)
23642364

2365-
/// FunctionType - A monomorphic function type.
2365+
/// FunctionType - A monomorphic function type, specified with an arrow.
23662366
///
2367-
/// If the AutoClosure bit is set to true, then the input type is known to be ()
2368-
/// and a value of this function type is only assignable (in source code) from
2369-
/// the destination type of the function. Sema inserts an ImplicitClosure to
2370-
/// close over the value. For example:
2371-
/// @autoclosure var x : () -> Int = 4
2367+
/// For example:
2368+
/// let x : (Float, Int) -> Int
23722369
class FunctionType : public AnyFunctionType {
23732370
public:
23742371
/// 'Constructor' Factory Function

lib/AST/ASTPrinter.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3695,9 +3695,12 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
36953695
return Options.ExcludeAttrList.end() != std::find(Options.ExcludeAttrList.
36963696
begin(), Options.ExcludeAttrList.end(), Kind);
36973697
};
3698-
if (info.isAutoClosure() && !IsAttrExcluded(DAK_AutoClosure))
3699-
Printer << "@autoclosure ";
3700-
else if (info.isNoEscape() && !IsAttrExcluded(DAK_NoEscape))
3698+
if (info.isAutoClosure() && !IsAttrExcluded(DAK_AutoClosure)) {
3699+
if (info.isNoEscape())
3700+
Printer << "@autoclosure ";
3701+
else
3702+
Printer << "@autoclosure(escaping) ";
3703+
} else if (info.isNoEscape() && !IsAttrExcluded(DAK_NoEscape))
37013704
// autoclosure implies noescape.
37023705
Printer << "@noescape ";
37033706

lib/Parse/ParseDecl.cpp

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,6 +1546,37 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, bool justChecking) {
15461546
Attributes.setAttr(attr, Loc);
15471547
}
15481548

1549+
// Handle @autoclosure(escaping)
1550+
if (attr == TAK_autoclosure) {
1551+
bool isEscaping = false;
1552+
1553+
// We need to do a bit of lookahead here to make sure we parse a (weird)
1554+
// type like: "@autoclosure (escaping) -> Int" correctly (escaping is the
1555+
// name of a type here). We also want to support the case where the
1556+
// function type coming up is a typealias, e.g. "@autoclosure (escaping) T".
1557+
if (Tok.is(tok::l_paren) && peekToken().getText() == "escaping") {
1558+
Parser::BacktrackingScope Backtrack(*this);
1559+
consumeToken(tok::l_paren);
1560+
consumeToken(tok::identifier);
1561+
isEscaping = Tok.is(tok::r_paren) && peekToken().isNot(tok::arrow);
1562+
}
1563+
1564+
if (isEscaping) {
1565+
consumeToken(tok::l_paren);
1566+
consumeToken(tok::identifier);
1567+
consumeToken(tok::r_paren);
1568+
}
1569+
1570+
if (!justChecking) {
1571+
if (isEscaping)
1572+
;
1573+
else
1574+
Attributes.setAttr(TAK_noescape, Loc);
1575+
}
1576+
}
1577+
1578+
1579+
15491580
// Handle any attribute-specific processing logic.
15501581

15511582
// In just-checking mode, we only need additional parsing for the "cc"
@@ -1697,9 +1728,9 @@ bool Parser::parseDeclAttributeList(DeclAttributes &Attributes,
16971728
Token next = peekToken();
16981729
auto Kind = TypeAttributes::getAttrKindFromString(next.getText());
16991730

1700-
// noescape is only valid as a decl attribute and type attribute (in
1701-
// parameter lists) but we disambiguate it as a decl attribute.
1702-
if (Kind == TAK_noescape)
1731+
// noescape/autoclosure are valid as a decl attribute and type attribute
1732+
// (in parameter lists) but we disambiguate them as a decl attribute.
1733+
if (Kind == TAK_noescape || Kind == TAK_autoclosure)
17031734
Kind = TAK_Count;
17041735

17051736
if (Kind != TAK_Count)

lib/Sema/CSSolver.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ enumerateDirectSupertypes(TypeChecker &tc, Type type) {
290290
// FIXME: Can weaken input type, but we really don't want to get in the
291291
// business of strengthening the result type.
292292

293-
// An [autoclosure] function type can be viewed as scalar of the result
293+
// An @autoclosure function type can be viewed as scalar of the result
294294
// type.
295295
if (functionTy->isAutoClosure())
296296
result.push_back(functionTy->getResult());

lib/Sema/MiscDiagnostics.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,7 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
446446

447447
TC.diagnose(DRE->getStartLoc(), diag::invalid_noescape_use,
448448
DRE->getDecl()->getName(), isa<ParamDecl>(DRE->getDecl()));
449-
if (DRE->getDecl()->getAttrs().hasAttribute<AutoClosureAttr>() &&
450-
DRE->getDecl()->getAttrs().getAttribute<NoEscapeAttr>()->isImplicit())
449+
if (AFT->isAutoClosure())
451450
TC.diagnose(DRE->getDecl()->getLoc(), diag::noescape_autoclosure,
452451
DRE->getDecl()->getName());
453452
}

lib/Sema/TypeCheckExpr.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,8 @@ namespace {
821821

822822
// If VD is a noescape decl, then the closure we're computing this for
823823
// must also be noescape.
824-
if (VD->getAttrs().hasAttribute<NoEscapeAttr>() &&
824+
if (VD->hasType() && VD->getType()->is<AnyFunctionType>() &&
825+
VD->getType()->castTo<AnyFunctionType>()->isNoEscape() &&
825826
!capture.isNoEscape() &&
826827
// Don't repeatedly diagnose the same thing.
827828
Diagnosed.insert(VD).second) {
@@ -832,8 +833,7 @@ namespace {
832833
TC.diagnose(Loc, isDecl ? diag::decl_closure_noescape_use :
833834
diag::closure_noescape_use, VD->getName());
834835

835-
if (VD->getAttrs().hasAttribute<AutoClosureAttr>() &&
836-
VD->getAttrs().getAttribute<NoEscapeAttr>()->isImplicit())
836+
if (VD->getType()->castTo<AnyFunctionType>()->isAutoClosure())
837837
TC.diagnose(VD->getLoc(), diag::noescape_autoclosure,
838838
VD->getName());
839839
}

lib/Sema/TypeCheckType.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,7 +1601,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
16011601
// function-type creator.
16021602
static const TypeAttrKind FunctionAttrs[] = {
16031603
TAK_objc_block, TAK_convention, TAK_thin, TAK_noreturn,
1604-
TAK_callee_owned, TAK_callee_guaranteed, TAK_noescape
1604+
TAK_callee_owned, TAK_callee_guaranteed, TAK_noescape, TAK_autoclosure
16051605
};
16061606

16071607
auto checkUnsupportedAttr = [&](TypeAttrKind attr) {
@@ -1649,8 +1649,6 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
16491649
thin = false;
16501650
}
16511651

1652-
bool isNoEscape = attrs.has(TAK_noescape);
1653-
16541652
auto calleeConvention = ParameterConvention::Direct_Unowned;
16551653
if (attrs.has(TAK_callee_owned)) {
16561654
if (attrs.has(TAK_callee_guaranteed)) {
@@ -1783,8 +1781,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
17831781
// Resolve the function type directly with these attributes.
17841782
FunctionType::ExtInfo extInfo(rep,
17851783
attrs.has(TAK_noreturn),
1786-
/*autoclosure is a decl attr*/false,
1787-
isNoEscape,
1784+
attrs.has(TAK_autoclosure),
1785+
attrs.has(TAK_noescape),
17881786
fnRepr->throws());
17891787

17901788
ty = resolveASTFunctionType(fnRepr, options, extInfo);

test/attr/attr_autoclosure.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func func8(@autoclosure _ x: inout () -> Bool) -> Bool { // expected-error {{@a
2323

2424

2525
// <rdar://problem/19707366> QoI: @autoclosure declaration change fixit
26-
let migrate4 : @autoclosure() -> () // expected-error {{attribute can only be applied to declarations, not types}} {{1-1=@autoclosure }} {{16-28=}}
26+
let migrate4 : (@autoclosure() -> ())->()
2727

2828

2929
struct SomeStruct {
@@ -110,8 +110,13 @@ class TestFunc12 {
110110

111111

112112
enum AutoclosureFailableOf<T> {
113-
case Success(@autoclosure () -> T) // expected-error {{attribute can only be applied to declarations, not types}}
113+
case Success(@autoclosure () -> T)
114114
case Failure()
115115
}
116116

117+
let _ : (@autoclosure () -> ()) -> ()
118+
let _ : (@autoclosure(escaping) () -> ()) -> ()
119+
120+
// escaping is the name of param type
121+
let _ : (@autoclosure(escaping) -> ()) -> () // expected-error {{use of undeclared type 'escaping'}}
117122

0 commit comments

Comments
 (0)