Skip to content

Commit b2641d6

Browse files
authored
Merge pull request #63756 from xedin/dont-delay-result-builder-conjunctions-5.8
[5.8][CSBindings] Solver result builder transformed closures as soon as al…
2 parents 7cc67db + 2e92b49 commit b2641d6

File tree

6 files changed

+167
-2
lines changed

6 files changed

+167
-2
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,9 @@ class TypeVariableType::Implementation {
486486
/// expression.
487487
bool isCodeCompletionToken() const;
488488

489+
/// Determine whether this type variable represents an opened opaque type.
490+
bool isOpaqueType() const;
491+
489492
/// Retrieve the representative of the equivalence class to which this
490493
/// type variable belongs.
491494
///
@@ -977,6 +980,11 @@ struct AppliedBuilderTransform {
977980
/// converted. Opaque types should be unopened.
978981
Type bodyResultType;
979982

983+
/// If transform is applied to a closure, this type represents
984+
/// contextual type the closure is converted type (e.g. a parameter
985+
/// type or or pattern type).
986+
Type contextualType;
987+
980988
/// The version of the original body with result builder applied
981989
/// as AST transformation.
982990
NullablePtr<BraceStmt> transformedBody;
@@ -5662,7 +5670,7 @@ class ConstraintSystem {
56625670
Optional<TypeMatchResult>
56635671
matchResultBuilder(AnyFunctionRef fn, Type builderType, Type bodyResultType,
56645672
ConstraintKind bodyResultConstraintKind,
5665-
ConstraintLocatorBuilder locator);
5673+
Type contextualType, ConstraintLocatorBuilder locator);
56665674

56675675
/// Matches a wrapped or projected value parameter type to its backing
56685676
/// property wrapper type by applying the property wrapper.

lib/Sema/BuilderTransform.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2311,6 +2311,7 @@ Optional<BraceStmt *> TypeChecker::applyResultBuilderBodyTransform(
23112311

23122312
if (auto result = cs.matchResultBuilder(
23132313
func, builderType, resultContextType, resultConstraintKind,
2314+
/*contextualType=*/Type(),
23142315
cs.getConstraintLocator(func->getBody()))) {
23152316
if (result->isFailure())
23162317
return nullptr;
@@ -2398,6 +2399,7 @@ Optional<ConstraintSystem::TypeMatchResult>
23982399
ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
23992400
Type bodyResultType,
24002401
ConstraintKind bodyResultConstraintKind,
2402+
Type contextualType,
24012403
ConstraintLocatorBuilder locator) {
24022404
builderType = simplifyType(builderType);
24032405
auto builder = builderType->getAnyNominal();
@@ -2522,6 +2524,7 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
25222524

25232525
transformInfo.builderType = builderType;
25242526
transformInfo.bodyResultType = bodyResultType;
2527+
transformInfo.contextualType = contextualType;
25252528
transformInfo.transformedBody = transformedBody->second;
25262529

25272530
// Record the transformation.

lib/Sema/CSBindings.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,61 @@ bool BindingSet::favoredOverConjunction(Constraint *conjunction) const {
10711071
if (forClosureResult() || forGenericParameter())
10721072
return false;
10731073
}
1074+
1075+
auto *locator = conjunction->getLocator();
1076+
if (locator->directlyAt<ClosureExpr>()) {
1077+
auto *closure = castToExpr<ClosureExpr>(locator->getAnchor());
1078+
1079+
if (auto transform = CS.getAppliedResultBuilderTransform(closure)) {
1080+
// Conjunctions that represent closures with result builder transformed
1081+
// bodies could be attempted right after their resolution if they meet
1082+
// all of the following criteria:
1083+
//
1084+
// - Builder type doesn't have any unresolved generic parameters;
1085+
// - Closure doesn't have any parameters;
1086+
// - The contextual result type is either concrete or opaque type.
1087+
auto contextualType = transform->contextualType;
1088+
if (!(contextualType && contextualType->is<FunctionType>()))
1089+
return true;
1090+
1091+
auto *contextualFnType =
1092+
CS.simplifyType(contextualType)->castTo<FunctionType>();
1093+
{
1094+
auto resultType = contextualFnType->getResult();
1095+
if (resultType->hasTypeVariable()) {
1096+
auto *typeVar = resultType->getAs<TypeVariableType>();
1097+
// If contextual result type is represented by an opaque type,
1098+
// it's a strong indication that body is self-contained, otherwise
1099+
// closure might rely on external types flowing into the body for
1100+
// disambiguation of `build{Partial}Block` or `buildFinalResult`
1101+
// calls.
1102+
if (!(typeVar && typeVar->getImpl().isOpaqueType()))
1103+
return true;
1104+
}
1105+
}
1106+
1107+
// If some of the closure parameters are unresolved, the conjunction
1108+
// has to be delayed to give them a chance to be inferred.
1109+
if (llvm::any_of(contextualFnType->getParams(), [](const auto &param) {
1110+
return param.getPlainType()->hasTypeVariable();
1111+
}))
1112+
return true;
1113+
1114+
// Check whether conjunction has any unresolved type variables
1115+
// besides the variable that represents the closure.
1116+
//
1117+
// Conjunction could refer to declarations from outer context
1118+
// (i.e. a variable declared in the outer closure) or generic
1119+
// parameters of the builder type), if any of such references
1120+
// are not yet inferred the conjunction has to be delayed.
1121+
auto *closureType = CS.getType(closure)->castTo<TypeVariableType>();
1122+
return llvm::any_of(
1123+
conjunction->getTypeVariables(), [&](TypeVariableType *typeVar) {
1124+
return !(typeVar == closureType || CS.getFixedType(typeVar));
1125+
});
1126+
}
1127+
}
1128+
10741129
return true;
10751130
}
10761131

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10964,7 +10964,7 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
1096410964
if (resultBuilderType) {
1096510965
if (auto result = matchResultBuilder(
1096610966
closure, resultBuilderType, closureType->getResult(),
10967-
ConstraintKind::Conversion, locator)) {
10967+
ConstraintKind::Conversion, contextualType, locator)) {
1096810968
return result->isSuccess();
1096910969
}
1097010970
}

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,22 @@ bool TypeVariableType::Implementation::isCodeCompletionToken() const {
154154
return locator && locator->directlyAt<CodeCompletionExpr>();
155155
}
156156

157+
bool TypeVariableType::Implementation::isOpaqueType() const {
158+
if (!locator)
159+
return false;
160+
161+
auto GP = locator->getLastElementAs<LocatorPathElt::GenericParameter>();
162+
if (!GP)
163+
return false;
164+
165+
if (auto *GPT = GP->getType()->getAs<GenericTypeParamType>()) {
166+
auto *decl = GPT->getDecl();
167+
return decl && decl->isOpaqueType();
168+
}
169+
170+
return false;
171+
}
172+
157173
void *operator new(size_t bytes, ConstraintSystem& cs,
158174
size_t alignment) {
159175
return cs.getAllocator().Allocate(bytes, alignment);
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// RUN: %target-typecheck-verify-swift -debug-constraints -disable-availability-checking 2>%t.err
2+
// RUN: %FileCheck %s < %t.err
3+
4+
protocol P<Output> {
5+
associatedtype Output
6+
}
7+
8+
struct S<Output> : P {
9+
init(_: Output) {}
10+
}
11+
12+
@resultBuilder
13+
struct Builder {
14+
static func buildExpression<T>(_ e: T) -> T { e }
15+
16+
static func buildBlock<T1>(_ t1: T1) -> some P<T1> {
17+
return S(t1)
18+
}
19+
20+
static func buildBlock<T1, T2>(_ t1: T1, _ t2: T2) -> some P<(T1, T2)> {
21+
return S((t1, t2))
22+
}
23+
24+
static func buildBlock<T1, T2, T3>(_ t1: T1, _ t2: T2, _ t3: T3) -> some P<(T1, T2, T3)> {
25+
return S((t1, t2, t3))
26+
}
27+
28+
static func buildOptional<T>(_ value: T?) -> T? { return value }
29+
}
30+
31+
do {
32+
func test<T, U>(_: T, @Builder _: () -> some P<U>) {}
33+
34+
// CHECK: ---Initial constraints for the given expression---
35+
// CHECK: (integer_literal_expr type='[[LITERAL_VAR:\$T[0-9]+]]' {{.*}}
36+
// CHECK: (attempting type variable [[CLOSURE:\$T[0-9]+]] := () -> {{.*}}
37+
// CHECK-NOT: (attempting type variable [[LITERAL_VAR]] := {{.*}}
38+
// CHECK: (attempting conjunction element pattern binding element @ 0
39+
// CHECK: (applying conjunction result to outer context
40+
// CHECK: (attempting type variable [[LITERAL_VAR]] := Int
41+
test(42) {
42+
1
43+
""
44+
}
45+
}
46+
47+
do {
48+
func test<T, U>(_: T, @Builder _: (T) -> some P<U>) {}
49+
50+
// CHECK: ---Initial constraints for the given expression---
51+
// CHECK: (integer_literal_expr type='[[LITERAL_VAR:\$T[0-9]+]]' {{.*}}
52+
// CHECK: (attempting type variable [[LITERAL_VAR]] := Int
53+
// CHECK: (attempting conjunction element pattern binding element @ 0
54+
test(42) { v in
55+
v
56+
""
57+
}
58+
}
59+
60+
do {
61+
func test<T: BinaryInteger, U>(@Builder _: (Bool) -> some P<T>, transform: (T?) -> U) {}
62+
63+
// CHECK: ---Initial constraints for the given expression---
64+
// CHECK: (attempting type variable {{.*}} := () -> {{.*}}
65+
// CHECK: (attempting conjunction element pattern binding element @ 0 :
66+
// CHECK-NEXT: (pattern_named 'x')
67+
// CHECK: (attempting conjunction element syntactic element
68+
// CHECK-NEXT: (call_expr {{.*}}
69+
// CHECK: (attempting type variable {{.*}} := (Bool) -> {{.*}}
70+
// CHECK: (attempting conjunction element pattern binding element @ 0
71+
// CHECK: (pattern_named implicit '$__builder{{.*}}')
72+
// CHECK: (applying conjunction result to outer context
73+
// CHECK: (attempting type variable {{.*}} := (Int?) -> {{.*}}
74+
// CHECK: (attempting disjunction choice {{.*}} bound to decl {{.*}}.Int.init(_:)
75+
let _ = {
76+
let x = 42
77+
test { cond in
78+
x
79+
} transform: { v in
80+
Int(v ?? 0)
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)