Skip to content

Commit a0426df

Browse files
authored
Merge pull request #33220 from xedin/rdar-66234725
[CSBindings] Don't attempt to rank unviable bindings
2 parents c6cd4b0 + d19c2cc commit a0426df

File tree

4 files changed

+72
-10
lines changed

4 files changed

+72
-10
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,28 @@ ConstraintSystem::determineBestBindings() {
377377
cache.insert({typeVar, getPotentialBindings(typeVar)});
378378
}
379379

380+
// Determine whether given type variable with its set of bindings is
381+
// viable to be attempted on the next step of the solver. If type variable
382+
// has no "direct" bindings of any kind e.g. direct bindings to concrete
383+
// types, default types from "defaultable" constraints or literal
384+
// conformances, such type variable is not viable to be evaluated to be
385+
// attempted next.
386+
auto isViableForRanking =
387+
[this](const ConstraintSystem::PotentialBindings &bindings) -> bool {
388+
auto *typeVar = bindings.TypeVar;
389+
390+
// If type variable is marked as a potential hole there is always going
391+
// to be at least one binding available for it.
392+
if (shouldAttemptFixes() && typeVar->getImpl().canBindToHole())
393+
return true;
394+
395+
return !bindings.Bindings.empty() || !bindings.Defaults.empty() ||
396+
llvm::any_of(bindings.Protocols, [&](Constraint *constraint) {
397+
return bool(
398+
TypeChecker::getDefaultType(constraint->getProtocol(), DC));
399+
});
400+
};
401+
380402
// Now let's see if we could infer something for related type
381403
// variables based on other bindings.
382404
for (auto *typeVar : getTypeVariables()) {
@@ -386,9 +408,21 @@ ConstraintSystem::determineBestBindings() {
386408

387409
auto &bindings = cachedBindings->getSecond();
388410

411+
// Before attempting to infer transitive bindings let's check
412+
// whether there are any viable "direct" bindings associated with
413+
// current type variable, if there are none - it means that this type
414+
// variable could only be used to transitively infer bindings for
415+
// other type variables and can't participate in ranking.
416+
//
417+
// Viable bindings include - any types inferred from constraints
418+
// associated with given type variable, any default constraints,
419+
// or any conformance requirements to literal protocols with can
420+
// produce a default type.
421+
bool isViable = isViableForRanking(bindings);
422+
389423
bindings.finalize(*this, cache);
390424

391-
if (!bindings)
425+
if (!bindings || !isViable)
392426
continue;
393427

394428
if (isDebugMode()) {

test/Constraints/rdar66234725.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
protocol P {}
4+
5+
protocol Func {
6+
associatedtype Result
7+
8+
init()
9+
10+
mutating func update<D: P>(data: D)
11+
12+
func finalize() -> Result
13+
}
14+
15+
struct S<T: P, F: Func> {
16+
var arr: [T]
17+
18+
func test() -> [F.Result] {
19+
return stride(from: 0, to: arr.endIndex, by: 2).map {
20+
(arr[$0], $0 < arr.index(before: arr.endIndex) ? arr[$0.advanced(by: 1)] : nil) // Ok
21+
}.map { (lhs, rhs) -> F.Result in
22+
var fun = F()
23+
fun.update(data: lhs)
24+
fun.update(data: rhs!)
25+
return fun.finalize()
26+
}
27+
}
28+
}

test/SILGen/function_conversion.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -663,14 +663,14 @@ struct FunctionConversionParameterSubstToOrigReabstractionTest {
663663
}
664664
}
665665

666-
// CHECK: sil hidden [ossa] @$s19function_conversion9dontCrashyyF
667-
// CHECK: [[FORCE_CAST:%.*]] = function_ref @$ss15_arrayForceCastySayq_GSayxGr0_lF
668-
// CHECK-NEXT: [[DOWNCAST_RESULT:%.*]] = apply [[FORCE_CAST]]<(String, String), (AnyHashable, Any)>({{.*}})
669-
// CHECK-NEXT: [[ADDR:%.*]] = alloc_stack $Array<(AnyHashable, Any)>
670-
// CHECK-NEXT: store [[DOWNCAST_RESULT]] to [init] [[ADDR]] : $*Array<(AnyHashable, Any)>
671-
// CHECK-NEXT: // function_ref Dictionary.init<A>(uniqueKeysWithValues:)
672-
// CHECK-NEXT: [[DICT_INIT:%.*]] = function_ref @$sSD20uniqueKeysWithValuesSDyxq_Gqd__n_tcSTRd__x_q_t7ElementRtd__lufC
673-
// CHECK-NEXT: apply [[DICT_INIT]]<AnyHashable, Any, [(AnyHashable, Any)]>([[ADDR]], [[TYPE:%.*]])
666+
// CHECK: sil {{.*}} [ossa] @$sS4SIgggoo_S2Ss11AnyHashableVyps5Error_pIegggrrzo_TR
667+
// CHECK: [[TUPLE:%.*]] = apply %4(%2, %3) : $@noescape @callee_guaranteed (@guaranteed String, @guaranteed String) -> (@owned String, @owned String)
668+
// CHECK: ([[LHS:%.*]], [[RHS:%.*]]) = destructure_tuple [[TUPLE]]
669+
// CHECK: [[ADDR:%.*]] = alloc_stack $String
670+
// CHECK: store [[LHS]] to [init] [[ADDR]] : $*String
671+
// CHECK: [[CVT:%.*]] = function_ref @$ss21_convertToAnyHashableys0cD0VxSHRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : Hashable> (@in_guaranteed τ_0_0) -> @out AnyHashable
672+
// CHECK: apply [[CVT]]<String>(%0, [[ADDR]])
673+
// CHECK: } // end sil function '$sS4SIgggoo_S2Ss11AnyHashableVyps5Error_pIegggrrzo_TR'
674674

675675
func dontCrash() {
676676
let userInfo = ["hello": "world"]

test/decl/typealias/generic.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ _ = A<String, Int>(a: "foo", // expected-error {{cannot convert value of type 'S
103103
b: 42) // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}}
104104
_ = B(a: 12, b: 42)
105105
_ = B(a: 12, b: 42 as Float)
106-
_ = B(a: "foo", b: 42) // expected-error {{conflicting arguments to generic parameter 'T1' ('String' vs. 'Int')}}
106+
_ = B(a: "foo", b: 42) // expected-error {{conflicting arguments to generic parameter 'T1' ('Int' vs. 'String')}}
107107
_ = C(a: "foo", b: 42)
108108
_ = C(a: 42, // expected-error {{cannot convert value of type 'Int' to expected argument type 'String'}}
109109
b: 42)

0 commit comments

Comments
 (0)