Skip to content

Commit daa4fff

Browse files
authored
Merge pull request #35503 from LucianoPAlmeida/SR-12033-autoclosure
[SR-12033] [Sema] Do not allow inferring defaultable closure `() -> $T` for autoclosure arguments result
2 parents 8b4bde5 + 3330083 commit daa4fff

File tree

3 files changed

+101
-2
lines changed

3 files changed

+101
-2
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,12 @@ void PotentialBindings::inferTransitiveBindings(
336336
addLiteral(literal.second.getSource());
337337

338338
// Infer transitive defaults.
339-
for (const auto &def : bindings.Defaults)
339+
for (const auto &def : bindings.Defaults) {
340+
if (def.getSecond()->getKind() == ConstraintKind::DefaultClosureType)
341+
continue;
342+
340343
addDefault(def.second);
344+
}
341345

342346
// TODO: We shouldn't need this in the future.
343347
if (entry.second->getKind() != ConstraintKind::Subtype)
@@ -366,11 +370,45 @@ void PotentialBindings::inferTransitiveBindings(
366370
}
367371
}
368372

373+
// If potential binding type variable is a closure that has a subtype relation
374+
// associated with argument conversion constraint located directly on an
375+
// autoclosure parameter.
376+
static bool
377+
isClosureInAutoClosureArgumentConversion(PotentialBindings &bindings) {
378+
379+
if (!bindings.TypeVar->getImpl().isClosureType())
380+
return false;
381+
382+
return llvm::any_of(
383+
bindings.SubtypeOf,
384+
[](std::pair<TypeVariableType *, Constraint *> subType) {
385+
if (subType.second->getKind() != ConstraintKind::ArgumentConversion)
386+
return false;
387+
return subType.second->getLocator()
388+
->isLastElement<LocatorPathElt::AutoclosureResult>();
389+
});
390+
}
391+
369392
void PotentialBindings::finalize(
370393
llvm::SmallDenseMap<TypeVariableType *, PotentialBindings>
371394
&inferredBindings) {
372395
inferTransitiveProtocolRequirements(inferredBindings);
373396
inferTransitiveBindings(inferredBindings);
397+
398+
// For autoclosure parameters if we have a closure argument which could
399+
// default to `() -> $T`, we avoid infering defaultable binding because
400+
// an autoclosure cannot accept a closure paramenter unless the result `$T`
401+
// is bound to a function type via another contextual binding. Also consider
402+
// adjacent vars because they can also default transitively.
403+
if (isClosureInAutoClosureArgumentConversion(*this)) {
404+
auto closureDefault = llvm::find_if(
405+
Defaults, [](const std::pair<CanType, Constraint *> &entry) {
406+
return entry.second->getKind() == ConstraintKind::DefaultClosureType;
407+
});
408+
if (closureDefault != Defaults.end()) {
409+
Defaults.erase(closureDefault);
410+
}
411+
}
374412
}
375413

376414
PotentialBindings::BindingScore

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2520,7 +2520,7 @@ namespace {
25202520
closure->walk(collectVarRefs);
25212521

25222522
// If walker discovered error expressions, let's fail constraint
2523-
// genreation only if closure is going to participate
2523+
// generation only if closure is going to participate
25242524
// in the type-check. This allows us to delay validation of
25252525
// multi-statement closures until body is opened.
25262526
if (shouldTypeCheckInEnclosingExpression(closure) &&

test/Constraints/closures.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,3 +1056,64 @@ func test_inout_with_invalid_member_ref() {
10561056
// expected-error@-1 {{value of tuple type 'Void' has no member 'createS'}}
10571057
// expected-error@-2 {{cannot pass immutable value as inout argument: '$0' is immutable}}
10581058
}
1059+
1060+
struct SR12033<T> {
1061+
public static func capture(_ thunk: () -> T) -> SR12033<T> {
1062+
.init()
1063+
}
1064+
public static func captureA(_ thunk: @autoclosure () -> T) -> SR12033<T> { // expected-note{{'captureA' declared here}}
1065+
.init()
1066+
}
1067+
public static func captureE(_ thunk: @escaping () -> T) -> SR12033<T> {
1068+
.init()
1069+
}
1070+
public static func captureAE(_ thunk: @autoclosure @escaping () -> T) -> SR12033<T> { // expected-note{{'captureAE' declared here}}
1071+
.init()
1072+
}
1073+
}
1074+
1075+
var number = 1
1076+
1077+
let t = SR12033<Int>.capture { number } // OK
1078+
let t2 = SR12033<Int>.captureE { number } // OK
1079+
let t3 = SR12033<Int>.captureA(number) // OK
1080+
1081+
let e = SR12033<Int>.captureA { number }
1082+
// expected-error@-1{{trailing closure passed to parameter of type 'Int' that does not accept a closure}}
1083+
let e2 = SR12033<Int>.captureAE { number }
1084+
// expected-error@-1{{trailing closure passed to parameter of type 'Int' that does not accept a closure}}
1085+
1086+
struct SR12033_S {
1087+
public static var zero: SR12033_S { .init() }
1088+
1089+
// captureGenericFuncA
1090+
public static func f<T>(_ thunk: @autoclosure () -> T) -> SR12033_S { // expected-note 2{{'f' declared here}}
1091+
// expected-note@-1 2{{in call to function 'f'}}
1092+
.init()
1093+
}
1094+
1095+
public static func unwrap<T>(_ optional: T?, _ defaultValue: @autoclosure () throws -> T) {}
1096+
1097+
func test() {
1098+
let number = 1
1099+
_ = Self.f(number) // OK
1100+
_ = Self.f { number } // expected-error{{trailing closure passed to parameter of type '_' that does not accept a closure}}
1101+
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
1102+
_ = Self.f { _ in number } // expected-error{{trailing closure passed to parameter of type '_' that does not accept a closure}}
1103+
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
1104+
}
1105+
1106+
// Inference with contextual type is OK `T` is infered as `() -> Int`
1107+
func test(_ o: (()-> Int)?) {
1108+
Self.unwrap(o, { 0 }) // Ok
1109+
Self.unwrap(o, { .zero }) // Ok
1110+
Self.unwrap(o, { _ in .zero }) // expected-error {{contextual closure type '() -> Int' expects 0 arguments, but 1 was used in closure body}}
1111+
}
1112+
1113+
// `T` is infered as `() -> U`
1114+
func testGeneric<U>(_ o: (() -> U)?) where U: BinaryInteger {
1115+
Self.unwrap(o, { .zero }) // OK
1116+
Self.unwrap(o, { 0 }) // OK
1117+
Self.unwrap(o, { _ in .zero }) // expected-error {{contextual closure type '() -> U' expects 0 arguments, but 1 was used in closure body}}
1118+
}
1119+
}

0 commit comments

Comments
 (0)