Skip to content

Commit d19c2cc

Browse files
committed
[CSBindings] Don't attempt to rank unviable bindings
If a type variable doesn't have any "direct" bindings let's not consider it as viable to be attempted next. Such type variables are helps purely to accommodate transitive binding inference for other members of subtype chain. Resolves: rdar://problem/66234725
1 parent 0c684f0 commit d19c2cc

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)