Skip to content

Commit 1d8c2a1

Browse files
authored
Merge pull request swiftlang#36545 from xedin/rdar-75476311
[ConstraintSystem] Bind external closure parameter type to a concrete…
2 parents d350a05 + 225e2db commit 1d8c2a1

File tree

6 files changed

+95
-11
lines changed

6 files changed

+95
-11
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8354,17 +8354,53 @@ static Type getOpenedResultBuilderTypeFor(ConstraintSystem &cs,
83548354
bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
83558355
Type contextualType,
83568356
ConstraintLocatorBuilder locator) {
8357+
auto *closureLocator = typeVar->getImpl().getLocator();
8358+
auto *closure = castToExpr<ClosureExpr>(closureLocator->getAnchor());
8359+
auto *inferredClosureType = getClosureType(closure);
8360+
83578361
auto getContextualParamAt =
8358-
[&contextualType](unsigned index) -> Optional<AnyFunctionType::Param> {
8362+
[&contextualType, &inferredClosureType](
8363+
unsigned index) -> Optional<AnyFunctionType::Param> {
83598364
auto *fnType = contextualType->getAs<FunctionType>();
8360-
return fnType && fnType->getNumParams() > index
8361-
? fnType->getParams()[index]
8362-
: Optional<AnyFunctionType::Param>();
8365+
if (!fnType)
8366+
return None;
8367+
8368+
auto numContextualParams = fnType->getNumParams();
8369+
if (numContextualParams != inferredClosureType->getNumParams() ||
8370+
numContextualParams <= index)
8371+
return None;
8372+
8373+
return fnType->getParams()[index];
83638374
};
83648375

8365-
auto *closureLocator = typeVar->getImpl().getLocator();
8366-
auto *closure = castToExpr<ClosureExpr>(closureLocator->getAnchor());
8367-
auto *inferredClosureType = getClosureType(closure);
8376+
// Check whether given contextual parameter type could be
8377+
// used to bind external closure parameter type.
8378+
auto isSuitableContextualType = [](Type contextualTy) {
8379+
// We need to wait until contextual type
8380+
// is fully resolved before binding it.
8381+
if (contextualTy->isTypeVariableOrMember())
8382+
return false;
8383+
8384+
// If contextual type has an error, let's wait for inference,
8385+
// otherwise contextual would interfere with diagnostics.
8386+
if (contextualTy->hasError())
8387+
return false;
8388+
8389+
if (isa<TypeAliasType>(contextualTy.getPointer())) {
8390+
auto underlyingTy = contextualTy->getDesugaredType();
8391+
// FIXME: typealias pointing to an existential type is special
8392+
// because if the typealias has type variables then we'd end up
8393+
// opening existential from a type with unresolved generic
8394+
// parameter(s), which CSApply can't currently simplify while
8395+
// building type-checked AST because `OpenedArchetypeType` doesn't
8396+
// propagate flags. Example is as simple as `{ $0.description }`
8397+
// where `$0` is `Error` that inferred from a (generic) typealias.
8398+
if (underlyingTy->isExistentialType() && contextualTy->hasTypeVariable())
8399+
return false;
8400+
}
8401+
8402+
return true;
8403+
};
83688404

83698405
// Determine whether a result builder will be applied.
83708406
auto resultBuilderType = getOpenedResultBuilderTypeFor(*this, locator);
@@ -8456,6 +8492,24 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
84568492
param.isVariadic() ? ArraySliceType::get(typeVar) : Type(typeVar);
84578493

84588494
auto externalType = param.getOldType();
8495+
8496+
// Performance optimization.
8497+
//
8498+
// If there is a concrete contextual type we could use, let's bind
8499+
// it to the external type right away because internal type has to
8500+
// be equal to that type anyway (through `BindParam` on external type
8501+
// i.e. <internal> bind param <external> conv <concrete contextual>).
8502+
//
8503+
// Note: it's correct to avoid doing this, but it would result
8504+
// in (a lot) more checking since solver would have to re-discover,
8505+
// re-attempt and fail parameter type while solving for overloaded
8506+
// choices in the body.
8507+
if (auto contextualParam = getContextualParamAt(i)) {
8508+
auto paramTy = simplifyType(contextualParam->getOldType());
8509+
if (isSuitableContextualType(paramTy))
8510+
addConstraint(ConstraintKind::Bind, externalType, paramTy, paramLoc);
8511+
}
8512+
84598513
if (oneWayConstraints) {
84608514
addConstraint(
84618515
ConstraintKind::OneWayBindParam, typeVar, externalType, paramLoc);

test/Constraints/closures.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ func rdar21078316() {
377377

378378
// <rdar://problem/20978044> QoI: Poor diagnostic when using an incorrect tuple element in a closure
379379
var numbers = [1, 2, 3]
380-
zip(numbers, numbers).filter { $0.2 > 1 } // expected-error {{value of tuple type '(Int, Int)' has no member '2'}}
380+
zip(numbers, numbers).filter { $0.2 > 1 } // expected-error {{value of tuple type '(Array<Int>.Element, Array<Int>.Element)' has no member '2'}}
381381

382382

383383

validation-test/Sema/type_checker_perf/slow/rdar19357292.swift renamed to validation-test/Sema/type_checker_perf/fast/rdar19357292.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,5 @@
44
func test(strings: [String]) {
55
for string in strings {
66
let _ = string.split(omittingEmptySubsequences: false) { $0 == "C" || $0 == "D" || $0 == "H" || $0 == "S"}
7-
// expected-error@-1 {{the compiler is unable to type-check this expression in reasonable time}}
87
}
98
}
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// RUN: %target-typecheck-verify-swift -solver-expression-time-threshold=1
22
// REQUIRES: tools-release,no_asan
33

4-
// expected-error@+1 {{the compiler is unable to type-check this expression in reasonable time}}
54
let _: (Character) -> Bool = { c in
65
("a" <= c && c <= "z") || ("A" <= c && c <= "Z") || c == "_"
76
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-typecheck-verify-swift -target x86_64-apple-macosx10.15 -solver-expression-time-threshold=1 -swift-version 5
2+
// REQUIRES: tools-release,no_asan,objc_interop
3+
// REQUIRES: OS=macosx
4+
5+
import Combine
6+
import Foundation
7+
import simd
8+
9+
class Entry : NSObject {}
10+
11+
class Query : NSObject {
12+
}
13+
14+
class Test {
15+
typealias QueryPublisher = AnyPublisher<Query, Never>
16+
17+
@Published var tokens: [Entry] = []
18+
@Published var text: String = ""
19+
20+
var test: QueryPublisher {
21+
$tokens
22+
.combineLatest($text)
23+
.debounce(for: 0.2, scheduler: RunLoop.main)
24+
.removeDuplicates(by: { (first, second) -> Bool in
25+
first.0 == second.0 && first.1 == second.1 // Ok (lot of overloads here) and first `==` is different from second
26+
})
27+
.map { _ in
28+
Query()
29+
}
30+
.eraseToAnyPublisher()
31+
}
32+
}

validation-test/Sema/type_checker_perf/slow/mixed_string_array_addition.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ func test(str: String, properties: [String]) {
66
// expected-error@+1 {{the compiler is unable to type-check this expression in reasonable time}}
77
method(str + "" + str + "") {
88
properties.map { param in
9-
"" + param + "" + param + ""
9+
"" + param + "" + param + "" + param + ""
1010
} + [""]
1111
}
1212
}

0 commit comments

Comments
 (0)