Skip to content

Commit fc05d4a

Browse files
authored
Merge pull request #35225 from xedin/refactor-literal-bindings
[CSBindings] Refactor literal protocol requirement handling
2 parents 7fb4815 + 8356ab4 commit fc05d4a

File tree

6 files changed

+487
-269
lines changed

6 files changed

+487
-269
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 94 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,6 @@ class SolutionApplicationTarget;
6666

6767
} // end namespace constraints
6868

69-
namespace unittest {
70-
71-
class SemaTest;
72-
73-
} // end namespace unittest
74-
7569
// Forward declare some TypeChecker related functions
7670
// so they could be made friends of ConstraintSystem.
7771
namespace TypeChecker {
@@ -2026,8 +2020,6 @@ enum class SolutionApplicationToFunctionResult {
20262020
class ConstraintSystem {
20272021
ASTContext &Context;
20282022

2029-
friend class swift::unittest::SemaTest;
2030-
20312023
public:
20322024
DeclContext *DC;
20332025
ConstraintSystemOptions Options;
@@ -4625,7 +4617,8 @@ class ConstraintSystem {
46254617
ConstraintKind bodyResultConstraintKind,
46264618
ConstraintLocatorBuilder locator);
46274619

4628-
private:
4620+
public: // binding inference logic is public for unit testing.
4621+
46294622
/// The kind of bindings that are permitted.
46304623
enum class AllowedBindingKind : uint8_t {
46314624
/// Only the exact type.
@@ -4700,6 +4693,8 @@ class ConstraintSystem {
47004693
return BindingSource.get<ConstraintLocator *>();
47014694
}
47024695

4696+
Constraint *getSource() const { return BindingSource.get<Constraint *>(); }
4697+
47034698
PotentialBinding withType(Type type) const {
47044699
return {type, Kind, BindingSource};
47054700
}
@@ -4721,6 +4716,50 @@ class ConstraintSystem {
47214716
}
47224717
};
47234718

4719+
struct LiteralRequirement {
4720+
/// The source of the literal requirement.
4721+
Constraint *Source;
4722+
/// The default type associated with this literal (if any).
4723+
Type DefaultType;
4724+
/// Determines whether this literal is a direct requirement
4725+
/// of the current type variable.
4726+
bool IsDirectRequirement;
4727+
4728+
/// If the literal is covered by existing type binding,
4729+
/// this points to the source of the binding.
4730+
mutable Constraint *CoveredBy = nullptr;
4731+
4732+
LiteralRequirement(Constraint *source, Type defaultTy, bool isDirect)
4733+
: Source(source), DefaultType(defaultTy),
4734+
IsDirectRequirement(isDirect) {}
4735+
4736+
Constraint *getSource() const { return Source; }
4737+
4738+
ProtocolDecl *getProtocol() const { return Source->getProtocol(); }
4739+
4740+
bool isCovered() const { return bool(CoveredBy); }
4741+
4742+
bool isDirectRequirement() const { return IsDirectRequirement; }
4743+
4744+
bool hasDefaultType() const { return bool(DefaultType); }
4745+
4746+
Type getDefaultType() const {
4747+
assert(hasDefaultType());
4748+
return DefaultType;
4749+
}
4750+
4751+
void setCoveredBy(Constraint *coveredBy) {
4752+
assert(!isCovered());
4753+
CoveredBy = coveredBy;
4754+
}
4755+
4756+
bool isCoveredBy(Type type, DeclContext *useDC) const;
4757+
4758+
/// Determines whether literal protocol associated with this
4759+
/// meta-information is viable for inclusion as a defaultable binding.
4760+
bool viableAsBinding() const { return !isCovered() && hasDefaultType(); }
4761+
};
4762+
47244763
struct PotentialBindings {
47254764
using BindingScore =
47264765
std::tuple<bool, bool, bool, bool, bool, unsigned char, int>;
@@ -4740,6 +4779,14 @@ class ConstraintSystem {
47404779
/// subtype/conversion/equivalence relations with other type variables.
47414780
Optional<llvm::SmallPtrSet<Constraint *, 4>> TransitiveProtocols;
47424781

4782+
/// The set of unique literal protocol requirements placed on this
4783+
/// type variable or inferred transitively through subtype chains.
4784+
///
4785+
/// Note that ordering is important when it comes to bindings, we'd
4786+
/// like to add any "direct" default types first to attempt them
4787+
/// before transitive ones.
4788+
llvm::SmallMapVector<ProtocolDecl *, LiteralRequirement, 2> Literals;
4789+
47434790
/// The set of constraints which would be used to infer default types.
47444791
llvm::SmallDenseMap<CanType, Constraint *, 2> Defaults;
47454792

@@ -4756,9 +4803,6 @@ class ConstraintSystem {
47564803

47574804
ASTNode AssociatedCodeCompletionToken = ASTNode();
47584805

4759-
/// Whether this type variable has literal bindings.
4760-
LiteralBindingKind LiteralBinding = LiteralBindingKind::None;
4761-
47624806
/// A set of all not-yet-resolved type variables this type variable
47634807
/// is a subtype of, supertype of or is equivalent to. This is used
47644808
/// to determine ordering inside of a chain of subtypes to help infer
@@ -4772,9 +4816,14 @@ class ConstraintSystem {
47724816

47734817
/// Determine whether the set of bindings is non-empty.
47744818
explicit operator bool() const {
4775-
return !Bindings.empty() || !Defaults.empty() || isDirectHole();
4819+
return !Bindings.empty() || getNumViableLiteralBindings() > 0 ||
4820+
!Defaults.empty() || isDirectHole();
47764821
}
47774822

4823+
/// Determines whether this type variable could be `nil`,
4824+
/// which means that all of its bindings should be optional.
4825+
bool canBeNil() const;
4826+
47784827
/// Determine whether attempting this type variable should be
47794828
/// delayed until the rest of the constraint system is considered
47804829
/// "fully bound" meaning constraints, which affect completeness
@@ -4822,8 +4871,8 @@ class ConstraintSystem {
48224871
if (!CS.shouldAttemptFixes())
48234872
return false;
48244873

4825-
return Bindings.empty() && Defaults.empty() &&
4826-
TypeVar->getImpl().canBindToHole();
4874+
return Bindings.empty() && getNumViableLiteralBindings() == 0 &&
4875+
Defaults.empty() && TypeVar->getImpl().canBindToHole();
48274876
}
48284877

48294878
/// Determine if the bindings only constrain the type variable from above
@@ -4839,6 +4888,8 @@ class ConstraintSystem {
48394888
});
48404889
}
48414890

4891+
unsigned getNumViableLiteralBindings() const;
4892+
48424893
unsigned getNumViableDefaultableBindings() const {
48434894
if (isDirectHole())
48444895
return 1;
@@ -4875,16 +4926,19 @@ class ConstraintSystem {
48754926
// It's considered to be non-default for purposes of
48764927
// ranking because we'd like to prioritize resolving
48774928
// closures to gain more information from their bodies.
4878-
auto numNonDefaultableBindings =
4879-
!b.Bindings.empty() ? b.Bindings.size()
4880-
: b.TypeVar->getImpl().isClosureType() ? 1 : 0;
4929+
unsigned numBindings =
4930+
b.Bindings.size() + b.getNumViableLiteralBindings();
4931+
auto numNonDefaultableBindings = numBindings > 0 ? numBindings
4932+
: b.TypeVar->getImpl().isClosureType()
4933+
? 1
4934+
: 0;
48814935

48824936
return std::make_tuple(b.isHole(),
48834937
numNonDefaultableBindings == 0,
48844938
b.isDelayed(),
48854939
b.isSubtypeOfExistentialType(),
48864940
b.involvesTypeVariables(),
4887-
static_cast<unsigned char>(b.LiteralBinding),
4941+
static_cast<unsigned char>(b.getLiteralKind()),
48884942
-numNonDefaultableBindings);
48894943
}
48904944

@@ -4928,26 +4982,27 @@ class ConstraintSystem {
49284982
return x.isPotentiallyIncomplete() < y.isPotentiallyIncomplete();
49294983
}
49304984

4931-
void foundLiteralBinding(ProtocolDecl *proto) {
4932-
switch (*proto->getKnownProtocolKind()) {
4933-
case KnownProtocolKind::ExpressibleByDictionaryLiteral:
4934-
case KnownProtocolKind::ExpressibleByArrayLiteral:
4935-
case KnownProtocolKind::ExpressibleByStringInterpolation:
4936-
LiteralBinding = LiteralBindingKind::Collection;
4937-
break;
4985+
LiteralBindingKind getLiteralKind() const;
49384986

4939-
case KnownProtocolKind::ExpressibleByFloatLiteral:
4940-
LiteralBinding = LiteralBindingKind::Float;
4941-
break;
4987+
void addDefault(Constraint *constraint);
49424988

4943-
default:
4944-
if (LiteralBinding != LiteralBindingKind::Collection)
4945-
LiteralBinding = LiteralBindingKind::Atom;
4946-
break;
4947-
}
4948-
}
4989+
void addLiteral(Constraint *constraint);
49494990

4950-
void addDefault(Constraint *constraint);
4991+
/// Determines whether the given literal protocol is "covered"
4992+
/// by the given binding - type of the binding could either be
4993+
/// equal (in canonical sense) to the protocol's default type,
4994+
/// or conform to a protocol.
4995+
///
4996+
/// \param literal The literal protocol requirement to check.
4997+
///
4998+
/// \param binding The binding to check for coverage.
4999+
///
5000+
/// \param canBeNil The flag that determines whether given type
5001+
/// variable requires all of its bindings to be optional.
5002+
///
5003+
/// \returns true if binding covers given literal protocol.
5004+
bool isLiteralCoveredBy(const LiteralRequirement &literal,
5005+
PotentialBinding &binding, bool canBeNil) const;
49515006

49525007
/// Add a potential binding to the list of bindings,
49535008
/// coalescing supertype bounds when we are able to compute the meet.
@@ -5008,11 +5063,6 @@ class ConstraintSystem {
50085063
ConstraintSystem::PotentialBindings>
50095064
&inferredBindings);
50105065

5011-
/// Infer bindings based on any protocol conformances that have default
5012-
/// types.
5013-
void inferDefaultTypes(ConstraintSystem &cs,
5014-
llvm::SmallPtrSetImpl<CanType> &existingTypes);
5015-
50165066
public:
50175067
bool infer(ConstraintSystem &cs,
50185068
llvm::SmallPtrSetImpl<CanType> &exactTypes,
@@ -5036,8 +5086,9 @@ class ConstraintSystem {
50365086
out << "delayed ";
50375087
if (isSubtypeOfExistentialType())
50385088
out << "subtype_of_existential ";
5039-
if (LiteralBinding != LiteralBindingKind::None)
5040-
out << "literal=" << static_cast<int>(LiteralBinding) << " ";
5089+
auto literalKind = getLiteralKind();
5090+
if (literalKind != LiteralBindingKind::None)
5091+
out << "literal=" << static_cast<int>(literalKind) << " ";
50415092
if (involvesTypeVariables())
50425093
out << "involves_type_vars ";
50435094

@@ -5102,7 +5153,6 @@ class ConstraintSystem {
51025153
Optional<Type> checkTypeOfBinding(TypeVariableType *typeVar, Type type) const;
51035154
Optional<PotentialBindings> determineBestBindings();
51045155

5105-
public:
51065156
/// Infer bindings for the given type variable based on current
51075157
/// state of the constraint system.
51085158
PotentialBindings inferBindingsFor(TypeVariableType *typeVar,

0 commit comments

Comments
 (0)