Skip to content

Commit 68ff93a

Browse files
authored
Merge pull request #4878 from slavapestov/fix-variadic-escaping-autoclosure-3.0
Sema: Variadic parameters are always @escaping and cannot be @autoclo…
2 parents 584c5cf + 1d1ecf3 commit 68ff93a

File tree

10 files changed

+114
-73
lines changed

10 files changed

+114
-73
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -906,10 +906,6 @@ ERROR(attribute_requires_operator_identifier,none,
906906
ERROR(attribute_requires_single_argument,none,
907907
"'%0' requires a function with one argument", (StringRef))
908908

909-
ERROR(inout_cant_be_variadic,none,
910-
"inout arguments cannot be variadic", ())
911-
ERROR(inout_only_parameter,none,
912-
"'inout' is only valid in parameter lists", ())
913909
ERROR(var_parameter_not_allowed,none,
914910
"parameters may not have the 'var' specifier", ())
915911

@@ -1831,10 +1827,12 @@ ERROR(property_behavior_invalid_parameter,none,
18311827
// Type Check Attributes
18321828
//------------------------------------------------------------------------------
18331829

1834-
ERROR(attr_only_only_one_decl_kind,none,
1830+
ERROR(attr_only_one_decl_kind,none,
18351831
"%0 may only be used on '%1' declarations", (DeclAttribute,StringRef))
1836-
ERROR(attr_only_only_on_parameters,none,
1832+
ERROR(attr_only_on_parameters,none,
18371833
"%0 may only be used on parameters", (StringRef))
1834+
ERROR(attr_not_on_variadic_parameters,none,
1835+
"%0 may not be used on variadic parameters", (StringRef))
18381836

18391837

18401838
ERROR(override_final,none,

lib/Sema/TypeCheckAttr.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ void TypeChecker::checkDeclAttributesEarly(Decl *D) {
681681
}
682682

683683
if (!OnlyKind.empty())
684-
Checker.diagnoseAndRemoveAttr(attr, diag::attr_only_only_one_decl_kind,
684+
Checker.diagnoseAndRemoveAttr(attr, diag::attr_only_one_decl_kind,
685685
attr, OnlyKind);
686686
else if (attr->isDeclModifier())
687687
Checker.diagnoseAndRemoveAttr(attr, diag::invalid_decl_modifier, attr);
@@ -1577,7 +1577,7 @@ void TypeChecker::checkTypeModifyingDeclAttributes(VarDecl *var) {
15771577
checkAutoClosureAttr(pd, attr);
15781578
else {
15791579
AttributeEarlyChecker Checker(*this, var);
1580-
Checker.diagnoseAndRemoveAttr(attr, diag::attr_only_only_one_decl_kind,
1580+
Checker.diagnoseAndRemoveAttr(attr, diag::attr_only_one_decl_kind,
15811581
attr, "parameter");
15821582
}
15831583
}
@@ -1586,7 +1586,7 @@ void TypeChecker::checkTypeModifyingDeclAttributes(VarDecl *var) {
15861586
checkNoEscapeAttr(pd, attr);
15871587
else {
15881588
AttributeEarlyChecker Checker(*this, var);
1589-
Checker.diagnoseAndRemoveAttr(attr, diag::attr_only_only_one_decl_kind,
1589+
Checker.diagnoseAndRemoveAttr(attr, diag::attr_only_one_decl_kind,
15901590
attr, "parameter");
15911591
}
15921592
}

lib/Sema/TypeCheckPattern.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -739,21 +739,21 @@ static bool validateParameterType(ParamDecl *decl, DeclContext *DC,
739739
TypeChecker &TC) {
740740
if (auto ty = decl->getTypeLoc().getType())
741741
return ty->is<ErrorType>();
742-
742+
743+
// If the element is a variadic parameter, resolve the parameter type as if
744+
// it were in non-parameter position, since we want functions to be
745+
// @escaping in this case.
746+
auto elementOptions = (options |
747+
(decl->isVariadic() ? TR_VariadicFunctionInput
748+
: TR_FunctionInput));
743749
bool hadError = TC.validateType(decl->getTypeLoc(), DC,
744-
options|TR_FunctionInput, resolver);
750+
elementOptions, resolver);
745751

746752
Type Ty = decl->getTypeLoc().getType();
747753
if (decl->isVariadic() && !hadError) {
748-
// If isn't legal to declare something both inout and variadic.
749-
if (Ty->is<InOutType>()) {
750-
TC.diagnose(decl->getStartLoc(), diag::inout_cant_be_variadic);
754+
Ty = TC.getArraySliceType(decl->getStartLoc(), Ty);
755+
if (Ty.isNull()) {
751756
hadError = true;
752-
} else {
753-
Ty = TC.getArraySliceType(decl->getStartLoc(), Ty);
754-
if (Ty.isNull()) {
755-
hadError = true;
756-
}
757757
}
758758
decl->getTypeLoc().setType(Ty);
759759
}

lib/Sema/TypeCheckType.cpp

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1779,6 +1779,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
17791779
bool isFunctionParam =
17801780
options.contains(TR_FunctionInput) ||
17811781
options.contains(TR_ImmediateFunctionInput);
1782+
bool isVariadicFunctionParam =
1783+
options.contains(TR_VariadicFunctionInput);
17821784

17831785
// The type we're working with, in case we want to build it differently
17841786
// based on the attributes we see.
@@ -1959,7 +1961,9 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
19591961
// @autoclosure is only valid on parameters.
19601962
if (!isFunctionParam && attrs.has(TAK_autoclosure)) {
19611963
TC.diagnose(attrs.getLoc(TAK_autoclosure),
1962-
diag::attr_only_only_on_parameters, "@autoclosure");
1964+
isVariadicFunctionParam
1965+
? diag::attr_not_on_variadic_parameters
1966+
: diag::attr_only_on_parameters, "@autoclosure");
19631967
attrs.clearAttribute(TAK_autoclosure);
19641968
}
19651969

@@ -2390,7 +2394,11 @@ Type TypeResolver::resolveInOutType(InOutTypeRepr *repr,
23902394
// inout is only valid for function parameters.
23912395
if (!(options & TR_FunctionInput) &&
23922396
!(options & TR_ImmediateFunctionInput)) {
2393-
TC.diagnose(repr->getInOutLoc(), diag::inout_only_parameter);
2397+
TC.diagnose(repr->getInOutLoc(),
2398+
(options & TR_VariadicFunctionInput)
2399+
? diag::attr_not_on_variadic_parameters
2400+
: diag::attr_only_on_parameters,
2401+
"'inout'");
23942402
repr->setInvalid();
23952403
return ErrorType::get(Context);
23962404
}
@@ -2510,38 +2518,58 @@ Type TypeResolver::resolveTupleType(TupleTypeRepr *repr,
25102518
if (options & TR_ImmediateFunctionInput)
25112519
elementOptions |= TR_FunctionInput;
25122520
}
2513-
2521+
2522+
bool complained = false;
2523+
2524+
// Variadic tuples are not permitted.
2525+
if (repr->hasEllipsis() &&
2526+
!(options & TR_ImmediateFunctionInput)) {
2527+
TC.diagnose(repr->getEllipsisLoc(), diag::tuple_ellipsis);
2528+
repr->removeEllipsis();
2529+
complained = true;
2530+
}
2531+
25142532
for (auto tyR : repr->getElements()) {
25152533
NamedTypeRepr *namedTyR = dyn_cast<NamedTypeRepr>(tyR);
2516-
if (namedTyR && !(options & TR_ImmediateFunctionInput)) {
2517-
Type ty = resolveType(namedTyR->getTypeRepr(), elementOptions);
2518-
if (!ty || ty->is<ErrorType>()) return ty;
2534+
Type ty;
2535+
Identifier name;
2536+
bool variadic = false;
25192537

2520-
elements.push_back(TupleTypeElt(ty, namedTyR->getName()));
2521-
} else {
2538+
// If the element has a label, stash the label and get the underlying type.
2539+
if (namedTyR) {
25222540
// FIXME: Preserve and serialize parameter names in function types, maybe
25232541
// with a new sugar type.
2524-
Type ty = resolveType(namedTyR ? namedTyR->getTypeRepr() : tyR,
2525-
elementOptions);
2526-
if (!ty || ty->is<ErrorType>()) return ty;
2542+
if (!(options & TR_ImmediateFunctionInput))
2543+
name = namedTyR->getName();
25272544

2528-
elements.push_back(TupleTypeElt(ty));
2545+
tyR = namedTyR->getTypeRepr();
25292546
}
2530-
}
25312547

2532-
// Tuple representations are limited outside of function inputs.
2533-
if (!(options & TR_ImmediateFunctionInput)) {
2534-
bool complained = false;
2548+
// If the element is a variadic parameter, resolve the parameter type as if
2549+
// it were in non-parameter position, since we want functions to be
2550+
// @escaping in this case.
2551+
auto thisElementOptions = elementOptions;
2552+
if (repr->hasEllipsis() &&
2553+
elements.size() == repr->getEllipsisIndex()) {
2554+
thisElementOptions = withoutContext(elementOptions);
2555+
thisElementOptions |= TR_VariadicFunctionInput;
2556+
variadic = true;
2557+
}
2558+
2559+
ty = resolveType(tyR, thisElementOptions);
2560+
if (!ty || ty->is<ErrorType>()) return ty;
2561+
2562+
// If the element is a variadic parameter, the underlying type is actually
2563+
// an ArraySlice of the element type.
2564+
if (variadic)
2565+
ty = TC.getArraySliceType(repr->getEllipsisLoc(), ty);
25352566

2536-
// Variadic tuples are not permitted.
2537-
if (repr->hasEllipsis()) {
2538-
TC.diagnose(repr->getEllipsisLoc(), diag::tuple_ellipsis);
2539-
repr->removeEllipsis();
2540-
complained = true;
2541-
}
2567+
elements.push_back(TupleTypeElt(ty, name, variadic));
2568+
}
25422569

2543-
// Single-element labeled tuples are not permitted outside of declarations
2544-
// or SIL, either.
2570+
// Single-element labeled tuples are not permitted outside of declarations
2571+
// or SIL, either.
2572+
if (!(options & TR_ImmediateFunctionInput)) {
25452573
if (elements.size() == 1 && elements[0].hasName()
25462574
&& !(options & TR_SILType)
25472575
&& !(options & TR_EnumCase)) {
@@ -2557,14 +2585,6 @@ Type TypeResolver::resolveTupleType(TupleTypeRepr *repr,
25572585
}
25582586
}
25592587

2560-
if (repr->hasEllipsis()) {
2561-
auto &element = elements[repr->getEllipsisIndex()];
2562-
Type baseTy = element.getType();
2563-
Type fullTy = TC.getArraySliceType(repr->getEllipsisLoc(), baseTy);
2564-
Identifier name = element.getName();
2565-
element = TupleTypeElt(fullTy, name, true);
2566-
}
2567-
25682588
return TupleType::get(elements, Context);
25692589
}
25702590

lib/Sema/TypeChecker.h

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -327,58 +327,61 @@ enum TypeResolutionFlags : unsigned {
327327
/// Whether this is the immediate input type to a function type,
328328
TR_ImmediateFunctionInput = 0x40,
329329

330+
/// Whether this is a variadic function input.
331+
TR_VariadicFunctionInput = 0x100,
332+
330333
/// Whether we are in the result type of a function body that is
331334
/// known to produce dynamic Self.
332-
TR_DynamicSelfResult = 0x100,
335+
TR_DynamicSelfResult = 0x200,
333336

334337
/// Whether this is a resolution based on a non-inferred type pattern.
335-
TR_FromNonInferredPattern = 0x200,
338+
TR_FromNonInferredPattern = 0x400,
336339

337340
/// Whether we are the variable type in a for/in statement.
338-
TR_EnumerationVariable = 0x400,
341+
TR_EnumerationVariable = 0x800,
339342

340343
/// Whether we are looking only in the generic signature of the context
341344
/// we're searching, rather than the entire context.
342-
TR_GenericSignature = 0x800,
345+
TR_GenericSignature = 0x1000,
343346

344347
/// Whether this type is the referent of a global type alias.
345-
TR_GlobalTypeAlias = 0x1000,
348+
TR_GlobalTypeAlias = 0x2000,
346349

347350
/// Whether this type is the value carried in an enum case.
348-
TR_EnumCase = 0x2000,
351+
TR_EnumCase = 0x4000,
349352

350353
/// Whether this type is being used in an expression or local declaration.
351354
///
352355
/// This affects what sort of dependencies are recorded when resolving the
353356
/// type.
354-
TR_InExpression = 0x4000,
357+
TR_InExpression = 0x8000,
355358

356359
/// Whether this type resolution is guaranteed not to affect downstream files.
357-
TR_KnownNonCascadingDependency = 0x8000,
360+
TR_KnownNonCascadingDependency = 0x10000,
358361

359362
/// Whether we should allow references to unavailable types.
360-
TR_AllowUnavailable = 0x10000,
363+
TR_AllowUnavailable = 0x20000,
361364

362365
/// Whether this is the payload subpattern of an enum pattern.
363-
TR_EnumPatternPayload = 0x20000,
366+
TR_EnumPatternPayload = 0x40000,
364367

365368
/// Whether we are binding an extension declaration, which limits
366369
/// the lookup.
367-
TR_ExtensionBinding = 0x40000,
370+
TR_ExtensionBinding = 0x80000,
368371

369372
/// Whether we are in the inheritance clause of a nominal type declaration
370373
/// or extension.
371-
TR_InheritanceClause = 0x80000,
374+
TR_InheritanceClause = 0x100000,
372375

373376
/// Whether we should resolve only the structure of the resulting
374377
/// type rather than its complete semantic properties.
375-
TR_ResolveStructure = 0x100000,
378+
TR_ResolveStructure = 0x200000,
376379

377380
/// Whether this is the type of an editor placeholder.
378-
TR_EditorPlaceholder = 0x200000,
381+
TR_EditorPlaceholder = 0x400000,
379382

380383
/// Whether we are in a type argument for an optional
381-
TR_ImmediateOptionalTypeArgument = 0x400000,
384+
TR_ImmediateOptionalTypeArgument = 0x800000,
382385
};
383386

384387
/// Option set describing how type resolution should work.
@@ -394,6 +397,7 @@ static inline TypeResolutionOptions
394397
withoutContext(TypeResolutionOptions options) {
395398
options -= TR_ImmediateFunctionInput;
396399
options -= TR_FunctionInput;
400+
options -= TR_VariadicFunctionInput;
397401
options -= TR_EnumCase;
398402
options -= TR_ImmediateOptionalTypeArgument;
399403
return options;

test/attr/attr_autoclosure.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,7 @@ func callAutoclosureWithNoEscape_3(_ fn: @autoclosure () -> Int) {
156156
takesAutoclosure(fn()) // ok
157157
}
158158

159+
// expected-error @+1 {{@autoclosure may not be used on variadic parameters}}
160+
func variadicAutoclosure(_ fn: @autoclosure () -> ()...) {
161+
for _ in fn {}
162+
}

test/attr/attr_escaping.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,18 @@ func testModuloOptionalness() {
127127
deepOptionalClosure = fn // expected-error{{assigning non-escaping parameter 'fn' to an @escaping closure}}
128128
}
129129
}
130+
131+
// Check that functions in vararg position are @escaping
132+
func takesEscapingFunction(fn: @escaping () -> ()) {}
133+
func takesArrayOfFunctions(array: [() -> ()]) {}
134+
135+
func takesVarargsOfFunctions(fns: () -> ()...) {
136+
takesArrayOfFunctions(array: fns)
137+
for fn in fns {
138+
takesEscapingFunction(fn: fn)
139+
}
140+
}
141+
142+
func takesNoEscapeFunction(fn: () -> ()) { // expected-note {{parameter 'fn' is implicitly non-escaping}}
143+
takesVarargsOfFunctions(fns: fn) // expected-error {{passing non-escaping parameter 'fn' to function expecting an @escaping closure}}
144+
}

test/attr/attr_inout.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ func f(x : inout Int) { } // okay
44

55
func h(_ : inout Int) -> (inout Int) -> (inout Int) -> Int { }
66

7-
func ff(x: (inout Int, inout Float)) { } // expected-error {{'inout' is only valid in parameter lists}}
7+
func ff(x: (inout Int, inout Float)) { } // expected-error {{'inout' may only be used on parameters}}
88

99
enum inout_carrier {
10-
case carry(inout Int) // expected-error {{'inout' is only valid in parameter lists}}
10+
case carry(inout Int) // expected-error {{'inout' may only be used on parameters}}
1111
}
1212

1313
func deprecated(inout x: Int) {} // expected-error {{'inout' before a parameter name is not allowed, place it before the parameter type instead}}

test/decl/func/vararg.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ f3({ print($0) })
1919
func f4(_ a: Int..., b: Int) { }
2020

2121
// rdar://16008564
22-
func inoutVariadic(_ i: inout Int...) { // expected-error {{inout arguments cannot be variadic}}
22+
func inoutVariadic(_ i: inout Int...) { // expected-error {{'inout' may not be used on variadic parameters}}
2323
}
2424

2525
// rdar://19722429

test/type/types.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ var h10 : Int?.Type?.Type
4444

4545
var i = Int?(42)
4646

47-
var bad_io : (Int) -> (inout Int, Int) // expected-error {{'inout' is only valid in parameter lists}}
47+
var bad_io : (Int) -> (inout Int, Int) // expected-error {{'inout' may only be used on parameters}}
4848

49-
func bad_io2(_ a: (inout Int, Int)) {} // expected-error {{'inout' is only valid in parameter lists}}
49+
func bad_io2(_ a: (inout Int, Int)) {} // expected-error {{'inout' may only be used on parameters}}
5050

5151
// <rdar://problem/15588967> Array type sugar default construction syntax doesn't work
5252
func test_array_construct<T>(_: T) {
@@ -148,12 +148,12 @@ let dictWithTuple = [String: (age:Int, count:Int)]()
148148
let bb2 = [Int!](repeating: nil, count: 2)
149149

150150
// <rdar://problem/21560309> inout allowed on function return type
151-
func r21560309<U>(_ body: (_: inout Int) -> inout U) {} // expected-error {{'inout' is only valid in parameter lists}}
151+
func r21560309<U>(_ body: (_: inout Int) -> inout U) {} // expected-error {{'inout' may only be used on parameters}}
152152
r21560309 { x in x }
153153

154154
// <rdar://problem/21949448> Accepts-invalid: 'inout' shouldn't be allowed on stored properties
155155
class r21949448 {
156-
var myArray: inout [Int] = [] // expected-error {{'inout' is only valid in parameter lists}}
156+
var myArray: inout [Int] = [] // expected-error {{'inout' may only be used on parameters}}
157157
}
158158

159159
// SE-0066 - Standardize function type argument syntax to require parentheses

0 commit comments

Comments
 (0)