Skip to content

Commit d652ba0

Browse files
authored
Merge pull request swiftlang#36008 from xedin/a-couple-of-binding-refactorings
[CSBindings] A couple of minor refactorings
2 parents 2f584b5 + 655aeef commit d652ba0

File tree

2 files changed

+58
-37
lines changed

2 files changed

+58
-37
lines changed

include/swift/Sema/CSBindings.h

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,33 @@ struct LiteralRequirement {
185185
CoveredBy = coveredBy;
186186
}
187187

188-
bool isCoveredBy(Type type, DeclContext *useDC) const;
188+
/// Determines whether this literal requirement is "covered"
189+
/// by the given binding - type of the binding could either be
190+
/// equal (in canonical sense) to the protocol's default type,
191+
/// or conform to a protocol.
192+
///
193+
/// \param binding The binding to check for coverage.
194+
///
195+
/// \param canBeNil The flag that determines whether given type
196+
/// variable requires all of its bindings to be optional.
197+
///
198+
/// \param useDC The declaration context in which this literal
199+
/// requirement is used.
200+
///
201+
/// \returns a pair of bool and a type:
202+
/// - bool, true if binding covers given literal protocol;
203+
/// - type, non-null if binding type has to be adjusted
204+
/// to cover given literal protocol;
205+
std::pair<bool, Type> isCoveredBy(const PotentialBinding &binding,
206+
bool canBeNil,
207+
DeclContext *useDC) const;
189208

190209
/// Determines whether literal protocol associated with this
191210
/// meta-information is viable for inclusion as a defaultable binding.
192211
bool viableAsBinding() const { return !isCovered() && hasDefaultType(); }
212+
213+
private:
214+
bool isCoveredBy(Type type, DeclContext *useDC) const;
193215
};
194216

195217
struct PotentialBindings {
@@ -231,7 +253,8 @@ struct PotentialBindings {
231253
/// bindings (contained in the binding type e.g. `Foo<$T0>`), or
232254
/// reachable through subtype/conversion relationship e.g.
233255
/// `$T0 subtype of $T1` or `$T0 arg conversion $T1`.
234-
llvm::SmallPtrSet<TypeVariableType *, 2> AdjacentVars;
256+
llvm::SmallDenseSet<std::pair<TypeVariableType *, Constraint *>, 2>
257+
AdjacentVars;
235258

236259
ASTNode AssociatedCodeCompletionToken = ASTNode();
237260

@@ -391,26 +414,6 @@ struct PotentialBindings {
391414

392415
void addLiteral(Constraint *constraint);
393416

394-
/// Determines whether the given literal protocol is "covered"
395-
/// by the given binding - type of the binding could either be
396-
/// equal (in canonical sense) to the protocol's default type,
397-
/// or conform to a protocol.
398-
///
399-
/// \param literal The literal protocol requirement to check.
400-
///
401-
/// \param binding The binding to check for coverage.
402-
///
403-
/// \param canBeNil The flag that determines whether given type
404-
/// variable requires all of its bindings to be optional.
405-
///
406-
/// \returns a pair of bool and a type:
407-
/// - bool, true if binding covers given literal protocol;
408-
/// - type, non-null if binding type has to be adjusted
409-
/// to cover given literal protocol;
410-
std::pair<bool, Type> isLiteralCoveredBy(const LiteralRequirement &literal,
411-
const PotentialBinding &binding,
412-
bool canBeNil) const;
413-
414417
/// Add a potential binding to the list of bindings,
415418
/// coalescing supertype bounds when we are able to compute the meet.
416419
void addPotentialBinding(PotentialBinding binding, bool allowJoinMeet = true);

lib/Sema/CSBindings.cpp

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ bool PotentialBindings::involvesTypeVariables() const {
119119
// on each step of the solver, but once bindings are computed
120120
// incrementally it becomes more important to double-check that
121121
// any adjacent type variables found previously are still unresolved.
122-
return llvm::any_of(AdjacentVars, [](TypeVariableType *typeVar) {
123-
return !typeVar->getImpl().getFixedType(/*record=*/nullptr);
122+
return llvm::any_of(AdjacentVars, [](const auto &adjacent) {
123+
return !adjacent.first->getImpl().getFixedType(/*record=*/nullptr);
124124
});
125125
}
126126

@@ -594,9 +594,9 @@ bool LiteralRequirement::isCoveredBy(Type type, DeclContext *useDC) const {
594594
}
595595

596596
std::pair<bool, Type>
597-
PotentialBindings::isLiteralCoveredBy(const LiteralRequirement &literal,
598-
const PotentialBinding &binding,
599-
bool canBeNil) const {
597+
LiteralRequirement::isCoveredBy(const PotentialBinding &binding,
598+
bool canBeNil,
599+
DeclContext *useDC) const {
600600
auto type = binding.BindingType;
601601
switch (binding.Kind) {
602602
case AllowedBindingKind::Exact:
@@ -616,7 +616,7 @@ PotentialBindings::isLiteralCoveredBy(const LiteralRequirement &literal,
616616
if (type->isTypeVariableOrMember() || type->isHole())
617617
return std::make_pair(false, Type());
618618

619-
if (literal.isCoveredBy(type, CS.DC)) {
619+
if (isCoveredBy(type, useDC)) {
620620
return std::make_pair(true, requiresUnwrap ? type : binding.BindingType);
621621
}
622622

@@ -628,7 +628,7 @@ PotentialBindings::isLiteralCoveredBy(const LiteralRequirement &literal,
628628
// If this literal protocol is not a direct requirement it
629629
// would not be possible to change optionality while inferring
630630
// bindings for a supertype, so this hack doesn't apply.
631-
if (!literal.isDirectRequirement())
631+
if (!isDirectRequirement())
632632
return std::make_pair(false, Type());
633633

634634
// If we're allowed to bind to subtypes, look through optionals.
@@ -726,7 +726,7 @@ void PotentialBindings::addPotentialBinding(PotentialBinding binding,
726726
Type adjustedTy;
727727

728728
std::tie(isCovered, adjustedTy) =
729-
isLiteralCoveredBy(info, binding, allowsNil);
729+
info.isCoveredBy(binding, allowsNil, CS.DC);
730730

731731
if (!isCovered)
732732
continue;
@@ -800,7 +800,7 @@ void PotentialBindings::addLiteral(Constraint *constraint) {
800800
Type adjustedTy;
801801

802802
std::tie(isCovered, adjustedTy) =
803-
isLiteralCoveredBy(literal, *binding, allowsNil);
803+
literal.isCoveredBy(*binding, allowsNil, CS.DC);
804804

805805
// No luck here, let's try next literal requirement.
806806
if (!isCovered)
@@ -983,7 +983,8 @@ PotentialBindings::inferFromRelational(Constraint *constraint) {
983983
findInferableTypeVars(second, typeVars);
984984

985985
if (typeVars.erase(TypeVar)) {
986-
AdjacentVars.insert(typeVars.begin(), typeVars.end());
986+
for (auto *typeVar : typeVars)
987+
AdjacentVars.insert({typeVar, constraint});
987988
}
988989

989990
return None;
@@ -1016,9 +1017,21 @@ PotentialBindings::inferFromRelational(Constraint *constraint) {
10161017
if (type->getWithoutSpecifierType()
10171018
->lookThroughAllOptionalTypes()
10181019
->is<DependentMemberType>()) {
1019-
type->getTypeVariables(AdjacentVars);
1020+
llvm::SmallPtrSet<TypeVariableType *, 4> referencedVars;
1021+
type->getTypeVariables(referencedVars);
1022+
1023+
bool containsSelf = false;
1024+
for (auto *var : referencedVars) {
1025+
// Add all type variables encountered in the type except
1026+
// to the current type variable.
1027+
if (var != TypeVar) {
1028+
AdjacentVars.insert({var, constraint});
1029+
continue;
1030+
}
1031+
1032+
containsSelf = true;
1033+
}
10201034

1021-
bool containsSelf = AdjacentVars.erase(TypeVar);
10221035
// If inferred type doesn't contain the current type variable,
10231036
// let's mark bindings as delayed until dependent member type
10241037
// is resolved.
@@ -1043,15 +1056,20 @@ PotentialBindings::inferFromRelational(Constraint *constraint) {
10431056
// Check whether we can perform this binding.
10441057
if (auto boundType = checkTypeOfBinding(TypeVar, type)) {
10451058
type = *boundType;
1046-
if (type->hasTypeVariable())
1047-
type->getTypeVariables(AdjacentVars);
1059+
if (type->hasTypeVariable()) {
1060+
llvm::SmallPtrSet<TypeVariableType *, 4> referencedVars;
1061+
type->getTypeVariables(referencedVars);
1062+
for (auto *var : referencedVars) {
1063+
AdjacentVars.insert({var, constraint});
1064+
}
1065+
}
10481066
} else {
10491067
auto *bindingTypeVar = type->getRValueType()->getAs<TypeVariableType>();
10501068

10511069
if (!bindingTypeVar)
10521070
return None;
10531071

1054-
AdjacentVars.insert(bindingTypeVar);
1072+
AdjacentVars.insert({bindingTypeVar, constraint});
10551073

10561074
// If current type variable is associated with a code completion token
10571075
// it's possible that it doesn't have enough contextual information

0 commit comments

Comments
 (0)