Skip to content

Commit e5e54e7

Browse files
committed
[CSBindings] Infer transitive defaults and add them at finalization
1 parent 91823fd commit e5e54e7

File tree

3 files changed

+58
-45
lines changed

3 files changed

+58
-45
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,6 @@ void ConstraintSystem::PotentialBindings::inferTransitiveBindings(
4444
return rhs->getAs<TypeVariableType>() == TypeVar;
4545
});
4646

47-
if (conversions.empty())
48-
return;
49-
5047
for (auto *constraint : conversions) {
5148
auto *tv =
5249
cs.simplifyType(constraint->getFirstType())->getAs<TypeVariableType>();
@@ -57,16 +54,19 @@ void ConstraintSystem::PotentialBindings::inferTransitiveBindings(
5754
if (relatedBindings == inferredBindings.end())
5855
continue;
5956

57+
auto &bindings = relatedBindings->getSecond();
58+
6059
// Infer transitive protocol requirements.
61-
for (auto *protocol : relatedBindings->getSecond().Protocols) {
62-
Protocols.push_back(protocol);
63-
}
60+
llvm::copy(bindings.Protocols, std::back_inserter(Protocols));
61+
62+
// Infer transitive defaults.
63+
llvm::copy(bindings.Defaults, std::back_inserter(Defaults));
6464

6565
// TODO: We shouldn't need this in the future.
6666
if (constraint->getKind() != ConstraintKind::Subtype)
6767
continue;
6868

69-
for (auto &binding : relatedBindings->getSecond().Bindings) {
69+
for (auto &binding : bindings.Bindings) {
7070
// We need the binding kind for the potential binding to
7171
// either be Exact or Supertypes in order for it to make sense
7272
// to add Supertype bindings based on the relationship between
@@ -92,6 +92,27 @@ void ConstraintSystem::PotentialBindings::inferTransitiveBindings(
9292
}
9393
}
9494

95+
void ConstraintSystem::PotentialBindings::inferDefaultTypes(
96+
ConstraintSystem &cs, llvm::SmallPtrSetImpl<CanType> &existingTypes) {
97+
/// Add defaultable constraints.
98+
for (auto *constraint : Defaults) {
99+
Type type = constraint->getSecondType();
100+
if (!existingTypes.insert(type->getCanonicalType()).second)
101+
continue;
102+
103+
if (constraint->getKind() == ConstraintKind::DefaultClosureType) {
104+
// If there are no other possible bindings for this closure
105+
// let's default it to the type inferred from its parameters/body,
106+
// otherwise we should only attempt contextual types as a
107+
// top-level closure type.
108+
if (!Bindings.empty())
109+
continue;
110+
}
111+
112+
addPotentialBinding({type, AllowedBindingKind::Exact, constraint});
113+
}
114+
}
115+
95116
void ConstraintSystem::PotentialBindings::finalize(
96117
ConstraintSystem &cs,
97118
const llvm::SmallDenseMap<TypeVariableType *,
@@ -105,6 +126,8 @@ void ConstraintSystem::PotentialBindings::finalize(
105126

106127
inferTransitiveBindings(cs, existingTypes, inferredBindings);
107128

129+
inferDefaultTypes(cs, existingTypes);
130+
108131
// Adjust optionality of existing bindings based on presence of
109132
// `ExpressibleByNilLiteral` requirement.
110133
if (llvm::any_of(Protocols, [](Constraint *constraint) {
@@ -153,6 +176,17 @@ void ConstraintSystem::PotentialBindings::finalize(
153176

154177
addPotentialBinding(PotentialBinding::forHole(cs.getASTContext(), locator));
155178
}
179+
180+
// Determine if the bindings only constrain the type variable from above with
181+
// an existential type; such a binding is not very helpful because it's
182+
// impossible to enumerate the existential type's subtypes.
183+
if (!Bindings.empty()) {
184+
SubtypeOfExistentialType =
185+
llvm::all_of(Bindings, [](const PotentialBinding &binding) {
186+
return binding.BindingType->isExistentialType() &&
187+
binding.Kind == AllowedBindingKind::Subtypes;
188+
});
189+
}
156190
}
157191

158192
Optional<ConstraintSystem::PotentialBindings>
@@ -516,7 +550,6 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
516550

517551
// Consider each of the constraints related to this type variable.
518552
llvm::SmallPtrSet<CanType, 4> exactTypes;
519-
SmallVector<Constraint *, 2> defaultableConstraints;
520553
SmallVector<PotentialBinding, 4> literalBindings;
521554
bool hasNonDependentMemberRelationalConstraints = false;
522555
bool hasDependentMemberRelationalConstraints = false;
@@ -636,7 +669,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
636669
// Do these in a separate pass.
637670
if (getFixedTypeRecursive(constraint->getFirstType(), true)
638671
->getAs<TypeVariableType>() == typeVar) {
639-
defaultableConstraints.push_back(constraint);
672+
result.Defaults.push_back(constraint);
640673
hasNonDependentMemberRelationalConstraints = true;
641674
}
642675
break;
@@ -854,34 +887,6 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
854887
}
855888
}
856889

857-
/// Add defaultable constraints last.
858-
for (auto constraint : defaultableConstraints) {
859-
Type type = constraint->getSecondType();
860-
if (!exactTypes.insert(type->getCanonicalType()).second)
861-
continue;
862-
863-
if (constraint->getKind() == ConstraintKind::DefaultClosureType) {
864-
// If there are no other possible bindings for this closure
865-
// let's default it to the type inferred from its parameters/body,
866-
// otherwise we should only attempt contextual types as a
867-
// top-level closure type.
868-
if (!result.Bindings.empty())
869-
continue;
870-
}
871-
872-
result.addPotentialBinding({type, AllowedBindingKind::Exact, constraint});
873-
}
874-
875-
// Determine if the bindings only constrain the type variable from above with
876-
// an existential type; such a binding is not very helpful because it's
877-
// impossible to enumerate the existential type's subtypes.
878-
result.SubtypeOfExistentialType =
879-
std::all_of(result.Bindings.begin(), result.Bindings.end(),
880-
[](const PotentialBinding &binding) {
881-
return binding.BindingType->isExistentialType() &&
882-
binding.Kind == AllowedBindingKind::Subtypes;
883-
});
884-
885890
// If there were both dependent-member and non-dependent-member relational
886891
// constraints, consider this "fully bound"; we don't want to touch it.
887892
if (hasDependentMemberRelationalConstraints) {

lib/Sema/ConstraintSystem.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4423,6 +4423,9 @@ class ConstraintSystem {
44234423
/// The set of protocol requirements placed on this type variable.
44244424
llvm::TinyPtrVector<Constraint *> Protocols;
44254425

4426+
/// The set of constraints which would be used to infer default types.
4427+
llvm::TinyPtrVector<Constraint *> Defaults;
4428+
44264429
/// Whether these bindings should be delayed until the rest of the
44274430
/// constraint system is considered "fully bound".
44284431
bool FullyBound = false;
@@ -4574,6 +4577,11 @@ class ConstraintSystem {
45744577
ConstraintSystem::PotentialBindings>
45754578
&inferredBindings);
45764579

4580+
/// Infer bindings based on any protocol conformances that have default
4581+
/// types.
4582+
void inferDefaultTypes(ConstraintSystem &cs,
4583+
llvm::SmallPtrSetImpl<CanType> &existingTypes);
4584+
45774585
/// Finalize binding computation for this type variable by
45784586
/// inferring bindings from context e.g. transitive bindings.
45794587
void finalize(ConstraintSystem &cs,

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 {{.*}} [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'
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:%.*]])
674674

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

0 commit comments

Comments
 (0)