Skip to content

Commit ea5eb89

Browse files
committed
[CSBindings] Determine literal coverage and default types during finalization
Based on collected direct and transitive information about protocol requirements let's determine literal protocol coverage by existing bindings as well as any default types which have to be introduced to the set as part of finalization phase.
1 parent e5e54e7 commit ea5eb89

File tree

1 file changed

+86
-117
lines changed

1 file changed

+86
-117
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 86 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,92 @@ void ConstraintSystem::PotentialBindings::inferTransitiveBindings(
9494

9595
void ConstraintSystem::PotentialBindings::inferDefaultTypes(
9696
ConstraintSystem &cs, llvm::SmallPtrSetImpl<CanType> &existingTypes) {
97+
// If we have any literal constraints, check whether there is already a
98+
// binding that provides a type that conforms to that literal protocol. In
99+
// such cases, don't add the default binding suggestion because the existing
100+
// suggestion is better.
101+
llvm::SmallPtrSet<ProtocolDecl *, 4> coveredLiteralProtocols;
102+
103+
for (auto &binding : Bindings) {
104+
Type type;
105+
106+
switch (binding.Kind) {
107+
case AllowedBindingKind::Exact:
108+
type = binding.BindingType;
109+
break;
110+
111+
case AllowedBindingKind::Subtypes:
112+
case AllowedBindingKind::Supertypes:
113+
type = binding.BindingType->getRValueType();
114+
break;
115+
}
116+
117+
if (type->isTypeVariableOrMember() || type->isHole())
118+
continue;
119+
120+
bool requiresUnwrap = false;
121+
for (auto *constraint : Protocols) {
122+
if (constraint->getKind() != ConstraintKind::LiteralConformsTo)
123+
continue;
124+
125+
auto *protocol = constraint->getProtocol();
126+
127+
assert(protocol);
128+
129+
if (coveredLiteralProtocols.count(protocol))
130+
continue;
131+
132+
do {
133+
// If the type conforms to this protocol, we're covered.
134+
if (TypeChecker::conformsToProtocol(type, protocol, cs.DC)) {
135+
coveredLiteralProtocols.insert(protocol);
136+
break;
137+
}
138+
139+
// If we're allowed to bind to subtypes, look through optionals.
140+
// FIXME: This is really crappy special case of computing a reasonable
141+
// result based on the given constraints.
142+
if (binding.Kind == AllowedBindingKind::Subtypes) {
143+
if (auto objTy = type->getOptionalObjectType()) {
144+
requiresUnwrap = true;
145+
type = objTy;
146+
continue;
147+
}
148+
}
149+
150+
requiresUnwrap = false;
151+
break;
152+
} while (true);
153+
}
154+
155+
if (requiresUnwrap)
156+
binding.BindingType = type;
157+
}
158+
159+
for (auto *constraint : Protocols) {
160+
auto *protocol = constraint->getProtocol();
161+
if (coveredLiteralProtocols.count(protocol))
162+
continue;
163+
164+
auto defaultType = TypeChecker::getDefaultType(protocol, cs.DC);
165+
if (!defaultType)
166+
continue;
167+
168+
if (!existingTypes.insert(defaultType->getCanonicalType()).second)
169+
continue;
170+
171+
// We need to figure out whether this is a direct conformance
172+
// requirement or inferred transitive one to identify binding
173+
// kind correctly.
174+
auto *conformingVar = cs.getRepresentative(
175+
constraint->getFirstType()->castTo<TypeVariableType>());
176+
addPotentialBinding({defaultType,
177+
TypeVar == conformingVar
178+
? AllowedBindingKind::Subtypes
179+
: AllowedBindingKind::Supertypes,
180+
constraint});
181+
}
182+
97183
/// Add defaultable constraints.
98184
for (auto *constraint : Defaults) {
99185
Type type = constraint->getSecondType();
@@ -704,50 +790,7 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
704790
// Record constraint where protocol requirement originated
705791
// this is useful to use for the binding later.
706792
result.Protocols.push_back(constraint);
707-
708-
// If there is a default literal type for this protocol, it's a
709-
// potential binding.
710-
auto defaultType = TypeChecker::getDefaultType(constraint->getProtocol(), DC);
711-
if (!defaultType)
712-
continue;
713-
714793
hasNonDependentMemberRelationalConstraints = true;
715-
716-
// Handle unspecialized types directly.
717-
if (!defaultType->hasUnboundGenericType()) {
718-
if (!exactTypes.insert(defaultType->getCanonicalType()).second)
719-
continue;
720-
721-
literalBindings.push_back(
722-
{defaultType, AllowedBindingKind::Subtypes, constraint});
723-
continue;
724-
}
725-
726-
// For generic literal types, check whether we already have a
727-
// specialization of this generic within our list.
728-
// FIXME: This assumes that, e.g., the default literal
729-
// int/float/char/string types are never generic.
730-
auto nominal = defaultType->getAnyNominal();
731-
if (!nominal)
732-
continue;
733-
734-
bool matched = false;
735-
for (auto exactType : exactTypes) {
736-
if (auto exactNominal = exactType->getAnyNominal()) {
737-
// FIXME: Check parents?
738-
if (nominal == exactNominal) {
739-
matched = true;
740-
break;
741-
}
742-
}
743-
}
744-
745-
if (!matched) {
746-
exactTypes.insert(defaultType->getCanonicalType());
747-
literalBindings.push_back(
748-
{defaultType, AllowedBindingKind::Subtypes, constraint});
749-
}
750-
751794
break;
752795
}
753796

@@ -813,80 +856,6 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const {
813856
}
814857
}
815858

816-
// If we have any literal constraints, check whether there is already a
817-
// binding that provides a type that conforms to that literal protocol. In
818-
// such cases, remove the default binding suggestion because the existing
819-
// suggestion is better.
820-
if (!literalBindings.empty()) {
821-
SmallPtrSet<ProtocolDecl *, 5> coveredLiteralProtocols;
822-
for (auto &binding : result.Bindings) {
823-
Type testType;
824-
825-
switch (binding.Kind) {
826-
case AllowedBindingKind::Exact:
827-
testType = binding.BindingType;
828-
break;
829-
830-
case AllowedBindingKind::Subtypes:
831-
case AllowedBindingKind::Supertypes:
832-
testType = binding.BindingType->getRValueType();
833-
break;
834-
}
835-
836-
// Attempting to check conformance of the type variable,
837-
// or unresolved type is invalid since it would result
838-
// in lose of viable literal bindings because that check
839-
// always returns trivial conformance.
840-
if (testType->isTypeVariableOrMember() || testType->is<UnresolvedType>())
841-
continue;
842-
843-
// Check each non-covered literal protocol to determine which ones
844-
// might be covered by non-defaulted bindings.
845-
bool updatedBindingType = false;
846-
for (auto &literalBinding : literalBindings) {
847-
auto *protocol = literalBinding.getDefaultedLiteralProtocol();
848-
849-
assert(protocol);
850-
851-
// Has already been covered by one of the bindings.
852-
if (coveredLiteralProtocols.count(protocol))
853-
continue;
854-
855-
do {
856-
// If the type conforms to this protocol, we're covered.
857-
if (DC->getParentModule()->lookupConformance(testType, protocol)) {
858-
coveredLiteralProtocols.insert(protocol);
859-
break;
860-
}
861-
862-
// If we're allowed to bind to subtypes, look through optionals.
863-
// FIXME: This is really crappy special case of computing a reasonable
864-
// result based on the given constraints.
865-
if (binding.Kind == AllowedBindingKind::Subtypes) {
866-
if (auto objTy = testType->getOptionalObjectType()) {
867-
updatedBindingType = true;
868-
testType = objTy;
869-
continue;
870-
}
871-
}
872-
873-
updatedBindingType = false;
874-
break;
875-
} while (true);
876-
}
877-
878-
if (updatedBindingType)
879-
binding.BindingType = testType;
880-
}
881-
882-
for (auto &literalBinding : literalBindings) {
883-
auto *protocol = literalBinding.getDefaultedLiteralProtocol();
884-
// For any literal type that has been covered, skip them.
885-
if (coveredLiteralProtocols.count(protocol) == 0)
886-
result.addPotentialBinding(std::move(literalBinding));
887-
}
888-
}
889-
890859
// If there were both dependent-member and non-dependent-member relational
891860
// constraints, consider this "fully bound"; we don't want to touch it.
892861
if (hasDependentMemberRelationalConstraints) {

0 commit comments

Comments
 (0)