Skip to content

Commit 86adc6f

Browse files
authored
Merge pull request #70148 from xedin/fix-perf-regression-with-keypath-inference
[TypeChecker] Improve performance of key path expression inference
2 parents c70447c + dde5014 commit 86adc6f

File tree

7 files changed

+106
-2
lines changed

7 files changed

+106
-2
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,10 @@ class TypeVariableType::Implementation {
519519
/// Determine whether this type variable represents an opened opaque type.
520520
bool isOpaqueType() const;
521521

522+
/// Determine whether this type variable represents a type of an array literal
523+
/// (represented by `ArrayExpr` in AST).
524+
bool isArrayLiteralType() const;
525+
522526
/// Retrieve the representative of the equivalence class to which this
523527
/// type variable belongs.
524528
///

lib/Sema/CSBindings.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,10 +1253,21 @@ bool BindingSet::favoredOverDisjunction(Constraint *disjunction) const {
12531253
return boundType->lookThroughAllOptionalTypes()->is<TypeVariableType>();
12541254
}
12551255

1256+
// If this is an array literal type, it's preferrable to bind it
1257+
// early (unless it's delayed) to connect all of its elements even
1258+
// if it doesn't have any bindings.
1259+
if (TypeVar->getImpl().isArrayLiteralType())
1260+
return !involvesTypeVariables();
1261+
12561262
// Don't prioritize type variables that don't have any direct bindings.
12571263
if (Bindings.empty())
12581264
return false;
12591265

1266+
// Always prefer key path type if it has bindings and is not delayed
1267+
// because that means that it was possible to infer its capability.
1268+
if (TypeVar->getImpl().isKeyPathType())
1269+
return true;
1270+
12601271
return !involvesTypeVariables();
12611272
}
12621273

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ bool TypeVariableType::Implementation::isOpaqueType() const {
191191
return false;
192192
}
193193

194+
bool TypeVariableType::Implementation::isArrayLiteralType() const {
195+
return locator && locator->directlyAt<ArrayExpr>();
196+
}
197+
194198
void *operator new(size_t bytes, ConstraintSystem& cs,
195199
size_t alignment) {
196200
return cs.getAllocator().Allocate(bytes, alignment);

test/Constraints/casts.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,8 @@ func test_compatibility_coercions(_ arr: [Int], _ optArr: [Int]?, _ dict: [Strin
349349
_ = [i: stringAnyDict] as [String: Any] // expected-error {{cannot convert value of type 'Int' to expected dictionary key type 'String'}}
350350

351351
// These are currently not peepholed.
352-
_ = [i].self as Magic as [String] // expected-error {{cannot convert value of type 'Int' to expected element type 'String'}}
353-
_ = (try [i]) as Magic as [String] // expected-error {{cannot convert value of type 'Int' to expected element type 'String'}}
352+
_ = [i].self as Magic as [String] // expected-warning {{coercion from '[Int]' to '[String]' may fail; use 'as?' or 'as!' instead}}
353+
_ = (try [i]) as Magic as [String] // expected-warning {{coercion from '[Int]' to '[String]' may fail; use 'as?' or 'as!' instead}}
354354
// expected-warning@-1 {{no calls to throwing functions occur within 'try' expression}}
355355

356356
// These are wrong, but make sure we don't warn about the value cast always succeeding.

test/SILGen/collection_downcast.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,4 +297,15 @@ func testCollectionCompatibilityCoercions(_ arr: [Int], _ optArr: [Any]?, _ set:
297297
// CHECK: [[CAST_FN:%.+]] = function_ref @$ss17_dictionaryUpCastySDyq0_q1_GSDyxq_GSHRzSHR0_r2_lF : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3>
298298
// CHECK: apply [[CAST_FN]]<String, Int, Int, String>([[DICT]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3>
299299
_ = promote(promote(promote(dict))) as [Int: String]
300+
301+
typealias Magic<T> = T
302+
303+
// These are currently not peepholed.
304+
// CHECK: [[CAST_FN:%.+]] = function_ref @$ss15_arrayForceCastySayq_GSayxGr0_lF : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1>
305+
// CHECK: apply [[CAST_FN]]<Int, String>
306+
[i].self as Magic as [String]
307+
308+
// CHECK: [[CAST_FN:%.+]] = function_ref @$ss15_arrayForceCastySayq_GSayxGr0_lF : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1>
309+
// CHECK: apply [[CAST_FN]]<Int, String>
310+
(try [i]) as Magic as [String]
300311
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// RUN: %scale-test --begin 1 --end 5 --step 1 --select NumConstraintScopes %s
2+
// REQUIRES: asserts,no_asan
3+
4+
struct Root {
5+
enum E: Int, Comparable {
6+
case test = 0
7+
static func < (_ lhs: Self, _ rhs: Self) -> Bool { false }
8+
}
9+
10+
let word: String
11+
let maybeWord: String?
12+
let e: E
13+
let maybeE: E?
14+
}
15+
16+
enum Order {
17+
case forward
18+
}
19+
20+
protocol P {
21+
}
22+
23+
struct Descriptor<Base> {
24+
public init<Value>(_ keyPath: KeyPath<Base, Value>, order: Order = .forward) where Value: Comparable { fatalError() }
25+
public init<Value>(_ keyPath: KeyPath<Base, Value?>, order: Order = .forward) where Value: Comparable { fatalError() }
26+
27+
public init(_ keyPath: KeyPath<Base, Double>, order: Order = .forward) { fatalError() }
28+
public init(_ keyPath: KeyPath<Base, Double?>, order: Order = .forward) { fatalError() }
29+
public init(_ keyPath: KeyPath<Base, Float>, order: Order = .forward) { fatalError() }
30+
public init(_ keyPath: KeyPath<Base, Float?>, order: Order = .forward) { fatalError() }
31+
public init(_ keyPath: KeyPath<Base, String>, order: Order = .forward) { fatalError() }
32+
public init(_ keyPath: KeyPath<Base, String?>, order: Order = .forward) { fatalError() }
33+
34+
public init(_ keyPath: KeyPath<Base, Int8>, order: Order = .forward) { fatalError() }
35+
public init(_ keyPath: KeyPath<Base, Int8?>, order: Order = .forward) { fatalError() }
36+
public init(_ keyPath: KeyPath<Base, Int16>, order: Order = .forward) { fatalError() }
37+
public init(_ keyPath: KeyPath<Base, Int16?>, order: Order = .forward) { fatalError() }
38+
public init(_ keyPath: KeyPath<Base, Int32>, order: Order = .forward) { fatalError() }
39+
public init(_ keyPath: KeyPath<Base, Int32?>, order: Order = .forward) { fatalError() }
40+
public init(_ keyPath: KeyPath<Base, Int64>, order: Order = .forward) { fatalError() }
41+
public init(_ keyPath: KeyPath<Base, Int64?>, order: Order = .forward) { fatalError() }
42+
43+
public init(_ keyPath: KeyPath<Base, UInt8>, order: Order = .forward) { fatalError() }
44+
public init(_ keyPath: KeyPath<Base, UInt8?>, order: Order = .forward) { fatalError() }
45+
public init(_ keyPath: KeyPath<Base, UInt16>, order: Order = .forward) { fatalError() }
46+
public init(_ keyPath: KeyPath<Base, UInt16?>, order: Order = .forward) { fatalError() }
47+
public init(_ keyPath: KeyPath<Base, UInt32>, order: Order = .forward) { fatalError() }
48+
public init(_ keyPath: KeyPath<Base, UInt32?>, order: Order = .forward) { fatalError() }
49+
public init(_ keyPath: KeyPath<Base, UInt64>, order: Order = .forward) { fatalError() }
50+
public init(_ keyPath: KeyPath<Base, UInt64?>, order: Order = .forward) { fatalError() }
51+
}
52+
53+
let _ = [
54+
%for i in range(0, N):
55+
Descriptor(\Root.word),
56+
Descriptor(\Root.maybeWord),
57+
Descriptor(\Root.e),
58+
Descriptor(\Root.maybeE),
59+
%end
60+
]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %scale-test --begin 2 --end 10 --step 1 --select NumConstraintScopes %s
2+
// REQUIRES: asserts,no_asan
3+
4+
struct Test {
5+
var id: String
6+
}
7+
8+
func test(data: [Test]) -> Set<String> {
9+
Set(data.map(\.id) +
10+
%for i in range(0, N):
11+
data.map(\.id) +
12+
%end
13+
data.map(\.id))
14+
}

0 commit comments

Comments
 (0)