Skip to content

Commit ef673c7

Browse files
committed
[ConstraintSystem] Handle binding nullability in producer instead of collector
Wrapping bindings into optional type based on presence of an `ExpressibleByNilLiteral` conformance requirement should be done after type variable has been selected for attempting. Otherwise such upfront work would be wasteful since it doesn't affect binding ranking in any way.
1 parent 4e32132 commit ef673c7

File tree

3 files changed

+54
-39
lines changed

3 files changed

+54
-39
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5817,14 +5817,17 @@ class TypeVarBindingProducer : public BindingProducer<TypeVariableBinding> {
58175817
llvm::SmallPtrSet<CanType, 4> ExploredTypes;
58185818
llvm::SmallPtrSet<TypeBase *, 4> BoundTypes;
58195819

5820+
/// Determines whether this type variable has a
5821+
/// `ExpressibleByNilLiteral` requirement which
5822+
/// means that bindings have to either conform
5823+
/// to that protocol or be wrapped in an optional.
5824+
bool CanBeNil;
5825+
58205826
public:
58215827
using Element = TypeVariableBinding;
58225828

58235829
TypeVarBindingProducer(ConstraintSystem &cs,
5824-
ConstraintSystem::PotentialBindings &bindings)
5825-
: BindingProducer(cs, bindings.TypeVar->getImpl().getLocator()),
5826-
TypeVar(bindings.TypeVar),
5827-
Bindings(bindings.Bindings.begin(), bindings.Bindings.end()) {}
5830+
ConstraintSystem::PotentialBindings &bindings);
58285831

58295832
/// Retrieve a set of bindings available in the current state.
58305833
ArrayRef<Binding> getCurrentBindings() const { return Bindings; }

lib/Sema/CSBindings.cpp

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -547,41 +547,6 @@ void ConstraintSystem::PotentialBindings::finalize(
547547
inferTransitiveBindings(cs, existingTypes, inferredBindings);
548548
inferDefaultTypes(cs, existingTypes);
549549

550-
// Adjust optionality of existing bindings based on presence of
551-
// `ExpressibleByNilLiteral` requirement.
552-
if (llvm::any_of(Protocols, [](Constraint *constraint) {
553-
auto *protocol = constraint->getProtocol();
554-
return protocol->isSpecificProtocol(
555-
KnownProtocolKind::ExpressibleByNilLiteral);
556-
})) {
557-
for (auto &binding : Bindings) {
558-
bool wrapInOptional = false;
559-
if (binding.Kind == AllowedBindingKind::Supertypes) {
560-
auto type = binding.BindingType->getRValueType();
561-
// If the type doesn't conform to ExpressibleByNilLiteral,
562-
// produce an optional of that type as a potential binding. We
563-
// overwrite the binding in place because the non-optional type
564-
// will fail to type-check against the nil-literal conformance.
565-
bool conformsToExprByNilLiteral = false;
566-
if (auto *nominalBindingDecl = type->getAnyNominal()) {
567-
SmallVector<ProtocolConformance *, 2> conformances;
568-
conformsToExprByNilLiteral = nominalBindingDecl->lookupConformance(
569-
cs.DC->getParentModule(),
570-
cs.getASTContext().getProtocol(
571-
KnownProtocolKind::ExpressibleByNilLiteral),
572-
conformances);
573-
}
574-
wrapInOptional = !conformsToExprByNilLiteral;
575-
} else if (binding.isDefaultableBinding() &&
576-
binding.BindingType->isAny()) {
577-
wrapInOptional = true;
578-
}
579-
580-
if (wrapInOptional)
581-
binding.BindingType = OptionalType::get(binding.BindingType);
582-
}
583-
}
584-
585550
// If there are no bindings, typeVar may be a hole.
586551
if (cs.shouldAttemptFixes() && Bindings.empty() &&
587552
TypeVar->getImpl().canBindToHole()) {

lib/Sema/ConstraintSystem.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5330,3 +5330,50 @@ bool ConstraintSystem::isReadOnlyKeyPathComponent(
53305330

53315331
return false;
53325332
}
5333+
5334+
TypeVarBindingProducer::TypeVarBindingProducer(
5335+
ConstraintSystem &cs, ConstraintSystem::PotentialBindings &bindings)
5336+
: BindingProducer(cs, bindings.TypeVar->getImpl().getLocator()),
5337+
TypeVar(bindings.TypeVar),
5338+
CanBeNil(llvm::any_of(bindings.Protocols, [](Constraint *constraint) {
5339+
auto *protocol = constraint->getProtocol();
5340+
return protocol->isSpecificProtocol(
5341+
KnownProtocolKind::ExpressibleByNilLiteral);
5342+
})) {
5343+
auto requiresOptionalAdjustment =
5344+
[&cs](const ConstraintSystem::PotentialBinding &binding) {
5345+
if (binding.Kind == BindingKind::Supertypes) {
5346+
auto type = binding.BindingType->getRValueType();
5347+
// If the type doesn't conform to ExpressibleByNilLiteral,
5348+
// produce an optional of that type as a potential binding. We
5349+
// overwrite the binding in place because the non-optional type
5350+
// will fail to type-check against the nil-literal conformance.
5351+
bool conformsToExprByNilLiteral = false;
5352+
if (auto *nominalBindingDecl = type->getAnyNominal()) {
5353+
SmallVector<ProtocolConformance *, 2> conformances;
5354+
conformsToExprByNilLiteral = nominalBindingDecl->lookupConformance(
5355+
cs.DC->getParentModule(),
5356+
cs.getASTContext().getProtocol(
5357+
KnownProtocolKind::ExpressibleByNilLiteral),
5358+
conformances);
5359+
}
5360+
return !conformsToExprByNilLiteral;
5361+
} else if (binding.isDefaultableBinding() &&
5362+
binding.BindingType->isAny()) {
5363+
return true;
5364+
}
5365+
5366+
return false;
5367+
};
5368+
5369+
for (const auto &binding : bindings.Bindings) {
5370+
// Adjust optionality of existing bindings based on presence of
5371+
// `ExpressibleByNilLiteral` requirement.
5372+
if (CanBeNil && requiresOptionalAdjustment(binding)) {
5373+
Bindings.push_back(
5374+
binding.withType(OptionalType::get(binding.BindingType)));
5375+
} else {
5376+
Bindings.push_back(binding);
5377+
}
5378+
}
5379+
}

0 commit comments

Comments
 (0)