diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index c0f92a2c4cde5..2b02a51626ae3 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -336,8 +336,12 @@ void PotentialBindings::inferTransitiveBindings( addLiteral(literal.second.getSource()); // Infer transitive defaults. - for (const auto &def : bindings.Defaults) + for (const auto &def : bindings.Defaults) { + if (def.getSecond()->getKind() == ConstraintKind::DefaultClosureType) + continue; + addDefault(def.second); + } // TODO: We shouldn't need this in the future. if (entry.second->getKind() != ConstraintKind::Subtype) @@ -366,11 +370,45 @@ void PotentialBindings::inferTransitiveBindings( } } +// If potential binding type variable is a closure that has a subtype relation +// associated with argument conversion constraint located directly on an +// autoclosure parameter. +static bool +isClosureInAutoClosureArgumentConversion(PotentialBindings &bindings) { + + if (!bindings.TypeVar->getImpl().isClosureType()) + return false; + + return llvm::any_of( + bindings.SubtypeOf, + [](std::pair subType) { + if (subType.second->getKind() != ConstraintKind::ArgumentConversion) + return false; + return subType.second->getLocator() + ->isLastElement(); + }); +} + void PotentialBindings::finalize( llvm::SmallDenseMap &inferredBindings) { inferTransitiveProtocolRequirements(inferredBindings); inferTransitiveBindings(inferredBindings); + + // For autoclosure parameters if we have a closure argument which could + // default to `() -> $T`, we avoid infering defaultable binding because + // an autoclosure cannot accept a closure paramenter unless the result `$T` + // is bound to a function type via another contextual binding. Also consider + // adjacent vars because they can also default transitively. + if (isClosureInAutoClosureArgumentConversion(*this)) { + auto closureDefault = llvm::find_if( + Defaults, [](const std::pair &entry) { + return entry.second->getKind() == ConstraintKind::DefaultClosureType; + }); + if (closureDefault != Defaults.end()) { + Defaults.erase(closureDefault); + } + } } PotentialBindings::BindingScore diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index dfa0c8781ebe5..a2bf0b25d641d 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2520,7 +2520,7 @@ namespace { closure->walk(collectVarRefs); // If walker discovered error expressions, let's fail constraint - // genreation only if closure is going to participate + // generation only if closure is going to participate // in the type-check. This allows us to delay validation of // multi-statement closures until body is opened. if (shouldTypeCheckInEnclosingExpression(closure) && diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index ead39e2a5eef1..642086f06b4c7 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -1056,3 +1056,64 @@ func test_inout_with_invalid_member_ref() { // expected-error@-1 {{value of tuple type 'Void' has no member 'createS'}} // expected-error@-2 {{cannot pass immutable value as inout argument: '$0' is immutable}} } + +struct SR12033 { + public static func capture(_ thunk: () -> T) -> SR12033 { + .init() + } + public static func captureA(_ thunk: @autoclosure () -> T) -> SR12033 { // expected-note{{'captureA' declared here}} + .init() + } + public static func captureE(_ thunk: @escaping () -> T) -> SR12033 { + .init() + } + public static func captureAE(_ thunk: @autoclosure @escaping () -> T) -> SR12033 { // expected-note{{'captureAE' declared here}} + .init() + } +} + +var number = 1 + +let t = SR12033.capture { number } // OK +let t2 = SR12033.captureE { number } // OK +let t3 = SR12033.captureA(number) // OK + +let e = SR12033.captureA { number } +// expected-error@-1{{trailing closure passed to parameter of type 'Int' that does not accept a closure}} +let e2 = SR12033.captureAE { number } +// expected-error@-1{{trailing closure passed to parameter of type 'Int' that does not accept a closure}} + +struct SR12033_S { + public static var zero: SR12033_S { .init() } + + // captureGenericFuncA + public static func f(_ thunk: @autoclosure () -> T) -> SR12033_S { // expected-note 2{{'f' declared here}} + // expected-note@-1 2{{in call to function 'f'}} + .init() + } + + public static func unwrap(_ optional: T?, _ defaultValue: @autoclosure () throws -> T) {} + + func test() { + let number = 1 + _ = Self.f(number) // OK + _ = Self.f { number } // expected-error{{trailing closure passed to parameter of type '_' that does not accept a closure}} + // expected-error@-1 {{generic parameter 'T' could not be inferred}} + _ = Self.f { _ in number } // expected-error{{trailing closure passed to parameter of type '_' that does not accept a closure}} + // expected-error@-1 {{generic parameter 'T' could not be inferred}} + } + + // Inference with contextual type is OK `T` is infered as `() -> Int` + func test(_ o: (()-> Int)?) { + Self.unwrap(o, { 0 }) // Ok + Self.unwrap(o, { .zero }) // Ok + Self.unwrap(o, { _ in .zero }) // expected-error {{contextual closure type '() -> Int' expects 0 arguments, but 1 was used in closure body}} + } + + // `T` is infered as `() -> U` + func testGeneric(_ o: (() -> U)?) where U: BinaryInteger { + Self.unwrap(o, { .zero }) // OK + Self.unwrap(o, { 0 }) // OK + Self.unwrap(o, { _ in .zero }) // expected-error {{contextual closure type '() -> U' expects 0 arguments, but 1 was used in closure body}} + } +}